X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Przemyslaw Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: philipk@HIDDEN, bug-gnu-emacs@HIDDEN
Resent-Date: Thu, 07 Aug 2025 11:35:02 +0000
Resent-Message-ID: <handler.79188.B.17545664458580 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: report 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords:
To: 79188 <at> debbugs.gnu.org
Cc: Philip Kaludercic <philipk@HIDDEN>
X-Debbugs-Original-To: bug-gnu-emacs@HIDDEN
X-Debbugs-Original-Xcc: Philip Kaludercic <philipk@HIDDEN>
Received: via spool by submit <at> debbugs.gnu.org id=B.17545664458580
(code B ref -1); Thu, 07 Aug 2025 11:35:02 +0000
Received: (at submit) by debbugs.gnu.org; 7 Aug 2025 11:34:05 +0000
Received: from localhost ([127.0.0.1]:33849 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1ujysm-0002EI-Sb
for submit <at> debbugs.gnu.org; Thu, 07 Aug 2025 07:34:05 -0400
Received: from lists.gnu.org ([2001:470:142::17]:42316)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1ujysk-0002Dc-S7
for submit <at> debbugs.gnu.org; Thu, 07 Aug 2025 07:34:03 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10])
by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.90_1) (envelope-from <pkryger@HIDDEN>) id 1ujysa-0007WK-Mi
for bug-gnu-emacs@HIDDEN; Thu, 07 Aug 2025 07:33:55 -0400
Received: from mail-wm1-x32f.google.com ([2a00:1450:4864:20::32f])
by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.90_1) (envelope-from <pkryger@HIDDEN>) id 1ujysW-0007qp-Mu
for bug-gnu-emacs@HIDDEN; Thu, 07 Aug 2025 07:33:51 -0400
Received: by mail-wm1-x32f.google.com with SMTP id
5b1f17b1804b1-459d62184c9so5663865e9.1
for <bug-gnu-emacs@HIDDEN>; Thu, 07 Aug 2025 04:33:47 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1754566426; x=1755171226; darn=gnu.org;
h=mime-version:message-id:date:subject:to:from:from:to:cc:subject
:date:message-id:reply-to;
bh=SL9tP2R0BjZ7TeEKpinYo5S9siboij0lwOHCGWJG7g0=;
b=OTCCsCILlwqE8y18losbzhBWyFisFYVPc9BSnbeQyfWhT4ztz1X5vFdFNYnrOaK2UR
A32lQs8pY6oL4RzNkJ3Q3aQJ6kLNNU37biKkUwaBzh5uLiQfagcSJ4wMqQRcXKV7TKiS
EA9WL5oRfvjfF1rSyUGDpoeIXmwq3ENkY6MYRxLFbqkNLGGhMyUCeBPB9OtugKfHALwN
lEaTrzlVzbCRvqFyxSR/HB2ayq4sBBYffgHYas6QlItJ5CihUDvhO6vuBndIiw6mjc7c
Gxvl+tNSWgnZ1k0DAcpkOcdBQ47LYIXj6dLvHpGjTpLgMvqjGA8jXu+nVHEqp4es5l/u
ImqA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1754566426; x=1755171226;
h=mime-version:message-id:date:subject:to:from:x-gm-message-state
:from:to:cc:subject:date:message-id:reply-to;
bh=SL9tP2R0BjZ7TeEKpinYo5S9siboij0lwOHCGWJG7g0=;
b=FdA4FTtRupia3Gx0MISp/FecO2rjLAV3NhnZNKYgnT5K3vnMO/vtCr4sMuHXHhgWb1
4c3DCgnHwtcBeSZmxE8l2hLheGh65im3uLztmQ2Cm2cVsIVhzCfRi3TLmL1QhI+qSSwT
/KghCM/6E+IipKK4HR0Z8caeEXyWEXhrePprS0J/R3U4mkUCtbC1r8695OfyrUonGSlo
y89+qxjoE4QI77lytTPNl4RI5C1aeuKaeISN8pQIYYWnLOJKxaHL+9cDKc87gkCntcuW
GQ3CDZjnx22XGDHOL7GOzkHT4Tb/bXfHJmClHaLaeM7J+1k7GVLV2y07JHuaVEDJkqq9
iynQ==
X-Gm-Message-State: AOJu0YwkuvagC4+/QvCgGQ2XtpBCv4bonE9FOlbIBcMuCaMhvLVP0bzU
a5YBp/wHHAy8kHfAD8sUmNTcRRv4cXp0WcJDo3ohJx3isRFEyF+fCfnPPbpkiQ==
X-Gm-Gg: ASbGncthvgjMOtktH1e/yu0iu6INXDUE2j4t222a05M64XBR24AZ5I52AeX9qBAaKfc
Kx8npQH5LA+GYMpsm7X50ZwG8yfIg+UoItxrdlso6wxW8q4kzMKSKnFu0dBgWTgcSYcM4NrxLyF
tGyjkr+BxDwYzeI6/zaUIllDC8r/3rDOt1RfwEX+MwiJVqOMLJQzbi43kjJYSnJDu+m+liq3F8X
pum5JNDwGmQGTY8HeRPkyA9Iuk5zrtFwWuvBcevky13uh4ZdoqrwERad/t9G6SUiY4afv1hbWG/
JdNox/+J3WZf1EbjGOGL5XL5quysBEUsv13X85b3cOvR8Grrd9bXOuqHha0CXxx3MekHTPs1SDn
4YnkvmF5WiPfDWAozt4rHFdXtmsXLcz3J/sF/u+xwnEv/2/OQUK1qn0JIY+yhgGw=
X-Google-Smtp-Source: AGHT+IGOBUIT3i5F07Z0HqRXP4m7g3PdTVBMi6XEUf6qeOOId3X7ndTsbcKtfYuTkqB6TqLntW8/KQ==
X-Received: by 2002:a05:600c:4ece:b0:458:a559:a693 with SMTP id
5b1f17b1804b1-459e70d9e6cmr63833075e9.18.1754566425914;
Thu, 07 Aug 2025 04:33:45 -0700 (PDT)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:1c7a:76b8:c20f:aea9])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-459e0e70218sm118594055e9.20.2025.08.07.04.33.45
for <bug-gnu-emacs@HIDDEN>
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Thu, 07 Aug 2025 04:33:45 -0700 (PDT)
From: Przemyslaw Kryger <pkryger@HIDDEN>
Date: Thu, 07 Aug 2025 12:33:44 +0100
Message-ID: <m2ectn9xif.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain
Received-SPF: pass client-ip=2a00:1450:4864:20::32f;
envelope-from=pkryger@HIDDEN; helo=mail-wm1-x32f.google.com
X-Spam_score_int: -20
X-Spam_score: -2.1
X-Spam_bar: --
X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001,
RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
SPF_PASS=-0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-Spam-Score: 1.0 (+)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -0.0 (/)
I am using package-vc to manage a few pakcages I maintain. However, in Emacs
31 I observed a couple issues.
The first discrepancy with what used to happen on Emacs 30 is when a package is
installed from a custom location, no *.elc files are produced. I don't know
what the expected behaviour should be here.
In addition to that when I attempt to rebuild such a package with
package-vc-rebuild it signals an error, which I believe shouldn't happen,
should it? In this case no *.elc files have been produced nor updated. Such a
workflow used to work on Emacs 30.
I observed this on a Emacs macport (from
https://github.com/jdtsmith/emacs-mac/tree/emacs-mac-gnu_master_exp), but the
issue is reproducible on master (68aaeb3519fd7f6176050e142f0dbc27e07992d2) as
well.
git clone https://github.com/pkryger/helm-projectile "${HOME}/tmp/helm-projectile"
emacs -Q
(require 'package)
(add-to-list 'package-archives '(melpa . "https://melpa.org/packages/"))
;; Just to avoid using existing elpa
(setq package-user-dir (expand-file-name "tmp/elpa" (getenv "HOME")))
(package-refresh-contents)
;; In my config I use hardcoded paths, but `use-package' needs a
;; string for `:load-path', so just for this sample
(let ((pkg-dir (expand-file-name "tmp/helm-projectile" (getenv "HOME"))))
(eval
`(use-package helm-projectile
:vc t
:load-path ,pkg-dir)))
;; At this point `helm-projectile' has been installed, but no *.elc files are
;; produced, which differs from Emacs 30.
(setq debug-on-error t)
M-x package-vc-rebuild RET helm-projectile RET
Which yields the following:
Debugger entered--Lisp error: (wrong-type-argument stringp nil)
expand-file-name(nil)
vc-file-getprop(nil vc-working-revision)
vc-working-revision(nil)
package-vc--unpack-1(#s(package-desc :name helm-projectile :version (1 3 1) :summary "Helm integration for Projectile" :reqs nil :kind vc :archive nil :dir "/Users/pkryger/tmp/elpa/helm-projectile/" :extras ((:commit . "2ecd3d85b7077f39bb2fefe2227cc46931d4b92b")) :signed nil) "/Users/pkryger/tmp/elpa/helm-projectile/")
package-vc-rebuild(#s(package-desc :name helm-projectile :version (1 3 1) :summary "Helm integration for Projectile" :reqs nil :kind vc :archive nil :dir "/Users/pkryger/tmp/elpa/helm-projectile/" :extras ((:commit . "2ecd3d85b7077f39bb2fefe2227cc46931d4b92b")) :signed nil))
funcall-interactively(package-vc-rebuild #s(package-desc :name helm-projectile :version (1 3 1) :summary "Helm integration for Projectile" :reqs nil :kind vc :archive nil :dir "/Users/pkryger/tmp/elpa/helm-projectile/" :extras ((:commit . "2ecd3d85b7077f39bb2fefe2227cc46931d4b92b")) :signed nil))
call-interactively(package-vc-rebuild record nil)
command-execute(package-vc-rebuild record)
execute-extended-command(nil "package-vc-rebuild" "pack-v-re")
funcall-interactively(execute-extended-command nil "package-vc-rebuild" "pack-v-re")
call-interactively(execute-extended-command nil nil)
command-execute(execute-extended-command)
Could these be introduced by 4226eb2b20408ba49787195bbc59bb0066c9c9e4?
In GNU Emacs 31.0.50 (build 1, aarch64-apple-darwin24.5.0, X toolkit,
cairo version 1.18.4, Xaw3d scroll bars) of 2025-08-07 built on
Przemyslaws-MacBook-Air.local
Repository revision: 68aaeb3519fd7f6176050e142f0dbc27e07992d2
Repository branch: master
System Description: macOS 15.5
Configured using:
'configure --without-ns --with-gnutls --with-modules
--with-native-compilation=no --with-jpeg=ifavailable
--with-gif=ifavailable --with-tiff=ifavailable CFLAGS=-O3'
Configured features:
ACL CAIRO FREETYPE GLIB GNUTLS GSETTINGS HARFBUZZ LCMS2 LIBXML2 MODULES
NOTIFY KQUEUE PDUMPER PNG RSVG SQLITE3 THREADS TOOLKIT_SCROLL_BARS
TREE_SITTER WEBP X11 XAW3D XDBE XIM XINERAMA XPM XRANDR LUCID ZLIB
Important settings:
value of $LANG: en_GB.UTF-8
locale-coding-system: utf-8-unix
Major mode: Lisp Interaction
Minor modes in effect:
xterm-mouse-mode: t
tooltip-mode: t
global-eldoc-mode: t
eldoc-mode: t
show-paren-mode: t
electric-indent-mode: t
mouse-wheel-mode: t
tool-bar-mode: t
menu-bar-mode: t
file-name-shadow-mode: t
global-font-lock-mode: t
font-lock-mode: t
blink-cursor-mode: t
minibuffer-regexp-mode: t
line-number-mode: t
indent-tabs-mode: t
transient-mark-mode: t
auto-composition-mode: t
auto-encryption-mode: t
auto-compression-mode: t
Load-path shadows:
/Users/pkryger/tmp/elpa/helm-4.0.4/helm-packages hides /Users/pkryger/tmp/elpa/helm-core-4.0.4/helm-packages
/Users/pkryger/tmp/elpa/helm-4.0.4/helm-x-icons hides /Users/pkryger/tmp/elpa/helm-core-4.0.4/helm-x-icons
Features:
(shadow sort mail-extr emacsbug use-package-ensure help-fns cl-print
debug backtrace find-func helm-projectile projectile helm-files
image-dired image-dired-tags image-dired-external image-dired-util
image-mode exif filenotify dired-x ffap tramp rx trampver
tramp-integration tramp-message tramp-compat shell pcomplete parse-time
iso8601 tramp-loaddefs helm-tags helm-buffers helm-x-icons helm-occur
helm-grep helm-regexp format-spec helm-utils helm-locate helm-help helm
helm-types helm-global-bindings helm-easymenu edmacro kmacro helm-core
helm-source helm-multi-match helm-lib cus-edit pp cus-start cus-load
wid-edit helm-projectile-autoloads helm-autoloads helm-core-autoloads
vc-git diff-mode track-changes files-x wfnames-autoloads smtpmail
dired-async dired-aux async-bytecomp async bug-reference async-autoloads
project skeleton ibuf-macs pcase find-dired grep ibuf-ext ibuffer
ibuffer-loaddefs thingatpt compile comint ansi-osc ansi-color ring
projectile-autoloads easy-mmode loaddefs-gen radix-tree tar-mode
arc-mode archive-mode package-vc vc vc-dispatcher lisp-mnt cl-extra
help-mode use-package-core finder-inf mm-archive message sendmail
yank-media dired dired-loaddefs rfc822 mml mml-sec epa derived gnus-util
text-property-search mailabbrev gmm-utils mailheader mm-decode mm-bodies
mm-encode mail-utils gnutls network-stream url-cache warnings url-http
url-auth mail-parse rfc2231 rfc2047 rfc2045 mm-util ietf-drums
mail-prsvr url-gw nsm puny epg rfc6068 epg-config package browse-url xdg
url url-proxy url-privacy url-expand url-methods url-history url-cookie
generate-lisp-file url-domsuf url-util mailcap url-handlers url-parse
auth-source cl-seq eieio eieio-core cl-macs icons password-cache json
map url-vars time-date subr-x cl-loaddefs cl-lib xt-mouse term/xterm
xterm byte-opt gv bytecomp byte-compile rmc iso-transl tooltip cconv
eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type
elisp-mode mwheel term/x-win x-win term/common-win x-dnd touch-screen
tool-bar dnd fontset image regexp-opt fringe tabulated-list replace
newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar
rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock
font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq
simple cl-generic indonesian philippine cham georgian utf-8-lang
misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms
cp51932 hebrew greek romanian slovak czech european ethiopic indian
cyrillic chinese composite emoji-zwj charscript charprop case-table
epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button
loaddefs theme-loaddefs faces cus-face macroexp files window
text-properties overlay sha1 md5 base64 format env code-pages mule
custom widget keymap hashtable-print-readable backquote threads kqueue
lcms2 dynamic-setting system-font-setting font-render-setting cairo
x-toolkit x multi-tty move-toolbar make-network-process tty-child-frames
emacs)
Memory information:
((conses 16 349318 58285) (symbols 48 22829 1) (strings 32 68024 3090)
(string-bytes 1 2006739) (vectors 16 34746)
(vector-slots 8 661887 21587) (floats 8 132 421)
(intervals 56 1420 25) (buffers 1064 20))
Content-Disposition: inline Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Mailer: MIME-tools 5.505 (Entity 5.505) Content-Type: text/plain; charset=utf-8 X-Loop: help-debbugs@HIDDEN From: help-debbugs@HIDDEN (GNU bug Tracking System) To: Przemyslaw Kryger <pkryger@HIDDEN> Subject: bug#79188: Acknowledgement (31.0.50; Cannot build packages installed from VC) Message-ID: <handler.79188.B.17545664458580.ack <at> debbugs.gnu.org> References: <m2ectn9xif.fsf@HIDDEN> X-Gnu-PR-Message: ack 79188 X-Gnu-PR-Package: emacs Reply-To: 79188 <at> debbugs.gnu.org Date: Thu, 07 Aug 2025 11:35:02 +0000 Thank you for filing a new bug report with debbugs.gnu.org. This is an automatically generated reply to let you know your message has been received. Your message is being forwarded to the package maintainers and other interested parties for their attention; they will reply in due course. As you requested using X-Debbugs-CC, your message was also forwarded to Philip Kaludercic <philipk@HIDDEN> (after having been given a bug report number, if it did not have one). Your message has been sent to the package maintainer(s): bug-gnu-emacs@HIDDEN If you wish to submit further information on this problem, please send it to 79188 <at> debbugs.gnu.org. Please do not send mail to help-debbugs@HIDDEN unless you wish to report a problem with the Bug-tracking system. --=20 79188: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D79188 GNU Bug Tracking System Contact help-debbugs@HIDDEN with problems
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Thu, 07 Aug 2025 12:56:02 +0000
Resent-Message-ID: <handler.79188.B79188.175457135523870 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords:
To: Przemyslaw Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.175457135523870
(code B ref 79188); Thu, 07 Aug 2025 12:56:02 +0000
Received: (at 79188) by debbugs.gnu.org; 7 Aug 2025 12:55:55 +0000
Received: from localhost ([127.0.0.1]:34010 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1uk09y-0006Cs-3z
for submit <at> debbugs.gnu.org; Thu, 07 Aug 2025 08:55:55 -0400
Received: from mout01.posteo.de ([185.67.36.65]:55601)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1uk09v-0006CX-2D
for 79188 <at> debbugs.gnu.org; Thu, 07 Aug 2025 08:55:52 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout01.posteo.de (Postfix) with ESMTPS id 77CFD240027
for <79188 <at> debbugs.gnu.org>; Thu, 7 Aug 2025 14:55:44 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net;
s=1984.ea087b; t=1754571344;
bh=Bz/AmoCwUG2eK15/vp/qodAT60wY6JhiY9im7rGh9fQ=;
h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type:
From;
b=infYiHWx1tCpQngh7Zke+BmO4U9zXtPYIyvckVv+PpFeJilQRHcvnS5hsRegz/Csu
s77uhtohW3bRTcZoSIWmCOhfnqD5dVOqqC3pz0KKRKbmwwwSzXzwHysPQETutYzESI
hREoXEas2/LF5lv52LZmKlW3fHr0f7cb0+ZpR0V1oD16UqZwlIrxEznwbo53WfuXq/
KUMqeSAD1QqJXpMVjVBnWT2z8R2U8y+9htftFkxEZVa76Yyrq+hRrNMZtJZp+G3JH5
fVlAyHdX7/SNEG2x7zu0CwMK4e6bHwmWdMWc5n7KgDLSO25suhHp8NViy9cDm8UaN7
uC+UaFcfCFVtHi3KMshlN+trYEYgzl2N5yj9Zi3YaHFHqs0QTP/3jERcq3jFxBM3PE
r7GvQQ8O5fCbSvU8iS0h1mmc6bzcXQcEe8CC15GbJbg3z+gty75ow+QhtpqtFe5Z4T
aIbyq7D4EvJt9WfgvplRbHPGnNESYGnYpcVCsckVJUFf4uPH9yd
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4byRwb4hLrz9rxK;
Thu, 7 Aug 2025 14:55:43 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2ectn9xif.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
Date: Thu, 07 Aug 2025 12:55:43 +0000
Message-ID: <87jz3f2svk.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
--=-=-=
Content-Type: text/plain
Przemyslaw Kryger <pkryger@HIDDEN> writes:
> I am using package-vc to manage a few pakcages I maintain. However, in Emacs
> 31 I observed a couple issues.
>
> The first discrepancy with what used to happen on Emacs 30 is when a package is
> installed from a custom location, no *.elc files are produced. I don't know
> what the expected behaviour should be here.
>
> In addition to that when I attempt to rebuild such a package with
> package-vc-rebuild it signals an error, which I believe shouldn't happen,
> should it? In this case no *.elc files have been produced nor updated. Such a
> workflow used to work on Emacs 30.
Both of these shouldn't happen.
> I observed this on a Emacs macport (from
> https://github.com/jdtsmith/emacs-mac/tree/emacs-mac-gnu_master_exp), but the
> issue is reproducible on master (68aaeb3519fd7f6176050e142f0dbc27e07992d2) as
> well.
>
> git clone https://github.com/pkryger/helm-projectile "${HOME}/tmp/helm-projectile"
> emacs -Q
>
> (require 'package)
> (add-to-list 'package-archives '(melpa . "https://melpa.org/packages/"))
^
this should be a string!
> ;; Just to avoid using existing elpa
> (setq package-user-dir (expand-file-name "tmp/elpa" (getenv "HOME")))
(Unrelated, but is there a reason you aren't doing (expand-file-name
"~/tmp/elpa")?)
> (package-refresh-contents)
> ;; In my config I use hardcoded paths, but `use-package' needs a
> ;; string for `:load-path', so just for this sample
> (let ((pkg-dir (expand-file-name "tmp/helm-projectile" (getenv "HOME"))))
> (eval
> `(use-package helm-projectile
> :vc t
> :load-path ,pkg-dir)))
For posterity, this expands to
--8<---------------cut here---------------start------------->8---
(progn
(eval-and-compile (add-to-list 'load-path "/tmp/helm-projectile/"))
(use-package-vc-install '(helm-projectile) "/tmp/helm-projectile/")
(defvar use-package--warning0
#'(lambda (keyword err)
(let
((msg
(format "%s/%s: %s" 'helm-projectile keyword
(error-message-string err))))
(display-warning 'use-package msg :error))))
(condition-case-unless-debug err
(if (not (require 'helm-projectile nil t))
(display-warning 'use-package
(format "Cannot load %s" 'helm-projectile)
:error))
(error (funcall use-package--warning0 :catch err))))
--8<---------------cut here---------------end--------------->8---
which for us means that we are interested in
(use-package-vc-install '(helm-projectile) "/tmp/helm-projectile/")
which in turn would invoke
(package-vc-install-from-checkout "/tmp/helm-projectile/" "helm-projectile")
>
> ;; At this point `helm-projectile' has been installed, but no *.elc files are
> ;; produced, which differs from Emacs 30.
>
> (setq debug-on-error t)
> M-x package-vc-rebuild RET helm-projectile RET
>
> Which yields the following:
>
> Debugger entered--Lisp error: (wrong-type-argument stringp nil)
> expand-file-name(nil)
> vc-file-getprop(nil vc-working-revision)
> vc-working-revision(nil)
> package-vc--unpack-1(#s(package-desc :name helm-projectile :version (1 3 1) :summary "Helm integration for Projectile" :reqs nil :kind vc :archive nil :dir "/Users/pkryger/tmp/elpa/helm-projectile/" :extras ((:commit . "2ecd3d85b7077f39bb2fefe2227cc46931d4b92b")) :signed nil) "/Users/pkryger/tmp/elpa/helm-projectile/")
> package-vc-rebuild(#s(package-desc :name helm-projectile :version (1 3 1) :summary "Helm integration for Projectile" :reqs nil :kind vc :archive nil :dir "/Users/pkryger/tmp/elpa/helm-projectile/" :extras ((:commit . "2ecd3d85b7077f39bb2fefe2227cc46931d4b92b")) :signed nil))
> funcall-interactively(package-vc-rebuild #s(package-desc :name helm-projectile :version (1 3 1) :summary "Helm integration for Projectile" :reqs nil :kind vc :archive nil :dir "/Users/pkryger/tmp/elpa/helm-projectile/" :extras ((:commit . "2ecd3d85b7077f39bb2fefe2227cc46931d4b92b")) :signed nil))
> call-interactively(package-vc-rebuild record nil)
> command-execute(package-vc-rebuild record)
> execute-extended-command(nil "package-vc-rebuild" "pack-v-re")
> funcall-interactively(execute-extended-command nil "package-vc-rebuild" "pack-v-re")
> call-interactively(execute-extended-command nil nil)
> command-execute(execute-extended-command)
I couldn't reproduce this stack trace :/ It seems like
`package-vc--main-file' returned nil. Can you check what the function
returns, perhaps using edebug?
> Could these be introduced by 4226eb2b20408ba49787195bbc59bb0066c9c9e4?
That seems reasonable, but in that case we should be able to reproduce
the issue with a more simple example (especially one that doesn't involve
use-package, MELPA and missing dependencies). I tried it out with a
local package I had lying around and I also noticed that we don't
byte-compile files anymore!
This should fix the first issue, but it probably won't change anything
about the latter:
--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline
diff --git a/lisp/package/package-vc.el b/lisp/package/package-vc.el
index db12c76133e..f2c7c460f6d 100644
--- a/lisp/package/package-vc.el
+++ b/lisp/package/package-vc.el
@@ -549,7 +549,14 @@ package-vc--unpack-1
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
- (package--compile new-desc)
+ (package--compile
+ (if lisp-dir
+ ;; In case we are installing a package from a local
+ ;; checkout, we want to compile the checkout, not the
+ ;; redirection!
+ (package-desc-create :dir lisp-dir)
+ new-desc))
+
(when package-native-compile
(package--native-compile-async new-desc))
;; After compilation, load again any files loaded by
--=-=-=
Content-Type: text/plain
>
> In GNU Emacs 31.0.50 (build 1, aarch64-apple-darwin24.5.0, X toolkit,
> cairo version 1.18.4, Xaw3d scroll bars) of 2025-08-07 built on
> Przemyslaws-MacBook-Air.local
> Repository revision: 68aaeb3519fd7f6176050e142f0dbc27e07992d2
> Repository branch: master
> System Description: macOS 15.5
>
> Configured using:
> 'configure --without-ns --with-gnutls --with-modules
> --with-native-compilation=no --with-jpeg=ifavailable
> --with-gif=ifavailable --with-tiff=ifavailable CFLAGS=-O3'
>
> Configured features:
> ACL CAIRO FREETYPE GLIB GNUTLS GSETTINGS HARFBUZZ LCMS2 LIBXML2 MODULES
> NOTIFY KQUEUE PDUMPER PNG RSVG SQLITE3 THREADS TOOLKIT_SCROLL_BARS
> TREE_SITTER WEBP X11 XAW3D XDBE XIM XINERAMA XPM XRANDR LUCID ZLIB
>
> Important settings:
> value of $LANG: en_GB.UTF-8
> locale-coding-system: utf-8-unix
>
> Major mode: Lisp Interaction
>
> Minor modes in effect:
> xterm-mouse-mode: t
> tooltip-mode: t
> global-eldoc-mode: t
> eldoc-mode: t
> show-paren-mode: t
> electric-indent-mode: t
> mouse-wheel-mode: t
> tool-bar-mode: t
> menu-bar-mode: t
> file-name-shadow-mode: t
> global-font-lock-mode: t
> font-lock-mode: t
> blink-cursor-mode: t
> minibuffer-regexp-mode: t
> line-number-mode: t
> indent-tabs-mode: t
> transient-mark-mode: t
> auto-composition-mode: t
> auto-encryption-mode: t
> auto-compression-mode: t
>
> Load-path shadows:
> /Users/pkryger/tmp/elpa/helm-4.0.4/helm-packages hides /Users/pkryger/tmp/elpa/helm-core-4.0.4/helm-packages
> /Users/pkryger/tmp/elpa/helm-4.0.4/helm-x-icons hides /Users/pkryger/tmp/elpa/helm-core-4.0.4/helm-x-icons
>
> Features:
> (shadow sort mail-extr emacsbug use-package-ensure help-fns cl-print
> debug backtrace find-func helm-projectile projectile helm-files
> image-dired image-dired-tags image-dired-external image-dired-util
> image-mode exif filenotify dired-x ffap tramp rx trampver
> tramp-integration tramp-message tramp-compat shell pcomplete parse-time
> iso8601 tramp-loaddefs helm-tags helm-buffers helm-x-icons helm-occur
> helm-grep helm-regexp format-spec helm-utils helm-locate helm-help helm
> helm-types helm-global-bindings helm-easymenu edmacro kmacro helm-core
> helm-source helm-multi-match helm-lib cus-edit pp cus-start cus-load
> wid-edit helm-projectile-autoloads helm-autoloads helm-core-autoloads
> vc-git diff-mode track-changes files-x wfnames-autoloads smtpmail
> dired-async dired-aux async-bytecomp async bug-reference async-autoloads
> project skeleton ibuf-macs pcase find-dired grep ibuf-ext ibuffer
> ibuffer-loaddefs thingatpt compile comint ansi-osc ansi-color ring
> projectile-autoloads easy-mmode loaddefs-gen radix-tree tar-mode
> arc-mode archive-mode package-vc vc vc-dispatcher lisp-mnt cl-extra
> help-mode use-package-core finder-inf mm-archive message sendmail
> yank-media dired dired-loaddefs rfc822 mml mml-sec epa derived gnus-util
> text-property-search mailabbrev gmm-utils mailheader mm-decode mm-bodies
> mm-encode mail-utils gnutls network-stream url-cache warnings url-http
> url-auth mail-parse rfc2231 rfc2047 rfc2045 mm-util ietf-drums
> mail-prsvr url-gw nsm puny epg rfc6068 epg-config package browse-url xdg
> url url-proxy url-privacy url-expand url-methods url-history url-cookie
> generate-lisp-file url-domsuf url-util mailcap url-handlers url-parse
> auth-source cl-seq eieio eieio-core cl-macs icons password-cache json
> map url-vars time-date subr-x cl-loaddefs cl-lib xt-mouse term/xterm
> xterm byte-opt gv bytecomp byte-compile rmc iso-transl tooltip cconv
> eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type
> elisp-mode mwheel term/x-win x-win term/common-win x-dnd touch-screen
> tool-bar dnd fontset image regexp-opt fringe tabulated-list replace
> newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar
> rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock
> font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq
> simple cl-generic indonesian philippine cham georgian utf-8-lang
> misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms
> cp51932 hebrew greek romanian slovak czech european ethiopic indian
> cyrillic chinese composite emoji-zwj charscript charprop case-table
> epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button
> loaddefs theme-loaddefs faces cus-face macroexp files window
> text-properties overlay sha1 md5 base64 format env code-pages mule
> custom widget keymap hashtable-print-readable backquote threads kqueue
> lcms2 dynamic-setting system-font-setting font-render-setting cairo
> x-toolkit x multi-tty move-toolbar make-network-process tty-child-frames
> emacs)
>
> Memory information:
> ((conses 16 349318 58285) (symbols 48 22829 1) (strings 32 68024 3090)
> (string-bytes 1 2006739) (vectors 16 34746)
> (vector-slots 8 661887 21587) (floats 8 132 421)
> (intervals 56 1420 25) (buffers 1064 20))
>
>
--
Philip Kaludercic
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: Fwd: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Thu, 07 Aug 2025 16:54:01 +0000
Resent-Message-ID: <handler.79188.B79188.17545856015603 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords:
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17545856015603
(code B ref 79188); Thu, 07 Aug 2025 16:54:01 +0000
Received: (at 79188) by debbugs.gnu.org; 7 Aug 2025 16:53:21 +0000
Received: from localhost ([127.0.0.1]:35718 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1uk3rk-0001SJ-R0
for submit <at> debbugs.gnu.org; Thu, 07 Aug 2025 12:53:21 -0400
Received: from mail-pj1-x1036.google.com ([2607:f8b0:4864:20::1036]:55663)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1uk3rh-0001Rz-Ft
for 79188 <at> debbugs.gnu.org; Thu, 07 Aug 2025 12:53:18 -0400
Received: by mail-pj1-x1036.google.com with SMTP id
98e67ed59e1d1-3214762071bso1522523a91.3
for <79188 <at> debbugs.gnu.org>; Thu, 07 Aug 2025 09:53:17 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1754585591; x=1755190391; darn=debbugs.gnu.org;
h=content-transfer-encoding:cc:subject:message-id:date:from
:in-reply-to:references:mime-version:from:to:cc:subject:date
:message-id:reply-to;
bh=4C6CwUQ8WPrNCJE1oMOd+L11AcyE8reQkwVcHGaKb8I=;
b=h67uALqfZ5YekZ+iU56sCWWEG77BufommcGPmLMIz0XsFnTpt3cNC8aalVnkZ/USdW
yCKHBeZW7WkGXTvs5bQWGUzbYb6z3EqyV0z9sjWoS3sztf6zG96EgMOIDlPPCd5v4kf7
rasF027djjpTAyIr+zi0WLgz9fcwUIUr+zOsWhK6q2PlMnTQgzQesJ8hhXO0cwl2zd9O
ccn9tt+wC5J+uccjO0l+Vx+c5lbkaZYVYxYilwfqY25tIrHGn8Q1lR02Ba0um6KaexlG
m7Y/W0q1johpV2rTDoFd5QY32bcFkcNhV6ZLao5PoYvptpdvWiJWWY+wsmCahMdxx/RW
q6kQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1754585591; x=1755190391;
h=content-transfer-encoding:cc:subject:message-id:date:from
:in-reply-to:references:mime-version:x-gm-message-state:from:to:cc
:subject:date:message-id:reply-to;
bh=4C6CwUQ8WPrNCJE1oMOd+L11AcyE8reQkwVcHGaKb8I=;
b=Xz1xQBQ8loWHY5okQwqJj1zBHY9hdtF0uQEjT/F4PqaVJ4zkLWidEn+3t2+X+MpNC0
e5JmXaMbzE88XuWyJJ1JYXh+NhPakpn0ClwUiasScknsy8iKRAm40UYUMuXhcHP5VvB7
69TrHbqTnXp1E+79eIZsRm8LDEpJMjBddqulH2z9rgOEGniA512u1CiH02XDvjcw+eAx
21skxsJDRHVKbz05DqiLKKS5nkGNWqJ+aSJ0bJjTcwP+Bq2AbUyJbNkam0d6E2fX82o1
8spwzrEwXE0sDua5HWmqskC9zqGwdQ82aDLdA6Ca6bQDQuZwR6VWZt9VBCRUhE/VoXby
RIOQ==
X-Gm-Message-State: AOJu0YyIy30DX8Y9JJb0xPRmkvwY9cxEKJIO4/xf8XnT7XHDh848exXT
peTBldZNga0YYUs9IPRxfcN1gkhvacAQc4eosQao1pryDCY5QOYEl4cxAhZI15RN5sSNUUmARFM
D3aYgn+zQb0w6XPPAYmg1pM1gaZKs3GEo9g==
X-Gm-Gg: ASbGncvJvk8FADQzjpMiqrGdalOGdvSDcMAxJl4apUV3VYHpqjAZdSWedAQ084T7XfL
KP9HIwmWFyvt+oNuIxGofZAQ/aNZKMXrZE1oOYTLnUZQ19snYwlaIpAaEtOT3eK/EutYywXO3hB
wU6kDeJe9vnk/c31oGgB86bSPrL3YFPIOtZIunz1hy481e4YMk5MhlmiJIt9ks+ROOdKUMzMI+y
yy9+S6W01s974Cd8c4vj41ZkX3DP+aut52RcRQRX740O/3HAuA=
X-Google-Smtp-Source: AGHT+IE3ZzNnk/ikvriWlm9i2gA9Un0YQ35IXyUkVUV6bXF77Vf+D5ADt7LDhvseAi0CTfvWDSeXlI0esatLn3bwJGQ=
X-Received: by 2002:a17:90b:3c4b:b0:31e:ff94:3fa0 with SMTP id
98e67ed59e1d1-32166c10291mr9505743a91.6.1754585590965; Thu, 07 Aug 2025
09:53:10 -0700 (PDT)
MIME-Version: 1.0
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
In-Reply-To: <m2cy97w04t.fsf@HIDDEN>
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Date: Thu, 7 Aug 2025 17:53:00 +0100
X-Gm-Features: Ac12FXykuCtVBaEfHQF2gbNoLSxWChl1jE_gmkr01oNSOi5YpMM5NP-bwJXwj5M
Message-ID: <CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 3.4 (+++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
has NOT identified this incoming email as spam. The original
message has been attached to this so you can view it or label
similar future email. If you have any questions, see
the administrator of that system for details.
Content preview: Forwarding - missed the debbugs Forwarded message ---------
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger Date: Thu, 7 Aug 2025 at 17:46 Subject: Re: bug#79188:
31.0.50; Cannot build packages installed from V [...]
Content analysis details: (3.4 points, 10.0 required)
pts rule name description
---- ---------------------- --------------------------------------------------
0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record
-0.0 SPF_PASS SPF: sender matches SPF record
1.2 MISSING_HEADERS Missing To: header
0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail
provider (pkryger[at]gmail.com)
-0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/,
no trust
[2607:f8b0:4864:20:0:0:0:1036 listed in]
[list.dnswl.org]
2.2 MALFORMED_FREEMAIL Bad headers on message from free email
service
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 2.4 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
has NOT identified this incoming email as spam. The original
message has been attached to this so you can view it or label
similar future email. If you have any questions, see
the administrator of that system for details.
Content preview: Forwarding - missed the debbugs Forwarded message ---------
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger Date: Thu, 7 Aug 2025 at 17:46 Subject: Re: bug#79188:
31.0.50; Cannot build packages installed from V [...]
Content analysis details: (2.4 points, 10.0 required)
pts rule name description
---- ---------------------- --------------------------------------------------
-0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/,
no trust
[2607:f8b0:4864:20:0:0:0:1036 listed in]
[list.dnswl.org]
0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record
-0.0 SPF_PASS SPF: sender matches SPF record
1.2 MISSING_HEADERS Missing To: header
0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail
provider (pkryger[at]gmail.com)
2.2 MALFORMED_FREEMAIL Bad headers on message from free email
service
-1.0 MAILING_LIST_MULTI Multiple indicators imply a widely-seen list
manager
Forwarding - missed the debbugs
---------- Forwarded message ---------
From: Przemys=C5=82aw Kryger <pkryger@HIDDEN>
Date: Thu, 7 Aug 2025 at 17:46
Subject: Re: bug#79188: 31.0.50; Cannot build packages installed from VC
To: Philip Kaludercic <philipk@HIDDEN>
Philip Kaludercic <philipk@HIDDEN> writes:
> Przemyslaw Kryger <pkryger@HIDDEN> writes:
>
>> I am using package-vc to manage a few pakcages I maintain. However, in =
Emacs
>> 31 I observed a couple issues.
>>
>> The first discrepancy with what used to happen on Emacs 30 is when a pac=
kage is
>> installed from a custom location, no *.elc files are produced. I don't =
know
>> what the expected behaviour should be here.
>>
>> In addition to that when I attempt to rebuild such a package with
>> package-vc-rebuild it signals an error, which I believe shouldn't happen=
,
>> should it? In this case no *.elc files have been produced nor updated. =
Such a
>> workflow used to work on Emacs 30.
>
> Both of these shouldn't happen.
Thank you for taking a look and for confirmation.
[...]
>> (add-to-list 'package-archives '(melpa . "https://melpa.org/packages/"))
> ^
> this should be a string!
Thanks for pointing out. It seems to work regardless.
>> ;; Just to avoid using existing elpa
>> (setq package-user-dir (expand-file-name "tmp/elpa" (getenv "HOME")))
>
> (Unrelated, but is there a reason you aren't doing (expand-file-name
> "~/tmp/elpa")?)
No, not really.
[...]
>> (let ((pkg-dir (expand-file-name "tmp/helm-projectile" (getenv "HOME")))=
)
>> (eval
>> `(use-package helm-projectile
>> :vc t
>> :load-path ,pkg-dir)))
>
> For posterity, this expands to
>
[...]
> which in turn would invoke
>
> (package-vc-install-from-checkout "/tmp/helm-projectile/" "helm-projectil=
e")
I think I reached very similar same conclusion. When I changed the
installation bit to:
(package-vc-install-from-checkout (expand-file-name "~/tmp/helm-projectile"=
)
"helm-projectile")
both issues still reproduce. That is after installation there are no
*.elc files to be found and an attempt to rebuild the package with
`package-vc-rebuild' yielded the same stack.
[...]
>> Which yields the following:
>>
>> Debugger entered--Lisp error: (wrong-type-argument stringp nil)
>> expand-file-name(nil)
>> vc-file-getprop(nil vc-working-revision)
>> vc-working-revision(nil)
>> package-vc--unpack-1(#s(package-desc :name helm-projectile :version (1=
3 1)
>> :summary "Helm integration for Projectile" :reqs nil :kind vc :archive n=
il
>> :dir "/Users/pkryger/tmp/elpa/helm-projectile/" :extras ((:commit
>> . "2ecd3d85b7077f39bb2fefe2227cc46931d4b92b")) :signed nil)
>> "/Users/pkryger/tmp/elpa/helm-projectile/")
>> package-vc-rebuild(#s(package-desc :name helm-projectile :version (1 3=
1) :summary "Helm integration for Projectile" :reqs nil :kind vc :archive =
nil :dir "/Users/pkryger/tmp/elpa/helm-projectile/" :extras ((:commit . "2e=
cd3d85b7077f39bb2fefe2227cc46931d4b92b")) :signed nil))
>> funcall-interactively(package-vc-rebuild #s(package-desc :name helm-pr=
ojectile :version (1 3 1) :summary "Helm integration for Projectile" :reqs =
nil :kind vc :archive nil :dir "/Users/pkryger/tmp/elpa/helm-projectile/" :=
extras ((:commit . "2ecd3d85b7077f39bb2fefe2227cc46931d4b92b")) :signed nil=
))
>> call-interactively(package-vc-rebuild record nil)
>> command-execute(package-vc-rebuild record)
>> execute-extended-command(nil "package-vc-rebuild" "pack-v-re")
>> funcall-interactively(execute-extended-command nil "package-vc-rebuild=
" "pack-v-re")
>> call-interactively(execute-extended-command nil nil)
>> command-execute(execute-extended-command)
>
> I couldn't reproduce this stack trace :/ It seems like
> `package-vc--main-file' returned nil. Can you check what the function
> returns, perhaps using edebug?
I run `package-vc-rebuild' and indeed the `package-vc--main-file' yields
is nil in Edebug instrumented `package-vc--unpack-file-1'.
>> Could these be introduced by 4226eb2b20408ba49787195bbc59bb0066c9c9e4?
>
> That seems reasonable, but in that case we should be able to reproduce
> the issue with a more simple example (especially one that doesn't involve
> use-package, MELPA and missing dependencies). I tried it out with a
> local package I had lying around and I also noticed that we don't
> byte-compile files anymore!
>
> This should fix the first issue, but it probably won't change anything
> about the latter:
>
> diff --git a/lisp/package/package-vc.el b/lisp/package/package-vc.el
> index db12c76133e..f2c7c460f6d 100644
> --- a/lisp/package/package-vc.el
> +++ b/lisp/package/package-vc.el
> @@ -549,7 +549,14 @@ package-vc--unpack-1
> ;; FIXME: Compilation should be done as a separate, optional, st=
ep.
> ;; E.g. for multi-package installs, we should first install all =
packages
> ;; and then compile them.
> - (package--compile new-desc)
> + (package--compile
> + (if lisp-dir
> + ;; In case we are installing a package from a local
> + ;; checkout, we want to compile the checkout, not the
> + ;; redirection!
> + (package-desc-create :dir lisp-dir)
> + new-desc))
> +
> (when package-native-compile
> (package--native-compile-async new-desc))
> ;; After compilation, load again any files loaded by
>
I don't have lisp/pakcage/package-vc.el, but I changed the file name to
lisp/emacs-lisp/packgage-vc.el and the patch applied cleanly.
Below I will use:
- "package source directory" to denote where package
resides (i.e., ${HOME}/tmp/helm-projectile)
- "package install directory" to denote where package is installed,
i.e. a result of:
(expand-file-name "helm-projectile" package-user-dir)
After I repeated the experiment the package installed with just
`package-vc-install-from-checkout' (as described above) and
helm-projectile.elc file has been produced into package source
directory.
Not sure if it is important but at this point my `load-path' has only
the package source directory and no package install directory. I wonder
how the helm-projectile-autoloads.el that has been produced into the
package install directory is going to take part further (in the same and
in a future Emacs session). Will both directories eventually end up in
the `load-path'?
I removed the compiled helm-projectile.elc from package source directory
and executed:
M-x package-vc-rebuild RET helm-projectile RET
which yield familiar stack trace.
The funny thing is that this time around, the package source directory
had no *.elc files created. However, the package install directory
contained helm-projectile-autoloads.elc [sic!].
I run the patched `package-vc--unpack-1' and this time `lisp-dir' was nil
(in l.550, where patch has been applied) and 'package-desc--main-file'
yielded nil again.
A question: shouldn't the newly generated *.elc files be put in package
install directory, just like the (non compiled) autoloads file is? In
my - very na=C3=AFve - view this would not only remove burden of doubling
`load-path' entries (will that happen) but would also allow for a
complete separation of compiled files between multiple Emacs versions
coexisting on the same machine and reusing the same package source
directories.
Last but not least. When stepping through `package-vc--unpack-1' under
Edebug for `package-vc-rebuild' I noticed that when it scans for
dependencies it examines files in package install directory. However,
these files (i.e., helm-projectile-pkg.el and
helm-projectile-autoloads.el) define no dependencies. Shouldn't the
scan happen for files in the package source directory? I think this was
what Emacs 30 did, due to symlink.
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Fri, 08 Aug 2025 11:08:02 +0000
Resent-Message-ID: <handler.79188.B79188.175465125217766 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords:
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.175465125217766
(code B ref 79188); Fri, 08 Aug 2025 11:08:02 +0000
Received: (at 79188) by debbugs.gnu.org; 8 Aug 2025 11:07:32 +0000
Received: from localhost ([127.0.0.1]:37414 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1ukKwd-0004cS-8S
for submit <at> debbugs.gnu.org; Fri, 08 Aug 2025 07:07:32 -0400
Received: from mail-wm1-x331.google.com ([2a00:1450:4864:20::331]:44089)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>)
id 1ukKwX-0004c4-L0; Fri, 08 Aug 2025 07:07:29 -0400
Received: by mail-wm1-x331.google.com with SMTP id
5b1f17b1804b1-459ebb6bbdfso13197535e9.0;
Fri, 08 Aug 2025 04:07:25 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1754651239; x=1755256039; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:cc:references:in-reply-to
:subject:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=ZQOFB19jutiNe16VqKa4qnB5yIBLOl7aFrsZcPVe+J8=;
b=DvT6mZ3j0sBtEtm3LppUwCe3AoT3R1SLJ3XmYkhCGakLJKs3LB1r0hcQEtYKj1g7aC
G0rUGiG8FS2C5QzhgIXlhY7ztASZX9444PVjoeF9413/O6tWh5iUDN4tp4PPPoN2p1fA
EFLWQI82WJUFXtys35p7RsjXwATWnuZGkK35oYmARGUjddKNK1kE3W9tUC0NzQFu/tum
Ai3L+4VPSCQGuOwHG2qwNRrXGS4g9ZubDAcyCeV4zDjE04pkgbUYPpgDs9tvTGaMIB0u
GOGPAdn1Uw+pt6R/uyqnf/z7kQVTkqNIOt1gsDmIGL70IQ6G5k3VKzQGR3KFx6DQxhVj
S26A==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1754651239; x=1755256039;
h=mime-version:user-agent:message-id:date:cc:references:in-reply-to
:subject:to:from:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to;
bh=ZQOFB19jutiNe16VqKa4qnB5yIBLOl7aFrsZcPVe+J8=;
b=YXWrIFGQ1GThwGUMXFUfvpfjVdk7f2y16JpZTviKjdasjcem0E7kLFCRTs6D45PGFB
VX+MpLPM1P/YdG7Ilt0jveZWeQLNBFiMXweSyRpY68Xif/1OBR191dTwdSg2g9yDRIX9
LsxQnuJLVY2rJIwMWQRJbDAo6udayfisEOIQZRn6l/4WrID8sKKyqVzeNZYGxCcgSF70
0jwH3L4EW8VbuQf5lUqsNCwiBPmAE8EvTzwe7oi+Abt28StX1Nak1iEOfjF8SB9zfHh/
LTOAC80gi8wzz46FnYWWvNIv87MyMUeTAIR/az7weaE+22+N6M5DSOXnOaKIwjM3HqHy
85qg==
X-Forwarded-Encrypted: i=1;
AJvYcCWvfN+CVlYu44WdAtA1XaxPv5v4AiMnzy5BDQRZfMJiCAEO75201PFBUGGAy409IbaXenhprZn/@debbugs.gnu.org
X-Gm-Message-State: AOJu0YxjGLWzpsK2bK7vs1bEw1UPuWXq2NBcZS19XZneZinP3IKR4O/K
/Dpk2x2Zpm8uxyde5Ts6VL4U5qLFX+79CCpzUYbl3PuY2Q0m3JLt2OLeLtCvliBi
X-Gm-Gg: ASbGnctdaxBR99FjGBrYULs1UdCxSENkEU42yz3TSFgDENFMnpCm4q2f1C+wMgMzVa2
HcV51KTwH66lCd+Zx/CTHgDcElvrvkqKHiIES3YezjFG+e6CC1XGbr6/q034VH7BKPk9xNoX4Xo
UNCnh6XWQ1jjplo6m2rBVZK7FTCeLcl635IOIrK1pveQ6ArRHvErvBiGpqtVumYt6sETZQazq6k
j7LPTZfDwdUY1OVIm894O3Ioe49qmZNeRu8O/lo9Dtv48MVkX8meFOUEOQVl8DEmQ0G94XmxVw2
mhp2WeM13wVPtoAfDMFbAfBSzKYKO1nymTjLgXbmG7ET6OcaSd9a1x92XoLfk2V/tpmbU6eFNSR
D/pQaYLCiMlduFWA9L38KwRYPae+Qq1rp3iHa3y3rxkvddIWGm1RlVqkQLhzYYEI=
X-Google-Smtp-Source: AGHT+IEJfEWQyHvFMRGKyKCLfbUiEmHpRzVQDMJQn9nc3HGSpNUl7OGFC2Rr8R0wK2DgMCg+7CcCsg==
X-Received: by 2002:a05:600c:15ca:b0:459:dde3:1a55 with SMTP id
5b1f17b1804b1-459f5507f88mr13471325e9.24.1754651238532;
Fri, 08 Aug 2025 04:07:18 -0700 (PDT)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:b8d6:64db:4c9b:7a99])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-459e5862fd9sm141886855e9.16.2025.08.08.04.07.17
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Fri, 08 Aug 2025 04:07:17 -0700 (PDT)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
("=?UTF-8?Q?Przemys=C5=82aw?= Kryger"'s message of "Thu, 7 Aug 2025
17:53:00 +0100")
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
Date: Fri, 08 Aug 2025 12:07:14 +0100
Message-ID: <m2a54avzq5.fsf_-_@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
tags 79188 + patch
quit
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>> That seems reasonable, but in that case we should be able to reproduce
>> the issue with a more simple example (especially one that doesn't involve
>> use-package, MELPA and missing dependencies). [...]
I managed to reproduce the issue with
https://github.com/pkryger/basic-stats.el, which has no extra
dependencies. I could reproduce all the issues I described in previous
message (https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D79188#11).
In addition I noticed, that `package-vc-upgrade' doesn't work as
well. This one was trying to pull inside the package install directory,
i.e, under `packgage-user-dir'.
>> This should fix the first issue, but it probably won't change anything
>> about the latter:
>>
>> diff --git a/lisp/package/package-vc.el b/lisp/package/package-vc.el
>> index db12c76133e..f2c7c460f6d 100644
>> --- a/lisp/package/package-vc.el
>> +++ b/lisp/package/package-vc.el
>> @@ -549,7 +549,14 @@ package-vc--unpack-1
>> ;; FIXME: Compilation should be done as a separate, optional, s=
t=3D
> ep.
>> ;; E.g. for multi-package installs, we should first install all=
=3D
> packages
>> ;; and then compile them.
>> - (package--compile new-desc)
>> + (package--compile
>> + (if lisp-dir
>> + ;; In case we are installing a package from a local
>> + ;; checkout, we want to compile the checkout, not the
>> + ;; redirection!
>> + (package-desc-create :dir lisp-dir)
>> + new-desc))
>> +
>> (when package-native-compile
>> (package--native-compile-async new-desc))
>> ;; After compilation, load again any files loaded by
>>
>
> I don't have lisp/pakcage/package-vc.el, but I changed the file name to
> lisp/emacs-lisp/packgage-vc.el and the patch applied cleanly.
>
> [...]
>
> After I repeated the experiment the package installed with just
> `package-vc-install-from-checkout' (as described above) and
> helm-projectile.elc file has been produced into package source
> directory.
Based on that work I developed a new patch. With both of the attached
patches applied I was able to run `package-vc-rebuild' and
`package-vc-reinstall' on the aforementioned package basic-stats and
observed that *.elc files were created in the source directory (i.e.,
the local checkout) and not in package install directory.
> A question: shouldn't the newly generated *.elc files be put in
> package install directory, just like the (non compiled) autoloads file
> is? In my - very na=3DC3=3DAFve - view this would not only remove burden
> of doubling `load-path' entries (will that happen) but would also
> allow for a complete separation of compiled files between multiple
> Emacs versions coexisting on the same machine and reusing the same
> package source directories.
While the patch attached fixes basic workflows, I wonder idea of having
*.elc in a package install directory is worth exploring. Would that
affect other functionalities? For example `load' and `require' should
just work (provided the package install directory is in front of package
source directory in `load-pat'), but what will happen with
`find-library'/`locate-library'? Are there any others?
--=-=-=
Content-Type: text/plain
Content-Disposition: attachment;
filename=0001-Compile-file-in-local-checkout-directory.patch
Content-Description: patch
From 56fa1014b1f8f2eb7f6d87304c3f31604fed48ba Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@HIDDEN>
Date: Fri, 8 Aug 2025 11:43:24 +0100
Subject: [PATCH 1/2] Compile file in local checkout directory
This partially fixes bug#79188.
* lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): Compile package
in a local checkout directory when it is installed from such a
location, for example with `package-vc-install-from-checkout'.
---
lisp/emacs-lisp/package-vc.el | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 7433fce2d89..9e118c7af02 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -546,7 +546,14 @@ package-vc--unpack-1
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
- (package--compile new-desc)
+ (package--compile
+ (if lisp-dir
+ ;; In case we are installing a package from a local
+ ;; checkout, we want to compile the checkout, not the
+ ;; redirection!
+ (package-desc-create :dir lisp-dir)
+ new-desc))
+
(when package-native-compile
(package--native-compile-async new-desc))
;; After compilation, load again any files loaded by
--
2.50.1
--=-=-=
Content-Type: text/plain
Content-Disposition: attachment;
filename=0002-Store-local-checkout-directory-in-autoloads-indirect.patch
Content-Description: patch
From 07596327df8bee5831003b62c811dd3fc53f2a88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Przemys=C5=82aw=20Kryger?= <pkryger@HIDDEN>
Date: Fri, 8 Aug 2025 11:43:52 +0100
Subject: [PATCH 2/2] Store local checkout directory in autoloads indirection
* lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): When installing
from a local checkout, store the value of `:lisp-dir' property of
`pkg-spec' in a "Package-spec" header in a generated autoloads
indirection file.
* lisp/emacs-lisp/package-vc.el (package-vc--pkg-spec-from-autoloads):
New function to retrieve package spec from a "Package-spec" header
from autoloads indirection file (if any).
* lisp/emacs-lisp/package-vc.el (package-vc-rebuild): Retrieve package
spec from autoloads indirection file (if any) and use it while calling
`package-vc--unpack-1'.
* lisp/emacs-lisp/package-vc.el (package-vc-upgrade): Retrieve package
spec from autoloads indirection file (if any) and use it while calling
`package-vc--unpack-1' and for `vc-pull'.
fixes: bug#79188
---
lisp/emacs-lisp/package-vc.el | 46 +++++++++++++++++++++++++++++------
1 file changed, 39 insertions(+), 7 deletions(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 9e118c7af02..400e648b8f5 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -508,7 +508,14 @@ package-vc--unpack-1
(when lisp-dir
(write-region
(with-temp-buffer
- (insert ";; Autoload indirection for package-vc\n\n")
+ (insert ";; Autoload indirection for package-vc\n")
+ (insert ";; Package-spec: ")
+ ;; Store the pkg-spec such that it can be reused by
+ ;; `package-rebuild' and `package-vc-upgrade' to restore
+ ;; the same conditions as were when the indirection has
+ ;; been created for the first time.
+ (prin1 pkg-spec (current-buffer))
+ (insert "\n\n")
(prin1 `(load (expand-file-name
,(expand-file-name auto-name lisp-dir)
(or (and load-file-name
@@ -589,6 +596,19 @@ package-vc--unpack-1
(declare-function project-remember-projects-under "project" (dir &optional recursive))
+(defun package-vc--pkg-spec-from-autoloads (pkg-desc)
+ "Read a \"Packcage-spec\" header from autoloads file for PKG-DESC."
+ (when-let* ((name (package-desc-name pkg-desc))
+ (autoloads (expand-file-name (format "%s-autoloads.el" name)
+ (package-desc-dir pkg-desc)))
+ ((file-exists-p autoloads))
+ (spec (with-temp-buffer
+ (insert-file-contents autoloads)
+ (ignore-errors
+ (read (lm-header "package-spec"))))))
+ (cons (symbol-name name)
+ spec)))
+
(defun package-vc--clone (pkg-desc pkg-spec dir rev)
"Clone the package PKG-DESC whose spec is PKG-SPEC into the directory DIR.
REV specifies a specific revision to checkout. This overrides the `:branch'
@@ -756,7 +776,10 @@ package-vc-upgrade
;;
;; If there is a better way to do this, it should be done.
(cl-assert (package-vc-p pkg-desc))
- (letrec ((pkg-dir (package-desc-dir pkg-desc))
+ (letrec ((pkg-spec (package-vc--pkg-spec-from-autoloads pkg-desc))
+ (pkg-dir (package-desc-dir pkg-desc))
+ (source-dir (or (plist-get (cdr pkg-spec) :lisp-dir)
+ pkg-dir))
(vc-flags)
(vc-filter-command-function
(lambda (command file-or-list flags)
@@ -764,18 +787,22 @@ package-vc-upgrade
(list command file-or-list flags)))
(post-upgrade
(lambda (_command _file-or-list flags)
- (when (and (file-equal-p pkg-dir default-directory)
+ (when (and (file-equal-p source-dir default-directory)
(eq flags vc-flags))
(unwind-protect
(with-demoted-errors "Failed to activate: %S"
- (package-vc--unpack-1 pkg-desc pkg-dir))
+ (let ((package-vc-selected-packages
+ (if pkg-spec
+ (cons pkg-spec package-vc-selected-packages)
+ package-vc-selected-packages)))
+ (package-vc--unpack-1 pkg-desc pkg-dir)))
(remove-hook 'vc-post-command-functions post-upgrade))))))
(add-hook 'vc-post-command-functions post-upgrade)
(with-demoted-errors "Failed to fetch: %S"
(require 'vc-dir)
(with-current-buffer (vc-dir-prepare-status-buffer
- (format " *package-vc-dir: %s*" pkg-dir)
- pkg-dir (vc-responsible-backend pkg-dir))
+ (format " *package-vc-dir: %s*" source-dir)
+ source-dir (vc-responsible-backend source-dir))
(vc-pull)))))
(defun package-vc--archives-initialize ()
@@ -966,7 +993,12 @@ package-vc-rebuild
is the responsibility of `package-vc-upgrade'. Interactively,
prompt for the name of the package to rebuild."
(interactive (list (package-vc--read-package-desc "Rebuild package: " t)))
- (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc)))
+ (let* ((pkg-spec (package-vc--pkg-spec-from-autoloads pkg-desc))
+ (package-vc-selected-packages
+ (if pkg-spec
+ (cons pkg-spec package-vc-selected-packages)
+ package-vc-selected-packages)))
+ (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc))))
;;;###autoload
(defun package-vc-prepare-patch (pkg-desc subject revisions)
--
2.50.1
--=-=-=--
Received: (at control) by debbugs.gnu.org; 8 Aug 2025 11:07:33 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Aug 08 07:07:33 2025
Received: from localhost ([127.0.0.1]:37416 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1ukKwe-0004cV-3c
for submit <at> debbugs.gnu.org; Fri, 08 Aug 2025 07:07:32 -0400
Received: from mail-wm1-x331.google.com ([2a00:1450:4864:20::331]:44089)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>)
id 1ukKwX-0004c4-L0; Fri, 08 Aug 2025 07:07:29 -0400
Received: by mail-wm1-x331.google.com with SMTP id
5b1f17b1804b1-459ebb6bbdfso13197535e9.0;
Fri, 08 Aug 2025 04:07:25 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1754651239; x=1755256039; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:cc:references:in-reply-to
:subject:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=ZQOFB19jutiNe16VqKa4qnB5yIBLOl7aFrsZcPVe+J8=;
b=DvT6mZ3j0sBtEtm3LppUwCe3AoT3R1SLJ3XmYkhCGakLJKs3LB1r0hcQEtYKj1g7aC
G0rUGiG8FS2C5QzhgIXlhY7ztASZX9444PVjoeF9413/O6tWh5iUDN4tp4PPPoN2p1fA
EFLWQI82WJUFXtys35p7RsjXwATWnuZGkK35oYmARGUjddKNK1kE3W9tUC0NzQFu/tum
Ai3L+4VPSCQGuOwHG2qwNRrXGS4g9ZubDAcyCeV4zDjE04pkgbUYPpgDs9tvTGaMIB0u
GOGPAdn1Uw+pt6R/uyqnf/z7kQVTkqNIOt1gsDmIGL70IQ6G5k3VKzQGR3KFx6DQxhVj
S26A==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1754651239; x=1755256039;
h=mime-version:user-agent:message-id:date:cc:references:in-reply-to
:subject:to:from:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to;
bh=ZQOFB19jutiNe16VqKa4qnB5yIBLOl7aFrsZcPVe+J8=;
b=YXWrIFGQ1GThwGUMXFUfvpfjVdk7f2y16JpZTviKjdasjcem0E7kLFCRTs6D45PGFB
VX+MpLPM1P/YdG7Ilt0jveZWeQLNBFiMXweSyRpY68Xif/1OBR191dTwdSg2g9yDRIX9
LsxQnuJLVY2rJIwMWQRJbDAo6udayfisEOIQZRn6l/4WrID8sKKyqVzeNZYGxCcgSF70
0jwH3L4EW8VbuQf5lUqsNCwiBPmAE8EvTzwe7oi+Abt28StX1Nak1iEOfjF8SB9zfHh/
LTOAC80gi8wzz46FnYWWvNIv87MyMUeTAIR/az7weaE+22+N6M5DSOXnOaKIwjM3HqHy
85qg==
X-Forwarded-Encrypted: i=1;
AJvYcCWvfN+CVlYu44WdAtA1XaxPv5v4AiMnzy5BDQRZfMJiCAEO75201PFBUGGAy409IbaXenhprZn/@debbugs.gnu.org
X-Gm-Message-State: AOJu0YxjGLWzpsK2bK7vs1bEw1UPuWXq2NBcZS19XZneZinP3IKR4O/K
/Dpk2x2Zpm8uxyde5Ts6VL4U5qLFX+79CCpzUYbl3PuY2Q0m3JLt2OLeLtCvliBi
X-Gm-Gg: ASbGnctdaxBR99FjGBrYULs1UdCxSENkEU42yz3TSFgDENFMnpCm4q2f1C+wMgMzVa2
HcV51KTwH66lCd+Zx/CTHgDcElvrvkqKHiIES3YezjFG+e6CC1XGbr6/q034VH7BKPk9xNoX4Xo
UNCnh6XWQ1jjplo6m2rBVZK7FTCeLcl635IOIrK1pveQ6ArRHvErvBiGpqtVumYt6sETZQazq6k
j7LPTZfDwdUY1OVIm894O3Ioe49qmZNeRu8O/lo9Dtv48MVkX8meFOUEOQVl8DEmQ0G94XmxVw2
mhp2WeM13wVPtoAfDMFbAfBSzKYKO1nymTjLgXbmG7ET6OcaSd9a1x92XoLfk2V/tpmbU6eFNSR
D/pQaYLCiMlduFWA9L38KwRYPae+Qq1rp3iHa3y3rxkvddIWGm1RlVqkQLhzYYEI=
X-Google-Smtp-Source: AGHT+IEJfEWQyHvFMRGKyKCLfbUiEmHpRzVQDMJQn9nc3HGSpNUl7OGFC2Rr8R0wK2DgMCg+7CcCsg==
X-Received: by 2002:a05:600c:15ca:b0:459:dde3:1a55 with SMTP id
5b1f17b1804b1-459f5507f88mr13471325e9.24.1754651238532;
Fri, 08 Aug 2025 04:07:18 -0700 (PDT)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:b8d6:64db:4c9b:7a99])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-459e5862fd9sm141886855e9.16.2025.08.08.04.07.17
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Fri, 08 Aug 2025 04:07:17 -0700 (PDT)
From: =?utf-8?Q?Przemys=C5=82aw_Kryger?= <pkryger@HIDDEN>
To: Philip Kaludercic <philipk@HIDDEN>
Subject: Re: bug#79188: 31.0.50; Cannot build packages installed from VC
In-Reply-To: <CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
(=?utf-8?Q?=22Przemys=C5=82aw?= Kryger"'s message of "Thu, 7 Aug 2025
17:53:00 +0100")
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
Date: Fri, 08 Aug 2025 12:07:14 +0100
Message-ID: <m2a54avzq5.fsf_-_@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: control
Cc: 79188 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
tags 79188 + patch
quit
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>> That seems reasonable, but in that case we should be able to reproduce
>> the issue with a more simple example (especially one that doesn't involve
>> use-package, MELPA and missing dependencies). [...]
I managed to reproduce the issue with
https://github.com/pkryger/basic-stats.el, which has no extra
dependencies. I could reproduce all the issues I described in previous
message (https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D79188#11).
In addition I noticed, that `package-vc-upgrade' doesn't work as
well. This one was trying to pull inside the package install directory,
i.e, under `packgage-user-dir'.
>> This should fix the first issue, but it probably won't change anything
>> about the latter:
>>
>> diff --git a/lisp/package/package-vc.el b/lisp/package/package-vc.el
>> index db12c76133e..f2c7c460f6d 100644
>> --- a/lisp/package/package-vc.el
>> +++ b/lisp/package/package-vc.el
>> @@ -549,7 +549,14 @@ package-vc--unpack-1
>> ;; FIXME: Compilation should be done as a separate, optional, s=
t=3D
> ep.
>> ;; E.g. for multi-package installs, we should first install all=
=3D
> packages
>> ;; and then compile them.
>> - (package--compile new-desc)
>> + (package--compile
>> + (if lisp-dir
>> + ;; In case we are installing a package from a local
>> + ;; checkout, we want to compile the checkout, not the
>> + ;; redirection!
>> + (package-desc-create :dir lisp-dir)
>> + new-desc))
>> +
>> (when package-native-compile
>> (package--native-compile-async new-desc))
>> ;; After compilation, load again any files loaded by
>>
>
> I don't have lisp/pakcage/package-vc.el, but I changed the file name to
> lisp/emacs-lisp/packgage-vc.el and the patch applied cleanly.
>
> [...]
>
> After I repeated the experiment the package installed with just
> `package-vc-install-from-checkout' (as described above) and
> helm-projectile.elc file has been produced into package source
> directory.
Based on that work I developed a new patch. With both of the attached
patches applied I was able to run `package-vc-rebuild' and
`package-vc-reinstall' on the aforementioned package basic-stats and
observed that *.elc files were created in the source directory (i.e.,
the local checkout) and not in package install directory.
> A question: shouldn't the newly generated *.elc files be put in
> package install directory, just like the (non compiled) autoloads file
> is? In my - very na=3DC3=3DAFve - view this would not only remove burden
> of doubling `load-path' entries (will that happen) but would also
> allow for a complete separation of compiled files between multiple
> Emacs versions coexisting on the same machine and reusing the same
> package source directories.
While the patch attached fixes basic workflows, I wonder idea of having
*.elc in a package install directory is worth exploring. Would that
affect other functionalities? For example `load' and `require' should
just work (provided the package install directory is in front of package
source directory in `load-pat'), but what will happen with
`find-library'/`locate-library'? Are there any others?
--=-=-=
Content-Type: text/plain
Content-Disposition: attachment;
filename=0001-Compile-file-in-local-checkout-directory.patch
Content-Description: patch
From 56fa1014b1f8f2eb7f6d87304c3f31604fed48ba Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@HIDDEN>
Date: Fri, 8 Aug 2025 11:43:24 +0100
Subject: [PATCH 1/2] Compile file in local checkout directory
This partially fixes bug#79188.
* lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): Compile package
in a local checkout directory when it is installed from such a
location, for example with `package-vc-install-from-checkout'.
---
lisp/emacs-lisp/package-vc.el | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 7433fce2d89..9e118c7af02 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -546,7 +546,14 @@ package-vc--unpack-1
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
- (package--compile new-desc)
+ (package--compile
+ (if lisp-dir
+ ;; In case we are installing a package from a local
+ ;; checkout, we want to compile the checkout, not the
+ ;; redirection!
+ (package-desc-create :dir lisp-dir)
+ new-desc))
+
(when package-native-compile
(package--native-compile-async new-desc))
;; After compilation, load again any files loaded by
--
2.50.1
--=-=-=
Content-Type: text/plain
Content-Disposition: attachment;
filename=0002-Store-local-checkout-directory-in-autoloads-indirect.patch
Content-Description: patch
From 07596327df8bee5831003b62c811dd3fc53f2a88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Przemys=C5=82aw=20Kryger?= <pkryger@HIDDEN>
Date: Fri, 8 Aug 2025 11:43:52 +0100
Subject: [PATCH 2/2] Store local checkout directory in autoloads indirection
* lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): When installing
from a local checkout, store the value of `:lisp-dir' property of
`pkg-spec' in a "Package-spec" header in a generated autoloads
indirection file.
* lisp/emacs-lisp/package-vc.el (package-vc--pkg-spec-from-autoloads):
New function to retrieve package spec from a "Package-spec" header
from autoloads indirection file (if any).
* lisp/emacs-lisp/package-vc.el (package-vc-rebuild): Retrieve package
spec from autoloads indirection file (if any) and use it while calling
`package-vc--unpack-1'.
* lisp/emacs-lisp/package-vc.el (package-vc-upgrade): Retrieve package
spec from autoloads indirection file (if any) and use it while calling
`package-vc--unpack-1' and for `vc-pull'.
fixes: bug#79188
---
lisp/emacs-lisp/package-vc.el | 46 +++++++++++++++++++++++++++++------
1 file changed, 39 insertions(+), 7 deletions(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 9e118c7af02..400e648b8f5 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -508,7 +508,14 @@ package-vc--unpack-1
(when lisp-dir
(write-region
(with-temp-buffer
- (insert ";; Autoload indirection for package-vc\n\n")
+ (insert ";; Autoload indirection for package-vc\n")
+ (insert ";; Package-spec: ")
+ ;; Store the pkg-spec such that it can be reused by
+ ;; `package-rebuild' and `package-vc-upgrade' to restore
+ ;; the same conditions as were when the indirection has
+ ;; been created for the first time.
+ (prin1 pkg-spec (current-buffer))
+ (insert "\n\n")
(prin1 `(load (expand-file-name
,(expand-file-name auto-name lisp-dir)
(or (and load-file-name
@@ -589,6 +596,19 @@ package-vc--unpack-1
(declare-function project-remember-projects-under "project" (dir &optional recursive))
+(defun package-vc--pkg-spec-from-autoloads (pkg-desc)
+ "Read a \"Packcage-spec\" header from autoloads file for PKG-DESC."
+ (when-let* ((name (package-desc-name pkg-desc))
+ (autoloads (expand-file-name (format "%s-autoloads.el" name)
+ (package-desc-dir pkg-desc)))
+ ((file-exists-p autoloads))
+ (spec (with-temp-buffer
+ (insert-file-contents autoloads)
+ (ignore-errors
+ (read (lm-header "package-spec"))))))
+ (cons (symbol-name name)
+ spec)))
+
(defun package-vc--clone (pkg-desc pkg-spec dir rev)
"Clone the package PKG-DESC whose spec is PKG-SPEC into the directory DIR.
REV specifies a specific revision to checkout. This overrides the `:branch'
@@ -756,7 +776,10 @@ package-vc-upgrade
;;
;; If there is a better way to do this, it should be done.
(cl-assert (package-vc-p pkg-desc))
- (letrec ((pkg-dir (package-desc-dir pkg-desc))
+ (letrec ((pkg-spec (package-vc--pkg-spec-from-autoloads pkg-desc))
+ (pkg-dir (package-desc-dir pkg-desc))
+ (source-dir (or (plist-get (cdr pkg-spec) :lisp-dir)
+ pkg-dir))
(vc-flags)
(vc-filter-command-function
(lambda (command file-or-list flags)
@@ -764,18 +787,22 @@ package-vc-upgrade
(list command file-or-list flags)))
(post-upgrade
(lambda (_command _file-or-list flags)
- (when (and (file-equal-p pkg-dir default-directory)
+ (when (and (file-equal-p source-dir default-directory)
(eq flags vc-flags))
(unwind-protect
(with-demoted-errors "Failed to activate: %S"
- (package-vc--unpack-1 pkg-desc pkg-dir))
+ (let ((package-vc-selected-packages
+ (if pkg-spec
+ (cons pkg-spec package-vc-selected-packages)
+ package-vc-selected-packages)))
+ (package-vc--unpack-1 pkg-desc pkg-dir)))
(remove-hook 'vc-post-command-functions post-upgrade))))))
(add-hook 'vc-post-command-functions post-upgrade)
(with-demoted-errors "Failed to fetch: %S"
(require 'vc-dir)
(with-current-buffer (vc-dir-prepare-status-buffer
- (format " *package-vc-dir: %s*" pkg-dir)
- pkg-dir (vc-responsible-backend pkg-dir))
+ (format " *package-vc-dir: %s*" source-dir)
+ source-dir (vc-responsible-backend source-dir))
(vc-pull)))))
(defun package-vc--archives-initialize ()
@@ -966,7 +993,12 @@ package-vc-rebuild
is the responsibility of `package-vc-upgrade'. Interactively,
prompt for the name of the package to rebuild."
(interactive (list (package-vc--read-package-desc "Rebuild package: " t)))
- (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc)))
+ (let* ((pkg-spec (package-vc--pkg-spec-from-autoloads pkg-desc))
+ (package-vc-selected-packages
+ (if pkg-spec
+ (cons pkg-spec package-vc-selected-packages)
+ package-vc-selected-packages)))
+ (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc))))
;;;###autoload
(defun package-vc-prepare-patch (pkg-desc subject revisions)
--
2.50.1
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Sat, 09 Aug 2025 11:45:01 +0000
Resent-Message-ID: <handler.79188.B79188.175473985222896 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.175473985222896
(code B ref 79188); Sat, 09 Aug 2025 11:45:01 +0000
Received: (at 79188) by debbugs.gnu.org; 9 Aug 2025 11:44:12 +0000
Received: from localhost ([127.0.0.1]:40478 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1ukhze-0005xD-PJ
for submit <at> debbugs.gnu.org; Sat, 09 Aug 2025 07:44:11 -0400
Received: from mout02.posteo.de ([185.67.36.66]:46923)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1ukhza-0005wV-O9
for 79188 <at> debbugs.gnu.org; Sat, 09 Aug 2025 07:44:08 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout02.posteo.de (Postfix) with ESMTPS id 43227240101
for <79188 <at> debbugs.gnu.org>; Sat, 9 Aug 2025 13:44:00 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net;
s=1984.ea087b; t=1754739840;
bh=VjARZ1beZChajdksJ7b3XVERxTH935ERrdzUQsKzY+s=;
h=From:To:Cc:Subject:Autocrypt:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:Content-Transfer-Encoding:From;
b=j/dTldmJ9sWlr0ND49/APn1/gIKeX0ZXh8fjavbBDdD+8XWzrmGFX/kJBfTXsz9pd
hPwaI6eDvHwlPlcZcdXV/Vyu0Kw09GJi74i5InzP9bdhB4P/GkU3XFLEXAi4LX1ZjF
hyb0Dcps147bZQk+JMVScLrEO4Qfl4mwG8GzobIukE6wzlJ44iXpPojQGa0mPs5dJ0
okk68EDWx/6p+WLeYHxKfErwfLDmwULIf0sACCm/3dmuZ08BtOP/ItY5+7djXqk7Cx
+3R11QCdGmZUY+TfXpYiz30AAFwG12RgmtAW9VehkMkZQPRAKomnK8HavC57JatIHH
q/wC+q9M+CpX8rHaQG2QkW2tp+4QlS0Kd4TEH5gZ04UPX3CgKI2soI15gjZ6IAYblu
BbAMYre061PDKy3TTnGmoYyqJc1Q9Zm+Ha3lYL07r/NEF9Pdbn0UsGoVUH++i4UjLu
K/3jRX44IKXCp0Azzy3FJK1Ek/VkDElr8zG1tw55V1uN6s1XBNd
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4bzfDv4jJRz9rxW;
Sat, 9 Aug 2025 13:43:59 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2a54avzq5.fsf_-_@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN>
Autocrypt: addr=philipk@HIDDEN; keydata=
mDMEZBBQQhYJKwYBBAHaRw8BAQdAHJuofBrfqFh12uQu0Yi7mrl525F28eTmwUDflFNmdui0QlBo
aWxpcCBLYWx1ZGVyY2ljIChnZW5lcmF0ZWQgYnkgYXV0b2NyeXB0LmVsKSA8cGhpbGlwa0Bwb3N0
ZW8ubmV0PoiWBBMWCAA+FiEEDg7HY17ghYlni8XN8xYDWXahwukFAmQQUEICGwMFCQHhM4AFCwkI
BwIGFQoJCAsCBBYCAwECHgECF4AACgkQ8xYDWXahwulikAEA77hloUiSrXgFkUVJhlKBpLCHUjA0
mWZ9j9w5d08+jVwBAK6c4iGP7j+/PhbkxaEKa4V3MzIl7zJkcNNjHCXmvFcEuDgEZBBQQhIKKwYB
BAGXVQEFAQEHQI5NLiLRjZy3OfSt1dhCmFyn+fN/QKELUYQetiaoe+MMAwEIB4h+BBgWCAAmFiEE
Dg7HY17ghYlni8XN8xYDWXahwukFAmQQUEICGwwFCQHhM4AACgkQ8xYDWXahwukm+wEA8cml4JpK
NeAu65rg+auKrPOP6TP/4YWRCTIvuYDm0joBALw98AMz7/qMHvSCeU/hw9PL6u6R2EScxtpKnWof
z4oM
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Sat, 09 Aug 2025 11:43:59 +0000
Message-ID: <87h5ygyb28.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> tags 79188 + patch
> quit
>
> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>>> That seems reasonable, but in that case we should be able to reproduce
>>> the issue with a more simple example (especially one that doesn't invol=
ve
>>> use-package, MELPA and missing dependencies). [...]
>
> I managed to reproduce the issue with
> https://github.com/pkryger/basic-stats.el, which has no extra
> dependencies. I could reproduce all the issues I described in previous
> message (https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D79188#11).
>
> In addition I noticed, that `package-vc-upgrade' doesn't work as
> well. This one was trying to pull inside the package install directory,
> i.e, under `packgage-user-dir'.
>
>>> This should fix the first issue, but it probably won't change anything
>>> about the latter:
>>>
>>> diff --git a/lisp/package/package-vc.el b/lisp/package/package-vc.el
>>> index db12c76133e..f2c7c460f6d 100644
>>> --- a/lisp/package/package-vc.el
>>> +++ b/lisp/package/package-vc.el
>>> @@ -549,7 +549,14 @@ package-vc--unpack-1
>>> ;; FIXME: Compilation should be done as a separate, optional, =
st=3D
>> ep.
>>> ;; E.g. for multi-package installs, we should first install al=
l =3D
>> packages
>>> ;; and then compile them.
>>> - (package--compile new-desc)
>>> + (package--compile
>>> + (if lisp-dir
>>> + ;; In case we are installing a package from a local
>>> + ;; checkout, we want to compile the checkout, not the
>>> + ;; redirection!
>>> + (package-desc-create :dir lisp-dir)
>>> + new-desc))
>>> +
>>> (when package-native-compile
>>> (package--native-compile-async new-desc))
>>> ;; After compilation, load again any files loaded by
>>>
>>
>> I don't have lisp/pakcage/package-vc.el, but I changed the file name to
>> lisp/emacs-lisp/packgage-vc.el and the patch applied cleanly.
>>
>> [...]
>>
>> After I repeated the experiment the package installed with just
>> `package-vc-install-from-checkout' (as described above) and
>> helm-projectile.elc file has been produced into package source
>> directory.
>
> Based on that work I developed a new patch. With both of the attached
> patches applied I was able to run `package-vc-rebuild' and
> `package-vc-reinstall' on the aforementioned package basic-stats and
> observed that *.elc files were created in the source directory (i.e.,
> the local checkout) and not in package install directory.
Thanks, I have some comments below.
>> A question: shouldn't the newly generated *.elc files be put in
>> package install directory, just like the (non compiled) autoloads file
>> is? In my - very na=3DC3=3DAFve - view this would not only remove burden
>> of doubling `load-path' entries (will that happen) but would also
>> allow for a complete separation of compiled files between multiple
>> Emacs versions coexisting on the same machine and reusing the same
>> package source directories.
>
> While the patch attached fixes basic workflows, I wonder idea of having
> *.elc in a package install directory is worth exploring. Would that
> affect other functionalities? For example `load' and `require' should
> just work (provided the package install directory is in front of package
> source directory in `load-pat'), but what will happen with
> `find-library'/`locate-library'? Are there any others?
By package install directory you mean the ~/.emacs.d/elpa/... directory
right? I get the advantage of not having incompatible .elc versions but
I am not an expert when it comes the load-order questions. I think we
should discuss this in a separate feature request and then ask someone
who knows more about that to avoid making clumsy mistakes. Does that
sound OK?
> From 56fa1014b1f8f2eb7f6d87304c3f31604fed48ba Mon Sep 17 00:00:00 2001
> From: Philip Kaludercic <philipk@HIDDEN>
> Date: Fri, 8 Aug 2025 11:43:24 +0100
> Subject: [PATCH 1/2] Compile file in local checkout directory
>
> This partially fixes bug#79188.
We usually reference bug numbers at the end of a commit message in
parentheses, but I can take care of that.
> * lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): Compile package
> in a local checkout directory when it is installed from such a
> location, for example with `package-vc-install-from-checkout'.
> ---
> lisp/emacs-lisp/package-vc.el | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
> index 7433fce2d89..9e118c7af02 100644
> --- a/lisp/emacs-lisp/package-vc.el
> +++ b/lisp/emacs-lisp/package-vc.el
> @@ -546,7 +546,14 @@ package-vc--unpack-1
> ;; FIXME: Compilation should be done as a separate, optional, st=
ep.
> ;; E.g. for multi-package installs, we should first install all =
packages
> ;; and then compile them.
> - (package--compile new-desc)
> + (package--compile
> + (if lisp-dir
> + ;; In case we are installing a package from a local
> + ;; checkout, we want to compile the checkout, not the
> + ;; redirection!
> + (package-desc-create :dir lisp-dir)
> + new-desc))
> +
> (when package-native-compile
> (package--native-compile-async new-desc))
> ;; After compilation, load again any files loaded by
> --=20
> 2.50.1
>
>
> From 07596327df8bee5831003b62c811dd3fc53f2a88 Mon Sep 17 00:00:00 2001
> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
> Date: Fri, 8 Aug 2025 11:43:52 +0100
> Subject: [PATCH 2/2] Store local checkout directory in autoloads indirect=
ion
>
> * lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): When installing
> from a local checkout, store the value of `:lisp-dir' property of
> `pkg-spec' in a "Package-spec" header in a generated autoloads
> indirection file.
> * lisp/emacs-lisp/package-vc.el (package-vc--pkg-spec-from-autoloads):
> New function to retrieve package spec from a "Package-spec" header
> from autoloads indirection file (if any).
> * lisp/emacs-lisp/package-vc.el (package-vc-rebuild): Retrieve package
> spec from autoloads indirection file (if any) and use it while calling
> `package-vc--unpack-1'.
> * lisp/emacs-lisp/package-vc.el (package-vc-upgrade): Retrieve package
> spec from autoloads indirection file (if any) and use it while calling
> `package-vc--unpack-1' and for `vc-pull'.
>
> fixes: bug#79188
(The formatting is off here as well, but again, I can take care of that.
In case you did not know, in log-edit-mode, you can use the
`log-edit-generate-changelog-from-diff' command (bound to C-c C-w) to
generate a changelog from the current diff).
> ---
> lisp/emacs-lisp/package-vc.el | 46 +++++++++++++++++++++++++++++------
> 1 file changed, 39 insertions(+), 7 deletions(-)
>
> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
> index 9e118c7af02..400e648b8f5 100644
> --- a/lisp/emacs-lisp/package-vc.el
> +++ b/lisp/emacs-lisp/package-vc.el
> @@ -508,7 +508,14 @@ package-vc--unpack-1
> (when lisp-dir
> (write-region
> (with-temp-buffer
> - (insert ";; Autoload indirection for package-vc\n\n")
> + (insert ";; Autoload indirection for package-vc\n")
> + (insert ";; Package-spec: ")
> + ;; Store the pkg-spec such that it can be reused by
> + ;; `package-rebuild' and `package-vc-upgrade' to restore
> + ;; the same conditions as were when the indirection has
> + ;; been created for the first time.
> + (prin1 pkg-spec (current-buffer))
This is strictly speaking not robust, as doesn't assure us that
something like (prin1 "one\ntwo") will result in a string without
newlines and not "break out" of the comment. If anything, we should
consider storing this in a separate file, but more on that below.
> + (insert "\n\n")
> (prin1 `(load (expand-file-name
> ,(expand-file-name auto-name lisp-dir)
> (or (and load-file-name
> @@ -589,6 +596,19 @@ package-vc--unpack-1
>=20=20
> (declare-function project-remember-projects-under "project" (dir &option=
al recursive))
>=20=20
> +(defun package-vc--pkg-spec-from-autoloads (pkg-desc)
> + "Read a \"Packcage-spec\" header from autoloads file for PKG-DESC."
> + (when-let* ((name (package-desc-name pkg-desc))
> + (autoloads (expand-file-name (format "%s-autoloads.el" nam=
e)
> + (package-desc-dir pkg-desc)))
> + ((file-exists-p autoloads))
> + (spec (with-temp-buffer
> + (insert-file-contents autoloads)
> + (ignore-errors
> + (read (lm-header "package-spec"))))))
> + (cons (symbol-name name)
> + spec)))
Generally speaking I am not sure if this approach is necessary, as we
already have `package-vc--desc->spec' and introducing this hack would
introduce an ambiguity as to where the authoritative package
specification is stored.
> +
> (defun package-vc--clone (pkg-desc pkg-spec dir rev)
> "Clone the package PKG-DESC whose spec is PKG-SPEC into the directory =
DIR.
> REV specifies a specific revision to checkout. This overrides the `:bra=
nch'
> @@ -756,7 +776,10 @@ package-vc-upgrade
> ;;
> ;; If there is a better way to do this, it should be done.
> (cl-assert (package-vc-p pkg-desc))
> - (letrec ((pkg-dir (package-desc-dir pkg-desc))
> + (letrec ((pkg-spec (package-vc--pkg-spec-from-autoloads pkg-desc))
So we are just shadowing the pkg-spec passed as an argument?
> + (pkg-dir (package-desc-dir pkg-desc))
> + (source-dir (or (plist-get (cdr pkg-spec) :lisp-dir)
> + pkg-dir))
Just an an example of what I was talking about above: Here for instance
we already have an inconstancy. Everywhere else in the file, we assume
that a package specification is just a plist, and not a (PACKAGE-NAME
. SPEC-PLIST) that requires a `cdr'. to access.
> (vc-flags)
> (vc-filter-command-function
> (lambda (command file-or-list flags)
> @@ -764,18 +787,22 @@ package-vc-upgrade
> (list command file-or-list flags)))
> (post-upgrade
> (lambda (_command _file-or-list flags)
> - (when (and (file-equal-p pkg-dir default-directory)
> + (when (and (file-equal-p source-dir default-directory)
> (eq flags vc-flags))
> (unwind-protect
> (with-demoted-errors "Failed to activate: %S"
> - (package-vc--unpack-1 pkg-desc pkg-dir))
> + (let ((package-vc-selected-packages
> + (if pkg-spec
> + (cons pkg-spec package-vc-selected-pack=
ages)
> + package-vc-selected-packages)))
> + (package-vc--unpack-1 pkg-desc pkg-dir)))
You'll have yo remind me (i.e. add a comment) why you are binding the
variable here and why you are distinguishing between pkg-spec being nil
or not?
> (remove-hook 'vc-post-command-functions post-upgrade))=
))))
> (add-hook 'vc-post-command-functions post-upgrade)
> (with-demoted-errors "Failed to fetch: %S"
> (require 'vc-dir)
> (with-current-buffer (vc-dir-prepare-status-buffer
> - (format " *package-vc-dir: %s*" pkg-dir)
> - pkg-dir (vc-responsible-backend pkg-dir))
> + (format " *package-vc-dir: %s*" source-dir)
> + source-dir (vc-responsible-backend source-di=
r))
> (vc-pull)))))
>=20=20
> (defun package-vc--archives-initialize ()
> @@ -966,7 +993,12 @@ package-vc-rebuild
> is the responsibility of `package-vc-upgrade'. Interactively,
> prompt for the name of the package to rebuild."
> (interactive (list (package-vc--read-package-desc "Rebuild package: " =
t)))
> - (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc)))
> + (let* ((pkg-spec (package-vc--pkg-spec-from-autoloads pkg-desc))
> + (package-vc-selected-packages
> + (if pkg-spec
> + (cons pkg-spec package-vc-selected-packages)
> + package-vc-selected-packages)))
> + (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc))))
>=20=20
> ;;;###autoload
> (defun package-vc-prepare-patch (pkg-desc subject revisions)
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Mon, 11 Aug 2025 10:30:02 +0000
Resent-Message-ID: <handler.79188.B79188.175490816113856 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.175490816113856
(code B ref 79188); Mon, 11 Aug 2025 10:30:02 +0000
Received: (at 79188) by debbugs.gnu.org; 11 Aug 2025 10:29:21 +0000
Received: from localhost ([127.0.0.1]:47188 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1ulPmJ-0003bP-Ia
for submit <at> debbugs.gnu.org; Mon, 11 Aug 2025 06:29:20 -0400
Received: from mail-wm1-x333.google.com ([2a00:1450:4864:20::333]:52441)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1ulPmE-0003b7-VX
for 79188 <at> debbugs.gnu.org; Mon, 11 Aug 2025 06:29:16 -0400
Received: by mail-wm1-x333.google.com with SMTP id
5b1f17b1804b1-459ddf8acf1so35032955e9.0
for <79188 <at> debbugs.gnu.org>; Mon, 11 Aug 2025 03:29:14 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1754908148; x=1755512948; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=OLhtoATN/xu1zedwHitBZfjxOnKzzZxZIdGEiyPSHDM=;
b=G0NPdwIEJ6p+ILXXTeIQF1RvZKfeHPA4INhIC9NNf9mcGeIP1C/EeN6enzimfhT8V0
LywMR0+htfb1AQ33heirPAwSlSJ3A+KAjgfuHhN0nCRyaAypPD77zk/I7zieNDKyeWkB
3hf7DfUgAVJzKDWokInOgilr5EXNEagXoFADFbFUjMjm8mmgnc4YumMVLESNneSBdGKs
8ii62eiUuoyxvgjTfmLnGUltfb9ROyI5hdD8d6IBwqdF+PqgEnGzcjo1D9xmSrMFwoxE
gKQcsD+WdGcNp5pcrXcoj7wpBQ1WYqyMT6tj1buouiQKCji+hBUvAIh2UHOTVIwvpcnW
IhLw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1754908148; x=1755512948;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to;
bh=OLhtoATN/xu1zedwHitBZfjxOnKzzZxZIdGEiyPSHDM=;
b=f3OaaOMHtIlk7fv9gxrk+0esJ4VTo/n01RkhE0/mlNPgSlr72VkEYwqWCCJIFjrdx5
tNvHIAFpyu76H0cQUYQ6MWYqV2JAWDS3R0DAx/T37Hug1OC82WxR2nrRUn+yVftUxdpP
DntDOBpiN0AcwANS3Q805BZIop5xKDfY18oyI/cS1oUG93rN4hZ9lgb5UBx37/FiCYkv
HqgJ/LfHvSDwcBZgo5GE+mL4HvnR2WyopspsVxxF7yzLyzRF5+glgn0WFgAPgm0Qy4Ib
7YnxqvVVpsSs5C1y43ry8wxkZdsXppjtTb0tmsnK3gs5mXpyTpHzsZDolS8rZtWNlUHa
Zyeg==
X-Gm-Message-State: AOJu0Ywh0RGra010+2roDF7inMCIHFnqbZ3MGpyvh0YVwzDyopugoo3g
rRKoi9Jdh6mIb+ltbF8UA40/RxmXnygpl0EYOU2gYJYRH89wjQ8nZBp1nO1E7A==
X-Gm-Gg: ASbGncubh63+EdFZFNYzAwP/utI/9KdObLglHaGtHQHoAmJSoGqyNl1eyz1Hkl01QuO
H4XWlayBrPz9mE9wfy3T5Z04+MpLyuocE9C5itidQa1o7MXlcNIAXRPdY4MtSce0BukstON8+fB
SZ5Q7/cDd6/fb5+3wGPfh7CvIXBRrAeLXzuItTwlkzxOr1/dK3js+sb/pRjJ46RTK8bNUou9xNs
22z6B/+j/aeHu1xPeGB+N6jMz3b96TVyagfTD3nJQ2RU5iFO+6uBeCz/GYsrmIcHl7xs4/ll3re
eEj6E0FEGpDfWgik2Umh5nsXHqldXRZMhMtedeaO77IwYyWwSDazdxoWMVEmZvIL3LW0/SwKtMB
zBQBJTsdcL9brPKRc4KdeGMaq3Wh7faDmdkbiQ6ImYFIDaJO6KtTUVyt9bg18FKGKxRTURZmrVw
==
X-Google-Smtp-Source: AGHT+IGtyI9ANu0hiE9KmdINeHZx9LQyzkGRw+SfBDe36qsNeHzCmeCnu0K5Z26uyiofUwN2iNzYSw==
X-Received: by 2002:a05:600c:4f42:b0:450:d01f:de6f with SMTP id
5b1f17b1804b1-459f4ec6a99mr119063975e9.15.1754908147302;
Mon, 11 Aug 2025 03:29:07 -0700 (PDT)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:24a2:4c7c:7241:a5eb])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-458953eb7acsm488563545e9.28.2025.08.11.03.29.06
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Mon, 11 Aug 2025 03:29:06 -0700 (PDT)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <87h5ygyb28.fsf@HIDDEN> (Philip Kaludercic's message of "Sat,
09 Aug 2025 11:43:59 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
Date: Mon, 11 Aug 2025 11:29:03 +0100
Message-ID: <m2o6smup74.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain
Philip Kaludercic <philipk@HIDDEN> writes:
[...]
>>> A question: shouldn't the newly generated *.elc files be put in
>>> package install directory, just like the (non compiled) autoloads file
>>> is? In my - very na=C3=AFve - view this would not only remove burden
>>> of doubling `load-path' entries (will that happen) but would also
>>> allow for a complete separation of compiled files between multiple
>>> Emacs versions coexisting on the same machine and reusing the same
>>> package source directories.
>>
>> While the patch attached fixes basic workflows, I wonder idea of having
>> *.elc in a package install directory is worth exploring. Would that
>> affect other functionalities? For example `load' and `require' should
>> just work (provided the package install directory is in front of package
>> source directory in `load-pat'), but what will happen with
>> `find-library'/`locate-library'? Are there any others?
>
> By package install directory you mean the ~/.emacs.d/elpa/... directory
> right?
Yes, I did meant that place.
> I get the advantage of not having incompatible .elc versions but
> I am not an expert when it comes the load-order questions. I think we
> should discuss this in a separate feature request and then ask someone
> who knows more about that to avoid making clumsy mistakes. Does that
> sound OK?
It does. Where do you recommend to post such a feature request be
posted? debbugs? emacs-devel?
>> From 56fa1014b1f8f2eb7f6d87304c3f31604fed48ba Mon Sep 17 00:00:00 2001
>> From: Philip Kaludercic <philipk@HIDDEN>
>> Date: Fri, 8 Aug 2025 11:43:24 +0100
>> Subject: [PATCH 1/2] Compile file in local checkout directory
>>
>> This partially fixes bug#79188.
>
> We usually reference bug numbers at the end of a commit message in
> parentheses, but I can take care of that.
[...]
>> From 07596327df8bee5831003b62c811dd3fc53f2a88 Mon Sep 17 00:00:00 2001
>> From: =?UTF-8?q?Przemys=C5=82aw=20Kryger?= <pkryger@HIDDEN>
>> Date: Fri, 8 Aug 2025 11:43:52 +0100
>> Subject: [PATCH 2/2] Store local checkout directory in autoloads indirection
>>
>> * lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): When installing
>> from a local checkout, store the value of `:lisp-dir' property of
>> `pkg-spec' in a "Package-spec" header in a generated autoloads
>> indirection file.
>> * lisp/emacs-lisp/package-vc.el (package-vc--pkg-spec-from-autoloads):
>> New function to retrieve package spec from a "Package-spec" header
>> from autoloads indirection file (if any).
>> * lisp/emacs-lisp/package-vc.el (package-vc-rebuild): Retrieve package
>> spec from autoloads indirection file (if any) and use it while calling
>> `package-vc--unpack-1'.
>> * lisp/emacs-lisp/package-vc.el (package-vc-upgrade): Retrieve package
>> spec from autoloads indirection file (if any) and use it while calling
>> `package-vc--unpack-1' and for `vc-pull'.
>>
>> fixes: bug#79188
>
> (The formatting is off here as well, but again, I can take care of that.
> In case you did not know, in log-edit-mode, you can use the
> `log-edit-generate-changelog-from-diff' command (bound to C-c C-w) to
> generate a changelog from the current diff).
Thank you for pointing that out, and recommendation of `log-edit-mode'.
Do you know if that can be achieved from within `magit' (or are there a
known integration points)?
I haven't posted too many patches to Emacs, so my format-fu may be not
up to standard.
I have attached new patches with comments addressed. I hope these are
formatted better. If not please feel free to update.
--=-=-=
Content-Type: text/x-diff
Content-Disposition: inline;
filename=0001-Compile-file-in-local-checkout-directory.patch
Content-Description: patch
From 8a785a9bb567e3143b5bd4ae58c3c355c7949945 Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@HIDDEN>
Date: Fri, 8 Aug 2025 11:43:24 +0100
Subject: [PATCH 1/2] Compile file in local checkout directory
* lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): Compile
package in a local checkout directory when it is installed from
such a location, for example with
`package-vc-install-from-checkout'.
(Bug#79188)
---
lisp/emacs-lisp/package-vc.el | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 7433fce2d89..9e118c7af02 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -546,7 +546,14 @@ package-vc--unpack-1
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
- (package--compile new-desc)
+ (package--compile
+ (if lisp-dir
+ ;; In case we are installing a package from a local
+ ;; checkout, we want to compile the checkout, not the
+ ;; redirection!
+ (package-desc-create :dir lisp-dir)
+ new-desc))
+
(when package-native-compile
(package--native-compile-async new-desc))
;; After compilation, load again any files loaded by
--
2.50.1
--=-=-=
Content-Type: text/x-diff
Content-Disposition: inline;
filename=0002-Store-local-checkout-directory-in-autoloads-indirect.patch
Content-Description: patch
From 24e845766d1a7c6f1d465db6c4041fc3a102d3a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Przemys=C5=82aw=20Kryger?= <pkryger@HIDDEN>
Date: Fri, 8 Aug 2025 11:43:52 +0100
Subject: [PATCH 2/2] Store local checkout directory in autoloads indirection
The checkout directory is saved in a generated autoloads
indirection file when installing with
`package-vc-install-from-checkout'. the intention to use the
checkout directory in subsequent calls to `package-vc-update',
`package-vc-upgrade', and `package-vc-ugrade-all'.
* lisp/emacs-lisp/package-vc.el (package-vc--desc->spec):
Retrieve package spec from package's autoloads indirection file
when there's no spec in `package-vc-selected-packages'.
(package-vc--unpack-1): When installing from a local checkout,
store the value of `:lisp-dir' property of `pkg-spec' in a
"Package-spec" header in a generated autoloads indirection file.
(package-vc-upgrade): When package has a local checkout - as
defined by a presence of `:lisp-dir' property in `pkg-spec' -
use it as a place where package source has been checked out.
(Bug#79188)
---
lisp/emacs-lisp/package-vc.el | 52 ++++++++++++++++++++++++-----------
1 file changed, 36 insertions(+), 16 deletions(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 9e118c7af02..87cfbc7595a 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -160,18 +160,28 @@ package-vc--desc->spec
"Retrieve the package specification for PKG-DESC.
The optional argument NAME can be used to override the default
name for PKG-DESC."
- (alist-get
- (setq name (or name (package-desc-name pkg-desc)))
- (if (and (package-desc-archive pkg-desc)
- (not (alist-get name package-vc-selected-packages
- nil nil #'string=)))
- (alist-get (intern (package-desc-archive pkg-desc))
- package-vc--archive-spec-alists)
- ;; Consult both our local list of package specifications, as well
- ;; as the lists provided by the archives.
- (apply #'append (cons package-vc-selected-packages
- (mapcar #'cdr package-vc--archive-spec-alists))))
- '() nil #'string=))
+ (let ((name (or name (package-desc-name pkg-desc))))
+ (or
+ (alist-get
+ name
+ (if (and (package-desc-archive pkg-desc)
+ (not (alist-get name package-vc-selected-packages
+ nil nil #'string=)))
+ (alist-get (intern (package-desc-archive pkg-desc))
+ package-vc--archive-spec-alists)
+ ;; Consult both our local list of package specifications, as well
+ ;; as the lists provided by the archives.
+ (apply #'append (cons package-vc-selected-packages
+ (mapcar #'cdr package-vc--archive-spec-alists))))
+ '() nil #'string=)
+ (when-let* ((autoloads (expand-file-name (format "%s-autoloads.el" name)
+ (package-desc-dir pkg-desc)))
+ ((file-exists-p autoloads)))
+ (with-temp-buffer
+ (insert-file-contents autoloads)
+ (ignore-errors
+ (read (lm-header "package-spec"))))))))
+
(defun package-vc--read-archive-data (archive)
"Update `package-vc--archive-spec-alists' for ARCHIVE.
@@ -508,7 +518,14 @@ package-vc--unpack-1
(when lisp-dir
(write-region
(with-temp-buffer
- (insert ";; Autoload indirection for package-vc\n\n")
+ (insert ";; Autoload indirection for package-vc\n")
+ (insert ";; Package-spec: ")
+ ;; Store the pkg-spec such that it can be reused by
+ ;; `package-rebuild' and `package-vc-upgrade' to restore
+ ;; the same conditions as were when the indirection has
+ ;; been created for the first time.
+ (prin1 pkg-spec (current-buffer))
+ (insert "\n\n")
(prin1 `(load (expand-file-name
,(expand-file-name auto-name lisp-dir)
(or (and load-file-name
@@ -757,6 +774,9 @@ package-vc-upgrade
;; If there is a better way to do this, it should be done.
(cl-assert (package-vc-p pkg-desc))
(letrec ((pkg-dir (package-desc-dir pkg-desc))
+ (checkout-dir (or (plist-get (package-vc--desc->spec pkg-desc)
+ :lisp-dir)
+ pkg-dir))
(vc-flags)
(vc-filter-command-function
(lambda (command file-or-list flags)
@@ -764,7 +784,7 @@ package-vc-upgrade
(list command file-or-list flags)))
(post-upgrade
(lambda (_command _file-or-list flags)
- (when (and (file-equal-p pkg-dir default-directory)
+ (when (and (file-equal-p checkout-dir default-directory)
(eq flags vc-flags))
(unwind-protect
(with-demoted-errors "Failed to activate: %S"
@@ -774,8 +794,8 @@ package-vc-upgrade
(with-demoted-errors "Failed to fetch: %S"
(require 'vc-dir)
(with-current-buffer (vc-dir-prepare-status-buffer
- (format " *package-vc-dir: %s*" pkg-dir)
- pkg-dir (vc-responsible-backend pkg-dir))
+ (format " *package-vc-dir: %s*" checkout-dir)
+ checkout-dir (vc-responsible-backend checkout-dir))
(vc-pull)))))
(defun package-vc--archives-initialize ()
--
2.50.1
--=-=-=
Content-Type: text/plain
More comments below. I hope they will make easier to understand the
new patches.
>> ---
>> lisp/emacs-lisp/package-vc.el | 46 +++++++++++++++++++++++++++++------
>> 1 file changed, 39 insertions(+), 7 deletions(-)
>>
>> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
>> index 9e118c7af02..400e648b8f5 100644
>> --- a/lisp/emacs-lisp/package-vc.el
>> +++ b/lisp/emacs-lisp/package-vc.el
>> @@ -508,7 +508,14 @@ package-vc--unpack-1
>> (when lisp-dir
>> (write-region
>> (with-temp-buffer
>> - (insert ";; Autoload indirection for package-vc\n\n")
>> + (insert ";; Autoload indirection for package-vc\n")
>> + (insert ";; Package-spec: ")
>> + ;; Store the pkg-spec such that it can be reused by
>> + ;; `package-rebuild' and `package-vc-upgrade' to restore
>> + ;; the same conditions as were when the indirection has
>> + ;; been created for the first time.
>> + (prin1 pkg-spec (current-buffer))
>
> This is strictly speaking not robust, as doesn't assure us that
> something like (prin1 "one\ntwo") will result in a string without
> newlines and not "break out" of the comment. If anything, we should
> consider storing this in a separate file, but more on that below.
I agree with you. I have developed these patches trying to avoid
touching any other workflow and leaned on the similar assumption/hack
that has been implemented in `package-vc-install-from-checkout'. That
is the variable `package-vc-selected-packages' will temporarily hold a
stub spec that will allow `package-vc--unpack-1' to use the checkout
directory and not the value of slot `:dir' in `pkg-desc'.
The new patches attached to this message are implemented with a slightly
different assumption: that `package-vc--unpack-1' will somehow get an
appropriate `pkg-spec' for the package being installed.
>> + (insert "\n\n")
>> (prin1 `(load (expand-file-name
>> ,(expand-file-name auto-name lisp-dir)
>> (or (and load-file-name
>> @@ -589,6 +596,19 @@ package-vc--unpack-1
>>
>> (declare-function project-remember-projects-under "project" (dir &optional recursive))
>>
>> +(defun package-vc--pkg-spec-from-autoloads (pkg-desc)
>> + "Read a \"Packcage-spec\" header from autoloads file for PKG-DESC."
>> + (when-let* ((name (package-desc-name pkg-desc))
>> + (autoloads (expand-file-name (format "%s-autoloads.el" name)
>> + (package-desc-dir pkg-desc)))
>> + ((file-exists-p autoloads))
>> + (spec (with-temp-buffer
>> + (insert-file-contents autoloads)
>> + (ignore-errors
>> + (read (lm-header "package-spec"))))))
>> + (cons (symbol-name name)
>> + spec)))
>
> Generally speaking I am not sure if this approach is necessary, as we
> already have `package-vc--desc->spec' and introducing this hack would
> introduce an ambiguity as to where the authoritative package
> specification is stored.
I am not really sure what did you mean by "where the authoritative
package specification is stored". Was it referring to a persistent
storage? Or to the in-memory storage? Anyway - in the new patch I have
moved code that reads header to `pakcage-vc--desc->spec' function. This
simplified the patch itself but also prompted me to consider an
alternative approach, which I will elaborate on in the end of the
message.
>> +
>> (defun package-vc--clone (pkg-desc pkg-spec dir rev)
>> "Clone the package PKG-DESC whose spec is PKG-SPEC into the directory DIR.
>> REV specifies a specific revision to checkout. This overrides the `:branch'
>> @@ -756,7 +776,10 @@ package-vc-upgrade
>> ;;
>> ;; If there is a better way to do this, it should be done.
>> (cl-assert (package-vc-p pkg-desc))
>> - (letrec ((pkg-dir (package-desc-dir pkg-desc))
>> + (letrec ((pkg-spec (package-vc--pkg-spec-from-autoloads pkg-desc))
>
> So we are just shadowing the pkg-spec passed as an argument?
I don't think I am getting this question. `pkg-spec' in function
`package-vc-upgrade' was a new variable introduced by the previous
patch. Function `package-vc-upgrade' had not `pkg-spec' before the
patch. Was your question, perhaps, prompted by the fact that the patch
was formatted in such a way it may seem it touches `package-vc--clone'?
>> + (pkg-dir (package-desc-dir pkg-desc))
>> + (source-dir (or (plist-get (cdr pkg-spec) :lisp-dir)
>> + pkg-dir))
>
> Just an an example of what I was talking about above: Here for instance
> we already have an inconstancy. Everywhere else in the file, we assume
> that a package specification is just a plist, and not a (PACKAGE-NAME
> . SPEC-PLIST) that requires a `cdr'. to access.
Agreed. In the new patch the `pkg-spec' is always in the same form.
>> (vc-flags)
>> (vc-filter-command-function
>> (lambda (command file-or-list flags)
>> @@ -764,18 +787,22 @@ package-vc-upgrade
>> (list command file-or-list flags)))
>> (post-upgrade
>> (lambda (_command _file-or-list flags)
>> - (when (and (file-equal-p pkg-dir default-directory)
>> + (when (and (file-equal-p source-dir default-directory)
>> (eq flags vc-flags))
>> (unwind-protect
>> (with-demoted-errors "Failed to activate: %S"
>> - (package-vc--unpack-1 pkg-desc pkg-dir))
>> + (let ((package-vc-selected-packages
>> + (if pkg-spec
>> + (cons pkg-spec package-vc-selected-packages)
>> + package-vc-selected-packages)))
>> + (package-vc--unpack-1 pkg-desc pkg-dir)))
>
> You'll have yo remind me (i.e. add a comment) why you are binding the
> variable here and why you are distinguishing between pkg-spec being nil
> or not?
Well, since I have used a different approach and this block is gone I
will not add a comment. For posterity: I was binding in this way to
avoid having a nil in the beginning of the
`package-vc-slected-packages'. I guess that would make it slightly
easier for anyone who's debugging this in the future.
[...]
When writing this new patch an idea occurred to me that installation a
package with `package-vc-install-from-checkout' could store the location
of the checkout directory in `package-vc-selected-packages', as a proper
`pkg-spec' structure.
That would remove a dichotomy that is present today: packages installed
wich `package-vc-install' have their specs persisted between Emacs
sessions, while packages installed with
`package-vc-install-from-checkout' not. Please note, that one may get
an impression (and I certainly did fell for it when I first started
using `package-vc') from reading a doc string of `package-vc-checkout'
that executing `package-vc-checkout' followed by
`package-vc-install-from-checkout' will result with the same end state
as `package-vc-install'. This is not true, as for the latter method
`spec-spec' may be stored in `package-vc-selected-packages' while the
former method will never add to `package-vc-selected-packages'. Except
for the temporary binding with a (stub?) `pkg-spec'.
Also, this could restore the semantics of property `:lisp-dir' in such a
temporary `pkg-spec'. What I mean is that it is an absolute path when
calling `package-vc--unpack-1' from `package-vc-install-from-checkout',
while info node (emacs) Fetching Package Sources clearly states:
A string providing the repository-relative name of the directory to
use for loading the Lisp sources, which defaults to the root
directory of the repository.
One more benefit would be that the robustness issue (which still
prevails in patches attached to this message) should be gone.
Should you think it's a good idea I'd look for a guidance as to where
such a value of the checkout directory be stored in a `pkg-spec'.
Encode it as "file:///absolute/path/to/checkout" value of property
`:url'? Or keep it as is (i.e., absolute path) in property `:lisp-dir'
and just detect that in handlers and update relevant info? Or add a
completely new property, say `:checkout-dir'?
Last but not least: how important is to keep backward compatibility?
Inside the master branch as well as across Emacs major versions.
Cheers,
PK
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Sat, 16 Aug 2025 13:04:02 +0000
Resent-Message-ID: <handler.79188.B79188.17553494093696 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17553494093696
(code B ref 79188); Sat, 16 Aug 2025 13:04:02 +0000
Received: (at 79188) by debbugs.gnu.org; 16 Aug 2025 13:03:29 +0000
Received: from localhost ([127.0.0.1]:41591 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1unGZE-0000xX-6C
for submit <at> debbugs.gnu.org; Sat, 16 Aug 2025 09:03:29 -0400
Received: from mout02.posteo.de ([185.67.36.66]:49419)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1unGZ8-0000x5-Vn
for 79188 <at> debbugs.gnu.org; Sat, 16 Aug 2025 09:03:26 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout02.posteo.de (Postfix) with ESMTPS id A4161240101
for <79188 <at> debbugs.gnu.org>; Sat, 16 Aug 2025 15:03:15 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1755349395; bh=2sPsTPjHpH5n1jsxCc2fFQDyWcnAP4/A7tTXvR56GSo=;
h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type:
From;
b=GV1JULBrIruQ2O9gjB4bxJTjF5xFTn0ewGu3kC/p97ZUPfIAR+wKqcfqQV+0G73Wq
eyE+EFrisc0/IF0CVYuvkUFtyWAzJUSKAnnkTFFenj6/aBF4ier0lKiSESfSLoX0Sd
FuN2I1OAVQS+rjIAVvaVMPHeb8svKl0ZFhdnqppWcEKNRfQM60OlK2DimQ1xLWt4Fy
DWPdhU8OxkDTrz8TRoSfWAHYxRs+LHan3lscdpqLJ0jLfWw7q3MDZtZ5lsQohLGBaS
VRq4htsSfytL+TZLt/SqF+hytCrjU2jB7ELz1rkDKguYsHhpsajBoqObaPZA6nk+KK
L/hO0aAhURbMQ==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4c3zg667lyz6tvc;
Sat, 16 Aug 2025 15:03:14 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2o6smup74.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN>
Date: Sat, 16 Aug 2025 13:03:15 +0000
Message-ID: <87cy8v2zcd.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
(Once again, I was busy and apologise for my delayed response!)
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> Philip Kaludercic <philipk@HIDDEN> writes:
>
> [...]
>>>> A question: shouldn't the newly generated *.elc files be put in
>>>> package install directory, just like the (non compiled) autoloads file
>>>> is? In my - very na=3DC3=3DAFve - view this would not only remove bur=
den
>>>> of doubling `load-path' entries (will that happen) but would also
>>>> allow for a complete separation of compiled files between multiple
>>>> Emacs versions coexisting on the same machine and reusing the same
>>>> package source directories.
>>>
>>> While the patch attached fixes basic workflows, I wonder idea of having
>>> *.elc in a package install directory is worth exploring. Would that
>>> affect other functionalities? For example `load' and `require' should
>>> just work (provided the package install directory is in front of package
>>> source directory in `load-pat'), but what will happen with
>>> `find-library'/`locate-library'? Are there any others?
>>
>> By package install directory you mean the ~/.emacs.d/elpa/... directory
>> right?
>
> Yes, I did meant that place.
1+
>> I get the advantage of not having incompatible .elc versions but
>> I am not an expert when it comes the load-order questions. I think we
>> should discuss this in a separate feature request and then ask someone
>> who knows more about that to avoid making clumsy mistakes. Does that
>> sound OK?
>
> It does. Where do you recommend to post such a feature request be
> posted? debbugs? emacs-devel?
I think the discussion (separate storage of .el and .elc files) is
general enough that we should post it on emacs-devel.
>>> From 56fa1014b1f8f2eb7f6d87304c3f31604fed48ba Mon Sep 17 00:00:00 2001
>>> From: Philip Kaludercic <philipk@HIDDEN>
>>> Date: Fri, 8 Aug 2025 11:43:24 +0100
>>> Subject: [PATCH 1/2] Compile file in local checkout directory
>>>
>>> This partially fixes bug#79188.
>>
>> We usually reference bug numbers at the end of a commit message in
>> parentheses, but I can take care of that.
>
> [...]
>>> From 07596327df8bee5831003b62c811dd3fc53f2a88 Mon Sep 17 00:00:00 2001
>>> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
>>> Date: Fri, 8 Aug 2025 11:43:52 +0100
>>> Subject: [PATCH 2/2] Store local checkout directory in autoloads indire=
ction
>>>
>>> * lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): When installing
>>> from a local checkout, store the value of `:lisp-dir' property of
>>> `pkg-spec' in a "Package-spec" header in a generated autoloads
>>> indirection file.
>>> * lisp/emacs-lisp/package-vc.el (package-vc--pkg-spec-from-autoloads):
>>> New function to retrieve package spec from a "Package-spec" header
>>> from autoloads indirection file (if any).
>>> * lisp/emacs-lisp/package-vc.el (package-vc-rebuild): Retrieve package
>>> spec from autoloads indirection file (if any) and use it while calling
>>> `package-vc--unpack-1'.
>>> * lisp/emacs-lisp/package-vc.el (package-vc-upgrade): Retrieve package
>>> spec from autoloads indirection file (if any) and use it while calling
>>> `package-vc--unpack-1' and for `vc-pull'.
>>>
>>> fixes: bug#79188
>>
>> (The formatting is off here as well, but again, I can take care of that.
>> In case you did not know, in log-edit-mode, you can use the
>> `log-edit-generate-changelog-from-diff' command (bound to C-c C-w) to
>> generate a changelog from the current diff).
>
> Thank you for pointing that out, and recommendation of `log-edit-mode'.
> Do you know if that can be achieved from within `magit' (or are there a
> known integration points)?
I don't know, I mostly use vc-mode myself when working on Emacs.
Perhaps you can ask the Magit maintainers if they have any workarounds?
> I haven't posted too many patches to Emacs, so my format-fu may be not
> up to standard.
>
> I have attached new patches with comments addressed. I hope these are
> formatted better. If not please feel free to update.
Looks good!
> From 8a785a9bb567e3143b5bd4ae58c3c355c7949945 Mon Sep 17 00:00:00 2001
> From: Philip Kaludercic <philipk@HIDDEN>
> Date: Fri, 8 Aug 2025 11:43:24 +0100
> Subject: [PATCH 1/2] Compile file in local checkout directory
>
> * lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): Compile
> package in a local checkout directory when it is installed from
> such a location, for example with
> `package-vc-install-from-checkout'.
>
> (Bug#79188)
[...]
>
> From 24e845766d1a7c6f1d465db6c4041fc3a102d3a8 Mon Sep 17 00:00:00 2001
> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
> Date: Fri, 8 Aug 2025 11:43:52 +0100
> Subject: [PATCH 2/2] Store local checkout directory in autoloads indirect=
ion
>
> The checkout directory is saved in a generated autoloads
> indirection file when installing with
> `package-vc-install-from-checkout'. the intention to use the
> checkout directory in subsequent calls to `package-vc-update',
> `package-vc-upgrade', and `package-vc-ugrade-all'.
>
> * lisp/emacs-lisp/package-vc.el (package-vc--desc->spec):
> Retrieve package spec from package's autoloads indirection file
> when there's no spec in `package-vc-selected-packages'.
> (package-vc--unpack-1): When installing from a local checkout,
> store the value of `:lisp-dir' property of `pkg-spec' in a
> "Package-spec" header in a generated autoloads indirection file.
> (package-vc-upgrade): When package has a local checkout - as
> defined by a presence of `:lisp-dir' property in `pkg-spec' -
> use it as a place where package source has been checked out.
>
> (Bug#79188)
> ---
> lisp/emacs-lisp/package-vc.el | 52 ++++++++++++++++++++++++-----------
> 1 file changed, 36 insertions(+), 16 deletions(-)
>
> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
> index 9e118c7af02..87cfbc7595a 100644
> --- a/lisp/emacs-lisp/package-vc.el
> +++ b/lisp/emacs-lisp/package-vc.el
> @@ -160,18 +160,28 @@ package-vc--desc->spec
> "Retrieve the package specification for PKG-DESC.
> The optional argument NAME can be used to override the default
> name for PKG-DESC."
> - (alist-get
> - (setq name (or name (package-desc-name pkg-desc)))
> - (if (and (package-desc-archive pkg-desc)
> - (not (alist-get name package-vc-selected-packages
> - nil nil #'string=3D)))
> - (alist-get (intern (package-desc-archive pkg-desc))
> - package-vc--archive-spec-alists)
> - ;; Consult both our local list of package specifications, as well
> - ;; as the lists provided by the archives.
> - (apply #'append (cons package-vc-selected-packages
> - (mapcar #'cdr package-vc--archive-spec-alists=
))))
> - '() nil #'string=3D))
> + (let ((name (or name (package-desc-name pkg-desc))))
> + (or
> + (alist-get
> + name
> + (if (and (package-desc-archive pkg-desc)
> + (not (alist-get name package-vc-selected-packages
> + nil nil #'string=3D)))
> + (alist-get (intern (package-desc-archive pkg-desc))
> + package-vc--archive-spec-alists)
> + ;; Consult both our local list of package specifications, as well
> + ;; as the lists provided by the archives.
> + (apply #'append (cons package-vc-selected-packages
> + (mapcar #'cdr package-vc--archive-spec-ali=
sts))))
> + '() nil #'string=3D)
> + (when-let* ((autoloads (expand-file-name (format "%s-autoloads.el" =
name)
> + (package-desc-dir pkg-desc=
)))
> + ((file-exists-p autoloads)))
> + (with-temp-buffer
> + (insert-file-contents autoloads)
> + (ignore-errors
> + (read (lm-header "package-spec"))))))))
This seems to be taking the opposite approach of what I had in mind. My
question, and it might just be that I am missing something because the
code isn't cached in my brain anymore, is why don't we re-use
`package-vc-selected-packages' and store the package specifications in
there, instead of duplicating this in the autoload file. I am thinking
about something along the lines of
--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline
diff --git a/lisp/package/package-vc.el b/lisp/package/package-vc.el
index 03767b99729..31b2bb6320e 100644
--- a/lisp/package/package-vc.el
+++ b/lisp/package/package-vc.el
@@ -942,10 +942,12 @@ package-vc-install-from-checkout
(package-vc--archives-initialize)
(let* ((dir (if interactive dir (expand-file-name dir))) ;avoid double expansion
(name (or name (file-name-base (directory-file-name dir))))
- (pkg-dir (expand-file-name name package-user-dir))
- (package-vc-selected-packages
- (cons (list name :lisp-dir dir)
- package-vc-selected-packages)))
+ (pkg-dir (expand-file-name name package-user-dir)))
+ (customize-save-variable
+ 'package-vc-selected-packages
+ (cons (list name :lisp-dir dir)
+ (seq-remove (lambda (spec) (string= name (car spec)))
+ package-vc-selected-packages)))
(when (file-exists-p pkg-dir)
(if (yes-or-no-p (format "Overwrite previous checkout for package `%s'?" name))
(package--delete-directory pkg-dir)
--=-=-=
Content-Type: text/plain
just perhaps with a helper function to avoid the duplication between
this function and `package-vc--unpack'.
This is really the crux of the issue in my eyes and luckily it is just a
technical discussion.
>
> (defun package-vc--read-archive-data (archive)
> "Update `package-vc--archive-spec-alists' for ARCHIVE.
> @@ -508,7 +518,14 @@ package-vc--unpack-1
> (when lisp-dir
> (write-region
> (with-temp-buffer
> - (insert ";; Autoload indirection for package-vc\n\n")
> + (insert ";; Autoload indirection for package-vc\n")
> + (insert ";; Package-spec: ")
> + ;; Store the pkg-spec such that it can be reused by
> + ;; `package-rebuild' and `package-vc-upgrade' to restore
> + ;; the same conditions as were when the indirection has
> + ;; been created for the first time.
> + (prin1 pkg-spec (current-buffer))
The issue with a newline in a string I mentioned earlier still persists
in this version... If we were to take this approach, I think it would
be better to store the specification in a <package name>-spec.eld file
so that we don't have to worry about these kinds of problems.
> + (insert "\n\n")
> (prin1 `(load (expand-file-name
> ,(expand-file-name auto-name lisp-dir)
> (or (and load-file-name
> @@ -757,6 +774,9 @@ package-vc-upgrade
> ;; If there is a better way to do this, it should be done.
> (cl-assert (package-vc-p pkg-desc))
> (letrec ((pkg-dir (package-desc-dir pkg-desc))
> + (checkout-dir (or (plist-get (package-vc--desc->spec pkg-desc)
> + :lisp-dir)
> + pkg-dir))
> (vc-flags)
> (vc-filter-command-function
> (lambda (command file-or-list flags)
> @@ -764,7 +784,7 @@ package-vc-upgrade
> (list command file-or-list flags)))
> (post-upgrade
> (lambda (_command _file-or-list flags)
> - (when (and (file-equal-p pkg-dir default-directory)
> + (when (and (file-equal-p checkout-dir default-directory)
> (eq flags vc-flags))
> (unwind-protect
> (with-demoted-errors "Failed to activate: %S"
> @@ -774,8 +794,8 @@ package-vc-upgrade
> (with-demoted-errors "Failed to fetch: %S"
> (require 'vc-dir)
> (with-current-buffer (vc-dir-prepare-status-buffer
> - (format " *package-vc-dir: %s*" pkg-dir)
> - pkg-dir (vc-responsible-backend pkg-dir))
> + (format " *package-vc-dir: %s*" checkout-dir)
> + checkout-dir (vc-responsible-backend checkout-dir))
> (vc-pull)))))
This is sensible!
> (defun package-vc--archives-initialize ()
--
Philip Kaludercic
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Mon, 18 Aug 2025 13:58:02 +0000
Resent-Message-ID: <handler.79188.B79188.17555254726763 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17555254726763
(code B ref 79188); Mon, 18 Aug 2025 13:58:02 +0000
Received: (at 79188) by debbugs.gnu.org; 18 Aug 2025 13:57:52 +0000
Received: from localhost ([127.0.0.1]:50585 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1uo0Mx-0001l0-RF
for submit <at> debbugs.gnu.org; Mon, 18 Aug 2025 09:57:52 -0400
Received: from mail-wr1-x42b.google.com ([2a00:1450:4864:20::42b]:60461)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1uo0Mu-0001kg-02
for 79188 <at> debbugs.gnu.org; Mon, 18 Aug 2025 09:57:49 -0400
Received: by mail-wr1-x42b.google.com with SMTP id
ffacd0b85a97d-3b9d41bea3cso4544097f8f.0
for <79188 <at> debbugs.gnu.org>; Mon, 18 Aug 2025 06:57:47 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1755525461; x=1756130261; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=NW3RITOM9MK+sgJwEU7CxhQQWQ+2lJhR0yGhGM4FZjY=;
b=gV0rvWd/zIyp1zc2TjiHkznChphkeCMuVJqaKnxyqaoF0AX7YJSy3dieYbfoV0L4ip
w8yprzMbqjsWnqWuHEjwco1hvPgivvrEo60fd+vEoKm+xv3lSTe3mCmNowdlYq5Z6sEH
j0YaCwGlLkbLDji/6Tb+Xd2+8Qog4gSYwJN9H5SJZ4mzlzqu58JncweMFu/FCRGukR/t
YG8fpzg6boQjI3/RxJrvyhPxoO07WPR0dlS5GL+9PTQLMwjfc6MCYwQSaz5leUxYsx5h
CCY3TDRkBx8B7CSdtOX2lRvMtfuCkWYcVIG8mvIWfivvAgboL+MeAfA6ytDu/xI3USZX
MBpw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1755525461; x=1756130261;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to;
bh=NW3RITOM9MK+sgJwEU7CxhQQWQ+2lJhR0yGhGM4FZjY=;
b=f50HHXzjdETH+Dl9nZCWZNDNu4+qqY2eh0DdLNzyh5ACk9RQcWWtRIlLc022STmHPU
Sw9/ixAoqfkvJQ/zUqoy8JWGzvenoXVOM6CmD5Ba5UIS4VwtFgUOP5OHiJ9aH2SUw7ZS
hbfqgepYzodrP56V1H2Fa3uq+FCr46VIuYcykTHoKIPI7tBbi6r0ojTVPshdPozqRwS4
DAD13W4+S6yVaTHmzH/MbVA7lY6viu88hOkip+UbQFBHUfZJeLgIQsHxj0E5UGQEUAdu
ucVsU1x5/aWd+NkbQNUNv4PPQm20CfsNlUvM9oeOPcP+l6J80b3VCHmKHJvjjiEXd6/z
l7uA==
X-Gm-Message-State: AOJu0YwyT7hIPuDzey+PVuYFO7wpkpVo/KBQdkxPuTYhtR+N4jY2iROZ
d5lmhQkAjfgkabY2cGwgArYz2aAIrW6KTdRrLXKe22+xf7HMGMygcfn8hLQY2A==
X-Gm-Gg: ASbGncsHJYykRhh1aDe4jpoZ8Y4K1l33kPgWZc4Oe0HLzGb0jMIeohuQOTgmtv6JE4D
VSf/WyWcaFfXub8Qd6dcS9TCzcYNGLlCx9umgAd09o1SpC+FKC4ooK0+xlp0awELWmEevdM4Npw
Xtf6rNzwJKJpzzCuJoFCRXLx2w7qvYGEnTKqM9gBj+xBfNehw2exBtFrNqToJuEGjZtiopGzU7i
Ui97wX0wQycw8k3g5SR6koNXmIMkNB7iFDZcSMImMfJe83NtWdCEr9nY3T7Q4RtPV9+9HHCvBKO
sBmvGIB1bgpbjaxxvTOxA+c/QvfsurxZbSZGuJ2X2zXNHuLR/hISjSTQEVIyUpNcM0GUePiecXb
r4yBkdwXp6+kP4X1jpu4N0FLDtS9hw9erCNkdZFf8R1b9MF/BoDQaFvaxY7j6uw==
X-Google-Smtp-Source: AGHT+IEy5cxmZh4oroIIJ8PdXh5m+IeO6jVH1yEM/9v742HIA7N4BPvcuTam1Dzpk9McZjGdRaaNpw==
X-Received: by 2002:a05:6000:18aa:b0:3b7:9350:44d4 with SMTP id
ffacd0b85a97d-3bb66943723mr10176471f8f.11.1755525461024;
Mon, 18 Aug 2025 06:57:41 -0700 (PDT)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:dce8:8ee:e8b1:a21c])
by smtp.gmail.com with ESMTPSA id
ffacd0b85a97d-3bb652f93d7sm13437173f8f.27.2025.08.18.06.57.40
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Mon, 18 Aug 2025 06:57:40 -0700 (PDT)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <87cy8v2zcd.fsf@HIDDEN> (Philip Kaludercic's message of "Sat,
16 Aug 2025 13:03:15 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
Date: Mon, 18 Aug 2025 14:57:39 +0100
Message-ID: <m2o6sc7mwc.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
Philip Kaludercic <philipk@HIDDEN> writes:
> (Once again, I was busy and apologise for my delayed response!)
No worries at all! This time it was me who added a couple days ;)
[...]
>> From 24e845766d1a7c6f1d465db6c4041fc3a102d3a8 Mon Sep 17 00:00:00 2001
>> From: =?UTF-8?q?Przemys=C5=82aw=20Kryger?= <pkryger@HIDDEN>
>> Date: Fri, 8 Aug 2025 11:43:52 +0100
>> Subject: [PATCH 2/2] Store local checkout directory in autoloads indirection
>>
>> The checkout directory is saved in a generated autoloads
>> indirection file when installing with
>> `package-vc-install-from-checkout'. the intention to use the
>> checkout directory in subsequent calls to `package-vc-update',
>> `package-vc-upgrade', and `package-vc-ugrade-all'.
>>
>> * lisp/emacs-lisp/package-vc.el (package-vc--desc->spec):
>> Retrieve package spec from package's autoloads indirection file
>> when there's no spec in `package-vc-selected-packages'.
>> (package-vc--unpack-1): When installing from a local checkout,
>> store the value of `:lisp-dir' property of `pkg-spec' in a
>> "Package-spec" header in a generated autoloads indirection file.
>> (package-vc-upgrade): When package has a local checkout - as
>> defined by a presence of `:lisp-dir' property in `pkg-spec' -
>> use it as a place where package source has been checked out.
>>
>> (Bug#79188)
>> ---
>> lisp/emacs-lisp/package-vc.el | 52 ++++++++++++++++++++++++-----------
>> 1 file changed, 36 insertions(+), 16 deletions(-)
>>
>> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
>> index 9e118c7af02..87cfbc7595a 100644
>> --- a/lisp/emacs-lisp/package-vc.el
>> +++ b/lisp/emacs-lisp/package-vc.el
>> @@ -160,18 +160,28 @@ package-vc--desc->spec
>> "Retrieve the package specification for PKG-DESC.
>> The optional argument NAME can be used to override the default
>> name for PKG-DESC."
>> - (alist-get
>> - (setq name (or name (package-desc-name pkg-desc)))
>> - (if (and (package-desc-archive pkg-desc)
>> - (not (alist-get name package-vc-selected-packages
>> - nil nil #'string=)))
>> - (alist-get (intern (package-desc-archive pkg-desc))
>> - package-vc--archive-spec-alists)
>> - ;; Consult both our local list of package specifications, as well
>> - ;; as the lists provided by the archives.
>> - (apply #'append (cons package-vc-selected-packages
>> - (mapcar #'cdr package-vc--archive-spec-alists))))
>> - '() nil #'string=))
>> + (let ((name (or name (package-desc-name pkg-desc))))
>> + (or
>> + (alist-get
>> + name
>> + (if (and (package-desc-archive pkg-desc)
>> + (not (alist-get name package-vc-selected-packages
>> + nil nil #'string=)))
>> + (alist-get (intern (package-desc-archive pkg-desc))
>> + package-vc--archive-spec-alists)
>> + ;; Consult both our local list of package specifications, as well
>> + ;; as the lists provided by the archives.
>> + (apply #'append (cons package-vc-selected-packages
>> + (mapcar #'cdr package-vc--archive-spec-alists))))
>> + '() nil #'string=)
>> + (when-let* ((autoloads (expand-file-name (format "%s-autoloads.el" name)
>> + (package-desc-dir pkg-desc)))
>> + ((file-exists-p autoloads)))
>> + (with-temp-buffer
>> + (insert-file-contents autoloads)
>> + (ignore-errors
>> + (read (lm-header "package-spec"))))))))
>
> This seems to be taking the opposite approach of what I had in mind. My
> question, and it might just be that I am missing something because the
> code isn't cached in my brain anymore, is why don't we re-use
> `package-vc-selected-packages' and store the package specifications in
> there, instead of duplicating this in the autoload file. I am thinking
> about something along the lines of
>
> diff --git a/lisp/package/package-vc.el b/lisp/package/package-vc.el
> index 03767b99729..31b2bb6320e 100644
> --- a/lisp/package/package-vc.el
> +++ b/lisp/package/package-vc.el
> @@ -942,10 +942,12 @@ package-vc-install-from-checkout
> (package-vc--archives-initialize)
> (let* ((dir (if interactive dir (expand-file-name dir))) ;avoid double expansion
> (name (or name (file-name-base (directory-file-name dir))))
> - (pkg-dir (expand-file-name name package-user-dir))
> - (package-vc-selected-packages
> - (cons (list name :lisp-dir dir)
> - package-vc-selected-packages)))
> + (pkg-dir (expand-file-name name package-user-dir)))
> + (customize-save-variable
> + 'package-vc-selected-packages
> + (cons (list name :lisp-dir dir)
> + (seq-remove (lambda (spec) (string= name (car spec)))
> + package-vc-selected-packages)))
> (when (file-exists-p pkg-dir)
> (if (yes-or-no-p (format "Overwrite previous checkout for package `%s'?" name))
> (package--delete-directory pkg-dir)
>
>
> just perhaps with a helper function to avoid the duplication between
> this function and `package-vc--unpack'.
>
> This is really the crux of the issue in my eyes and luckily it is just a
> technical discussion.
I think this is very similar to what I was trying to allude to in the
ending of my previous email. I will omit some of it, however, I think
it is worth considering how to store the path to checkout directory. I
think it could be worthwhile to restore semantics of property
`:lisp-dir', such that it follows description from info (emacs) Fetching
Package Sources:
A string providing the repository-relative name of the directory to
use for loading the Lisp sources, which defaults to the root
directory of the repository.
Path to the checkout directory could be either encoded in spec as
"file:///absolute/path/to/checkout" value of property `:url', or stored
in a new property in spec, say `:checkout-dir'. That way a user could
add manual package spec to `package-vc-selected-packages' before calling
`package-install-from-checkout' allowing for installing from checkout
packages that use non standard lisp directory. Of such an approach would
require update in info. What's your opinion?
>>
>> (defun package-vc--read-archive-data (archive)
>> "Update `package-vc--archive-spec-alists' for ARCHIVE.
>> @@ -508,7 +518,14 @@ package-vc--unpack-1
>> (when lisp-dir
>> (write-region
>> (with-temp-buffer
>> - (insert ";; Autoload indirection for package-vc\n\n")
>> + (insert ";; Autoload indirection for package-vc\n")
>> + (insert ";; Package-spec: ")
>> + ;; Store the pkg-spec such that it can be reused by
>> + ;; `package-rebuild' and `package-vc-upgrade' to restore
>> + ;; the same conditions as were when the indirection has
>> + ;; been created for the first time.
>> + (prin1 pkg-spec (current-buffer))
>
> The issue with a newline in a string I mentioned earlier still persists
> in this version... If we were to take this approach, I think it would
> be better to store the specification in a <package name>-spec.eld file
> so that we don't have to worry about these kinds of problems.
Agreed. For now I will explore how storing the spec in
`package-vc-selected-packages' works. But should we decide to resurrect
this approach I will store the data in <package-name>-spec.eld.
[...]
Cheers,
PK
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Mon, 18 Aug 2025 14:46:02 +0000
Resent-Message-ID: <handler.79188.B79188.175552835316710 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.175552835316710
(code B ref 79188); Mon, 18 Aug 2025 14:46:02 +0000
Received: (at 79188) by debbugs.gnu.org; 18 Aug 2025 14:45:53 +0000
Received: from localhost ([127.0.0.1]:50700 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1uo17Q-0004LR-Dw
for submit <at> debbugs.gnu.org; Mon, 18 Aug 2025 10:45:53 -0400
Received: from mout02.posteo.de ([185.67.36.66]:45665)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1uo17M-0004Kx-Dr
for 79188 <at> debbugs.gnu.org; Mon, 18 Aug 2025 10:45:49 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout02.posteo.de (Postfix) with ESMTPS id 94197240101
for <79188 <at> debbugs.gnu.org>; Mon, 18 Aug 2025 16:45:41 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1755528341; bh=WGFBOIISxlmtsmGXaXH0LAnrmMAWEa414KpJCLN/vAw=;
h=From:To:Cc:Subject:Autocrypt:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:Content-Transfer-Encoding:From;
b=Y4txeCD3Yd5MsitN1DNpjWVml5/ECorCTzJh/Q7wOcMzTFq3j7VTYiBmgJLl+ME+p
Yntg1R1l7my/f2t/EAPIo9Nxp46ezfqN9SY3ChrIG3Vg/gMBBEICebp5fGSshCcFIP
/Kk+fOgv/tC/F98YdMJ1cz+RhmlA3g1Qw+BhjZAqJngb50UZGjo2tZa9UaVhapB5Uu
v93m/Azn0DlYBFXyjGm4uJ1+Xd6Ux2PyeukrMz+B8IyX8gjeAdpPtg0ymenz5GuOnI
4yd2o4nu32opcHOflrAN2mclRS7c+LfJBHIQW5KJOmEuNf8TVDWV6nU5WmTSJXx3IZ
Sn3yAZmn7B0Tw==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4c5FrP00Yqz6tvy;
Mon, 18 Aug 2025 16:45:40 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2o6sc7mwc.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN>
Autocrypt: addr=philipk@HIDDEN; keydata=
mDMEZBBQQhYJKwYBBAHaRw8BAQdAHJuofBrfqFh12uQu0Yi7mrl525F28eTmwUDflFNmdui0QlBo
aWxpcCBLYWx1ZGVyY2ljIChnZW5lcmF0ZWQgYnkgYXV0b2NyeXB0LmVsKSA8cGhpbGlwa0Bwb3N0
ZW8ubmV0PoiWBBMWCAA+FiEEDg7HY17ghYlni8XN8xYDWXahwukFAmQQUEICGwMFCQHhM4AFCwkI
BwIGFQoJCAsCBBYCAwECHgECF4AACgkQ8xYDWXahwulikAEA77hloUiSrXgFkUVJhlKBpLCHUjA0
mWZ9j9w5d08+jVwBAK6c4iGP7j+/PhbkxaEKa4V3MzIl7zJkcNNjHCXmvFcEuDgEZBBQQhIKKwYB
BAGXVQEFAQEHQI5NLiLRjZy3OfSt1dhCmFyn+fN/QKELUYQetiaoe+MMAwEIB4h+BBgWCAAmFiEE
Dg7HY17ghYlni8XN8xYDWXahwukFAmQQUEICGwwFCQHhM4AACgkQ8xYDWXahwukm+wEA8cml4JpK
NeAu65rg+auKrPOP6TP/4YWRCTIvuYDm0joBALw98AMz7/qMHvSCeU/hw9PL6u6R2EScxtpKnWof
z4oM
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Mon, 18 Aug 2025 14:45:41 +0000
Message-ID: <878qjgwuwb.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
[...]
>> This seems to be taking the opposite approach of what I had in mind. My
>> question, and it might just be that I am missing something because the
>> code isn't cached in my brain anymore, is why don't we re-use
>> `package-vc-selected-packages' and store the package specifications in
>> there, instead of duplicating this in the autoload file. I am thinking
>> about something along the lines of
>>
>> diff --git a/lisp/package/package-vc.el b/lisp/package/package-vc.el
>> index 03767b99729..31b2bb6320e 100644
>> --- a/lisp/package/package-vc.el
>> +++ b/lisp/package/package-vc.el
>> @@ -942,10 +942,12 @@ package-vc-install-from-checkout
>> (package-vc--archives-initialize)
>> (let* ((dir (if interactive dir (expand-file-name dir))) ;avoid doubl=
e expansion
>> (name (or name (file-name-base (directory-file-name dir))))
>> - (pkg-dir (expand-file-name name package-user-dir))
>> - (package-vc-selected-packages
>> - (cons (list name :lisp-dir dir)
>> - package-vc-selected-packages)))
>> + (pkg-dir (expand-file-name name package-user-dir)))
>> + (customize-save-variable
>> + 'package-vc-selected-packages
>> + (cons (list name :lisp-dir dir)
>> + (seq-remove (lambda (spec) (string=3D name (car spec)))
>> + package-vc-selected-packages)))
>> (when (file-exists-p pkg-dir)
>> (if (yes-or-no-p (format "Overwrite previous checkout for package=
`%s'?" name))
>> (package--delete-directory pkg-dir)
>>
>>
>> just perhaps with a helper function to avoid the duplication between
>> this function and `package-vc--unpack'.
>>
>> This is really the crux of the issue in my eyes and luckily it is just a
>> technical discussion.
>
>
> I think this is very similar to what I was trying to allude to in the
> ending of my previous email. I will omit some of it, however, I think
> it is worth considering how to store the path to checkout directory. I
> think it could be worthwhile to restore semantics of property
> `:lisp-dir', such that it follows description from info (emacs) Fetching
> Package Sources:
>
> A string providing the repository-relative name of the directory to
> use for loading the Lisp sources, which defaults to the root
> directory of the repository.
>
> Path to the checkout directory could be either encoded in spec as
> "file:///absolute/path/to/checkout" value of property `:url', or stored
> in a new property in spec, say `:checkout-dir'. That way a user could
> add manual package spec to `package-vc-selected-packages' before calling
> `package-install-from-checkout' allowing for installing from checkout
> packages that use non standard lisp directory. Of such an approach would
> require update in info. What's your opinion?
I would like to avoid introducing new keywords, as package-vc reuses
the package specifications from ELPA. I recognise that the
file:///... approach might be pretty, but I don't think it is necessary
for our needs -- so I don't have any strong opinions, assuming that
either of the two options do not introduce great complexity.
>>>=20=20
>>> (defun package-vc--read-archive-data (archive)
>>> "Update `package-vc--archive-spec-alists' for ARCHIVE.
>>> @@ -508,7 +518,14 @@ package-vc--unpack-1
>>> (when lisp-dir
>>> (write-region
>>> (with-temp-buffer
>>> - (insert ";; Autoload indirection for package-vc\n\n")
>>> + (insert ";; Autoload indirection for package-vc\n")
>>> + (insert ";; Package-spec: ")
>>> + ;; Store the pkg-spec such that it can be reused by
>>> + ;; `package-rebuild' and `package-vc-upgrade' to restore
>>> + ;; the same conditions as were when the indirection has
>>> + ;; been created for the first time.
>>> + (prin1 pkg-spec (current-buffer))
>>
>> The issue with a newline in a string I mentioned earlier still persists
>> in this version... If we were to take this approach, I think it would
>> be better to store the specification in a <package name>-spec.eld file
>> so that we don't have to worry about these kinds of problems.
>
> Agreed. For now I will explore how storing the spec in
> `package-vc-selected-packages' works. But should we decide to resurrect
> this approach I will store the data in <package-name>-spec.eld.
Look forward to hearing if this works or not!
> [...]
>
>
> Cheers,
> PK
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Mon, 01 Sep 2025 16:27:01 +0000
Resent-Message-ID: <handler.79188.B79188.17567440121310 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17567440121310
(code B ref 79188); Mon, 01 Sep 2025 16:27:01 +0000
Received: (at 79188) by debbugs.gnu.org; 1 Sep 2025 16:26:52 +0000
Received: from localhost ([127.0.0.1]:58334 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1ut7Mo-0000L3-HT
for submit <at> debbugs.gnu.org; Mon, 01 Sep 2025 12:26:52 -0400
Received: from mail-wm1-x332.google.com ([2a00:1450:4864:20::332]:47253)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1ut7Mk-0000Kk-LY
for 79188 <at> debbugs.gnu.org; Mon, 01 Sep 2025 12:26:48 -0400
Received: by mail-wm1-x332.google.com with SMTP id
5b1f17b1804b1-45b7c01a8c1so35601235e9.2
for <79188 <at> debbugs.gnu.org>; Mon, 01 Sep 2025 09:26:46 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1756744000; x=1757348800; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=7tyMxfd9LNVPDXf6XSchWAKf7C9TnDp2McTthRQKszE=;
b=jHn2OKshIb4Ma2RBuwHvY7+C+SqQIApX31VfjR3RnnOfUs0nRbG7NGIathvruShdev
3E8sp7mdnXCtpd0iIpGM1fxTDFeI83P/qfs/pzp97yPI8wifONGBpI8Ra1cl6SePZdCu
QMLsRw/ajOT3dyTEmlywetSoNPSNylJiLSSG2YJ/hsmSnRnWYw+2FFWgbg25zummNeqB
kdf89Vxbl8AUZquoiklrii+YAz4dtPgLPi7MgM61NcqLF8AZQAdYjFh6NQ8K5SG/gBAk
UemU+zHAfLk11wF7KmcP9Am/ZJM1nhNhDyuv4VmhqZLOr4mY4HubZbZQAHiXvajoM1aW
OZow==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1756744000; x=1757348800;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to;
bh=7tyMxfd9LNVPDXf6XSchWAKf7C9TnDp2McTthRQKszE=;
b=E075gKVa2hgaL1hgsR3tlBbzfOKqXeRzB5vkI4LM23VCJ/ZKyyHRd/0bUN/bIafbcv
kDy1Khu68Kb9ik0F3HyedlrB3tXdfsNeWSOsNFkGDwDVyTGM3b23sq9IIf8h5V3IUyY4
sGX3wKiUTAmmYrxz5+wOmHdN2bwiN/hVZ4x8IoKhTgsY7WWTZe444xdNuQKgsfjFaEA1
xChC8+RG346u0I61j7yIVQ1obd68f5ULq8tZ3eWVNnkMGbp2jnFJDBDj7KseCH1zqg5O
kq5ZZ2yxmZHtMDi7VxgpUH6nuevI3FKkQt2tFhQ+CyF5hM+MwTsWaNNvLiLCwqHKh7E1
q8yg==
X-Gm-Message-State: AOJu0YyIfM/koCs+xQZnSxo5D61Ez8YlgbTdW4ofWvTaSbnw7uQ07ddj
7nSAKVFLUa3EGjhQJ0/lzuVc/p8/y0b8GCmOAvX+/BkSt6216BsUYOoWclPkj4PH
X-Gm-Gg: ASbGncsRG6LSChP0hNNSXFe1ZdpNnt71EYyVnD6DCuZe4o5a3OTySZ2Z4JULvm5Rirj
kFVLUFnZPV/Pz2X9nsXapl6rIxOOfmRD9yfEgL+opxNiKzf5/t6aSH06awoSUceT+5R8MFxTYkN
v0jD+8MVszD2BMrGnz+uGwC3YgSdu43yxlgf0AaiF/TclQU0993zJ4Ihb8UK61Rli6HbHc+OUsT
qYq5EHMuxNpZl1e85jA7Pehvyw8LeDF/+/dbw1tuLzwtDESjip9PbsRwhnkWmmtWvvKyGxlowiE
U7EsKpgjzi2fXzxC5i0ePFnMlMJlpO6sOFc1DNrky+yzTsgj1dTUhXPyZIJIA9S3LY1EYBCLjTi
89S0wmYYxJX9KJtY4HJ6qQw6U+SmClwiD5cCUIH4Ey0V+sZn5tZcSRP1u8/545ezM83wafeXAE5
X2yHMrOPvg
X-Google-Smtp-Source: AGHT+IGRJUXm2J0dgm6hMnZC2PqP1itrAgtduzyvHwUEF8z/uzcoVaaxVmRnypv/2MK3moGgX5uCkA==
X-Received: by 2002:a05:600c:154a:b0:45b:8a20:5437 with SMTP id
5b1f17b1804b1-45b95fd646bmr305325e9.31.1756743999414;
Mon, 01 Sep 2025 09:26:39 -0700 (PDT)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:e0c5:b0fc:ca2d:7cca])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-45b7e7f14bbsm165476015e9.8.2025.09.01.09.26.38
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Mon, 01 Sep 2025 09:26:38 -0700 (PDT)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <878qjgwuwb.fsf@HIDDEN> (Philip Kaludercic's message of "Mon,
18 Aug 2025 14:45:41 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
Date: Mon, 01 Sep 2025 17:26:37 +0100
Message-ID: <m2h5xm5ebm.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Philip Kaludercic <philipk@HIDDEN> writes:
> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>>> This seems to be taking the opposite approach of what I had in mind. My
>>> question, and it might just be that I am missing something because the
>>> code isn't cached in my brain anymore, is why don't we re-use
>>> `package-vc-selected-packages' and store the package specifications in
>>> there, instead of duplicating this in the autoload file. I am thinking
>>> about something along the lines of
>>>
>>> diff --git a/lisp/package/package-vc.el b/lisp/package/package-vc.el
>>> index 03767b99729..31b2bb6320e 100644
>>> --- a/lisp/package/package-vc.el
>>> +++ b/lisp/package/package-vc.el
>>> @@ -942,10 +942,12 @@ package-vc-install-from-checkout
>>> (package-vc--archives-initialize)
>>> (let* ((dir (if interactive dir (expand-file-name dir))) ;avoid doub=
le expansion
>>> (name (or name (file-name-base (directory-file-name dir))))
>>> - (pkg-dir (expand-file-name name package-user-dir))
>>> - (package-vc-selected-packages
>>> - (cons (list name :lisp-dir dir)
>>> - package-vc-selected-packages)))
>>> + (pkg-dir (expand-file-name name package-user-dir)))
>>> + (customize-save-variable
>>> + 'package-vc-selected-packages
>>> + (cons (list name :lisp-dir dir)
>>> + (seq-remove (lambda (spec) (string=3D name (car spec)))
>>> + package-vc-selected-packages)))
>>> (when (file-exists-p pkg-dir)
>>> (if (yes-or-no-p (format "Overwrite previous checkout for packag=
e `%s'?" name))
>>> (package--delete-directory pkg-dir)
>>>
>>>
>>> just perhaps with a helper function to avoid the duplication between
>>> this function and `package-vc--unpack'.
>>>
>>> This is really the crux of the issue in my eyes and luckily it is just a
>>> technical discussion.
>>
>>
>> I think this is very similar to what I was trying to allude to in the
>> ending of my previous email. I will omit some of it, however, I think
>> it is worth considering how to store the path to checkout directory. I
>> think it could be worthwhile to restore semantics of property
>> `:lisp-dir', such that it follows description from info (emacs) Fetching
>> Package Sources:
>>
>> A string providing the repository-relative name of the directory to
>> use for loading the Lisp sources, which defaults to the root
>> directory of the repository.
>>
>> Path to the checkout directory could be either encoded in spec as
>> "file:///absolute/path/to/checkout" value of property `:url', or stored
>> in a new property in spec, say `:checkout-dir'. That way a user could
>> add manual package spec to `package-vc-selected-packages' before calling
>> `package-install-from-checkout' allowing for installing from checkout
>> packages that use non standard lisp directory. Of such an approach would
>> require update in info. What's your opinion?
>
> I would like to avoid introducing new keywords, as package-vc reuses
> the package specifications from ELPA. I recognise that the
> file:///... approach might be pretty, but I don't think it is necessary
> for our needs -- so I don't have any strong opinions, assuming that
> either of the two options do not introduce great complexity.
>
> [...]
I used the idea above and explored a route of using schema file://, as I
think it leads to a more direct reading of value of
`package-vc-selected-packages' as well as handling it in code. I think
I fished out all (most?) the places that needed update (there is a few
of them), please see attached patches.
--=-=-=
Content-Type: text/plain
Content-Disposition: attachment;
filename=0001-Compile-file-in-local-checkout-directory.patch
Content-Description: patch
From 8a785a9bb567e3143b5bd4ae58c3c355c7949945 Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@HIDDEN>
Date: Fri, 8 Aug 2025 11:43:24 +0100
Subject: [PATCH 1/2] Compile file in local checkout directory
* lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): Compile
package in a local checkout directory when it is installed from
such a location, for example with
`package-vc-install-from-checkout'.
(Bug#79188)
---
lisp/emacs-lisp/package-vc.el | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 7433fce2d89..9e118c7af02 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -546,7 +546,14 @@ package-vc--unpack-1
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
- (package--compile new-desc)
+ (package--compile
+ (if lisp-dir
+ ;; In case we are installing a package from a local
+ ;; checkout, we want to compile the checkout, not the
+ ;; redirection!
+ (package-desc-create :dir lisp-dir)
+ new-desc))
+
(when package-native-compile
(package--native-compile-async new-desc))
;; After compilation, load again any files loaded by
--
2.50.1
--=-=-=
Content-Type: text/plain
Content-Disposition: attachment;
filename=0002-Encode-local-checkout-directory-in-package-spec.patch
Content-Description: patch
From 500b2fd5af46e3ef1d13f3a7e6ddc6d27e370ae6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Przemys=C5=82aw=20Kryger?= <pkryger@HIDDEN>
Date: Fri, 8 Aug 2025 11:43:52 +0100
Subject: [PATCH 2/2] Encode local checkout directory in package spec
The checkout directory is saved in a package spec in
`package-vc-selected-packages' when installing with
`package-vc-install-from-checkout'.
The intention to use the checkout directory in subsequent calls
to `package-vc-install-selected-packages', `package-vc-update',
`package-vc-upgrade', and `package-vc-ugrade-all'.
* lisp/emacs-lisp/package-vc.el: Update Commentary section.
(package-vc--checkout-dir): New helper function to extract
checkout directory encoded in property `:url' of `pkg-spec'.
The local checkout directory is determined by scheme file://.
(package-vc-install-selected-packages): Handle packages whose
specs have checkout directories pointing to a local checkout.
(package-vc-selected-packages): Update doc string.
(package-vc-commit): When `pkg-spec' has a local checkout prefer
that over package directory from `pkg-desc'.
(package-vc--main-file): When a `pkg-spec' has a local checkout
prefer that over package directory from `pkg-desc'.
(package-vc--unpack-1): When installing a package from a local
checkout use it to calculate `lisp-path', determine if autoload
indirection to `lisp-path' should be generated, and if
`lisp-path' should be used for compilation.
(package-vc--add-and-save-selected-packages): New helper
function to add new `pkg-spec' to `package-vc-selected-packages'
ans store the value of the variable.
(package-vc--unpack): Use the new helper function
`package-vc--add-and-save-selected-packages'.
(package-vc-upgrade): When a package spec has a local checkout
directory prefer that over package directory from `pkg-desc'.
(package-vc-install-from-checkout): Encode the local directory
used for installation in property `:url' of installed package.
(package-vc-rebuild): When a package spec has a local checkout
directory prefer that over package directory from `pkg-desc'.
(package-vc-prepare-patch): When a package spec has a local
checkout directory prefer that over package directory from
`pkg-desc'.
(package-vc-log-incoming): When a package spec has a local
checkout directory prefer that over package directory from
`pkg-desc'.
(Bug#79188)
---
lisp/emacs-lisp/package-vc.el | 106 +++++++++++++++++++++-------------
1 file changed, 67 insertions(+), 39 deletions(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 9e118c7af02..605e04ba7f4 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -31,8 +31,7 @@
;; aren't interested in activating a package, you can use
;; `package-vc-checkout' instead, which will prompt you for a target
;; directory. If you wish to reuse an existing checkout, the command
-;; `package-vc-install-from-checkout' will create a symbolic link and
-;; prepare the package.
+;; `package-vc-install-from-checkout' will prepare the package.
;;
;; If you make local changes that you wish to share with an upstream
;; maintainer, the command `package-vc-prepare-patch' can prepare
@@ -85,6 +84,13 @@ package-vc-register-as-project
(defvar package-vc-selected-packages) ; pacify byte-compiler
+(defun package-vc--checkout-dir (pkg-spec)
+ "Return local checkout directory encoded in property `url' of PKG-SPEC."
+ (when-let* ((url (plist-get pkg-spec :url))
+ ((string-match (rx "file://" (group (+ any)))
+ url)))
+ (file-name-as-directory (match-string 1 url))))
+
;;;###autoload
(defun package-vc-install-selected-packages ()
"Ensure packages specified in `package-vc-selected-packages' are installed."
@@ -101,11 +107,14 @@ package-vc-install-selected-packages
(package-vc-install name spec))
((listp spec)
(package-vc--archives-initialize)
- (package-vc--unpack
- (or (cadr (assoc name package-archive-contents))
- (package-desc-create :name name :kind 'vc))
- spec)))))))
-
+ (if-let* ((pkg-dir (package-vc--checkout-dir spec)))
+ (package-vc--unpack-1
+ (package-desc-create :name name :dir pkg-dir :kind 'vc)
+ (file-name-as-directory pkg-dir))
+ (package-vc--unpack
+ (or (cadr (assoc name package-archive-contents))
+ (package-desc-create :name name :kind 'vc))
+ spec))))))))
(defcustom package-vc-selected-packages nil
"List of packages to install from their VCS repositories.
@@ -120,7 +129,10 @@ package-vc-selected-packages
The command `package-vc-install' updates the value of this user
option to store package specifications for packages that are not
-specified in any archive."
+specified in any archive.
+
+The command `package-vc-install-from-chcekout' updates the value of
+this user option to store package's checkout location."
:type '(alist :tag "List of packages you want to be installed"
:key-type (symbol :tag "Package")
:value-type
@@ -220,8 +232,10 @@ package-vc-commit
;; directory (as is possible when dealing with git repositories).
;; This should be a fallback option.
(cl-loop with dir = (let ((pkg-spec (package-vc--desc->spec pkg-desc)))
- (or (plist-get pkg-spec :lisp-dir)
- (package-desc-dir pkg-desc)))
+ (or (expand-file-name
+ (or (plist-get pkg-spec :lisp-dir) ".")
+ (or (package-vc--checkout-dir pkg-spec)
+ (package-desc-dir pkg-desc)))))
for file in (directory-files dir t "\\.el\\'" t)
when (vc-working-revision file) return it
finally return "unknown"))
@@ -245,7 +259,8 @@ package-vc--main-file
(name (symbol-name (package-desc-name pkg-desc)))
(directory (expand-file-name
(or (plist-get pkg-spec :lisp-dir) ".")
- (or (package-desc-dir pkg-desc)
+ (or (package-vc--checkout-dir pkg-spec)
+ (package-desc-dir pkg-desc)
(expand-file-name name package-user-dir))))
(file (expand-file-name
(or (plist-get pkg-spec :main-file)
@@ -461,8 +476,9 @@ package-vc--unpack-1
identify a package as a VC package later on), building
documentation and marking the package as installed."
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
- (lisp-dir (plist-get pkg-spec :lisp-dir))
- (lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
+ (checkout-dir (package-vc--checkout-dir pkg-spec))
+ (lisp-path (expand-file-name (or (plist-get pkg-spec :lisp-dir) ".")
+ (or checkout-dir pkg-dir)))
missing)
;; In case the package was installed directly from source, the
@@ -505,12 +521,12 @@ package-vc--unpack-1
(let* ((name (package-desc-name pkg-desc))
(auto-name (format "%s-autoloads.el" name)))
(package-generate-autoloads name lisp-path)
- (when lisp-dir
+ (when checkout-dir
(write-region
(with-temp-buffer
(insert ";; Autoload indirection for package-vc\n\n")
(prin1 `(load (expand-file-name
- ,(expand-file-name auto-name lisp-dir)
+ ,(expand-file-name auto-name lisp-path)
(or (and load-file-name
(file-name-directory load-file-name))
(car load-path))))
@@ -547,12 +563,11 @@ package-vc--unpack-1
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
(package--compile
- (if lisp-dir
- ;; In case we are installing a package from a local
- ;; checkout, we want to compile the checkout, not the
- ;; redirection!
- (package-desc-create :dir lisp-dir)
- new-desc))
+ ;; In case we are installing a package from a local checkout,
+ ;; we want to compile the checkout, not the redirection!
+ (if checkout-dir
+ (package-desc-create :dir lisp-path)
+ new-desc))
(when package-native-compile
(package--native-compile-async new-desc))
@@ -628,6 +643,14 @@ package-vc-non-code-file-names
user is fetching code from a repository that does not contain any
Emacs Lisp files.")
+(defun package-vc--add-and-save-selected-packages (name pkg-spec)
+ "Store package NAME with PKG-SPEC in `package-vc-selected-packages'."
+ (customize-save-variable
+ 'package-vc-selected-packages
+ (cons (cons name pkg-spec)
+ (seq-remove (lambda (spec) (string= name (car spec)))
+ package-vc-selected-packages))))
+
(defun package-vc--unpack (pkg-desc pkg-spec &optional rev)
"Install the package described by PKG-DESC.
PKG-SPEC is a package specification, a property list describing
@@ -682,11 +705,7 @@ package-vc--unpack
;; Ensure we have a copy of the package specification
(unless (seq-some (lambda (alist) (equal (alist-get name (cdr alist)) pkg-spec))
package-vc--archive-spec-alists)
- (customize-save-variable
- 'package-vc-selected-packages
- (cons (cons name pkg-spec)
- (seq-remove (lambda (spec) (string= name (car spec)))
- package-vc-selected-packages))))
+ (package-vc--add-and-save-selected-packages name pkg-spec))
(package-vc--unpack-1 pkg-desc pkg-dir)))
@@ -757,6 +776,9 @@ package-vc-upgrade
;; If there is a better way to do this, it should be done.
(cl-assert (package-vc-p pkg-desc))
(letrec ((pkg-dir (package-desc-dir pkg-desc))
+ (checkout-dir (or (package-vc--checkout-dir
+ (package-vc--desc->spec pkg-desc))
+ pkg-dir))
(vc-flags)
(vc-filter-command-function
(lambda (command file-or-list flags)
@@ -764,18 +786,18 @@ package-vc-upgrade
(list command file-or-list flags)))
(post-upgrade
(lambda (_command _file-or-list flags)
- (when (and (file-equal-p pkg-dir default-directory)
+ (when (and (file-equal-p checkout-dir default-directory)
(eq flags vc-flags))
- (unwind-protect
- (with-demoted-errors "Failed to activate: %S"
- (package-vc--unpack-1 pkg-desc pkg-dir))
- (remove-hook 'vc-post-command-functions post-upgrade))))))
+ (unwind-protect
+ (with-demoted-errors "Failed to activate: %S"
+ (package-vc--unpack-1 pkg-desc pkg-dir))
+ (remove-hook 'vc-post-command-functions post-upgrade))))))
(add-hook 'vc-post-command-functions post-upgrade)
(with-demoted-errors "Failed to fetch: %S"
(require 'vc-dir)
(with-current-buffer (vc-dir-prepare-status-buffer
- (format " *package-vc-dir: %s*" pkg-dir)
- pkg-dir (vc-responsible-backend pkg-dir))
+ (format " *package-vc-dir: %s*" checkout-dir)
+ checkout-dir (vc-responsible-backend checkout-dir))
(vc-pull)))))
(defun package-vc--archives-initialize ()
@@ -941,13 +963,12 @@ package-vc-install-from-checkout
(let* ((dir (if interactive dir (expand-file-name dir))) ;avoid double expansion
(name (or name (file-name-base (directory-file-name dir))))
(pkg-dir (file-name-concat package-user-dir name))
- (package-vc-selected-packages
- (cons (list name :lisp-dir dir)
- package-vc-selected-packages)))
+ (pkg-spec (list :url (format "file://%s" dir))))
(when (file-exists-p pkg-dir)
(if (yes-or-no-p (format "Overwrite previous checkout for package `%s'?" name))
(package--delete-directory pkg-dir)
(error "There already exists a checkout for %s" name)))
+ (package-vc--add-and-save-selected-packages (intern name) pkg-spec)
(make-directory pkg-dir t)
(package-vc--unpack-1
(package-desc-create
@@ -966,7 +987,10 @@ package-vc-rebuild
is the responsibility of `package-vc-upgrade'. Interactively,
prompt for the name of the package to rebuild."
(interactive (list (package-vc--read-package-desc "Rebuild package: " t)))
- (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc)))
+ (package-vc--unpack-1 pkg-desc
+ (or (package-vc--checkout-dir
+ (package-vc--desc->spec pkg-desc))
+ (package-desc-dir pkg-desc))))
;;;###autoload
(defun package-vc-prepare-patch (pkg-desc subject revisions)
@@ -986,7 +1010,9 @@ package-vc-prepare-patch
(and (not vc-prepare-patches-separately)
(read-string "Subject: " "[PATCH] " nil nil t))
(vc-prepare-patch-prompt-revisions)))
- (let ((default-directory (package-desc-dir pkg-desc)))
+ (let ((default-directory (or (package-vc--checkout-dir
+ (package-vc--desc->spec pkg-desc))
+ (package-desc-dir pkg-desc))))
(vc-prepare-patch (package-maintainers pkg-desc t)
subject revisions)))
@@ -994,7 +1020,9 @@ package-vc-log-incoming
"Call `vc-log-incoming' for the package PKG-DESC."
(interactive
(list (package-vc--read-package-desc "Incoming log for package: " t)))
- (let ((default-directory (package-desc-dir pkg-desc)))
+ (let ((default-directory (or (package-vc--checkout-dir
+ (package-vc--desc->spec pkg-desc))
+ (package-desc-dir pkg-desc))))
(call-interactively #'vc-log-incoming)))
(provide 'package-vc)
--
2.50.1
--=-=-=
Content-Type: text/plain
For FWIW I created some tests to help with development, and attaching
them for posterity mostly. I think these scenarios could be a base for
some tests that could be a part of Emacs. Yet as of now they would
require some more work to avoid dependencies between tests, as well as
dependency on ELPA, and - perhaps - removal of actual installation.
--=-=-=
Content-Type: text/plain
Content-Disposition: attachment; filename=package-vc-tests.el
Content-Description: tests
;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
;;; Code:
(require 'package-vc)
(require 'package)
(require 'vc-git)
(require 'cl-lib)
(require 'ert)
(defvar package-vc-tests-dir
(make-temp-file "package-vc-tests-" t (format-time-string "-%Y%m%d.%H%M%S")))
(setq package-user-dir (expand-file-name "elpa" package-vc-tests-dir))
(defvar package-vc-tests-packages
`(;; checkout and install with `package-vc-install' (on ELPA)
(diminish . ,(expand-file-name "diminish" package-user-dir))
;; checkout and install with `package-vc-install' (not on ELPA)
(ultra-scroll . ,(expand-file-name "ultra-scroll" package-user-dir))
;; checkout with `package-vc-checktout' and install with
;; `package-vc-install-from-checkout'
(dash . ,(expand-file-name "dash" package-vc-tests-dir))
;; checkout with git and install with `package-vc-install-from-checkout'
(basic-stats . ,(expand-file-name "basic-stats.el" package-vc-tests-dir))
;; TODO: a package with source files in lisp/ directory (both methods of
;; installation)
;; TODO: a package with source files in a non-standard :lisp-dir (both
;; methods of installation)
))
;; TODO: add test for deleting packages, with asserting
;; `package-vc-selected-packages'
;; TODO: clarify `package-vc-install-all' behaviour with regards to packages
;; installed with `package-vc' but not stored in `package-vc-selected-packages'
;; i.e., packages from ELPAs
(defun package-vc-tests-package-desc (package &optional installed)
"Return descriptor of PACKAGE.
When INSTALLED is non-nil the descriptor will come from `package-alist'.
Otherwise the descriptor will be from `package-archive-contents'. This
is to mimic `package-vc--read-package-desc'."
(cadr (assoc (if (stringp package) package (symbol-name package))
(if installed package-alist package-archive-contents)
#'string=)))
(defun package-vc-tests-assert-delete-elc ()
"Assert that .elc files are in expected directories and delete them.
When ALL is non nil, check all packages under test."
(dolist (pkg-checkout-dir package-vc-tests-packages)
(let* ((dir (cdr pkg-checkout-dir))
(elc-files (directory-files dir nil (rx ".elc" string-end))))
(should-not (equal (cons dir elc-files)
(list dir)))
(dolist (elc-file elc-files)
(delete-file elc-file)))))
(defun package-vc-tests-packages-heads (reset)
"Return HEAD revisions of `package-vc-tests-packages'.
When RESET is non-nil also reset to a previous version."
(mapcar (lambda (pkg-checkout-dir)
(let ((default-directory (cdr pkg-checkout-dir)))
(prog1
(cons (car pkg-checkout-dir)
(vc-git-working-revision nil))
(when reset
(vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))))
package-vc-tests-packages))
(ert-deftest package-vc-tests-000-install ()
(package-refresh-contents)
(package-vc--archives-initialize)
(package-vc-install 'diminish)
(should-not (alist-get "diminish" package-vc-selected-packages
nil nil #'string=))
(package-vc-install '(ultra-scroll
:url "https://github.com/jdtsmith/ultra-scroll.git"))
(should (equal "https://github.com/jdtsmith/ultra-scroll.git"
(plist-get (alist-get "ultra-scroll"
package-vc-selected-packages
nil nil #'string=)
:url)))
(let ((checkout-dir (expand-file-name "dash" package-vc-tests-dir)))
(package-vc-checkout (package-vc-tests-package-desc 'dash)
checkout-dir)
(package-vc-install-from-checkout checkout-dir)
(should (equal (format "file://%s" checkout-dir)
(plist-get (alist-get "dash"
package-vc-selected-packages
nil nil #'string=)
:url))))
(let ((checkout-dir (expand-file-name "basic-stats.el" package-vc-tests-dir)))
(shell-command
(format "git clone https://github.com/pkryger/basic-stats.el.git %s"
checkout-dir))
(package-vc-install-from-checkout checkout-dir "basic-stats")
(should (equal (format "file://%s" checkout-dir)
(plist-get (alist-get "basic-stats"
package-vc-selected-packages
nil nil #'string=)
:url))))
(package-vc-tests-assert-delete-elc))
(ert-deftest package-vc-tests-001-main-file ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(should (equal (package-vc--main-file
(package-vc-tests-package-desc (car pkg-checkout-dir) t))
(format "%s/%s.el"
(cdr pkg-checkout-dir)
(car pkg-checkout-dir))))))
(ert-deftest package-vc-tests-002-commit ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(let ((pkg (car pkg-checkout-dir))
(commit (package-vc-commit
(package-vc-tests-package-desc (car pkg-checkout-dir) t))))
(should-not (equal (cons pkg commit)
(list pkg)))
(should-not (equal (list pkg "unknown")
(list pkg commit))))))
(defmacro package-vc-tests-package-vc-upgrade-wait (seconds count &rest body)
"Wait up to SECONDS for COUNT packages upgrading BODY.
Return nil on timeout or non nil otherwise."
(declare (indent 2))
`(letrec ((packages-count ,count)
(post-vc-command (lambda (command _ flags)
;; A crude filter for vc commands
(when (and (equal command "git")
(string-prefix-p "*vc-git" (buffer-name)))
(cl-decf packages-count)))))
(add-hook 'vc-post-command-functions post-vc-command 100)
(unwind-protect
(progn
,@body
(catch 'done
(dotimes (i (* 10 ,seconds))
(sleep-for 0.1)
(when (eql packages-count 0)
(throw 'done t)))))
(remove-hook 'vc-post-command-functions post-vc-command))))
(ert-deftest package-vc-tests-003-upgrade-all ()
(let ((heads (package-vc-tests-packages-heads t)))
(should
(package-vc-tests-package-vc-upgrade-wait
5 (length package-vc-tests-packages)
(package-vc-upgrade-all)))
(should (equal heads (package-vc-tests-packages-heads nil))))
(package-vc-tests-assert-delete-elc))
(ert-deftest package-vc-tests-004-upgrade ()
(let ((heads (package-vc-tests-packages-heads t)))
(should
(package-vc-tests-package-vc-upgrade-wait
5 (length package-vc-tests-packages)
(dolist (pkg-checkout-dir package-vc-tests-packages)
(package-vc-upgrade
(package-vc-tests-package-desc (car pkg-checkout-dir) t)))))
(should (equal heads (package-vc-tests-packages-heads nil))))
(package-vc-tests-assert-delete-elc))
(ert-deftest package-vc-tests-005-rebuild ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(package-vc-rebuild
(package-vc-tests-package-desc (car pkg-checkout-dir) t)))
(package-vc-tests-assert-delete-elc))
(ert-deftest package-vc-tests-006-prepare-patch ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(cl-letf* ((call-count 0)
((symbol-function #'package-maintainers)
(lambda (&rest _)
"test-maintainers"))
((symbol-function #'vc-prepare-patch)
(lambda (addressee subject revisions)
(should (equal (file-name-as-directory default-directory)
(file-name-as-directory (cdr pkg-checkout-dir))))
(should (equal "test-maintainers" addressee))
(should (equal "test-subject" subject))
(should (equal "test-revisions" revisions))
(cl-incf call-count))))
(package-vc-prepare-patch (package-vc-tests-package-desc
(car pkg-checkout-dir)
t)
"test-subject"
"test-revisions")
(should (eql 1 call-count)))))
(ert-deftest package-vc-tests-007-log-incoming ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(cl-letf* ((call-count 0)
((symbol-function #'vc-log-incoming)
(lambda ()
(interactive)
(should (equal (file-name-as-directory default-directory)
(file-name-as-directory (cdr pkg-checkout-dir))))
(cl-incf call-count))))
(package-vc-log-incoming (package-vc-tests-package-desc
(car pkg-checkout-dir) t))
(should (eql 1 call-count)))))
(provide 'package-vc-tests)
;;; package-vc-tests.el ends here
--=-=-=
Content-Type: text/plain
When developing these I found a few more issues, I'd like to bring up.
If these seem to be actual bugs, I am happy to submit them as new bugs,
but for now I'd put them here:
1. There's a bit of code in `package-vc--unpack' to check for existence
of directory "lisp" or "src" (in case there's no property `:lisp-dir')
in the spec. However the variable `lisp-dir' doesn't seem to be used
any further. If this requires a fix, then in the light of the above
patches, I think such a heuristic could be reused when installing from a
custom checkout.
2. When `package-delete' is called for a package installed with
package-vc the package spec is not being removed from
`package-vc-selected-packages'. Is this an issue?
3. When `package-vc-install-all' is called it will go over
`package-vc-selected-packages'. This variable is populated by some of
packages installed with package-vc. I wonder if all package specs
should be stored in the list, and perhaps updated when the spec is
updated in the ELPA. Is that something worth addressing?
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Tue, 16 Sep 2025 18:14:01 +0000
Resent-Message-ID: <handler.79188.B79188.175804640514206 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.175804640514206
(code B ref 79188); Tue, 16 Sep 2025 18:14:01 +0000
Received: (at 79188) by debbugs.gnu.org; 16 Sep 2025 18:13:25 +0000
Received: from localhost ([127.0.0.1]:50114 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1uyaBA-0003h4-VF
for submit <at> debbugs.gnu.org; Tue, 16 Sep 2025 14:13:25 -0400
Received: from mout02.posteo.de ([185.67.36.66]:35095)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1uyaB7-0003gm-EE
for 79188 <at> debbugs.gnu.org; Tue, 16 Sep 2025 14:13:22 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout02.posteo.de (Postfix) with ESMTPS id BF930240101
for <79188 <at> debbugs.gnu.org>; Tue, 16 Sep 2025 20:13:14 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1758046394; bh=hsNsGQBCT5Ha68S8L36wcgrqzC/6+bPEwmH5g516H/8=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:Content-Transfer-Encoding:From;
b=T+pJWy4nfvMFQkmR0AhuzRpaNDPCM2lZo74aGjhzWi6+bhiGpxUyvjQtqdu0c44MI
IKM/V+LQQBJCfXZNJajtYmIUMzSKsVbWZ3KcrXRZt3rIy1PsAGDk2JsafAW4QuEkua
YVE6v881FC3P5suOeB1LnqfUGO5wrbxrAKu+/7vIlEaIaIvCR/qo7z22TtRQv/iOlv
ITgAWJT1w5zymbAXsSwII0cQ7rLeM3uRU55rAoSeM+9NNMaETuJxSdS7CEoANrTwSh
me0Djtqi5SVqBfzQ/M38hxeOves3n00FKWKNrmnCylALikTNQ12KWBF5bjkR8fgAcA
ybpS2w3lUYZ+Q==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4cR94V1xmGz6twv;
Tue, 16 Sep 2025 20:13:14 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2h5xm5ebm.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Tue, 16 Sep 2025 18:13:14 +0000
Message-ID: <87plbqw9je.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> Hello Philip,
>
> Just a friendly reminder. Did you have a chance to read through my last
> proposal?
I did read through it, and I was part-way through responding to the
patch on a different device that I cannot access right now. This
includes code-modifications to the patch, that I would like to avoid
re-writing. I might be able to set it up by tomorrow, and respond to
your previous message then. Sorry for the delay!
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Wed, 17 Sep 2025 23:06:01 +0000
Resent-Message-ID: <handler.79188.B79188.17581503529442 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17581503529442
(code B ref 79188); Wed, 17 Sep 2025 23:06:01 +0000
Received: (at 79188) by debbugs.gnu.org; 17 Sep 2025 23:05:52 +0000
Received: from localhost ([127.0.0.1]:58477 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1uz1Di-0002SA-T4
for submit <at> debbugs.gnu.org; Wed, 17 Sep 2025 19:05:52 -0400
Received: from mout02.posteo.de ([185.67.36.66]:33177)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1uz1De-0002Rl-N0
for 79188 <at> debbugs.gnu.org; Wed, 17 Sep 2025 19:05:49 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout02.posteo.de (Postfix) with ESMTPS id 85E14240101
for <79188 <at> debbugs.gnu.org>; Thu, 18 Sep 2025 01:05:39 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1758150339; bh=QioBIGC6aykJFNgf0atSN3T2l/hgI9BDnUSmA4PLgt8=;
h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type:
From;
b=TYcxzN6FGW3GMGYqQ5JrcVx5p6iAGvXn+e3Q7lTdJEDGhXKZY82kHtMOaBkSMyeOq
iTP6jWug5lsf/LNwh/9fhvWeu0xt9NdpUW8QtTF6rpsxmgpsqjSM5ptz1gaoqbC0KB
miF1MscWrzlav2BSMzl7Po7mTGmq8FZiNhFQYmJ8lx9j5mpo4exnKnPWoH4S6+CYHS
K/pb4GXPMw7ks1lvmmcOnMVsMv5wUpjI8gekM+HukeoLJUdDxJ8y7QcF6LxToYxkZX
XOm3pMWN8eyrrb7UkI9r+XH2OPj+MARYAKqOBs3H2liHSV6Bfupu8ras08/ehA5XnL
etRgbLV8V+k7w==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4cRvWQ63yXz6twq;
Thu, 18 Sep 2025 01:05:38 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2h5xm5ebm.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN>
Date: Wed, 17 Sep 2025 23:05:39 +0000
Message-ID: <87cy7ovfwd.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> Philip Kaludercic <philipk@HIDDEN> writes:
>
>> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>
>>>> This seems to be taking the opposite approach of what I had in mind. =
My
>>>> question, and it might just be that I am missing something because the
>>>> code isn't cached in my brain anymore, is why don't we re-use
>>>> `package-vc-selected-packages' and store the package specifications in
>>>> there, instead of duplicating this in the autoload file. I am thinking
>>>> about something along the lines of
>>>>
>>>> diff --git a/lisp/package/package-vc.el b/lisp/package/package-vc.el
>>>> index 03767b99729..31b2bb6320e 100644
>>>> --- a/lisp/package/package-vc.el
>>>> +++ b/lisp/package/package-vc.el
>>>> @@ -942,10 +942,12 @@ package-vc-install-from-checkout
>>>> (package-vc--archives-initialize)
>>>> (let* ((dir (if interactive dir (expand-file-name dir))) ;avoid dou=
ble expansion
>>>> (name (or name (file-name-base (directory-file-name dir))))
>>>> - (pkg-dir (expand-file-name name package-user-dir))
>>>> - (package-vc-selected-packages
>>>> - (cons (list name :lisp-dir dir)
>>>> - package-vc-selected-packages)))
>>>> + (pkg-dir (expand-file-name name package-user-dir)))
>>>> + (customize-save-variable
>>>> + 'package-vc-selected-packages
>>>> + (cons (list name :lisp-dir dir)
>>>> + (seq-remove (lambda (spec) (string=3D name (car spec)))
>>>> + package-vc-selected-packages)))
>>>> (when (file-exists-p pkg-dir)
>>>> (if (yes-or-no-p (format "Overwrite previous checkout for packa=
ge `%s'?" name))
>>>> (package--delete-directory pkg-dir)
>>>>
>>>>
>>>> just perhaps with a helper function to avoid the duplication between
>>>> this function and `package-vc--unpack'.
>>>>
>>>> This is really the crux of the issue in my eyes and luckily it is just=
a
>>>> technical discussion.
>>>
>>>
>>> I think this is very similar to what I was trying to allude to in the
>>> ending of my previous email. I will omit some of it, however, I think
>>> it is worth considering how to store the path to checkout directory. I
>>> think it could be worthwhile to restore semantics of property
>>> `:lisp-dir', such that it follows description from info (emacs) Fetching
>>> Package Sources:
>>>
>>> A string providing the repository-relative name of the directory to
>>> use for loading the Lisp sources, which defaults to the root
>>> directory of the repository.
>>>
>>> Path to the checkout directory could be either encoded in spec as
>>> "file:///absolute/path/to/checkout" value of property `:url', or stored
>>> in a new property in spec, say `:checkout-dir'. That way a user could
>>> add manual package spec to `package-vc-selected-packages' before calling
>>> `package-install-from-checkout' allowing for installing from checkout
>>> packages that use non standard lisp directory. Of such an approach wou=
ld
>>> require update in info. What's your opinion?
>>
>> I would like to avoid introducing new keywords, as package-vc reuses
>> the package specifications from ELPA. I recognise that the
>> file:///... approach might be pretty, but I don't think it is necessary
>> for our needs -- so I don't have any strong opinions, assuming that
>> either of the two options do not introduce great complexity.
>>
>> [...]
>
> I used the idea above and explored a route of using schema file://, as I
> think it leads to a more direct reading of value of
> `package-vc-selected-packages' as well as handling it in code. I think
> I fished out all (most?) the places that needed update (there is a few
> of them), please see attached patches.
>
> From 8a785a9bb567e3143b5bd4ae58c3c355c7949945 Mon Sep 17 00:00:00 2001
> From: Philip Kaludercic <philipk@HIDDEN>
> Date: Fri, 8 Aug 2025 11:43:24 +0100
> Subject: [PATCH 1/2] Compile file in local checkout directory
>
> * lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): Compile
> package in a local checkout directory when it is installed from
> such a location, for example with
> `package-vc-install-from-checkout'.
>
> (Bug#79188)
[...]
I can apply this patch right away, so that you do not have to re-send
it.
>
>
> From 500b2fd5af46e3ef1d13f3a7e6ddc6d27e370ae6 Mon Sep 17 00:00:00 2001
> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
> Date: Fri, 8 Aug 2025 11:43:52 +0100
> Subject: [PATCH 2/2] Encode local checkout directory in package spec
>
> The checkout directory is saved in a package spec in
> `package-vc-selected-packages' when installing with
> `package-vc-install-from-checkout'.
>
> The intention to use the checkout directory in subsequent calls
> to `package-vc-install-selected-packages', `package-vc-update',
> `package-vc-upgrade', and `package-vc-ugrade-all'.
>
> * lisp/emacs-lisp/package-vc.el: Update Commentary section.
> (package-vc--checkout-dir): New helper function to extract
> checkout directory encoded in property `:url' of `pkg-spec'.
> The local checkout directory is determined by scheme file://.
> (package-vc-install-selected-packages): Handle packages whose
> specs have checkout directories pointing to a local checkout.
> (package-vc-selected-packages): Update doc string.
> (package-vc-commit): When `pkg-spec' has a local checkout prefer
> that over package directory from `pkg-desc'.
> (package-vc--main-file): When a `pkg-spec' has a local checkout
> prefer that over package directory from `pkg-desc'.
> (package-vc--unpack-1): When installing a package from a local
> checkout use it to calculate `lisp-path', determine if autoload
> indirection to `lisp-path' should be generated, and if
> `lisp-path' should be used for compilation.
> (package-vc--add-and-save-selected-packages): New helper
> function to add new `pkg-spec' to `package-vc-selected-packages'
> ans store the value of the variable.
> (package-vc--unpack): Use the new helper function
> `package-vc--add-and-save-selected-packages'.
> (package-vc-upgrade): When a package spec has a local checkout
> directory prefer that over package directory from `pkg-desc'.
> (package-vc-install-from-checkout): Encode the local directory
> used for installation in property `:url' of installed package.
> (package-vc-rebuild): When a package spec has a local checkout
> directory prefer that over package directory from `pkg-desc'.
> (package-vc-prepare-patch): When a package spec has a local
> checkout directory prefer that over package directory from
> `pkg-desc'.
> (package-vc-log-incoming): When a package spec has a local
> checkout directory prefer that over package directory from
> `pkg-desc'.
>
> (Bug#79188)
> ---
> lisp/emacs-lisp/package-vc.el | 106 +++++++++++++++++++++-------------
> 1 file changed, 67 insertions(+), 39 deletions(-)
>
> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
> index 9e118c7af02..605e04ba7f4 100644
> --- a/lisp/emacs-lisp/package-vc.el
> +++ b/lisp/emacs-lisp/package-vc.el
> @@ -31,8 +31,7 @@
> ;; aren't interested in activating a package, you can use
> ;; `package-vc-checkout' instead, which will prompt you for a target
> ;; directory. If you wish to reuse an existing checkout, the command
> -;; `package-vc-install-from-checkout' will create a symbolic link and
> -;; prepare the package.
> +;; `package-vc-install-from-checkout' will prepare the package.
Good catch!
> ;;
> ;; If you make local changes that you wish to share with an upstream
> ;; maintainer, the command `package-vc-prepare-patch' can prepare
> @@ -85,6 +84,13 @@ package-vc-register-as-project
>=20=20
> (defvar package-vc-selected-packages) ; pacify byte-compiler
>=20=20
> +(defun package-vc--checkout-dir (pkg-spec)
> + "Return local checkout directory encoded in property `url' of PKG-SPEC=
."
> + (when-let* ((url (plist-get pkg-spec :url))
> + ((string-match (rx "file://" (group (+ any)))
> + url)))
> + (file-name-as-directory (match-string 1 url))))
My main suggestion would be to make this function more general. See my
alternative patch below.
> ;;;###autoload
> (defun package-vc-install-selected-packages ()
> "Ensure packages specified in `package-vc-selected-packages' are insta=
lled."
> @@ -101,11 +107,14 @@ package-vc-install-selected-packages
> (package-vc-install name spec))
> ((listp spec)
> (package-vc--archives-initialize)
> - (package-vc--unpack
> - (or (cadr (assoc name package-archive-contents))
> - (package-desc-create :name name :kind 'vc))
> - spec)))))))
> -
> + (if-let* ((pkg-dir (package-vc--checkout-dir spec)))
> + (package-vc--unpack-1
> + (package-desc-create :name name :dir pkg-dir :kind 'vc)
> + (file-name-as-directory pkg-dir))
> + (package-vc--unpack
> + (or (cadr (assoc name package-archive-contents))
> + (package-desc-create :name name :kind 'vc))
> + spec))))))))
I do not get this change. package-vc--unpack respects :lisp-dir
internally, why should we preempt it?
>=20=20
> (defcustom package-vc-selected-packages nil
> "List of packages to install from their VCS repositories.
> @@ -120,7 +129,10 @@ package-vc-selected-packages
>=20=20
> The command `package-vc-install' updates the value of this user
> option to store package specifications for packages that are not
> -specified in any archive."
> +specified in any archive.
> +
> +The command `package-vc-install-from-chcekout' updates the value of
> +this user option to store package's checkout location."
> :type '(alist :tag "List of packages you want to be installed"
> :key-type (symbol :tag "Package")
> :value-type
> @@ -220,8 +232,10 @@ package-vc-commit
> ;; directory (as is possible when dealing with git repositories).
> ;; This should be a fallback option.
> (cl-loop with dir =3D (let ((pkg-spec (package-vc--desc->spec pkg-desc=
)))
> - (or (plist-get pkg-spec :lisp-dir)
> - (package-desc-dir pkg-desc)))
> + (or (expand-file-name
> + (or (plist-get pkg-spec :lisp-dir) ".")
> + (or (package-vc--checkout-dir pkg-spec)
> + (package-desc-dir pkg-desc)))))
> for file in (directory-files dir t "\\.el\\'" t)
> when (vc-working-revision file) return it
> finally return "unknown"))
> @@ -245,7 +259,8 @@ package-vc--main-file
> (name (symbol-name (package-desc-name pkg-desc)))
> (directory (expand-file-name
> (or (plist-get pkg-spec :lisp-dir) ".")
> - (or (package-desc-dir pkg-desc)
> + (or (package-vc--checkout-dir pkg-spec)
> + (package-desc-dir pkg-desc)
> (expand-file-name name package-user-dir))))
> (file (expand-file-name
> (or (plist-get pkg-spec :main-file)
> @@ -461,8 +476,9 @@ package-vc--unpack-1
> identify a package as a VC package later on), building
> documentation and marking the package as installed."
> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> - (lisp-dir (plist-get pkg-spec :lisp-dir))
> - (lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
> + (checkout-dir (package-vc--checkout-dir pkg-spec))
> + (lisp-path (expand-file-name (or (plist-get pkg-spec :lisp-dir)=
".")
> + (or checkout-dir pkg-dir)))
> missing)
>=20=20
> ;; In case the package was installed directly from source, the
> @@ -505,12 +521,12 @@ package-vc--unpack-1
> (let* ((name (package-desc-name pkg-desc))
> (auto-name (format "%s-autoloads.el" name)))
> (package-generate-autoloads name lisp-path)
> - (when lisp-dir
> + (when checkout-dir
> (write-region
> (with-temp-buffer
> (insert ";; Autoload indirection for package-vc\n\n")
> (prin1 `(load (expand-file-name
> - ,(expand-file-name auto-name lisp-dir)
> + ,(expand-file-name auto-name lisp-path)
> (or (and load-file-name
> (file-name-directory load-file-name=
))
> (car load-path))))
> @@ -547,12 +563,11 @@ package-vc--unpack-1
> ;; E.g. for multi-package installs, we should first install all =
packages
> ;; and then compile them.
> (package--compile
> - (if lisp-dir
> - ;; In case we are installing a package from a local
> - ;; checkout, we want to compile the checkout, not the
> - ;; redirection!
> - (package-desc-create :dir lisp-dir)
> - new-desc))
> + ;; In case we are installing a package from a local checkout,
> + ;; we want to compile the checkout, not the redirection!
> + (if checkout-dir
> + (package-desc-create :dir lisp-path)
> + new-desc))
>=20=20
> (when package-native-compile
> (package--native-compile-async new-desc))
> @@ -628,6 +643,14 @@ package-vc-non-code-file-names
> user is fetching code from a repository that does not contain any
> Emacs Lisp files.")
>=20=20
> +(defun package-vc--add-and-save-selected-packages (name pkg-spec)
> + "Store package NAME with PKG-SPEC in `package-vc-selected-packages'."
> + (customize-save-variable
> + 'package-vc-selected-packages
> + (cons (cons name pkg-spec)
> + (seq-remove (lambda (spec) (string=3D name (car spec)))
> + package-vc-selected-packages))))
> +
> (defun package-vc--unpack (pkg-desc pkg-spec &optional rev)
> "Install the package described by PKG-DESC.
> PKG-SPEC is a package specification, a property list describing
> @@ -682,11 +705,7 @@ package-vc--unpack
> ;; Ensure we have a copy of the package specification
> (unless (seq-some (lambda (alist) (equal (alist-get name (cdr alist)=
) pkg-spec))
> package-vc--archive-spec-alists)
> - (customize-save-variable
> - 'package-vc-selected-packages
> - (cons (cons name pkg-spec)
> - (seq-remove (lambda (spec) (string=3D name (car spec)))
> - package-vc-selected-packages))))
> + (package-vc--add-and-save-selected-packages name pkg-spec))
>=20=20
> (package-vc--unpack-1 pkg-desc pkg-dir)))
>=20=20
> @@ -757,6 +776,9 @@ package-vc-upgrade
> ;; If there is a better way to do this, it should be done.
> (cl-assert (package-vc-p pkg-desc))
> (letrec ((pkg-dir (package-desc-dir pkg-desc))
> + (checkout-dir (or (package-vc--checkout-dir
> + (package-vc--desc->spec pkg-desc))
> + pkg-dir))
> (vc-flags)
> (vc-filter-command-function
> (lambda (command file-or-list flags)
> @@ -764,18 +786,18 @@ package-vc-upgrade
> (list command file-or-list flags)))
> (post-upgrade
> (lambda (_command _file-or-list flags)
> - (when (and (file-equal-p pkg-dir default-directory)
> + (when (and (file-equal-p checkout-dir default-directory)
> (eq flags vc-flags))
> - (unwind-protect
> - (with-demoted-errors "Failed to activate: %S"
> - (package-vc--unpack-1 pkg-desc pkg-dir))
> - (remove-hook 'vc-post-command-functions post-upgrade))=
))))
> + (unwind-protect
> + (with-demoted-errors "Failed to activate: %S"
> + (package-vc--unpack-1 pkg-desc pkg-dir))
> + (remove-hook 'vc-post-command-functions post-upgrade=
))))))
Am I missing something or did you just change the indentation here?
> (add-hook 'vc-post-command-functions post-upgrade)
> (with-demoted-errors "Failed to fetch: %S"
> (require 'vc-dir)
> (with-current-buffer (vc-dir-prepare-status-buffer
> - (format " *package-vc-dir: %s*" pkg-dir)
> - pkg-dir (vc-responsible-backend pkg-dir))
> + (format " *package-vc-dir: %s*" checkout-dir)
> + checkout-dir (vc-responsible-backend checkou=
t-dir))
> (vc-pull)))))
>=20=20
> (defun package-vc--archives-initialize ()
> @@ -941,13 +963,12 @@ package-vc-install-from-checkout
> (let* ((dir (if interactive dir (expand-file-name dir))) ;avoid double=
expansion
> (name (or name (file-name-base (directory-file-name dir))))
> (pkg-dir (file-name-concat package-user-dir name))
> - (package-vc-selected-packages
> - (cons (list name :lisp-dir dir)
> - package-vc-selected-packages)))
> + (pkg-spec (list :url (format "file://%s" dir))))
> (when (file-exists-p pkg-dir)
> (if (yes-or-no-p (format "Overwrite previous checkout for package =
`%s'?" name))
> (package--delete-directory pkg-dir)
> (error "There already exists a checkout for %s" name)))
> + (package-vc--add-and-save-selected-packages (intern name) pkg-spec)
This makes me thin: Should we perhaps move the code that adjusts the
selected packages from package-vc--unpack to package-vc--unpack-1?
> (make-directory pkg-dir t)
> (package-vc--unpack-1
> (package-desc-create
> @@ -966,7 +987,10 @@ package-vc-rebuild
> is the responsibility of `package-vc-upgrade'. Interactively,
> prompt for the name of the package to rebuild."
> (interactive (list (package-vc--read-package-desc "Rebuild package: " =
t)))
> - (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc)))
> + (package-vc--unpack-1 pkg-desc
> + (or (package-vc--checkout-dir
> + (package-vc--desc->spec pkg-desc))
> + (package-desc-dir pkg-desc))))
>=20=20
> ;;;###autoload
> (defun package-vc-prepare-patch (pkg-desc subject revisions)
> @@ -986,7 +1010,9 @@ package-vc-prepare-patch
> (and (not vc-prepare-patches-separately)
> (read-string "Subject: " "[PATCH] " nil nil t))
> (vc-prepare-patch-prompt-revisions)))
> - (let ((default-directory (package-desc-dir pkg-desc)))
> + (let ((default-directory (or (package-vc--checkout-dir
> + (package-vc--desc->spec pkg-desc))
> + (package-desc-dir pkg-desc))))
> (vc-prepare-patch (package-maintainers pkg-desc t)
> subject revisions)))
>=20=20
> @@ -994,7 +1020,9 @@ package-vc-log-incoming
> "Call `vc-log-incoming' for the package PKG-DESC."
> (interactive
> (list (package-vc--read-package-desc "Incoming log for package: " t)))
> - (let ((default-directory (package-desc-dir pkg-desc)))
> + (let ((default-directory (or (package-vc--checkout-dir
> + (package-vc--desc->spec pkg-desc))
> + (package-desc-dir pkg-desc))))
> (call-interactively #'vc-log-incoming)))
>=20=20
> (provide 'package-vc)
Here is my alternative patch, that tries to extract most of the
repetitive logic into `package-vc--checkout-dir', thus making the
remaining changes simpler overall:
--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline
diff --git a/lisp/package/package-vc.el b/lisp/package/package-vc.el
index 03767b99729..eb3f40c1f56 100644
--- a/lisp/package/package-vc.el
+++ b/lisp/package/package-vc.el
@@ -175,6 +175,24 @@ package-vc--desc->spec
(mapcar #'cdr package-vc--archive-spec-alists))))
'() nil #'string=))
+(defun package-vc--checkout-dir (pkg-desc &optional lisp-dir)
+ "Return the directory of the actual VC checkout for PKG-DESC.
+For most packages this is the same as `package-desc-dir', unless the
+package has been installed via `package-vc-install-from-checkout'. In
+that case the package redirects to the actual VC checkout. If the
+optional LISP-DIR argument is non-nil, then check if a related package
+specification has a `:lisp-dir' field to indicate that Lisp files are
+located in a sub directory of a checkout and return that instead."
+ (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
+ (url (plist-get pkg-spec :url)))
+ (expand-file-name
+ (or (and (not lisp-dir) (plist-get pkg-spec :lisp-dir)) ".")
+ (cond
+ ((save-match-data
+ (and url (string-match (rx "file://" (group (+ any))) url)
+ (match-string 1 url))))
+ (t (package-desc-dir pkg-desc))))))
+
(defun package-vc--read-archive-data (archive)
"Update `package-vc--archive-spec-alists' for ARCHIVE.
This function is meant to be used as a hook for `package-read-archive-hook'."
@@ -221,9 +239,7 @@ package-vc-commit
;; FIXME: vc should be extended to allow querying the commit of a
;; directory (as is possible when dealing with git repositories).
;; This should be a fallback option.
- (cl-loop with dir = (let ((pkg-spec (package-vc--desc->spec pkg-desc)))
- (or (plist-get pkg-spec :lisp-dir)
- (package-desc-dir pkg-desc)))
+ (cl-loop with dir = (package-vc--checkout-dir pkg-desc :lisp-dir)
for file in (directory-files dir t "\\.el\\'" t)
when (vc-working-revision file) return it
finally return "unknown"))
@@ -245,10 +261,7 @@ package-vc--main-file
(cl-assert (package-vc-p pkg-desc))
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
(name (symbol-name (package-desc-name pkg-desc)))
- (directory (expand-file-name
- (or (plist-get pkg-spec :lisp-dir) ".")
- (or (package-desc-dir pkg-desc)
- (expand-file-name name package-user-dir))))
+ (directory (package-vc--checkout-dir pkg-desc :lisp-dir))
(file (expand-file-name
(or (plist-get pkg-spec :main-file)
(concat name ".el"))
@@ -371,7 +384,7 @@ package-vc--build-documentation
FILE can be an Org file, indicated by its \".org\" extension,
otherwise it's assumed to be an Info file."
(let* ((pkg-name (package-desc-name pkg-desc))
- (default-directory (package-desc-dir pkg-desc))
+ (default-directory (package-vc--checkout-dir pkg-desc))
(docs-directory (file-name-directory (expand-file-name file)))
(output (expand-file-name (format "%s.info" pkg-name)))
(log-buffer (get-buffer-create (format " *package-vc doc: %s*" pkg-name)))
@@ -463,8 +476,9 @@ package-vc--unpack-1
identify a package as a VC package later on), building
documentation and marking the package as installed."
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
- (lisp-dir (plist-get pkg-spec :lisp-dir))
- (lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
+ (lisp-dir (expand-file-name
+ (or (plist-get pkg-spec :lisp-dir) ".")
+ pkg-dir))
missing)
;; In case the package was installed directly from source, the
@@ -482,7 +496,7 @@ package-vc--unpack-1
"\\|")
regexp-unmatchable))
(deps '()))
- (dolist (file (directory-files lisp-path t "\\.el\\'" t))
+ (dolist (file (directory-files lisp-dir t "\\.el\\'" t))
(unless (string-match-p ignored-files file)
(with-temp-buffer
(insert-file-contents file)
@@ -506,8 +520,8 @@ package-vc--unpack-1
;; Generate autoloads
(let* ((name (package-desc-name pkg-desc))
(auto-name (format "%s-autoloads.el" name)))
- (package-generate-autoloads name lisp-path)
- (when lisp-dir
+ (package-generate-autoloads name lisp-dir)
+ (when (plist-get pkg-spec :lisp-dir)
(write-region
(with-temp-buffer
(insert ";; Autoload indirection for package-vc\n\n")
@@ -578,14 +592,14 @@ package-vc--unpack-1
(package-strip-rcs-id
(or (lm-header "package-version")
(lm-header "version"))))
- (vc-working-revision main-file)
+ (if main-file (vc-working-revision main-file) '\?\?\?)
(if missing
- (format
- " Failed to install the following dependencies: %s"
- (mapconcat
- (lambda (p)
- (format "%s (%s)" (car p) (cadr p)))
- missing ", "))
+ (format
+ " Failed to install the following dependencies: %s"
+ (mapconcat
+ (lambda (p)
+ (format "%s (%s)" (car p) (cadr p)))
+ missing ", "))
"")))
t))
@@ -758,7 +772,7 @@ package-vc-upgrade
;;
;; If there is a better way to do this, it should be done.
(cl-assert (package-vc-p pkg-desc))
- (letrec ((pkg-dir (package-desc-dir pkg-desc))
+ (letrec ((pkg-dir (package-vc--checkout-dir pkg-desc))
(vc-flags)
(vc-filter-command-function
(lambda (command file-or-list flags)
@@ -968,7 +982,7 @@ package-vc-rebuild
is the responsibility of `package-vc-upgrade'. Interactively,
prompt for the name of the package to rebuild."
(interactive (list (package-vc--read-package-desc "Rebuild package: " t)))
- (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc)))
+ (package-vc--unpack-1 pkg-desc (package-vc--checkout-dir pkg-desc)))
;;;###autoload
(defun package-vc-prepare-patch (pkg-desc subject revisions)
@@ -988,7 +1002,7 @@ package-vc-prepare-patch
(and (not vc-prepare-patches-separately)
(read-string "Subject: " "[PATCH] " nil nil t))
(vc-prepare-patch-prompt-revisions)))
- (let ((default-directory (package-desc-dir pkg-desc)))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc)))
(vc-prepare-patch (package-maintainers pkg-desc t)
subject revisions)))
@@ -996,7 +1010,7 @@ package-vc-log-incoming
"Call `vc-log-incoming' for the package PKG-DESC."
(interactive
(list (package-vc--read-package-desc "Incoming log for package: " t)))
- (let ((default-directory (package-desc-dir pkg-desc)))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc)))
(call-interactively #'vc-log-incoming)))
(provide 'package-vc)
--=-=-=
Content-Type: text/plain
I haven't tested it yet extensively, but it doesn't appear to break
anything right away, and commands like package-vc-rebuild appear to be
invoked in the right directories. WDYT?
--
Philip Kaludercic
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Thu, 18 Sep 2025 21:13:01 +0000
Resent-Message-ID: <handler.79188.B79188.175822993128831 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.175822993128831
(code B ref 79188); Thu, 18 Sep 2025 21:13:01 +0000
Received: (at 79188) by debbugs.gnu.org; 18 Sep 2025 21:12:11 +0000
Received: from localhost ([127.0.0.1]:34517 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1uzLvG-0007Ux-QX
for submit <at> debbugs.gnu.org; Thu, 18 Sep 2025 17:12:11 -0400
Received: from mout01.posteo.de ([185.67.36.65]:51803)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1uzLvE-0007UJ-16
for 79188 <at> debbugs.gnu.org; Thu, 18 Sep 2025 17:12:09 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout01.posteo.de (Postfix) with ESMTPS id E621E240027
for <79188 <at> debbugs.gnu.org>; Thu, 18 Sep 2025 23:12:00 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1758229920; bh=McBKn71B7X59a0e9mGvieirO4e242L4WGKVTkApJxvY=;
h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type:
From;
b=i/YHEp4dv4nmH+2Cu/IRkysfGEYu8JTeJ0HFgn5YpZCy19mzI4H8+KEL6lnXqUDdV
s0TXSm4C8xf7BaWg78QVgjIvcy3WrQATPNN7qbsiY+ox3S451gaqucVG6R3bQL0+FV
wsOnDmMFYYIwjDlzMeqf5mBU/R/U4SAPW0wKledsc9X84f1moOh+Ji+86ZKOcC5XDB
dvFWLYuaZvSXkfKeDGkM3ZDlqi4UCjhldoUkYfgh52lMmDmA8nkA5IPrFCWxshuUU+
XZdyvlFDb4UfM5YIAkrgzuvrcCyZoTSBtXDsj1Kptuq1q3ZKQOXppSQXFakKHrOO3K
mQ6Ans0NGe1Bw==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4cSSxr2Ydzz6twC;
Thu, 18 Sep 2025 23:12:00 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <87cy7ovfwd.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
Date: Thu, 18 Sep 2025 21:12:00 +0000
Message-ID: <87bjn7wjmo.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
--=-=-=
Content-Type: text/plain
Philip Kaludercic <philipk@HIDDEN> writes:
[...]
> I haven't tested it yet extensively, but it doesn't appear to break
> anything right away, and commands like package-vc-rebuild appear to be
> invoked in the right directories. WDYT?
Here is an updated patch that I have tested some more:
--=-=-=
Content-Type: text/x-diff
Content-Disposition: attachment;
filename=0001-Add-command-to-apply-an-entire-diff-at-once.patch
From 905fddb596fe89165d495fe2e89e35d6a18cbac8 Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@HIDDEN>
Date: Sun, 11 Jun 2023 23:30:03 +0200
Subject: [PATCH 1/2] Add command to apply an entire diff at once
* lisp/vc/diff-mode.el (diff-mode-map): Bind 'diff-apply-everything'.
(diff-apply-everything): Add new command.
---
lisp/vc/diff-mode.el | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el
index d776375d681..d81f0af365e 100644
--- a/lisp/vc/diff-mode.el
+++ b/lisp/vc/diff-mode.el
@@ -216,6 +216,7 @@ diff-mode-map
"C-x 4 A" #'diff-add-change-log-entries-other-window
;; Misc operations.
"C-c C-a" #'diff-apply-hunk
+ "C-c C-x" #'diff-apply-everything
"C-c C-e" #'diff-ediff-patch
"C-c C-n" #'diff-restrict-view
"C-c C-s" #'diff-split-hunk
@@ -2033,6 +2034,16 @@ diff-apply-hunk
(when diff-advance-after-apply-hunk
(diff-hunk-next))))))
+(defun diff-apply-everything ()
+ "Apply the entire diff."
+ (interactive)
+ (save-excursion
+ (goto-char (point-min))
+ (while (let ((inhibit-message t)
+ (start (point)))
+ (diff-hunk-next)
+ (/= start (point)))
+ (diff-apply-hunk))))
(defun diff-test-hunk (&optional reverse)
"See whether it's possible to apply the current hunk.
--
2.39.2
--=-=-=
Content-Type: text/plain
--
Philip Kaludercic
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Fri, 19 Sep 2025 07:53:01 +0000
Resent-Message-ID: <handler.79188.B79188.175826833515092 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.175826833515092
(code B ref 79188); Fri, 19 Sep 2025 07:53:01 +0000
Received: (at 79188) by debbugs.gnu.org; 19 Sep 2025 07:52:15 +0000
Received: from localhost ([127.0.0.1]:36737 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1uzVug-0003vK-L6
for submit <at> debbugs.gnu.org; Fri, 19 Sep 2025 03:52:15 -0400
Received: from mail-wr1-x42e.google.com ([2a00:1450:4864:20::42e]:61790)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1uzVub-0003ui-Vd
for 79188 <at> debbugs.gnu.org; Fri, 19 Sep 2025 03:52:11 -0400
Received: by mail-wr1-x42e.google.com with SMTP id
ffacd0b85a97d-3ee64bc6b85so586568f8f.3
for <79188 <at> debbugs.gnu.org>; Fri, 19 Sep 2025 00:52:09 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1758268323; x=1758873123; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=F2dtyEaqJrYE8FxZWRkEiV9zMbsi6zuK98wP1Dghp8U=;
b=KIcOTn3UwhHYfqFVpsVJPG8oTT1/3PNKkB9rC9DO0QGpN5MbDHDd3YtNpUR+4CzwxM
8kNrIl/3dlaOHUP6gnvdofYgGCmoZapp0m75XglLi15QQakIYMjIm8dYp3HE7JNYIq8v
r5h05jb+LRem/LlW5GQwPvRhTEeZkLewwsPMPay+KKrs8bUPgYgN2ZH8uSmB0KFoYwx8
5gAmcAxgTp0oD/1mM3fbhaY1+jWpoM2rGXQ6LDou+VktDqHROd2OTa4kQxn2BEpF5LxU
7dkqIIZI3atJtIWzU//YqILjGELqrVDuIdwstQvRZqEajNy1XkcQ7zN+SiYQ7Zsz7Izu
/4Cg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1758268323; x=1758873123;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to;
bh=F2dtyEaqJrYE8FxZWRkEiV9zMbsi6zuK98wP1Dghp8U=;
b=SlVMHzDn33PkA5aSwwFVJvheRfCezGKgoNYu2yrtJAbtjcPU6zjYIYy3mkVcABvmfi
ePe1yxAQuS3WGmqPCdDCvZjs63piRyUYjjKdPYGPQumK1blN97pRFFcVU9qrUDtSfAz6
c17Iax3Bxzill7iSM6LnXeVNU7ISkHfO2lExO7iNyFDuuCBzx6zCaO9Wfh9ubfZPnkSI
boz4DJ4cDUfi+WrLeA4NW6a9+lNiJ0/R9dIZVLqUUp3QwEBfHX9rMV6w+gGG555q1nIq
47DeqTFBz3lGaf1RpCzuAiW5u1bGIFKolgKSJ6DYWzNMM69NUsyWLK7ftj/zKxP/T7Rh
jzzg==
X-Gm-Message-State: AOJu0YxYF5HRpVVPtRaeicAELjgu3+6c5u7cXZPlwpHmcPKP2queMjRj
FyYsOIV6m5OGZN40dBPvMns+e8LXKM6GCkCNJmV4erWKeI4i4bPOGph5ClBpUA==
X-Gm-Gg: ASbGncuuoeZdJCPkdvScYjUVRuivLuMun+P9EpnaRDYP89oEJDcj6REsJbXI74tkaSd
44rOoKKYV3KIaxutVvPO+n1WNfQXFHMbaMCSatzslgQcUJHFIvm78Q1GH96pxRlHKpnbw69Xgrs
ftXAmzTxybsz1tUeNYPckqkvf6Tk9eZAhExbho1V+g+st0AfZauysmVM1CzSrW07X67NjF/aagr
4S2Fi/zQx0+ysJh4TZTpyUAwi4evsoFcsgUqPNPrkbDWjci9cRp5ny0BbszA8yS6fuUPWht6X9m
z8bTAr5OHQKApP4W4DzdXA7mNGf9yNDhzEetl5SbuuUctyGXVpPw9IpmI87BnpooHWL70tqiRw/
H/mAjdtpqQL0olZxl/WquqzKFIJi0owcL08tj6Rd3zUIu8Zt84CHeUpfT3sHqJA8=
X-Google-Smtp-Source: AGHT+IEl6pOgf0Y0AbWm9nv8Y1D7PMOHoE28Ro8ubQ5rGkit5JFqrxBDlNoniAPcwD4ibFFM2MaDzA==
X-Received: by 2002:a05:6000:290a:b0:3eb:5e99:cbb9 with SMTP id
ffacd0b85a97d-3ee7da56fd3mr1819212f8f.10.1758268322611;
Fri, 19 Sep 2025 00:52:02 -0700 (PDT)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:380b:2060:2f18:d84d])
by smtp.gmail.com with ESMTPSA id
ffacd0b85a97d-3ee07407cffsm6647690f8f.16.2025.09.19.00.52.01
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Fri, 19 Sep 2025 00:52:01 -0700 (PDT)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <87bjn7wjmo.fsf@HIDDEN> (Philip Kaludercic's message of "Thu,
18 Sep 2025 21:12:00 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN>
Date: Fri, 19 Sep 2025 08:52:01 +0100
Message-ID: <m21po26fry.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
Philip Kaludercic <philipk@HIDDEN> writes:
> Philip Kaludercic <philipk@HIDDEN> writes:
> [...]
>
> Here is my alternative patch, that tries to extract most of the
> repetitive logic into `package-vc--checkout-dir', thus making the
> remaining changes simpler overall:
> [...]
>
> I haven't tested it yet extensively, but it doesn't appear to break
> anything right away, and commands like package-vc-rebuild appear to be
> invoked in the right directories. WDYT?
Thanks for it. I haven't applied nor tested it yet, but I gave it a
quick glance and it seems all right. I will test it more and comment
over the weekend (or soon after).
> [...]
> Here is an updated patch that I have tested some more:
This "updated patch" doesn't seem relevant to package-vc. Is this the
right file attached?
--
Cheers,
PK
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Fri, 19 Sep 2025 08:12:01 +0000
Resent-Message-ID: <handler.79188.B79188.175826948624361 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.175826948624361
(code B ref 79188); Fri, 19 Sep 2025 08:12:01 +0000
Received: (at 79188) by debbugs.gnu.org; 19 Sep 2025 08:11:26 +0000
Received: from localhost ([127.0.0.1]:36855 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1uzWDE-0006Kc-Uf
for submit <at> debbugs.gnu.org; Fri, 19 Sep 2025 04:11:26 -0400
Received: from mout02.posteo.de ([185.67.36.66]:52581)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1uzWDA-0006JA-MG
for 79188 <at> debbugs.gnu.org; Fri, 19 Sep 2025 04:11:22 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout02.posteo.de (Postfix) with ESMTPS id EDE35240101
for <79188 <at> debbugs.gnu.org>; Fri, 19 Sep 2025 10:11:12 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1758269472; bh=c3mjBltalM8JTmbv0w9dHeerLuP3dvHY63bGJOWozNA=;
h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type:
From;
b=LuI+PH2N4Owaq5M8DjYsc3ljKqHzNLZr8Gq0veT0N9TjQSjXQe313tAXCwxtDG1nO
PxUKEmHw0SVKEW/mSNgww3JZmc5S0g3ilnii7Wg0L+bhhwQTjJiPtv/d2g0jlnVnq/
uR/dd0hlAxUT0K1LF+gD9wmqRi3r3EcAjNtjmUMMsaSjwZ2dIBwJndqTp6bB9UHHqR
zho21p3mYl6a3e2CEG8WwBLvr5QbQwTo1SCLSCscjYHkPwdw3Rgy/i09+nqH3brNRM
bGTd7bVUCAL/7rpqZhQJcnJTWRfM9YBVkWxPDB22x2OZOIyp1qkE9Y5jLzQs8OsGko
XKd0h0cnbumjQ==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4cSlZQ129dz6v1B;
Fri, 19 Sep 2025 10:11:10 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m21po26fry.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
Date: Fri, 19 Sep 2025 08:11:11 +0000
Message-ID: <87tt0yc15u.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> Philip Kaludercic <philipk@HIDDEN> writes:
>
>> Philip Kaludercic <philipk@HIDDEN> writes:
>> [...]
>>
>> Here is my alternative patch, that tries to extract most of the
>> repetitive logic into `package-vc--checkout-dir', thus making the
>> remaining changes simpler overall:
>> [...]
>>
>> I haven't tested it yet extensively, but it doesn't appear to break
>> anything right away, and commands like package-vc-rebuild appear to be
>> invoked in the right directories. WDYT?
>
> Thanks for it. I haven't applied nor tested it yet, but I gave it a
> quick glance and it seems all right. I will test it more and comment
> over the weekend (or soon after).
1+
>> [...]
>> Here is an updated patch that I have tested some more:
>
> This "updated patch" doesn't seem relevant to package-vc. Is this the
> right file attached?
Right, I selected the wrong file ^^
--=-=-=
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename=0001-Fix-detection-of-VC-package-checkouts-bug-79188.patch
Content-Transfer-Encoding: quoted-printable
From e8e487c85718fccd18994f31b8cc8facec9fcb53 Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@HIDDEN>
Date: Thu, 18 Sep 2025 19:43:46 +0200
Subject: [PATCH] Fix detection of VC package checkouts (bug#79188)
MIME-Version: 1.0
Content-Type: text/plain; charset=3DUTF-8
Content-Transfer-Encoding: 8bit
* lisp/emacs-lisp/package-vc.el (package-vc--checkout-dir): New
function to determine the real checkout of a VC package.
(package-vc-commit, package-vc--main-file)
(package-vc--build-documentation, package-vc-upgrade)
(package-vc-rebuild, package-vc-prepare-patch)
(package-vc-log-incoming): Use 'package-vc--checkout-dir'.
(package-vc--unpack-1): Use the right directories in the right
places.
(package-vc--save-selected-packages): Refactor new helper
function out of 'package-vc--unpack' to modify 'package-vc-selected-package=
s'.
(package-vc--unpack, package-vc-install-from-checkout): Use
'package-vc--save-selected-packages'.
Co-developed-by: Przemys=C5=82aw Kryger <pkryger@HIDDEN>
---
lisp/emacs-lisp/package-vc.el | 168 ++++++++++++++++++++++---------------
1 file changed, 99 insertions(+), 69 deletions(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 03767b99729..0da5ae4734d 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -175,6 +175,24 @@ package-vc--desc->spec
(mapcar #'cdr package-vc--archive-spec-alists))=
))
'() nil #'string=3D))
=20
+(defun package-vc--checkout-dir (pkg-desc &optional lisp-dir)
+ "Return the directory of the actual VC checkout for PKG-DESC.
+For most packages this is the same as `package-desc-dir', unless the
+package has been installed via `package-vc-install-from-checkout'. In
+that case the package redirects to the actual VC checkout. If the
+optional LISP-DIR argument is non-nil, then check if a related package
+specification has a `:lisp-dir' field to indicate that Lisp files are
+located in a sub directory of a checkout and return that instead."
+ (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
+ (url (plist-get pkg-spec :url)))
+ (expand-file-name
+ (or (and (not lisp-dir) (plist-get pkg-spec :lisp-dir)) ".")
+ (cond
+ ((save-match-data
+ (and url (string-match (rx "file://" (group (+ any))) url)
+ (match-string 1 url))))
+ (t (package-desc-dir pkg-desc))))))
+
(defun package-vc--read-archive-data (archive)
"Update `package-vc--archive-spec-alists' for ARCHIVE.
This function is meant to be used as a hook for `package-read-archive-hook=
'."
@@ -221,9 +239,7 @@ package-vc-commit
;; FIXME: vc should be extended to allow querying the commit of a
;; directory (as is possible when dealing with git repositories).
;; This should be a fallback option.
- (cl-loop with dir =3D (let ((pkg-spec (package-vc--desc->spec pkg-desc)))
- (or (plist-get pkg-spec :lisp-dir)
- (package-desc-dir pkg-desc)))
+ (cl-loop with dir =3D (package-vc--checkout-dir pkg-desc 'lisp-dir)
for file in (directory-files dir t "\\.el\\'" t)
when (vc-working-revision file) return it
finally return "unknown"))
@@ -245,10 +261,7 @@ package-vc--main-file
(cl-assert (package-vc-p pkg-desc))
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
(name (symbol-name (package-desc-name pkg-desc)))
- (directory (expand-file-name
- (or (plist-get pkg-spec :lisp-dir) ".")
- (or (package-desc-dir pkg-desc)
- (expand-file-name name package-user-dir))))
+ (directory (package-vc--checkout-dir pkg-desc 'lisp-dir))
(file (expand-file-name
(or (plist-get pkg-spec :main-file)
(concat name ".el"))
@@ -353,7 +366,8 @@ package-vc--make
"Process :make and :shell-command in PKG-SPEC.
PKG-DESC is the package descriptor for the package that is being
prepared."
- (let ((target (plist-get pkg-spec :make))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc))
+ (target (plist-get pkg-spec :make))
(cmd (plist-get pkg-spec :shell-command))
(buf (format " *package-vc make %s*" (package-desc-name pkg-desc))=
))
(when (or cmd target)
@@ -371,7 +385,7 @@ package-vc--build-documentation
FILE can be an Org file, indicated by its \".org\" extension,
otherwise it's assumed to be an Info file."
(let* ((pkg-name (package-desc-name pkg-desc))
- (default-directory (package-desc-dir pkg-desc))
+ (default-directory (package-vc--checkout-dir pkg-desc))
(docs-directory (file-name-directory (expand-file-name file)))
(output (expand-file-name (format "%s.info" pkg-name)))
(log-buffer (get-buffer-create (format " *package-vc doc: %s*" pk=
g-name)))
@@ -463,8 +477,8 @@ package-vc--unpack-1
identify a package as a VC package later on), building
documentation and marking the package as installed."
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
- (lisp-dir (plist-get pkg-spec :lisp-dir))
- (lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
+ (checkout-dir (package-vc--checkout-dir pkg-desc))
+ (lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
missing)
=20
;; In case the package was installed directly from source, the
@@ -476,13 +490,13 @@ package-vc--unpack-1
(lambda (ignore)
(wildcard-to-regexp
(if (string-match-p "\\`/" ignore)
- (concat pkg-dir ignore)
+ (concat checkout-dir ignore)
(concat "*/" ignore))))
(plist-get pkg-spec :ignored-files)
"\\|")
regexp-unmatchable))
(deps '()))
- (dolist (file (directory-files lisp-path t "\\.el\\'" t))
+ (dolist (file (directory-files lisp-dir t "\\.el\\'" t))
(unless (string-match-p ignored-files file)
(with-temp-buffer
(insert-file-contents file)
@@ -501,38 +515,54 @@ package-vc--unpack-1
missing)
missing)))
=20
- (let ((default-directory (file-name-as-directory pkg-dir))
- (pkg-file (expand-file-name (package--description-file pkg-dir) =
pkg-dir)))
- ;; Generate autoloads
- (let* ((name (package-desc-name pkg-desc))
- (auto-name (format "%s-autoloads.el" name)))
- (package-generate-autoloads name lisp-path)
- (when lisp-dir
- (write-region
- (with-temp-buffer
- (insert ";; Autoload indirection for package-vc\n\n")
- (prin1 `(load (expand-file-name
- ,(expand-file-name auto-name lisp-dir)
- (or (and load-file-name
- (file-name-directory load-file-name))
- (car load-path))))
- (current-buffer))
- (buffer-string))
- nil (expand-file-name auto-name pkg-dir))))
-
- ;; Generate package file
- (package-vc--generate-description-file pkg-desc pkg-file)
-
- ;; Process :make and :shell-command arguments before building docume=
ntation
- (when (or (eq package-vc-allow-build-commands t)
- (memq (package-desc-name pkg-desc)
- package-vc-allow-build-commands))
- (package-vc--make pkg-spec pkg-desc))
-
- ;; Detect a manual
- (when (executable-find "install-info")
- (dolist (doc-file (ensure-list (plist-get pkg-spec :doc)))
- (package-vc--build-documentation pkg-desc doc-file))))
+ ;; Generate autoloads
+ (let* ((name (package-desc-name pkg-desc))
+ (auto-name (format "%s-autoloads.el" name)))
+ (package-generate-autoloads name lisp-dir)
+ ;; There are two cases when we wish to "indirect" the loading of
+ ;; autoload files: 1. a package specification has a `:lisp-dir'
+ ;; entry listing indicting that the actual Lisp code is located in
+ ;; a subdirectory of the checkout, 2. the package has been
+ ;; installed using `package-vc-install-from-checkout' and we want
+ ;; to load the other directory instead -- which is outside of the
+ ;; checkout. We can therefore take file inequality as a sign that
+ ;; we have to set up an indirection.
+ (unless (file-equal-p lisp-dir pkg-dir)
+ (write-region
+ (concat
+ ";; Autoload indirection for package-vc\n\n"
+ (prin1-to-string
+ ;; The indirection is just a single load statement to the
+ ;; actual file (we don't want to use symbolic links due to
+ ;; portability reasons). Detecting which of the two cases
+ ;; mentioned above we are setting up can be done by checking
+ ;; if the directory with the lisp code is a subdirectory of
+ ;; the package directory.
+ `(load ,(if (file-in-directory-p lisp-dir pkg-dir)
+ `(expand-file-name
+ ,(file-relative-name
+ (expand-file-name auto-name lisp-dir)
+ pkg-dir)
+ (or (and load-file-name
+ (file-name-directory load-file-name))
+ (car load-path)))
+ (expand-file-name auto-name lisp-dir)))))
+ nil (expand-file-name auto-name pkg-dir))))
+
+ ;; Generate package file
+ (let ((pkg-file (expand-file-name (package--description-file pkg-dir) =
pkg-dir)))
+ (package-vc--generate-description-file pkg-desc pkg-file))
+
+ ;; Process :make and :shell-command arguments before building document=
ation
+ (when (or (eq package-vc-allow-build-commands t)
+ (memq (package-desc-name pkg-desc)
+ package-vc-allow-build-commands))
+ (package-vc--make pkg-spec pkg-desc))
+
+ ;; Detect a manual
+ (when (executable-find "install-info")
+ (dolist (doc-file (ensure-list (plist-get pkg-spec :doc)))
+ (package-vc--build-documentation pkg-desc doc-file)))
=20
;; Remove any previous instance of PKG-DESC from `package-alist'
(let ((pkgs (assq (package-desc-name pkg-desc) package-alist)))
@@ -548,13 +578,7 @@ package-vc--unpack-1
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all pa=
ckages
;; and then compile them.
- (package--compile
- (if lisp-dir
- ;; In case we are installing a package from a local
- ;; checkout, we want to compile the checkout, not the
- ;; redirection!
- (package-desc-create :dir lisp-dir)
- new-desc))
+ (package--compile (package-desc-create :dir lisp-dir))
=20
(when package-native-compile
(package--native-compile-async new-desc))
@@ -580,12 +604,12 @@ package-vc--unpack-1
(lm-header "version"))))
(vc-working-revision main-file)
(if missing
- (format
- " Failed to install the following dependencies: %s"
- (mapconcat
- (lambda (p)
- (format "%s (%s)" (car p) (cadr p)))
- missing ", "))
+ (format
+ " Failed to install the following dependencies: %s"
+ (mapconcat
+ (lambda (p)
+ (format "%s (%s)" (car p) (cadr p)))
+ missing ", "))
"")))
t))
=20
@@ -630,6 +654,14 @@ package-vc-non-code-file-names
user is fetching code from a repository that does not contain any
Emacs Lisp files.")
=20
+(defun package-vc--save-selected-packages (name pkg-spec)
+ "Save the package specification PKG-SPEC for a package NAME."
+ (customize-save-variable
+ 'package-vc-selected-packages
+ (cons (cons name pkg-spec)
+ (seq-remove (lambda (spec) (string=3D name (car spec)))
+ package-vc-selected-packages))))
+
(defun package-vc--unpack (pkg-desc pkg-spec &optional rev)
"Install the package described by PKG-DESC.
PKG-SPEC is a package specification, a property list describing
@@ -682,13 +714,8 @@ package-vc--unpack
(throw 'done (setq lisp-dir name)))))
=20
;; Ensure we have a copy of the package specification
- (unless (seq-some (lambda (alist) (equal (alist-get name (cdr alist)) =
pkg-spec))
- package-vc--archive-spec-alists)
- (customize-save-variable
- 'package-vc-selected-packages
- (cons (cons name pkg-spec)
- (seq-remove (lambda (spec) (string=3D name (car spec)))
- package-vc-selected-packages))))
+ (when (null (package-vc--desc->spec pkg-desc name))
+ (package-vc--save-selected-packages name pkg-spec))
=20
(package-vc--unpack-1 pkg-desc pkg-dir)))
=20
@@ -758,7 +785,7 @@ package-vc-upgrade
;;
;; If there is a better way to do this, it should be done.
(cl-assert (package-vc-p pkg-desc))
- (letrec ((pkg-dir (package-desc-dir pkg-desc))
+ (letrec ((pkg-dir (package-vc--checkout-dir pkg-desc))
(vc-flags)
(vc-filter-command-function
(lambda (command file-or-list flags)
@@ -951,6 +978,9 @@ package-vc-install-from-checkout
(package--delete-directory pkg-dir)
(error "There already exists a checkout for %s" name)))
(make-directory pkg-dir t)
+ ;; We store a custom package specification so that
+ ;; `package-vc--checkout-dir' can later retrieve the actual checkout.
+ (package-vc--save-selected-packages name (list :url (concat "file://" =
dir)))
(package-vc--unpack-1
(package-desc-create
:name (intern name)
@@ -968,7 +998,7 @@ package-vc-rebuild
is the responsibility of `package-vc-upgrade'. Interactively,
prompt for the name of the package to rebuild."
(interactive (list (package-vc--read-package-desc "Rebuild package: " t)=
))
- (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc)))
+ (package-vc--unpack-1 pkg-desc (package-vc--checkout-dir pkg-desc)))
=20
;;;###autoload
(defun package-vc-prepare-patch (pkg-desc subject revisions)
@@ -988,7 +1018,7 @@ package-vc-prepare-patch
(and (not vc-prepare-patches-separately)
(read-string "Subject: " "[PATCH] " nil nil t))
(vc-prepare-patch-prompt-revisions)))
- (let ((default-directory (package-desc-dir pkg-desc)))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc)))
(vc-prepare-patch (package-maintainers pkg-desc t)
subject revisions)))
=20
@@ -996,7 +1026,7 @@ package-vc-log-incoming
"Call `vc-log-incoming' for the package PKG-DESC."
(interactive
(list (package-vc--read-package-desc "Incoming log for package: " t)))
- (let ((default-directory (package-desc-dir pkg-desc)))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc)))
(call-interactively #'vc-log-incoming)))
=20
(provide 'package-vc)
--=20
2.47.3
--=-=-=
Content-Type: text/plain
(I double checked this time, and renamed the files so that you should be
able to apply it to master.)
> --
> Cheers,
> PK
--
Philip Kaludercic
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Sun, 21 Sep 2025 15:35:02 +0000
Resent-Message-ID: <handler.79188.B79188.175846886822979 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.175846886822979
(code B ref 79188); Sun, 21 Sep 2025 15:35:02 +0000
Received: (at 79188) by debbugs.gnu.org; 21 Sep 2025 15:34:28 +0000
Received: from localhost ([127.0.0.1]:55257 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1v0M56-0005yY-3R
for submit <at> debbugs.gnu.org; Sun, 21 Sep 2025 11:34:28 -0400
Received: from mout02.posteo.de ([185.67.36.66]:49579)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1v0M51-0005xZ-WE
for 79188 <at> debbugs.gnu.org; Sun, 21 Sep 2025 11:34:25 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout02.posteo.de (Postfix) with ESMTPS id 403AC240101
for <79188 <at> debbugs.gnu.org>; Sun, 21 Sep 2025 17:34:16 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1758468856; bh=IVAuX7EyrORCEdoIL3WTiV8dHXqV5JIs7QAfcZWtkd4=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:From;
b=iDGitOEKu7ZgT8stpj1RbQwklvDr2wbyL4A276wd26R8F3Fa4m2svlPdr0qH9y/l4
5GmXu+7Sk1I/WipHrblx7DiBlNW2lHhmpQewcNNMUzJ82BEYwgWerMJVreeEuvExAR
DF/rlDKQ93ebVZtRVLfDJ3HXUFwejFE3e09sPcU/X022gpsrZEhn/XOmNMZu0fiCoi
wcwHyQVSbLLW6L1+htZzxlqtaTVvSjtIrowMzbP+fa2GvqE40F0rNn98fD3kUCpUW7
c4MmJ45Hvxu1LnhEk84PMMii7fgh38mHG35LNU8uu5hlzw1G/c3ZQjbOFT3mfFBH4N
419x2ViVUyWKw==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4cV9Jl5TqPz9rwn;
Sun, 21 Sep 2025 17:34:15 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2h5xm5ebm.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Sun, 21 Sep 2025 15:34:15 +0000
Message-ID: <87segfvmyw.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
[...]
> From 8a785a9bb567e3143b5bd4ae58c3c355c7949945 Mon Sep 17 00:00:00 2001
> From: Philip Kaludercic <philipk@HIDDEN>
> Date: Fri, 8 Aug 2025 11:43:24 +0100
> Subject: [PATCH 1/2] Compile file in local checkout directory
>
> * lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): Compile
> package in a local checkout directory when it is installed from
> such a location, for example with
> `package-vc-install-from-checkout'.
>
> (Bug#79188)
> ---
> lisp/emacs-lisp/package-vc.el | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
> index 7433fce2d89..9e118c7af02 100644
> --- a/lisp/emacs-lisp/package-vc.el
> +++ b/lisp/emacs-lisp/package-vc.el
> @@ -546,7 +546,14 @@ package-vc--unpack-1
> ;; FIXME: Compilation should be done as a separate, optional, step.
> ;; E.g. for multi-package installs, we should first install all packages
> ;; and then compile them.
> - (package--compile new-desc)
> + (package--compile
> + (if lisp-dir
> + ;; In case we are installing a package from a local
> + ;; checkout, we want to compile the checkout, not the
> + ;; redirection!
> + (package-desc-create :dir lisp-dir)
> + new-desc))
> +
> (when package-native-compile
> (package--native-compile-async new-desc))
> ;; After compilation, load again any files loaded by
I just realised, that we don't need this patch if we apply the later
patch I provided.
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Fri, 26 Sep 2025 17:03:02 +0000
Resent-Message-ID: <handler.79188.B79188.175890617523392 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.175890617523392
(code B ref 79188); Fri, 26 Sep 2025 17:03:02 +0000
Received: (at 79188) by debbugs.gnu.org; 26 Sep 2025 17:02:55 +0000
Received: from localhost ([127.0.0.1]:36533 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1v2BqQ-00065D-6e
for submit <at> debbugs.gnu.org; Fri, 26 Sep 2025 13:02:54 -0400
Received: from mail-wm1-x335.google.com ([2a00:1450:4864:20::335]:58738)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1v2BqH-00064t-VS
for 79188 <at> debbugs.gnu.org; Fri, 26 Sep 2025 13:02:47 -0400
Received: by mail-wm1-x335.google.com with SMTP id
5b1f17b1804b1-46e3ea0445fso4735905e9.1
for <79188 <at> debbugs.gnu.org>; Fri, 26 Sep 2025 10:02:45 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1758906159; x=1759510959; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=9l+bYAHJMvgj86P9kBn3WG5pnogV1/rdjSZu1wrRlEQ=;
b=ftvVv6UWiTT/aYS9BCC7TwFUnG7MgGA+gO81vYCdg5/6WnXgO3jqiRHvbHLmTA+KaM
fYT4wwHdbhXnnFJokJI6w7McXkIxcwJj/WbnOQPAPyFQMrl4YNHy3waagUy4i5fFx2Gx
oE1dO4MHR7MvNV0tCOP9tt+HQnZaruzmzoFaN5LZVchwlbJiP4S5dvq9YtQF94+lY/2f
q120GPiJtQ6YCFdyqem1yAmn8gQ8Ou7BIn19c1AqpB9/ASB1R22e0jHiFgtVYON0P6cs
SNH/5NvwtrSPP/PQIR+QDxC3g2BPuWzcLQbqcyuobEazn6Z6Qael3tjE9j8PQRprirgl
/9+g==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1758906159; x=1759510959;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to;
bh=9l+bYAHJMvgj86P9kBn3WG5pnogV1/rdjSZu1wrRlEQ=;
b=idE1soO8kgzbXGdGs26sutPnv2Mokdf44XcIRmowikP2SLzdBEwbpTsUAAuhc4EQey
QtmdGpWwRwO4cYbwzjagX64A7CoFCes0Tn5AzPosB91nxltH2zO0NRJMZmkQ00wRwAt2
OWGqP8aocgWYVydkg4yvdMYtz56+TQSsHMPyWU6bdjRuLYprwL3/jxCEobr5LI8XuZzo
rXRpwXWil8UUQIY2FDhovT7CywzRRSu1WEgxtzahVm59oYloGzIPuqsEt14K7e5vvOCO
FHzKu5ugBleDvV77+LrPFHVbtKWXDUMksZGZtTChSzT9htliY8gtjczF4X4em79SUE1f
ILPg==
X-Gm-Message-State: AOJu0YyQADTUysw5aSnv+4iV7bsK/lIHh1FYsznXJDvff5EWTLMNPFfc
qrORPSdX0Jag0tkispb1HtcyDUJwHEsgIsxSvq9VRrtmfvi+iRDiBiC6xZCIVw==
X-Gm-Gg: ASbGncvCnL3EGNqeDliTh2UPt7r36QwGXPWQ04klpeRK+7UA4Un9S2l/2gCp1rP9YaT
Ulse+x9NuTeoJcucWd1g4qLGBA8NGfUQT9Jm5LXUWuIDY1bZ1yi/3/v8zgCnn5S0KS7zQkCej4n
vO9S+UqRkSqOyV/LlUVOE9hfNUyyoW6BZvTdcXRoGZCPkwns8Yi5RsyZ+osyTenbsWCoMhV6qPY
V+7b29mH5GSnyeqHVBI+loJSKdl5Vxsy9UMgl1hET97N4eI2HFXbrHmT9SQuWmW1iarW8QNOR9c
h56BaAt+slgQrXLiVNCvBTFuHTWi/2+89tv4piV0IaYiVCgO6Xwa2p1QdxrIfs17F3XMzQbPPhU
0nhY8s8af7Kyc17iJoZaaQWR3reDVfsSQxqmsMTg7oklVXGqnu4F4VkC8mR953uL+Zr3mXGUZYg
==
X-Google-Smtp-Source: AGHT+IFfugNfhFItoAKmWNElfPpNqUZmVgWENvKbC6FD4GaGNzj+ZZ/wD8QEQFLsbE7kGZ03pyXMMA==
X-Received: by 2002:a05:600c:32b0:b0:458:a7fa:211d with SMTP id
5b1f17b1804b1-46e32a0e0e3mr47234255e9.29.1758906158529;
Fri, 26 Sep 2025 10:02:38 -0700 (PDT)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:91a7:7470:5a72:d25e])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-46e33bf6ecbsm87123225e9.22.2025.09.26.10.02.36
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Fri, 26 Sep 2025 10:02:37 -0700 (PDT)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <87tt0yc15u.fsf@HIDDEN> (Philip Kaludercic's message of "Fri,
19 Sep 2025 08:11:11 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN>
Date: Fri, 26 Sep 2025 18:02:36 +0100
Message-ID: <m2bjmxgn9v.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain
Philip Kaludercic <philipk@HIDDEN> writes:
> [...]
>>> Philip Kaludercic <philipk@HIDDEN> writes:
>>> [...]
>>>
>>> Here is my alternative patch, that tries to extract most of the
>>> repetitive logic into `package-vc--checkout-dir', thus making the
>>> remaining changes simpler overall:
>>> [...]
>>>
>>> I haven't tested it yet extensively, but it doesn't appear to break
>>> anything right away, and commands like package-vc-rebuild appear to be
>>> invoked in the right directories. WDYT?
> [...]
>>> Here is an updated patch that I have tested some more:
>>
>> This "updated patch" doesn't seem relevant to package-vc. Is this the
>> right file attached?
>
> Right, I selected the wrong file ^^
>
>
>
> (I double checked this time, and renamed the files so that you should be
> able to apply it to master.)
That's make things so much easier. Thank you!
There was a single rejection:
- (package--compile
- (if lisp-dir
- ;; In case we are installing a package from a local
- ;; checkout, we want to compile the checkout, not the
- ;; redirection!
- (package-desc-create :dir lisp-dir)
- new-desc))
+ (package--compile (package-desc-create :dir lisp-dir))
but I applied it manually and it seems to work. I tested it with this suite:
--=-=-=
Content-Type: application/emacs-lisp
Content-Disposition: attachment; filename=package-vc-tests.el
Content-Transfer-Encoding: quoted-printable
Content-Description: Tests for package-vc
;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
;;; Code:
(require 'package-vc)
(require 'package)
(require 'vc-git)
(require 'cl-lib)
(require 'ert)
(defvar package-vc-tests-dir
(make-temp-file "package-vc-tests-" t (format-time-string "-%Y%m%d.%H%M%S=
")))
(setq package-user-dir (expand-file-name "elpa" package-vc-tests-dir))
(defvar package-vc-tests-packages
`(;; checkout and install with `package-vc-install' (on ELPA)
(diminish . ,(expand-file-name "diminish" package-user-dir))
;; checkout and install with `package-vc-install' (not on ELPA)
(ultra-scroll . ,(expand-file-name "ultra-scroll" package-user-dir))
;; checkout with `package-vc-checktout' and install with
;; `package-vc-install-from-checkout'
(gcmh . ,(expand-file-name "gcmh" package-vc-tests-dir))
;; checkout with git and install with `package-vc-install-from-checkout'
(basic-stats . ,(expand-file-name "basic-stats.el" package-vc-tests-dir=
))
;; TODO: a package with source files in lisp/ directory (both methods of
;; installation)
;; TODO: a package with source files in a non-standard :lisp-dir (both
;; methods of installation)
))
;; TODO: add test for deleting packages, with asserting
;; `package-vc-selected-packages'
;; TODO: clarify `package-vc-install-all' behaviour with regards to packages
;; installed with `package-vc' but not stored in `package-vc-selected-packa=
ges'
;; i.e., packages from ELPAs
(defun package-vc-tests-package-desc (package &optional installed)
"Return descriptor of PACKAGE.
When INSTALLED is non-nil the descriptor will come from `package-alist'.
Otherwise the descriptor will be from `package-archive-contents'. This
is to mimic `package-vc--read-package-desc'."
(cadr (assoc (if (stringp package) package (symbol-name package))
(if installed package-alist package-archive-contents)
#'string=3D)))
(defun package-vc-tests-assert-delete-elc ()
"Assert that .elc files are in expected directories and delete them.
When ALL is non nil, check all packages under test."
(dolist (pkg-checkout-dir package-vc-tests-packages)
(let* ((dir (cdr pkg-checkout-dir))
(elc-files (directory-files dir nil (rx ".elc" string-end))))
(should-not (equal (cons dir elc-files)
(list dir)))
(dolist (elc-file elc-files)
(delete-file (expand-file-name elc-file dir))))))
(defun package-vc-tests-packages-heads (reset)
"Return HEAD revisions of `package-vc-tests-packages'.
When RESET is non-nil also reset to a previous version."
(mapcar (lambda (pkg-checkout-dir)
(let ((default-directory (cdr pkg-checkout-dir)))
(prog1
(cons (car pkg-checkout-dir)
(vc-git-working-revision nil))
(when reset
(vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))))
package-vc-tests-packages))
(ert-deftest package-vc-tests-000-install ()
(package-refresh-contents)
(package-vc--archives-initialize)
(package-vc-install 'diminish)
(should-not (alist-get "diminish" package-vc-selected-packages
nil nil #'string=3D))
(package-vc-install '(ultra-scroll
:url "https://github.com/jdtsmith/ultra-scroll.git"=
))
(should (equal "https://github.com/jdtsmith/ultra-scroll.git"
(plist-get (alist-get "ultra-scroll"
package-vc-selected-packages
nil nil #'string=3D)
:url)))
(let ((checkout-dir (expand-file-name "gcmh" package-vc-tests-dir)))
(package-vc-checkout (package-vc-tests-package-desc 'gcmh)
checkout-dir)
(package-vc-install-from-checkout checkout-dir)
(should (equal (format "file://%s" checkout-dir)
(plist-get (alist-get "gcmh"
package-vc-selected-packages
nil nil #'string=3D)
:url))))
(let ((checkout-dir (expand-file-name "basic-stats.el" package-vc-tests-d=
ir)))
(shell-command
(format "git clone https://github.com/pkryger/basic-stats.el.git %s"
checkout-dir))
(package-vc-install-from-checkout checkout-dir "basic-stats")
(should (equal (format "file://%s" checkout-dir)
(plist-get (alist-get "basic-stats"
package-vc-selected-packages
nil nil #'string=3D)
:url))))
(package-vc-tests-assert-delete-elc))
(ert-deftest package-vc-tests-001-main-file ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(should (equal (package-vc--main-file
(package-vc-tests-package-desc (car pkg-checkout-dir) t))
(format "%s/%s.el"
(cdr pkg-checkout-dir)
(car pkg-checkout-dir))))))
(ert-deftest package-vc-tests-002-commit ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(let ((pkg (car pkg-checkout-dir))
(commit (package-vc-commit
(package-vc-tests-package-desc (car pkg-checkout-dir) t))=
))
(should-not (equal (cons pkg commit)
(list pkg)))
(should-not (equal (list pkg "unknown")
(list pkg commit))))))
(defmacro package-vc-tests-package-vc-upgrade-wait (seconds count &rest bod=
y)
"Wait up to SECONDS for COUNT packages upgrading BODY.
Return nil on timeout or non nil otherwise."
(declare (indent 2))
`(letrec ((packages-count ,count)
(post-vc-command (lambda (command _ flags)
;; A crude filter for vc commands
(when (and (equal command "git")
(string-prefix-p "*vc-git" (buffe=
r-name)))
(cl-decf packages-count)))))
(add-hook 'vc-post-command-functions post-vc-command 100)
(unwind-protect
(progn
,@body
(catch 'done
(dotimes (i (* 10 ,seconds))
(sleep-for 0.1)
(when (eql packages-count 0)
(throw 'done t)))))
(remove-hook 'vc-post-command-functions post-vc-command))))
(ert-deftest package-vc-tests-003-upgrade-all ()
(let ((heads (package-vc-tests-packages-heads t)))
(should
(package-vc-tests-package-vc-upgrade-wait
5 (length package-vc-tests-packages)
(package-vc-upgrade-all)))
(should (equal heads
(package-vc-tests-packages-heads nil))))
(package-vc-tests-assert-delete-elc))
(ert-deftest package-vc-tests-004-upgrade ()
(let ((heads (package-vc-tests-packages-heads t)))
(should
(package-vc-tests-package-vc-upgrade-wait
5 (length package-vc-tests-packages)
(dolist (pkg-checkout-dir package-vc-tests-packages)
(package-vc-upgrade
(package-vc-tests-package-desc (car pkg-checkout-dir) t)))))
(should (equal heads
(package-vc-tests-packages-heads nil))))
(package-vc-tests-assert-delete-elc))
(ert-deftest package-vc-tests-005-rebuild ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(package-vc-rebuild
(package-vc-tests-package-desc (car pkg-checkout-dir) t)))
(package-vc-tests-assert-delete-elc))
(ert-deftest package-vc-tests-006-prepare-patch ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(cl-letf* ((call-count 0)
((symbol-function #'package-maintainers)
(lambda (&rest _)
"test-maintainers"))
((symbol-function #'vc-prepare-patch)
(lambda (addressee subject revisions)
(should (equal (file-name-as-directory default-directory)
(file-name-as-directory (cdr pkg-checkout-=
dir))))
(should (equal "test-maintainers" addressee))
(should (equal "test-subject" subject))
(should (equal "test-revisions" revisions))
(cl-incf call-count))))
(package-vc-prepare-patch (package-vc-tests-package-desc
(car pkg-checkout-dir)
t)
"test-subject"
"test-revisions")
(should (eql 1 call-count)))))
(ert-deftest package-vc-tests-007-log-incoming ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(cl-letf* ((call-count 0)
((symbol-function #'vc-log-incoming)
(lambda ()
(interactive)
(should (equal (file-name-as-directory default-directory)
(file-name-as-directory (cdr pkg-checkout-=
dir))))
(cl-incf call-count))))
(package-vc-log-incoming (package-vc-tests-package-desc
(car pkg-checkout-dir) t))
(should (eql 1 call-count)))))
(provide 'package-vc-tests)
;;; package-vc-tests.el ends here
--=-=-=
Content-Type: text/plain
using the following command:
emacs -batch -l test/lisp/package-vc-tests.el -f ert-run-tests-batch-and-exit
It all passes for me.
However, I added a few fixes:
1. Remove temporary binding for `package-vc-selected-packages' in
function `package-vc-install-from-checkout'. It not only simplifies the
code, but also removes the superfluous binding (which is never used),
but also ensures that side effect of changing a value of
`package-vc-selected-packages' is visible after the function call.
2. Updated the value passed to `package--native-compile-async'.
3. Updated a couple of comments.
Please see the following patch:
--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment;
filename=0001-Fix-native-compilation-and-storage-of-VC-packages.patch
Content-Description: Patch
From 70731b0e197e286f6d09606e2cf79b1275bf868e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Przemys=C5=82aw=20Kryger?= <pkryger@HIDDEN>
Date: Fri, 26 Sep 2025 17:24:44 +0100
Subject: [PATCH] Fix native compilation and storage of VC packages
* lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): Use a
`package' with `:dir' pointing to where package code is.
(package-vc-install-from-checkout): Remove superfluous
`package-vc-selected-packages' binding.
---
lisp/emacs-lisp/package-vc.el | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 078a7bd8136..d99bdb1813c 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -31,8 +31,7 @@
;; aren't interested in activating a package, you can use
;; `package-vc-checkout' instead, which will prompt you for a target
;; directory. If you wish to reuse an existing checkout, the command
-;; `package-vc-install-from-checkout' will create a symbolic link and
-;; prepare the package.
+;; `package-vc-install-from-checkout' will prepare the package.
;;
;; If you make local changes that you wish to share with an upstream
;; maintainer, the command `package-vc-prepare-patch' can prepare
@@ -568,7 +567,8 @@ package-vc--unpack-1
(setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
;; Update package-alist.
- (let ((new-desc (package-load-descriptor pkg-dir)))
+ (let ((new-desc (package-load-descriptor pkg-dir))
+ (compile-desc (package-desc-create :dir lisp-dir)))
;; Activation has to be done before compilation, so that if we're
;; upgrading and macros have changed we load the new definitions
;; before compiling.
@@ -576,9 +576,9 @@ package-vc--unpack-1
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
- (package--compile (package-desc-create :dir lisp-dir))
+ (package--compile compile-desc)
(when package-native-compile
- (package--native-compile-async new-desc))
+ (package--native-compile-async compile-desc))
;; After compilation, load again any files loaded by
;; `activate-1', so that we use the byte-compiled definitions.
(package--reload-previously-loaded new-desc)))
@@ -966,17 +966,15 @@ package-vc-install-from-checkout
(package-vc--archives-initialize)
(let* ((dir (if interactive dir (expand-file-name dir))) ;avoid double expansion
(name (or name (file-name-base (directory-file-name dir))))
- (pkg-dir (file-name-concat package-user-dir name))
- (package-vc-selected-packages
- (cons (list name :lisp-dir dir)
- package-vc-selected-packages)))
+ (pkg-dir (file-name-concat package-user-dir name)))
(when (file-exists-p pkg-dir)
(if (yes-or-no-p (format "Overwrite previous checkout for package `%s'?" name))
(package--delete-directory pkg-dir)
(error "There already exists a checkout for %s" name)))
(make-directory pkg-dir t)
- ;; We store a custom package specification so that
- ;; `package-vc--checkout-dir' can later retrieve the actual checkout.
+ ;; We store a custom package specification so that it is available
+ ;; for `package-vc--unpack-1' as well as `package-vc--checkout-dir'
+ ;; can later retrieve the actual checkout.
(package-vc--save-selected-packages name (list :url (concat "file://" dir)))
(package-vc--unpack-1
(package-desc-create
--
2.51.0
--=-=-=
Content-Type: text/plain
When adding the last fix, I started to think that there are a few more
areas that I am not sure how they work. Unfortunately, I won't have
time to dig deeper very soon, so just bringing them to your attention,
and you can decide whether or not to install patches we have already.
IMHO, they are a reasonable fix for the immediate issue.
1. In `package-vc--unpack-1' there are calls to `package-activate-1' and
`package--reload-previously-loaded' (just around where compilation
happens). But I am not convinced these calls will result in expected
side effects when a package has been installed with
`package-vc-install-from-checkout'.
2. In `package-vc-unpack-1' there are calls to `package-vc--make' and
`package-vc--build-documentation' which, again may be not doing what is
expected for packages installed with `package-vc-install-from-checkout'.
3. I am not sure what will happen when someone checkouts a repository to
`package-user-dir' making it so the 'package-vc-install-from-checkout'
calculates `pkg-dir' that is the same as a checkout dir. I know it's
not the smartest thing to do, but perhaps detect it and raise an error?
4. I struggle to understand how the value of `:lisp-dir' calculated in
`package-vc-unpack' (lines 701-711) is used in further code. Will need
to find a package that specifies that and try to debug it further.
5. Perhaps the `package-vc-install-from-checkout' could be extended in
such a way to allow user to specify their `pkg-spec'. That should
include the checkout directory, as well as other values from spec
(lisp-dir, make, doc)?
5. I am not sure how `package-delete' will work with these changes. I
guess it should at least remove the pkg-dir as well as entry from
`package-vc-selected-packages'.
Please let me know if you think any of these require immediate
attention, I will try to boost a priority for it.
Cheers,
PK
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Sat, 11 Oct 2025 20:48:02 +0000
Resent-Message-ID: <handler.79188.B79188.176021563918146 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176021563918146
(code B ref 79188); Sat, 11 Oct 2025 20:48:02 +0000
Received: (at 79188) by debbugs.gnu.org; 11 Oct 2025 20:47:19 +0000
Received: from localhost ([127.0.0.1]:46966 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1v7gUo-0004ib-Ep
for submit <at> debbugs.gnu.org; Sat, 11 Oct 2025 16:47:19 -0400
Received: from mout01.posteo.de ([185.67.36.65]:37343)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1v7gUP-0004he-6J
for 79188 <at> debbugs.gnu.org; Sat, 11 Oct 2025 16:46:58 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout01.posteo.de (Postfix) with ESMTPS id 7C737240027
for <79188 <at> debbugs.gnu.org>; Sat, 11 Oct 2025 22:46:44 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1760215604; bh=FcKbX32VPrt3sU58p4+NZIBvTjk7PGStbhw7Jq+A+v0=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:Content-Transfer-Encoding:From;
b=a+At9oKKbYhZ4LUopwhEWcl9YgCbUsgt+GTnmjUoCdUISlxDSFPkBwensa1quUT50
hj3ljxuMWR1sTRm7X09O6kqkrqyGoJ2U6hHZBgI8AHfhcipV+p2oUkvQVA9G6TDrjT
nB2zzQL8JggbUGo9gl2oVYSRDakwAsWJAb7PN58WRBy/vbS6iA+3BMPxHXPUI+14y7
lQQBOd8b/2QDwhEGuLefxuw0n6AI+lrUigRpZTtaYfeQQjpgj8nSzIt+vR5AbPLLjB
8cR8GzHYovkOFr7Hiu3UIEt5qGhf/cr+xV0/fV2HxB92EZWELMFzwbR3bqUD+pttOi
y+A/2wIUmUcjg==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4ckbJ35NJ5z6txb;
Sat, 11 Oct 2025 22:46:43 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2bjmxgn9v.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Sat, 11 Oct 2025 20:46:43 +0000
Message-ID: <87v7kl2mkx.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -0.7 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.7 (-)
Sorry for the delay in responding, in the back of my mind I had assumed
that I sent the last message and was waiting on a response from you ^^
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> Philip Kaludercic <philipk@HIDDEN> writes:
>
>> [...]
>>>> Philip Kaludercic <philipk@HIDDEN> writes:
>>>> [...]
>>>>
>>>> Here is my alternative patch, that tries to extract most of the
>>>> repetitive logic into `package-vc--checkout-dir', thus making the
>>>> remaining changes simpler overall:
>>>> [...]
>>>>
>>>> I haven't tested it yet extensively, but it doesn't appear to break
>>>> anything right away, and commands like package-vc-rebuild appear to be
>>>> invoked in the right directories. WDYT?
>> [...]
>>>> Here is an updated patch that I have tested some more:
>>>
>>> This "updated patch" doesn't seem relevant to package-vc. Is this the
>>> right file attached?
>>
>> Right, I selected the wrong file ^^
>>
>>
>>
>> (I double checked this time, and renamed the files so that you should be
>> able to apply it to master.)
>
> That's make things so much easier. Thank you!
>
> There was a single rejection:
>
> - (package--compile
> - (if lisp-dir
> - ;; In case we are installing a package from a local
> - ;; checkout, we want to compile the checkout, not the
> - ;; redirection!
> - (package-desc-create :dir lisp-dir)
> - new-desc))
> + (package--compile (package-desc-create :dir lisp-dir))
>
> but I applied it manually and it seems to work. I tested it with this sui=
te:
>
> ;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
>
> ;;; Code:
>
> (require 'package-vc)
> (require 'package)
The latter shouldn't be necessary, as package-vc depends on package?
> (require 'vc-git)
> (require 'cl-lib)
> (require 'ert)
>
> (defvar package-vc-tests-dir
> (make-temp-file "package-vc-tests-" t (format-time-string "-%Y%m%d.%H%M=
%S")))
>
> (setq package-user-dir (expand-file-name "elpa" package-vc-tests-dir))
>
> (defvar package-vc-tests-packages
> `(;; checkout and install with `package-vc-install' (on ELPA)
> (diminish . ,(expand-file-name "diminish" package-user-dir))
> ;; checkout and install with `package-vc-install' (not on ELPA)
> (ultra-scroll . ,(expand-file-name "ultra-scroll" package-user-dir))
> ;; checkout with `package-vc-checktout' and install with
> ;; `package-vc-install-from-checkout'
> (gcmh . ,(expand-file-name "gcmh" package-vc-tests-dir))
> ;; checkout with git and install with `package-vc-install-from-checko=
ut'
> (basic-stats . ,(expand-file-name "basic-stats.el" package-vc-tests-d=
ir))
> ;; TODO: a package with source files in lisp/ directory (both methods=
of
> ;; installation)
>
> ;; TODO: a package with source files in a non-standard :lisp-dir (both
> ;; methods of installation)
> ))
Part of me is uncomfortable with the idea of having our tests depend on
the package structure of packages that are not under our control. Would
it be possible to restrict the tests to packages that are on GNU ELPA
and are versioned inside of elpa.git (i.e. have ":url nil")?
Alternatively, we could consider git-bundle(1) files as test data to
emacs.git.
>
> ;; TODO: add test for deleting packages, with asserting
> ;; `package-vc-selected-packages'
>
> ;; TODO: clarify `package-vc-install-all' behaviour with regards to packa=
ges
> ;; installed with `package-vc' but not stored in `package-vc-selected-pac=
kages'
> ;; i.e., packages from ELPAs
>
> (defun package-vc-tests-package-desc (package &optional installed)
> "Return descriptor of PACKAGE.
> When INSTALLED is non-nil the descriptor will come from `package-alist'.
> Otherwise the descriptor will be from `package-archive-contents'. This
> is to mimic `package-vc--read-package-desc'."
> (cadr (assoc (if (stringp package) package (symbol-name package))
> (if installed package-alist package-archive-contents)
> #'string=3D)))
>
> (defun package-vc-tests-assert-delete-elc ()
> "Assert that .elc files are in expected directories and delete them.
> When ALL is non nil, check all packages under test."
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (let* ((dir (cdr pkg-checkout-dir))
> (elc-files (directory-files dir nil (rx ".elc" string-end))))
> (should-not (equal (cons dir elc-files)
> (list dir)))
> (dolist (elc-file elc-files)
> (delete-file (expand-file-name elc-file dir))))))
>
> (defun package-vc-tests-packages-heads (reset)
> "Return HEAD revisions of `package-vc-tests-packages'.
> When RESET is non-nil also reset to a previous version."
> (mapcar (lambda (pkg-checkout-dir)
> (let ((default-directory (cdr pkg-checkout-dir)))
> (prog1
> (cons (car pkg-checkout-dir)
> (vc-git-working-revision nil))
> (when reset
> (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))))
> package-vc-tests-packages))
>
> (ert-deftest package-vc-tests-000-install ()
> (package-refresh-contents)
> (package-vc--archives-initialize)
> (package-vc-install 'diminish)
> (should-not (alist-get "diminish" package-vc-selected-packages
> nil nil #'string=3D))
>
> (package-vc-install '(ultra-scroll
> :url "https://github.com/jdtsmith/ultra-scroll.gi=
t"))
> (should (equal "https://github.com/jdtsmith/ultra-scroll.git"
> (plist-get (alist-get "ultra-scroll"
> package-vc-selected-packages
> nil nil #'string=3D)
> :url)))
>
> (let ((checkout-dir (expand-file-name "gcmh" package-vc-tests-dir)))
> (package-vc-checkout (package-vc-tests-package-desc 'gcmh)
> checkout-dir)
> (package-vc-install-from-checkout checkout-dir)
> (should (equal (format "file://%s" checkout-dir)
> (plist-get (alist-get "gcmh"
> package-vc-selected-packages
> nil nil #'string=3D)
> :url))))
>
> (let ((checkout-dir (expand-file-name "basic-stats.el" package-vc-tests=
-dir)))
> (shell-command
> (format "git clone https://github.com/pkryger/basic-stats.el.git %s"
> checkout-dir))
> (package-vc-install-from-checkout checkout-dir "basic-stats")
> (should (equal (format "file://%s" checkout-dir)
> (plist-get (alist-get "basic-stats"
> package-vc-selected-packages
> nil nil #'string=3D)
> :url))))
>
> (package-vc-tests-assert-delete-elc))
>
> (ert-deftest package-vc-tests-001-main-file ()
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (should (equal (package-vc--main-file
> (package-vc-tests-package-desc (car pkg-checkout-dir) =
t))
> (format "%s/%s.el"
> (cdr pkg-checkout-dir)
> (car pkg-checkout-dir))))))
>
> (ert-deftest package-vc-tests-002-commit ()
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (let ((pkg (car pkg-checkout-dir))
> (commit (package-vc-commit
> (package-vc-tests-package-desc (car pkg-checkout-dir) t=
))))
> (should-not (equal (cons pkg commit)
> (list pkg)))
> (should-not (equal (list pkg "unknown")
> (list pkg commit))))))
>
> (defmacro package-vc-tests-package-vc-upgrade-wait (seconds count &rest b=
ody)
> "Wait up to SECONDS for COUNT packages upgrading BODY.
> Return nil on timeout or non nil otherwise."
> (declare (indent 2))
> `(letrec ((packages-count ,count)
> (post-vc-command (lambda (command _ flags)
> ;; A crude filter for vc commands
> (when (and (equal command "git")
> (string-prefix-p "*vc-git" (buf=
fer-name)))
> (cl-decf packages-count)))))
> (add-hook 'vc-post-command-functions post-vc-command 100)
> (unwind-protect
> (progn
> ,@body
> (catch 'done
> (dotimes (i (* 10 ,seconds))
> (sleep-for 0.1)
> (when (eql packages-count 0)
> (throw 'done t)))))
> (remove-hook 'vc-post-command-functions post-vc-command))))
>
> (ert-deftest package-vc-tests-003-upgrade-all ()
> (let ((heads (package-vc-tests-packages-heads t)))
> (should
> (package-vc-tests-package-vc-upgrade-wait
> 5 (length package-vc-tests-packages)
> (package-vc-upgrade-all)))
> (should (equal heads
> (package-vc-tests-packages-heads nil))))
> (package-vc-tests-assert-delete-elc))
>
> (ert-deftest package-vc-tests-004-upgrade ()
> (let ((heads (package-vc-tests-packages-heads t)))
> (should
> (package-vc-tests-package-vc-upgrade-wait
> 5 (length package-vc-tests-packages)
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (package-vc-upgrade
> (package-vc-tests-package-desc (car pkg-checkout-dir) t)))))
> (should (equal heads
> (package-vc-tests-packages-heads nil))))
> (package-vc-tests-assert-delete-elc))
>
> (ert-deftest package-vc-tests-005-rebuild ()
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (package-vc-rebuild
> (package-vc-tests-package-desc (car pkg-checkout-dir) t)))
> (package-vc-tests-assert-delete-elc))
>
> (ert-deftest package-vc-tests-006-prepare-patch ()
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (cl-letf* ((call-count 0)
> ((symbol-function #'package-maintainers)
> (lambda (&rest _)
> "test-maintainers"))
> ((symbol-function #'vc-prepare-patch)
> (lambda (addressee subject revisions)
> (should (equal (file-name-as-directory default-director=
y)
> (file-name-as-directory (cdr pkg-checkou=
t-dir))))
> (should (equal "test-maintainers" addressee))
> (should (equal "test-subject" subject))
> (should (equal "test-revisions" revisions))
> (cl-incf call-count))))
> (package-vc-prepare-patch (package-vc-tests-package-desc
> (car pkg-checkout-dir)
> t)
> "test-subject"
> "test-revisions")
> (should (eql 1 call-count)))))
>
> (ert-deftest package-vc-tests-007-log-incoming ()
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (cl-letf* ((call-count 0)
> ((symbol-function #'vc-log-incoming)
> (lambda ()
> (interactive)
> (should (equal (file-name-as-directory default-director=
y)
> (file-name-as-directory (cdr pkg-checkou=
t-dir))))
> (cl-incf call-count))))
> (package-vc-log-incoming (package-vc-tests-package-desc
> (car pkg-checkout-dir) t))
> (should (eql 1 call-count)))))
>
> (provide 'package-vc-tests)
>
> ;;; package-vc-tests.el ends here
>
>
> using the following command:
>
> emacs -batch -l test/lisp/package-vc-tests.el -f ert-run-tests-batch-and-=
exit
>
> It all passes for me.
>
> However, I added a few fixes:
>
> 1. Remove temporary binding for `package-vc-selected-packages' in
> function `package-vc-install-from-checkout'. It not only simplifies the
> code, but also removes the superfluous binding (which is never used),
> but also ensures that side effect of changing a value of
> `package-vc-selected-packages' is visible after the function call.
It is used, the point of rebinding the variable is so that
`package-vc--desc->spec' returns the constructed package specification
in `package-vc--unpack-1'?
But reading through your patch I understand what you mean, and the
change looks like it should make sense. I will have to test it in
practice before pushing it to master. OK?
> 2. Updated the value passed to `package--native-compile-async'.
>
> 3. Updated a couple of comments.
>
> Please see the following patch:
>
>>From 70731b0e197e286f6d09606e2cf79b1275bf868e Mon Sep 17 00:00:00 2001
> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
> Date: Fri, 26 Sep 2025 17:24:44 +0100
> Subject: [PATCH] Fix native compilation and storage of VC packages
>
> * lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): Use a
> `package' with `:dir' pointing to where package code is.
> (package-vc-install-from-checkout): Remove superfluous
> `package-vc-selected-packages' binding.
> ---
> lisp/emacs-lisp/package-vc.el | 20 +++++++++-----------
> 1 file changed, 9 insertions(+), 11 deletions(-)
>
> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
> index 078a7bd8136..d99bdb1813c 100644
> --- a/lisp/emacs-lisp/package-vc.el
> +++ b/lisp/emacs-lisp/package-vc.el
> @@ -31,8 +31,7 @@
> ;; aren't interested in activating a package, you can use
> ;; `package-vc-checkout' instead, which will prompt you for a target
> ;; directory. If you wish to reuse an existing checkout, the command
> -;; `package-vc-install-from-checkout' will create a symbolic link and
> -;; prepare the package.
> +;; `package-vc-install-from-checkout' will prepare the package.
> ;;
> ;; If you make local changes that you wish to share with an upstream
> ;; maintainer, the command `package-vc-prepare-patch' can prepare
> @@ -568,7 +567,8 @@ package-vc--unpack-1
> (setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
>=20=20
> ;; Update package-alist.
> - (let ((new-desc (package-load-descriptor pkg-dir)))
> + (let ((new-desc (package-load-descriptor pkg-dir))
> + (compile-desc (package-desc-create :dir lisp-dir)))
> ;; Activation has to be done before compilation, so that if we're
> ;; upgrading and macros have changed we load the new definitions
> ;; before compiling.
> @@ -576,9 +576,9 @@ package-vc--unpack-1
> ;; FIXME: Compilation should be done as a separate, optional, st=
ep.
> ;; E.g. for multi-package installs, we should first install all =
packages
> ;; and then compile them.
> - (package--compile (package-desc-create :dir lisp-dir))
> + (package--compile compile-desc)
> (when package-native-compile
> - (package--native-compile-async new-desc))
> + (package--native-compile-async compile-desc))
> ;; After compilation, load again any files loaded by
> ;; `activate-1', so that we use the byte-compiled definitions.
> (package--reload-previously-loaded new-desc)))
> @@ -966,17 +966,15 @@ package-vc-install-from-checkout
> (package-vc--archives-initialize)
> (let* ((dir (if interactive dir (expand-file-name dir))) ;avoid double=
expansion
> (name (or name (file-name-base (directory-file-name dir))))
> - (pkg-dir (file-name-concat package-user-dir name))
> - (package-vc-selected-packages
> - (cons (list name :lisp-dir dir)
> - package-vc-selected-packages)))
> + (pkg-dir (file-name-concat package-user-dir name)))
> (when (file-exists-p pkg-dir)
> (if (yes-or-no-p (format "Overwrite previous checkout for package =
`%s'?" name))
> (package--delete-directory pkg-dir)
> (error "There already exists a checkout for %s" name)))
> (make-directory pkg-dir t)
> - ;; We store a custom package specification so that
> - ;; `package-vc--checkout-dir' can later retrieve the actual checkout.
> + ;; We store a custom package specification so that it is available
> + ;; for `package-vc--unpack-1' as well as `package-vc--checkout-dir'
> + ;; can later retrieve the actual checkout.
> (package-vc--save-selected-packages name (list :url (concat "file://=
" dir)))
> (package-vc--unpack-1
> (package-desc-create
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Mon, 13 Oct 2025 10:52:02 +0000
Resent-Message-ID: <handler.79188.B79188.176035268424744 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176035268424744
(code B ref 79188); Mon, 13 Oct 2025 10:52:02 +0000
Received: (at 79188) by debbugs.gnu.org; 13 Oct 2025 10:51:24 +0000
Received: from localhost ([127.0.0.1]:51389 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1v8G9E-0006R0-5x
for submit <at> debbugs.gnu.org; Mon, 13 Oct 2025 06:51:24 -0400
Received: from mail-wm1-x330.google.com ([2a00:1450:4864:20::330]:49457)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1v8G99-0006Qj-TO
for 79188 <at> debbugs.gnu.org; Mon, 13 Oct 2025 06:51:21 -0400
Received: by mail-wm1-x330.google.com with SMTP id
5b1f17b1804b1-46e2c3b6d4cso29716895e9.3
for <79188 <at> debbugs.gnu.org>; Mon, 13 Oct 2025 03:51:19 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1760352672; x=1760957472; darn=debbugs.gnu.org;
h=content-transfer-encoding:mime-version:user-agent:message-id:date
:references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date
:message-id:reply-to;
bh=LylteLm20tv2TaggYdvvrIgY7Q3zvOvwiA6DsGmeUlM=;
b=EUvG/JQ1XV0SDrpDvj+4k+mteDq3foe0BXRjssrLiZDpEby0MBlyjbbJrS8WoBy3ye
qG1VS7E8Oid6UwWZcdTfuzmKTtvCucnrCh3JAUuK5w7+/76gHStUTxukANJwm7fJjwZR
v04z/OgSwfa4y7PkDe8tvw6sCrIycswDthPo6Nplnua6PWUMdfBG2BVtkr1XZN0QEw2v
fzdiyz3KOHyYBjB6PQ97M5WEkZuVpWWXlfryK3JiIVRQdvaX8pWYQDH+3yZwBv2Ltox9
sP5cwW6Tg7xg+BipmqOn4d8gCnutQ/YYwWPPhQzFr/W0erJ6aXccR3esd5ZBFP/8sDiW
QsJg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1760352672; x=1760957472;
h=content-transfer-encoding:mime-version:user-agent:message-id:date
:references:in-reply-to:subject:cc:to:from:x-gm-message-state:from
:to:cc:subject:date:message-id:reply-to;
bh=LylteLm20tv2TaggYdvvrIgY7Q3zvOvwiA6DsGmeUlM=;
b=dkGYBLov5lyeP2wYOsxaktrz0jmVqrI3OXb/vzy3aTS49RQtb9gITzrIO2fUHgRph9
GVBg+btYh/R61lp7qtieZqkroOjPZFgM8/b9iAvLyHSJt/LhTFtLhuXdsdQEDZ6c78fb
lrrn1VbrqjkJw4sSmewlIl9eT4BGUCD+lMhJBbwITlpU/FtrcRD4ozM2IO/AILR4V+NY
g5aUWguXEYO8f9TEAKSQOenkHCVvq+zYNpur6/2IPq1jU8O9CLu3QTe8OrfMxPoMWs3n
6gpwwkhO9VpUtnx3QtoT2RnrcbPTNjBVfC+5c1WZHcAamqd610loPZglWSXHy5HNT22X
nEWg==
X-Gm-Message-State: AOJu0Yzv2vGB4xTMs3d6KbJQ05y/96YvzdP7aJkfRi/ryi/Pr55gQwoj
xH7QMWTUTL3rF31B7G/utwh3OWJlQI4FXr2oOc7691wkwdvsPR6nRO+Xk4Vulw==
X-Gm-Gg: ASbGnctDtla/DYF/COGME1ssewgd6aU+Clg0ImpPt4zjW950TXdpFEpB3EQFIhJ2vzt
SDr/eLMjXNlxCkeXL967T9NfBJV/p3y2DZDvo85XO75h1y6+YxgS4sOm9F52v5JMhl4SvSb/jDe
v+/2vG02XD93JIIjB4ITHCCvOYoxFlGzXOrWJfrbCiLZWiKAbfbfk+2nSGiZp1NHHIHegQGiGDf
QJelh6D2mUG5sVKGx7cgJi/h3ANZW4fNCYez4Yslem2C3i5jrbt83PxoyS71PVI31EZ6DRTlrvT
UQhIl6y5kdGBcCoL3E9K3warYPsdDAXZOOiYqCnvYI7RBjV0q3Vjv2Th4jWwwyOv+zAjp/VKK5M
SQM30HiEywBShkGcecQJt4f/yEVSzQQCef5vxSCFpuOSmZJjJinyH6KFCXrLbITO8wpsMYZhDvf
Mww9qxBQ==
X-Google-Smtp-Source: AGHT+IEZPXbavZSGh0RrPftn9UXptKFjEsPTqsSt+S8108f+92UOtSr6Pr8oWmKntdaMLQRHX3vQMQ==
X-Received: by 2002:a05:600c:3b1f:b0:46e:42cb:d93f with SMTP id
5b1f17b1804b1-46fa9a98ef7mr147304555e9.15.1760352671977;
Mon, 13 Oct 2025 03:51:11 -0700 (PDT)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:5df7:4e0d:9397:ac16])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-46fb483c7e0sm181292855e9.7.2025.10.13.03.51.10
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Mon, 13 Oct 2025 03:51:11 -0700 (PDT)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <87v7kl2mkx.fsf@HIDDEN> (Philip Kaludercic's message of "Sat,
11 Oct 2025 20:46:43 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN>
Date: Mon, 13 Oct 2025 11:51:10 +0100
Message-ID: <m24is3dqht.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
Philip Kaludercic <philipk@HIDDEN> writes:
> Sorry for the delay in responding, in the back of my mind I had assumed
> that I sent the last message and was waiting on a response from you ^^
No worries. This happens to me too often to my likening.
>
> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>
>> Philip Kaludercic <philipk@HIDDEN> writes:
>>
>> [...]
>> I tested it with this suite:
>>
>> ;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -=
*-
>>
>> ;;; Code:
>>
>> (require 'package-vc)
>> (require 'package)
>
> The latter shouldn't be necessary, as package-vc depends on package?
I like to not relay on transitive dependencies. But happy to remove.
>> [...]
>> (defvar package-vc-tests-packages
>> `(;; checkout and install with `package-vc-install' (on ELPA)
>> (diminish . ,(expand-file-name "diminish" package-user-dir))
>> ;; checkout and install with `package-vc-install' (not on ELPA)
>> (ultra-scroll . ,(expand-file-name "ultra-scroll" package-user-dir))
>> ;; checkout with `package-vc-checktout' and install with
>> ;; `package-vc-install-from-checkout'
>> (gcmh . ,(expand-file-name "gcmh" package-vc-tests-dir))
>> ;; checkout with git and install with `package-vc-install-from-check=
out'
>> (basic-stats . ,(expand-file-name "basic-stats.el" package-vc-tests-=
dir))
>> ;; TODO: a package with source files in lisp/ directory (both method=
s of
>> ;; installation)
>>
>> ;; TODO: a package with source files in a non-standard :lisp-dir (bo=
th
>> ;; methods of installation)
>> ))
>
> Part of me is uncomfortable with the idea of having our tests depend on
> the package structure of packages that are not under our control. Would
> it be possible to restrict the tests to packages that are on GNU ELPA
> and are versioned inside of elpa.git (i.e. have ":url nil")?
>
> Alternatively, we could consider git-bundle(1) files as test data to
> emacs.git.
I did that to have a few real life samples. But I am completely with
you on this. Didn't know about git-bundle(1) but it seems perfect tool
for the job.
I gather that you like the idea of having something like that in Emacs
source code, such that all scenarios could be tested, correct? How
about just creating a few dummy packages for the purposes of testing
package-vc? Have been also thinking about having own tiny ELPA for that
purposes, such that tests could be run in complete isolation. But not
sure how much work it would be. Any tips?
>> However, I added a few fixes:
>>
>> 1. Remove temporary binding for `package-vc-selected-packages' in
>> function `package-vc-install-from-checkout'. It not only simplifies the
>> code, but also removes the superfluous binding (which is never used),
>> but also ensures that side effect of changing a value of
>> `package-vc-selected-packages' is visible after the function call.
>
> It is used, the point of rebinding the variable is so that
> `package-vc--desc->spec' returns the constructed package specification
> in `package-vc--unpack-1'?
IIUC this was strictly necessary until
`package-vc--save-selected-packages' has been added just before
`pakcage-vc-unpack-1' call.
> But reading through your patch I understand what you mean, and the
> change looks like it should make sense. I will have to test it in
> practice before pushing it to master. OK?
This sounds good to me!
Do you have any comments on the other issues I highlighted in previous
message? Repeating them for convenience:
When adding the last fix, I started to think that there are a few more
areas that I am not sure how they work. Unfortunately, I won't have
time to dig deeper very soon, so just bringing them to your attention,
and you can decide whether or not to install patches we have already.
IMHO, they are a reasonable fix for the immediate issue.
1. In `package-vc--unpack-1' there are calls to `package-activate-1' and
`package--reload-previously-loaded' (just around where compilation
happens). But I am not convinced these calls will result in expected
side effects when a package has been installed with
`package-vc-install-from-checkout'.
2. In `package-vc-unpack-1' there are calls to `package-vc--make' and
`package-vc--build-documentation' which, again may be not doing what is
expected for packages installed with `package-vc-install-from-checkout'.
3. I am not sure what will happen when someone checkouts a repository to
`package-user-dir' making it so the 'package-vc-install-from-checkout'
calculates `pkg-dir' that is the same as a checkout dir. I know it's
not the smartest thing to do, but perhaps detect it and raise an error?
4. I struggle to understand how the value of `:lisp-dir' calculated in
`package-vc-unpack' (lines 701-711) is used in further code. Will need
to find a package that specifies that and try to debug it further.
5. Perhaps the `package-vc-install-from-checkout' could be extended in
such a way to allow user to specify their `pkg-spec'. That should
include the checkout directory, as well as other values from spec
(lisp-dir, make, doc)?
5. I am not sure how `package-delete' will work with these changes. I
guess it should at least remove the pkg-dir as well as entry from
`package-vc-selected-packages'.
Please let me know if you think any of these require immediate
attention, I will try to boost a priority for it.
Cheers,
PK
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Thu, 16 Oct 2025 16:41:01 +0000
Resent-Message-ID: <handler.79188.B79188.176063284218746 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176063284218746
(code B ref 79188); Thu, 16 Oct 2025 16:41:01 +0000
Received: (at 79188) by debbugs.gnu.org; 16 Oct 2025 16:40:42 +0000
Received: from localhost ([127.0.0.1]:36828 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1v9R1t-0004sF-GX
for submit <at> debbugs.gnu.org; Thu, 16 Oct 2025 12:40:42 -0400
Received: from mail-wr1-x435.google.com ([2a00:1450:4864:20::435]:50246)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1v9R1o-0004rc-A9
for 79188 <at> debbugs.gnu.org; Thu, 16 Oct 2025 12:40:37 -0400
Received: by mail-wr1-x435.google.com with SMTP id
ffacd0b85a97d-42557c5cedcso601627f8f.0
for <79188 <at> debbugs.gnu.org>; Thu, 16 Oct 2025 09:40:36 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1760632827; x=1761237627; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=ex9+c74jA4DJ/MAVnbcre+HzxDZ+6kMTc6MGuwSPLb4=;
b=Q2+cpo9SI+9JNMks4btKz3ARu5/HqmTeDtYRIkR7MwiLCyQFbTQI0lfsVoU2fwqGAP
N+L60rgI7nMHUkw9E/yhFv76+XCn0psYV3qB5S9BDNmOOkYG++eE6+oLBFEoY9cKZiPt
x68gmu/meeKL9pHQTdjHyJASVqCPzwjlvYq2lRakjYmOhRHjTkYYcwrJZrbE0DQLqPWR
jIqVwsUtaQhyW7WS4yMyUj9V8UH0ufNBrztJ7FJkod5f8MpiuYS10NMcPt3w+0fI2Jmd
fs3nkFo2scJr6Bgs/IC8gSUCw2ALdaOXczk/loK2G/2ybSbBmBBRYyw6LOlbe6ixxbu3
hlzQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1760632827; x=1761237627;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to;
bh=ex9+c74jA4DJ/MAVnbcre+HzxDZ+6kMTc6MGuwSPLb4=;
b=msvG9xfC1atvpnM9vo9iM42G0yi/GdNKN8QlgvLUiIPb7oqkLH0ihoIpuM1gpLH7gw
u5CVIDaOMlg4LVuDX3TRawBM5WXWEF1+rvUcStJ5BPnS3IoWU9KG1ljDDZ1y6/S+cLgY
KZ/w6DbqzLV13Mij7rjXzvJ2EEmn1pRVSxRTy9CH1WBgd6gMVgDozYcQeo0TcqX7yASH
SMhuGVyw83YuZr3cYUkkmFsnLiB+DCJvUBY5dUK3xAoudjxRCPh3scglzBsDVlieXnfb
wtT384NieiXxUqgAGAvosStQ0+jhxScXddl6hz1A/hQzk+L1UFI0gqfI29K1wW6Et5LC
CZfw==
X-Gm-Message-State: AOJu0YyW4Zx2SlOkHt5RHQAzRDfiUTUhev560xX3xOXkOk4HDbKH5siu
bP60NTYjwSc6xqJ9p9WUuhspkynRb6iaePgczggko+5aA2EVabsJJLD+936j8g==
X-Gm-Gg: ASbGncuHeZtNiKkJAPf+t0AgKJfYCybRlq8s9qR5Z8BV8hvBusj94WRlvB/AIJI5qcB
Rk3HpiHE78My7ne8UkOmhd3VvGhGEZADh6kv2CU8+7VIjhFwmokcT59VSxFL/+dHJL/d9trKDAD
jTmhNclFFcWfPh+0CnkZUm2UJwhLF74q38Z12C7sPqd/VbNY5gWWkZdVyTFF/NLOYfrEXpnorK7
7mabtNiVlYZI8FV7rLbPvI5nBvbftrkwzILZ4xQERCSspT6ixLJBuh6nELjUZ1ndQWoqDRcYvV7
tKwzb5sruIfW0fcK8pqb/FKQ9thZzn5nlhZeo/nY7DaAL6Uwg1CJEJfCykTZDq1K8fkKaYgcb0g
kiJ+dw4bLZaZp0i/HBYkLCzMvgMC0PdgRhH0pI+ya8imCwJ79jhaVsZW80SaY5q1+EB69tavYeR
vvO+1onyvFlHwNQda1M8+6leI0ylHSQ3aLOX4S8kv2
X-Google-Smtp-Source: AGHT+IHKi/ZmHwdzIfacnSgxKu4vcCap2UGEYki+bLHhCCTOKezaYzP08oGeOjG8iHjPGhnP6LpMog==
X-Received: by 2002:a05:6000:400e:b0:3ec:c50c:7164 with SMTP id
ffacd0b85a97d-42704d52205mr593642f8f.15.1760632826789;
Thu, 16 Oct 2025 09:40:26 -0700 (PDT)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:640b:7c30:1452:12e4])
by smtp.gmail.com with ESMTPSA id
ffacd0b85a97d-426ce5cfe69sm36764305f8f.32.2025.10.16.09.40.25
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Thu, 16 Oct 2025 09:40:25 -0700 (PDT)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <m24is3dqht.fsf@HIDDEN> ("=?UTF-8?Q?Przemys=C5=82aw?=
Kryger"'s message of "Mon, 13 Oct 2025 11:51:10 +0100")
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
Date: Thu, 16 Oct 2025 17:40:24 +0100
Message-ID: <m2ldlax0jr.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
I have found a bit of time and took a look on some of the issues
highlighted below. To my understanding some of fixes are needed.
Please see below.
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> [...]
> Do you have any comments on the other issues I highlighted in previous
> message? Repeating them for convenience:
>
> [...]
>
> 1. In `package-vc--unpack-1' there are calls to `package-activate-1' and
> `package--reload-previously-loaded' (just around where compilation
> happens). But I am not convinced these calls will result in expected
> side effects when a package has been installed with
> `package-vc-install-from-checkout'.
>
> 2. In `package-vc-unpack-1' there are calls to `package-vc--make' and
> `package-vc--build-documentation' which, again may be not doing what is
> expected for packages installed with `package-vc-install-from-checkout'.
So as I suspected not everything was all right. With the patches up to
this message, when a user installed a package with
`package-install-from-checkout' and then subsequently upgraded it with
`package-upgrade' then the pkg-desc entry for the package in
`package-alist' become corrupted. After the installation the `dir' slot
in `pkg-desc' has been pointing to the `pkg-dir', i.e., a directory
under `package-user-dir' that contains "-pkg.el" and forwarding
"-autoloads.el" files. However, after the upgrade the slot `dir' points
to checkout directory. To my understanding this is undesirable, as for
example a subsequent call to `package-delete' will delete the checkout
directory leaving the `pkg-dir' with forwarding "-autoloads.el" file
that tries load non existent "-autoloads.el".
Please find a patch for that:
--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment;
filename=0001-Fix-incorrect-pkg-desc-after-package-vc-upgrade.patch
Content-Description: patch
From 2b3375490fba5dc00ba7305e670286fb41401cbc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Przemys=C5=82aw=20Kryger?= <pkryger@HIDDEN>
Date: Wed, 15 Oct 2025 08:00:02 +0100
Subject: [PATCH] Fix incorrect pkg-desc after package-vc-upgrade
After installing a package with
`package-vc-install-from-checkout' and subsequently upgrading it
with `package-vc-upgrade' the pkg-desc for the package becomes
corrupted. After the upgrade the pkg-desc's dir (a.k.a
`pkg-dir') points to checkout directory. This will cause the
subsequent `package-delete' to delete the checkout directory and
leaving incorrect forwarding autoloads file in
`package-user-directory'.
* lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): Remove
superfluous `pkg-dir' argument. After calling
`package-activate-1', ensure that source files are reloaded when
`lisp-dir' is not a subdirectory of `pkg-dir' and call
`package--add-info-node' when `checkoud-dir' is different than
`pkg-dir'.
(package-vc--unpack, package-vc-upgrade)
(package-vc-install-from-checkout, package-vc-rebuild): Remove
`pkg-dir' argument from `package-vc--unpack-1' calls.
* lisp/emacs-lisp/package.el (package--add-info-node): New
function to install info node for package. Extracted from
`package-activate-1'.
(package-activate-1): Call `package--add-info-node'.
---
lisp/emacs-lisp/package-vc.el | 56 ++++++++++++++++++++++-------------
lisp/emacs-lisp/package.el | 15 ++++++----
2 files changed, 45 insertions(+), 26 deletions(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index d99bdb1813c..21bdf3e401f 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -467,13 +467,15 @@ package-vc-install-dependencies
(mapc #'package-install-from-archive to-install)
missing))
-(defun package-vc--unpack-1 (pkg-desc pkg-dir)
- "Prepare PKG-DESC that is already checked-out in PKG-DIR.
-This includes downloading missing dependencies, generating
-autoloads, generating a package description file (used to
-identify a package as a VC package later on), building
-documentation and marking the package as installed."
- (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
+(defun package-vc--unpack-1 (pkg-desc)
+ "Prepare PKG-DESC that is already checked-out.
+The checkout directory is determined by relevant pkg-spec or from `dir'
+slot of PKG-DESC. This includes downloading missing dependencies,
+generating autoloads, generating a package description file (used to
+identify a package as a VC package later on), building documentation and
+marking the package as installed."
+ (let* ((pkg-dir (package-desc-dir pkg-desc))
+ (pkg-spec (package-vc--desc->spec pkg-desc))
(checkout-dir (package-vc--checkout-dir pkg-desc))
(lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
missing)
@@ -567,12 +569,24 @@ package-vc--unpack-1
(setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
;; Update package-alist.
- (let ((new-desc (package-load-descriptor pkg-dir))
- (compile-desc (package-desc-create :dir lisp-dir)))
+ (let* ((new-desc (package-load-descriptor pkg-dir))
+ (compile-desc (package-desc-create :name (package-desc-name new-desc)
+ :dir lisp-dir)))
;; Activation has to be done before compilation, so that if we're
;; upgrading and macros have changed we load the new definitions
;; before compiling.
(when (package-activate-1 new-desc :reload :deps)
+ ;; `package-activate-1' will reload all necessary package files
+ ;; as long as they are locate in a subdirectory of `pkg-dir'.
+ ;; If that's not the case, we want to reload all package files
+ ;; from the `lisp-dir' before compilation.
+ (unless (file-in-directory-p lisp-dir pkg-dir)
+ (package--reload-previously-loaded compile-desc))
+ ;; `package-activate-1' will add info node as long as dir file
+ ;; exists in `pkg-dir'. We need to manually add it when
+ ;; `checkout-dir' is in different location.
+ (unless (file-equal-p pkg-dir checkout-dir)
+ (package--add-info-node checkout-dir))
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
@@ -580,8 +594,10 @@ package-vc--unpack-1
(when package-native-compile
(package--native-compile-async compile-desc))
;; After compilation, load again any files loaded by
- ;; `activate-1', so that we use the byte-compiled definitions.
- (package--reload-previously-loaded new-desc)))
+ ;; `package-activate-1', so that we use the byte-compiled
+ ;; definitions. This time we'll use `compile-desc' straight
+ ;; away.
+ (package--reload-previously-loaded compile-desc)))
;; Mark package as selected
(let ((name (package-desc-name pkg-desc)))
@@ -714,7 +730,7 @@ package-vc--unpack
(when (null (package-vc--desc->spec pkg-desc name))
(package-vc--save-selected-packages name pkg-spec))
- (package-vc--unpack-1 pkg-desc pkg-dir)))
+ (package-vc--unpack-1 pkg-desc)))
(defun package-vc--read-package-name (prompt &optional allow-url installed)
"Query the user for a VC package and return a name with PROMPT.
@@ -782,7 +798,7 @@ package-vc-upgrade
;;
;; If there is a better way to do this, it should be done.
(cl-assert (package-vc-p pkg-desc))
- (letrec ((pkg-dir (package-vc--checkout-dir pkg-desc))
+ (letrec ((checkout-dir (package-vc--checkout-dir pkg-desc))
(vc-flags)
(vc-filter-command-function
(lambda (command file-or-list flags)
@@ -790,18 +806,19 @@ package-vc-upgrade
(list command file-or-list flags)))
(post-upgrade
(lambda (_command _file-or-list flags)
- (when (and (file-equal-p pkg-dir default-directory)
+ (when (and (file-equal-p checkout-dir default-directory)
(eq flags vc-flags))
(unwind-protect
(with-demoted-errors "Failed to activate: %S"
- (package-vc--unpack-1 pkg-desc pkg-dir))
+ (package-vc--unpack-1 pkg-desc))
(remove-hook 'vc-post-command-functions post-upgrade))))))
(add-hook 'vc-post-command-functions post-upgrade)
(with-demoted-errors "Failed to fetch: %S"
(require 'vc-dir)
(with-current-buffer (vc-dir-prepare-status-buffer
- (format " *package-vc-dir: %s*" pkg-dir)
- pkg-dir (vc-responsible-backend pkg-dir))
+ (format " *package-vc-dir: %s*" checkout-dir)
+ checkout-dir
+ (vc-responsible-backend checkout-dir))
(vc-pull)))))
(defun package-vc--archives-initialize ()
@@ -980,8 +997,7 @@ package-vc-install-from-checkout
(package-desc-create
:name (intern name)
:dir pkg-dir
- :kind 'vc)
- (file-name-as-directory pkg-dir))))
+ :kind 'vc))))
;;;###autoload
(defun package-vc-rebuild (pkg-desc)
@@ -993,7 +1009,7 @@ package-vc-rebuild
is the responsibility of `package-vc-upgrade'. Interactively,
prompt for the name of the package to rebuild."
(interactive (list (package-vc--read-package-desc "Rebuild package: " t)))
- (package-vc--unpack-1 pkg-desc (package-vc--checkout-dir pkg-desc)))
+ (package-vc--unpack-1 pkg-desc))
;;;###autoload
(defun package-vc-prepare-patch (pkg-desc subject revisions)
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index ba9999c20e6..fb073579bc1 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -903,6 +903,14 @@ package--reload-previously-loaded
(mapc (lambda (c) (load (car c) nil t))
(sort result (lambda (x y) (< (cdr x) (cdr y))))))))
+(defun package--add-info-node (pkg-dir)
+ "Add info node located in PKG-DIR."
+ (when (file-exists-p (expand-file-name "dir" pkg-dir))
+ ;; FIXME: not the friendliest, but simple.
+ (require 'info)
+ (info-initialize)
+ (add-to-list 'Info-directory-list pkg-dir)))
+
(defun package-activate-1 (pkg-desc &optional reload deps)
"Activate package given by PKG-DESC, even if it was already active.
If DEPS is non-nil, also activate its dependencies (unless they
@@ -934,12 +942,7 @@ package-activate-1
The following files have already been loaded: %S")))
(with-demoted-errors "Error loading autoloads: %s"
(load (package--autoloads-file-name pkg-desc) nil t)))
- ;; Add info node.
- (when (file-exists-p (expand-file-name "dir" pkg-dir))
- ;; FIXME: not the friendliest, but simple.
- (require 'info)
- (info-initialize)
- (add-to-list 'Info-directory-list pkg-dir))
+ (package--add-info-node pkg-dir)
(push name package-activated-list)
;; Don't return nil.
t)))
--
2.51.0
--=-=-=
Content-Type: text/plain
And upgraded test file with extra assertions to ensure `package-alist'
and `load-history' contain correct entries:
--=-=-=
Content-Type: application/emacs-lisp
Content-Disposition: attachment; filename=package-vc-tests.el
Content-Transfer-Encoding: quoted-printable
Content-Description: tests
;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
;;; Code:
(require 'package-vc)
(require 'package)
(require 'vc-git)
(require 'cl-lib)
(require 'ert)
(defvar package-vc-tests-dir
(make-temp-file "package-vc-tests-" t (format-time-string "-%Y%m%d.%H%M%S=
")))
(setq package-user-dir (expand-file-name "elpa" package-vc-tests-dir))
(defvar package-vc-tests-packages
`(;; checkout and install with `package-vc-install' (on ELPA)
(diminish . ,(expand-file-name "diminish" package-user-dir))
;; checkout and install with `package-vc-install' (not on ELPA)
(ultra-scroll . ,(expand-file-name "ultra-scroll" package-user-dir))
;; checkout with `package-vc-checktout' and install with
;; `package-vc-install-from-checkout'
(gcmh . ,(expand-file-name "gcmh" package-vc-tests-dir))
;; checkout with git and install with `package-vc-install-from-checkout'
(basic-stats . ,(expand-file-name "basic-stats.el" package-vc-tests-dir=
))
;; TODO: a package with source files in lisp/ directory (both methods of
;; installation)
;; TODO: a package with source files in a non-standard :lisp-dir (both
;; methods of installation)
))
;; TODO: add test for deleting packages, with asserting
;; `package-vc-selected-packages'
;; TODO: clarify `package-vc-install-all' behaviour with regards to packages
;; installed with `package-vc' but not stored in `package-vc-selected-packa=
ges'
;; i.e., packages from ELPAs
(defun package-vc-tests-package-desc (package &optional installed)
"Return descriptor of PACKAGE.
When INSTALLED is non-nil the descriptor will come from `package-alist'.
Otherwise the descriptor will be from `package-archive-contents'. This
is to mimic `package-vc--read-package-desc'."
(cadr (assoc (if (stringp package) package (symbol-name package))
(if installed package-alist package-archive-contents)
#'string=3D)))
(defun package-vc-tests-package-main-file (pkg-checkout-dir)
"Return a main file of PKG-CHECKOUT-DIR."
(format "%s/%s.el" (cdr pkg-checkout-dir) (car pkg-checkout-dir)))
(defun package-vc-tests-load-history-position (pkg type)
"Return a PKG's position in `load-history'.
If TYPE is `:autoloads' return a position of a PKG autoloads file.
Otherwise, if TYPE is `:main' return a position of PKG main file (not
compiled). Otherwise, if TYPE is `:main-compiled' return a position of
PKG compiled main file. Otherwise, if TYPE is `:marker' return a
position of a marker PKG."
(let ((pkg-file (pcase type
(:autoloads
(rx-to-string
`(seq ,(format "%s/%s/%s-autoloads.el"
package-user-dir pkg pkg)
string-end)))
(:main
(rx-to-string
`(seq ,(format "%s"
(package-vc-tests-package-main-file
(assoc pkg package-vc-tests-packages)=
))
string-end)))
(:main-compiled
(rx-to-string
`(seq ,(format "%s"
(package-vc-tests-package-main-file
(assoc pkg package-vc-tests-packages)=
))
"c"
string-end)))
(:marker
(rx-to-string `(seq "/" ,(format "%s" pkg))))))
(interesting-entry
(rx-to-string `(seq string-start
,(file-truename package-vc-tests-dir)))))
(cl-position-if
(lambda (file)
(string-match pkg-file file))
(cl-remove-if-not (lambda (file-name)
(string-match interesting-entry file-name))
(mapcar #'file-truename
(cl-remove-if-not #'stringp
(mapcar #'car load-history=
)))))))
(defun package-vc-tests-assert-delete-elc ()
"Assert that .elc files are in expected directories and delete them.
When ALL is non nil, check all packages under test."
(dolist (pkg-checkout-dir package-vc-tests-packages)
(let* ((dir (cdr pkg-checkout-dir))
(elc-files (directory-files dir nil (rx ".elc" string-end)))
(autoloads-rx (rx-to-string
`(seq ,(format "%s" (car pkg-checkout-dir))
"-autoloads.elc"
string-end))))
(should-not (equal (cons dir elc-files)
(list dir)))
(should-not (cl-find-if (lambda (elc)
(string-match autoloads-rx elc))
elc-files))
(dolist (elc-file elc-files)
(delete-file (expand-file-name elc-file dir))))))
(defun package-vc-tests-assert-packge-alist ()
"Assert that entries in `package-alist' are correct."
(dolist (pkg (mapcar #'car package-vc-tests-packages))
(let ((pkg-spec (should (cadr (assq pkg package-alist)))))
(should (equal (file-name-as-directory
(package-desc-dir pkg-spec))
(file-name-as-directory
(expand-file-name (format "%s" pkg)
package-user-dir)))))))
(defun package-vc-tests-packages-heads (reset)
"Return HEAD revisions of `package-vc-tests-packages'.
When RESET is non-nil also reset to a previous version."
(mapcar (lambda (pkg-checkout-dir)
(let ((default-directory (cdr pkg-checkout-dir)))
(prog1
(cons (car pkg-checkout-dir)
(vc-git-working-revision nil))
(when reset
(vc-git-command nil 0 nil "reset" "--hard" "HEAD^")
;; FIXME: compilation of tests loads basic-stats.el
(when (file-exists-p "test")
(shell-command (format "rm -rf test")))))))
package-vc-tests-packages))
(ert-deftest package-vc-tests-000-install ()
(package-refresh-contents)
(package-vc--archives-initialize)
(push (list (format "%s/install-begin" package-vc-tests-dir))
load-history)
(package-vc-install 'diminish)
(should-not (alist-get "diminish" package-vc-selected-packages
nil nil #'string=3D))
(package-vc-install '(ultra-scroll
:url "https://github.com/jdtsmith/ultra-scroll.git"=
))
(should (equal "https://github.com/jdtsmith/ultra-scroll.git"
(plist-get (alist-get "ultra-scroll"
package-vc-selected-packages
nil nil #'string=3D)
:url)))
(let ((checkout-dir (expand-file-name "gcmh" package-vc-tests-dir)))
(package-vc-checkout (package-vc-tests-package-desc 'gcmh)
checkout-dir)
(package-vc-install-from-checkout checkout-dir)
(should (equal (format "file://%s" checkout-dir)
(plist-get (alist-get "gcmh"
package-vc-selected-packages
nil nil #'string=3D)
:url))))
(let ((checkout-dir (expand-file-name "basic-stats.el" package-vc-tests-d=
ir)))
(shell-command
(format "git clone https://github.com/pkryger/basic-stats.el.git %s"
checkout-dir))
;; FIXME: compilation of tests loads basic-stats.el
(shell-command (format "rm -rf %s/test" checkout-dir))
(package-vc-install-from-checkout checkout-dir "basic-stats")
(should (equal (format "file://%s" checkout-dir)
(plist-get (alist-get "basic-stats"
package-vc-selected-packages
nil nil #'string=3D)
:url))))
(push (list (format "%s/install-end" package-vc-tests-dir))
load-history)
(dolist (package package-alist)
(dolist (pkg-desc (cdr package))
(when (package-vc-p pkg-desc)
(message "*** installed %s" pkg-desc))))
(package-vc-tests-assert-packge-alist)
(package-vc-tests-assert-delete-elc))
(ert-deftest package-vc-tests-001-main-file ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(should (equal (package-vc--main-file
(package-vc-tests-package-desc (car pkg-checkout-dir) t))
(package-vc-tests-package-main-file pkg-checkout-dir)))))
(ert-deftest package-vc-tests-002-commit ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(let ((pkg (car pkg-checkout-dir))
(commit (package-vc-commit
(package-vc-tests-package-desc (car pkg-checkout-dir) t))=
))
(should-not (equal (cons pkg commit)
(list pkg)))
(should-not (equal (list pkg "unknown")
(list pkg commit))))))
(ert-deftest package-vc-tests-003-load-history-after-install ()
(let ((install-begin (should (package-vc-tests-load-history-position
'install-begin :marker)))
(install-end (should (package-vc-tests-load-history-position
'install-end :marker))))
(dolist (pkg (mapcar #'car package-vc-tests-packages))
(let ((autoloads-pos
(should (package-vc-tests-load-history-position pkg :autoloads=
))))
(should (< install-end autoloads-pos install-begin)))
(should-not (package-vc-tests-load-history-position pkg :main))
(should-not (package-vc-tests-load-history-position pkg :main-compile=
d)))))
(ert-deftest package-vc-tests-004-require ()
(dolist (pkg (mapcar #'car package-vc-tests-packages))
(should (require pkg)))
(let ((install-end (should (package-vc-tests-load-history-position
'install-end :marker))))
(dolist (pkg (mapcar #'car package-vc-tests-packages))
(let ((main-pos (should (package-vc-tests-load-history-position pkg :=
main))))
(should (< main-pos install-end)))
(should-not (package-vc-tests-load-history-position pkg :main-compile=
d)))))
(defmacro package-vc-tests-package-vc-upgrade-wait (seconds count &rest bod=
y)
"Wait up to SECONDS for COUNT packages upgrading BODY.
Return nil on timeout or non nil otherwise."
(declare (indent 2))
`(letrec ((packages-count ,count)
(post-vc-command (lambda (command _ flags)
;; A crude filter for vc commands
(when (and (equal command "git")
(string-prefix-p "*vc-git" (buffe=
r-name)))
(cl-decf packages-count)))))
(add-hook 'vc-post-command-functions post-vc-command 100)
(unwind-protect
(progn
,@body
(catch 'done
(dotimes (i (* 10 ,seconds))
(sleep-for 0.1)
(when (eql packages-count 0)
(throw 'done t)))))
(remove-hook 'vc-post-command-functions post-vc-command))))
(ert-deftest package-vc-tests-005-upgrade-all ()
(push (list (format "%s/upgrade-all-begin" package-vc-tests-dir))
load-history)
(let ((heads (package-vc-tests-packages-heads t)))
(should
(package-vc-tests-package-vc-upgrade-wait
5 (length package-vc-tests-packages)
(package-vc-upgrade-all)))
(should (equal heads
(package-vc-tests-packages-heads nil))))
(push (list (format "%s/upgrade-all-end" package-vc-tests-dir))
load-history)
(package-vc-tests-assert-packge-alist)
(package-vc-tests-assert-delete-elc))
(ert-deftest package-vc-tests-006-load-history-after-upgrade-all ()
(let ((upgrade-all-begin (should (package-vc-tests-load-history-position
'upgrade-all-begin :marker)))
(upgrade-all-end (should (package-vc-tests-load-history-position
'upgrade-all-end :marker))))
(dolist (pkg (mapcar #'car package-vc-tests-packages))
(let ((autoloads-pos (should (package-vc-tests-load-history-position =
pkg :autoloads)))
(main-pos (should (package-vc-tests-load-history-position pkg :=
main)))
(main-compiled-pos (should (package-vc-tests-load-history-posit=
ion pkg :main-compiled))))
(should (< upgrade-all-end autoloads-pos upgrade-all-begin))
(should (< upgrade-all-end main-pos upgrade-all-begin))
(should (< upgrade-all-end main-compiled-pos upgrade-all-begin))))))
(ert-deftest package-vc-tests-007-upgrade ()
(push (list (format "%s/upgrade-begin" package-vc-tests-dir))
load-history)
(let ((heads (package-vc-tests-packages-heads t)))
(should
(package-vc-tests-package-vc-upgrade-wait
5 (length package-vc-tests-packages)
(dolist (pkg-checkout-dir package-vc-tests-packages)
(package-vc-upgrade
(package-vc-tests-package-desc (car pkg-checkout-dir) t)))))
(should (equal heads
(package-vc-tests-packages-heads nil))))
(push (list (format "%s/upgrade-end" package-vc-tests-dir))
load-history)
(package-vc-tests-assert-packge-alist)
(package-vc-tests-assert-delete-elc))
(ert-deftest package-vc-tests-008-load-history-after-upgrade ()
(let ((upgrade-begin (should (package-vc-tests-load-history-position
'upgrade-begin :marker)))
(upgrade-end (should (package-vc-tests-load-history-position
'upgrade-end :marker))))
(dolist (pkg (mapcar #'car package-vc-tests-packages))
(let ((autoloads-pos
(should (package-vc-tests-load-history-position pkg :autoloads=
)))
(main-pos
(should (package-vc-tests-load-history-position pkg :main)))
(main-compiled-pos
(should (package-vc-tests-load-history-position pkg :main-comp=
iled))))
(should (< upgrade-end autoloads-pos upgrade-begin))
(should (< upgrade-end main-pos upgrade-begin))
(should (< upgrade-end main-compiled-pos upgrade-begin))))))
(ert-deftest package-vc-tests-009-rebuild ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(package-vc-rebuild
(package-vc-tests-package-desc (car pkg-checkout-dir) t)))
(package-vc-tests-assert-packge-alist)
(package-vc-tests-assert-delete-elc))
(ert-deftest package-vc-tests-010-prepare-patch ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(cl-letf* ((call-count 0)
((symbol-function #'package-maintainers)
(lambda (&rest _)
"test-maintainers"))
((symbol-function #'vc-prepare-patch)
(lambda (addressee subject revisions)
(should (equal (file-name-as-directory default-directory)
(file-name-as-directory (cdr pkg-checkout-=
dir))))
(should (equal "test-maintainers" addressee))
(should (equal "test-subject" subject))
(should (equal "test-revisions" revisions))
(cl-incf call-count))))
(package-vc-prepare-patch (package-vc-tests-package-desc
(car pkg-checkout-dir)
t)
"test-subject"
"test-revisions")
(should (eql 1 call-count)))))
(ert-deftest package-vc-tests-011-log-incoming ()
(dolist (pkg-checkout-dir package-vc-tests-packages)
(cl-letf* ((call-count 0)
((symbol-function #'vc-log-incoming)
(lambda ()
(interactive)
(should (equal (file-name-as-directory default-directory)
(file-name-as-directory (cdr pkg-checkout-=
dir))))
(cl-incf call-count))))
(package-vc-log-incoming (package-vc-tests-package-desc
(car pkg-checkout-dir) t))
(should (eql 1 call-count)))))
(provide 'package-vc-tests)
;;; package-vc-tests.el ends here
--=-=-=
Content-Type: text/plain
> 3. I am not sure what will happen when someone checkouts a repository to
> `package-user-dir' making it so the 'package-vc-install-from-checkout'
> calculates `pkg-dir' that is the same as a checkout dir. I know it's
> not the smartest thing to do, but perhaps detect it and raise an error?
>
> 4. I struggle to understand how the value of `:lisp-dir' calculated in
> `package-vc-unpack' (lines 701-711) is used in further code. Will need
> to find a package that specifies that and try to debug it further.
>
> 5. Perhaps the `package-vc-install-from-checkout' could be extended in
> such a way to allow user to specify their `pkg-spec'. That should
> include the checkout directory, as well as other values from spec
> (lisp-dir, make, doc)?
I have not looked at these yet. Perhaps will find some time in next
couple of weeks. With my current understanding these are unlikely to
make things any worse than what is here today. I have a one more
question:
6. Perhaps `package-vc-rebuild' should delete all *.elc files, such that
subsequent `package--reload-previously-loaded' calls will certainly pick
up what is in the code, such that downgrades are supported (i.e., the
*.el file will become older than *.elc).
> 5. I am not sure how `package-delete' will work with these changes. I
> guess it should at least remove the pkg-dir as well as entry from
> `package-vc-selected-packages'.
I guess this will be question 7 now ;). I am thinking about adding a
hook, say `package-delete-hook' that will be called with a `pkg-desc' of
the package being deleted. `package-vc' could register it's own handler
and delete such an entry.
And last but not least:
8. I have noticed that `package-reinstall' allows to reinstall a VC
package. But that will certainly won't do the right thing - it will
delete the package, but the subsequent installation will either happen
from an ELPA or will fail if no ELPA exists. I am thinking about of two
options:
a. Remove VC packages from completion offers, and block the function,
asking user to use `package-vc-rebuild'.
b. Forward the call to `package-vc-rebuild' for VC packages. Perhaps
after asking user if they want to do so. The question could be
suppress-able with a new variable
(e.g. `package-reinstall-vc-package-forward' with values `always',
`ask', `never'). And the `package-vc-rebuild' could be also set as a
variable (e.g., `package-reinstall-vc-package-function').
> [...]
Cheers,
PK
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Fri, 17 Oct 2025 15:00:07 +0000
Resent-Message-ID: <handler.79188.B79188.176071316411902 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176071316411902
(code B ref 79188); Fri, 17 Oct 2025 15:00:07 +0000
Received: (at 79188) by debbugs.gnu.org; 17 Oct 2025 14:59:24 +0000
Received: from localhost ([127.0.0.1]:52294 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1v9lvO-00035l-8c
for submit <at> debbugs.gnu.org; Fri, 17 Oct 2025 10:59:24 -0400
Received: from mail-wm1-x32f.google.com ([2a00:1450:4864:20::32f]:53335)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1v9lv0-00032Z-Tm
for 79188 <at> debbugs.gnu.org; Fri, 17 Oct 2025 10:59:04 -0400
Received: by mail-wm1-x32f.google.com with SMTP id
5b1f17b1804b1-4712c6d9495so1131445e9.2
for <79188 <at> debbugs.gnu.org>; Fri, 17 Oct 2025 07:58:58 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1760713131; x=1761317931; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=yA+ZwBxFoLcOsTHsg4cFj2vJXgWr2UZa32FW9CEO1o8=;
b=IFoobzXs2pzejKFSrhIdtK5y63y8YXuJG3rprsf1S7X9VplQ2C4v5EmQ4z2JXV2bcZ
b5q275vpWynfZspwhnbX0Sos478Pj1/XRIvDrGy80x5eEguV6xdG1sb4UhtMIfaEtVs9
hM8iVyixIYdzfLj9oULimlHMrL6LsABqLXfIpxiiX6zmbD6hC96OE7LglW8wD2xpTOCE
PRrRl2qxK7RIeTaVEQ4KOLm81PAWz9AC5nURanZvbBaWyX3i0Kl3XE7CDekasLyHTcld
dnWkUBSmqN6SDn60il1P9GdKhRLXQe2ujLSSHZW87ftsXrbd0APcO3ngJo99Rq5eHysN
+NCQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1760713131; x=1761317931;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to;
bh=yA+ZwBxFoLcOsTHsg4cFj2vJXgWr2UZa32FW9CEO1o8=;
b=Jwo5w5Zj2XX/P5GDmNTmQFEpyKw41wBYsRWPVfCb7W6MH4Lhi2kZzM1RmO9bDlnlIu
9dqngOqGGnHwpccIbw2OS/0Gn+oWW+Grpmg+Sz8s9/OC2uRT+BfTu8XI0BhU9R2+OMzY
pX/gujy8L3GhYE4uSDsRO4FCtMk4ELLNceIJNK30JF+2VTqAeEJVgpAB81HdgoKzw7MZ
SclxhFTRazD9nYuUwjMEeAyVkW7Vip9KJhwNHBJ600VJgReYPKZdrhlZUkDDpD6xoDvq
ojdZoWtxxy8F+ZiwJvzHiwxJuQeBCpyqeJ7qp54o2b6gjqLBD5zye+efgCoPywqd4D5o
yoMw==
X-Gm-Message-State: AOJu0Yx4ndi7zhbUsbXMmjCEKs7Fx30OoE1kR38X3aeeyxfUfzEHAhsF
KhdMGwIS388wFleduTzXqBHNa1KuDSponlc3a7q5jAK7czdzBRvi1qUvmrfxGg==
X-Gm-Gg: ASbGnctSl6Z7vbBhXtrAN0BhKTBh8G0pVBnn8MWLFidsVyZUh6XlQ5rpaxjmvR8AA/w
pilfdFXn0TTKqMfanT3pvb6wthlu2/WgUouCKlmMXqIcNoRhFsLdX21zSvJpfVQv0b5l+ZUq4V9
7B15GVSLv3+AlEcBrvHPhna6jsGuyalzMegMrUBBcWVVYp8Cwc4YAMKuQzZbEJtn1xV+JrSDYMG
oR6SvDGoLZ3dM/op01oGcki3G8nCWl7ZbhHK94T9IBvGeEoEUkZIJea5/1WUWDx4J9dYLXwVove
cwaslbay+WC6f+kofySMYCzPoMKZbNY83VLl7taJjkfVDKpgmtlXLwNA9x1bvGavHShXbaQV8sS
dAKYcPDni4GJapk1UpaOXUDT9HtVmtFzQo/6sjtNObJHa8odUNglaDZ1bK8vhYPfqE+Y4Gqvk8y
G/eDY6E+HKRAvNkLSvuGWb4AOl9fWuBZbZjDPqV8Av
X-Google-Smtp-Source: AGHT+IFq80FIKWZIEZcF1eDexX5b8lNwY6SDLz2wtk9dVZF7q9+f2S7ZFGHHWEvsh12Q7lW2XCOxHQ==
X-Received: by 2002:a05:600c:190b:b0:46e:3b1a:20d7 with SMTP id
5b1f17b1804b1-47117903f8bmr35312615e9.19.1760713130788;
Fri, 17 Oct 2025 07:58:50 -0700 (PDT)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:a006:e068:7e70:956d])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-4711435b06fsm111688295e9.0.2025.10.17.07.58.49
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Fri, 17 Oct 2025 07:58:49 -0700 (PDT)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <87v7kl2mkx.fsf@HIDDEN> (Philip Kaludercic's message of "Sat,
11 Oct 2025 20:46:43 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN>
Date: Fri, 17 Oct 2025 15:58:48 +0100
Message-ID: <m2h5vxwp5j.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Philip Kaludercic <philipk@HIDDEN> writes:
> [...]
> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>
>> Philip Kaludercic <philipk@HIDDEN> writes:
>>
>> [...]
>> ;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -=
*-
>>
>> ;;; Code:
>>
>> (require 'package-vc)
>> (require 'package)
>
> The latter shouldn't be necessary, as package-vc depends on package?
>
>> (require 'vc-git)
>> (require 'cl-lib)
>> (require 'ert)
>>
>> (defvar package-vc-tests-dir
>> (make-temp-file "package-vc-tests-" t (format-time-string "-%Y%m%d.%H%=
M%S")))
>>
>> (setq package-user-dir (expand-file-name "elpa" package-vc-tests-dir))
>>
>> (defvar package-vc-tests-packages
>> `(;; checkout and install with `package-vc-install' (on ELPA)
>> (diminish . ,(expand-file-name "diminish" package-user-dir))
>> ;; checkout and install with `package-vc-install' (not on ELPA)
>> (ultra-scroll . ,(expand-file-name "ultra-scroll" package-user-dir))
>> ;; checkout with `package-vc-checktout' and install with
>> ;; `package-vc-install-from-checkout'
>> (gcmh . ,(expand-file-name "gcmh" package-vc-tests-dir))
>> ;; checkout with git and install with `package-vc-install-from-check=
out'
>> (basic-stats . ,(expand-file-name "basic-stats.el" package-vc-tests-=
dir))
>> ;; TODO: a package with source files in lisp/ directory (both method=
s of
>> ;; installation)
>>
>> ;; TODO: a package with source files in a non-standard :lisp-dir (bo=
th
>> ;; methods of installation)
>> ))
>
> Part of me is uncomfortable with the idea of having our tests depend on
> the package structure of packages that are not under our control. Would
> it be possible to restrict the tests to packages that are on GNU ELPA
> and are versioned inside of elpa.git (i.e. have ":url nil")?
>
> Alternatively, we could consider git-bundle(1) files as test data to
> emacs.git.
> [...]
So I went for the git-bundle(1) approach, and I think this is the way to
go. Mainly because the bundle files can be easily developed as
required, as well as they can be trivially kept in sync with the test
code as well as the code under test. This is just a single commit after
all. Not withstanding is the fact that it eliminates a need to fetch
anything from ELPAs over network speeding the execution time by a factor
of 10 (from 12-17sec to 1-2sec on my laptop).
Attached please find the test file altogether with required resources. I
have tested it on a code with patches that you have sent on Fri, 19 Sep
2025 [1] and subsequent two that I have sent on Fri, 26 Sep 2025 [2] and
Thu, 16 Oct 2025 [3]. Please let me know what you think.
--=-=-=
Content-Type: text/x-patch; charset=utf-8
Content-Disposition: attachment;
filename=0001-Add-tests-for-package-vc.patch
Content-Transfer-Encoding: quoted-printable
Content-Description: patch
From a9b4328b1314f326be8a8c8164793d918cc7a78e Mon Sep 17 00:00:00 2001
From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
Date: Tue, 2 Sep 2025 09:28:13 +0100
Subject: [PATCH] Add tests for package-vc
* test/lisp/package-vc-tests.el (package-vc-tests-dir):
Temporary directory to store `package' and test data during the
test.
(package-vc-tests-resources-dir): Directory where bundle files
(repositories with test packages): are located.
(package-vc-tests-packages): List of packages to tests, together
with their checkout locations.
(package-vc-tests-package-desc): Retrieve a `package-desc' for
tested package.
(package-vc-tests-package-main-file): Calculate expected
location of package's main file.
(package-vc-tests-load-history-position): Calculate a position
in load-history of a file. The position only accounts for
interesting files, that is only files that are in
`package-vc-tests-dir'.
(package-vc-tests-assert-delete-elc): Assert that .elc files
have been gernerated for a package and delete them.
(package-vc-tests-assert-package-alist): Assert that
`pakcage-alist' contains a `package-desc' for package, and that
the `pakcage-desc' has correct slot `version' and slot `dir'.
(package-vc-tests-reset-heads): Reset heads of checkouts of
tested packages to a HEAD^.
(package-vc-tests-packages-heads): Return a list of checkouts of
tested packages current HEAD revisions.
(package-vc-tests-000-install): Test that packages can be
installed with `package-vc-install' and
`package-vc-install-from-checkout', including
`package-vc-checkout'.
(package-vc-tests-001-main-file): Test that
`package-vc--main-file' return main file in expected locations.
(package-vc-tests-002-commit): Test that `package-vc-commit' is
returning a revision.
(package-vc-tests-003-load-history-after-install): Test that
`load-history' has entries for autoloads of tested packages.
(package-vc-tests-package-vc-upgrade-wait): Helper function to
wait for a package being upgraded. This is needed due to
asynchronous nature of `vc-pull'.
(package-vc-tests-004-upgrade-all): Test that
`package-vc-upgrade-all' indeed upgrades all packages.
(package-vc-tests-005-load-history-after-upgrade-all): Test that
`load-history' has entries for autoloads of tested packages.
(package-vc-tests-006-require): Test that packages can be
`require'd, and that `load-history' has entries for non-compiled
package main files.
(package-vc-tests-007-upgrade): Test that `package-vc-upgrade'
upgrades a package.
(package-vc-tests-008-load-history-after-upgrade): Test that
`load-history' has entries for autoloads, non-compiled main
files, and compiled main files after a package has been
upgraded.
(package-vc-tests-009-rebuild): Test that a downgraded package
can be rebuild with `package-vc-rebuild', and that appropriate
files are reloaded.
(package-vc-tests-010-prepare-patch): Test that
`package-vc-prepare-patch' calls `vc-prepare-patch' with
expected arguments.
(package-vc-tests-011-log-incoming): Test that
`package-vc-log-incoming' calls `vc-log-incoming' with expected
arguments.
---
.../test-package-1.bundle | Bin 0 -> 764 bytes
.../test-package-2.bundle | Bin 0 -> 763 bytes
.../test-package-3.bundle | Bin 0 -> 764 bytes
.../test-package-4.bundle | Bin 0 -> 767 bytes
test/lisp/package-vc-tests.el | 454 ++++++++++++++++++
5 files changed, 454 insertions(+)
create mode 100644 test/lisp/package-vc-resources/test-package-1.bundle
create mode 100644 test/lisp/package-vc-resources/test-package-2.bundle
create mode 100644 test/lisp/package-vc-resources/test-package-3.bundle
create mode 100644 test/lisp/package-vc-resources/test-package-4.bundle
create mode 100644 test/lisp/package-vc-tests.el
diff --git a/test/lisp/package-vc-resources/test-package-1.bundle b/test/li=
sp/package-vc-resources/test-package-1.bundle
new file mode 100644
index 0000000000000000000000000000000000000000..1ba31bb56c8a4e78c04ced881f6=
8aa56113e5258
GIT binary patch
literal 764
zcmV<Y0t5XcAa*h!XK8dGVs&n0Y-I{JVmM_pGcqzTH8nCgH)UoqH8?OdGcqtSG-PEn
zVKQVjW-~Z5WH&h=3Da%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J_4tSiM%s~nQ
zArye&y{B*=3Dg!*(;h-lv?=3DmbxFPD42}m=3DV*myLGRkZqV-MUwo|+aYNR5p@=3D|diD;cs
z&SLTcr8G7K2r2oPGn=3Du}*f=3DJT5sU{&I=3DUdTk6tV3QL7X*I4y$#fXwjLPE+NF`k=3DC0
zUr)UAeO-F0d^4ZFvFi&Cmvx-VmP^|SE3|hVUkND$``j|LM*j=3D!NO2ky|4Hl(VDn1C
zoeOxJD=3DA7%RWLV5Gc+-_NU^lEOind7OR}&uFf}wYFix{HGDu0aFiJH}u}m>BG2%)r
zEy>6)QV1xjO3ke-KH8L6uHao%nVwptU{jC{W;mqhCT8a7CFkebDHxiY8JHWGSelwE
zXd4(B7;phab2CdyQpq=3Dg%Pq60xI_VB5ElS2>^vQ<0(hJ=3DG%zqTF;OT<EiTb5NKDR7
zOi$G{)Jx4_D7YLrk)dQyz>^)-HM+(gZut*A>j70B5Tv~qc$|%pu};G<5QcX@#VHx;
zAe~Fa=3D8P<i6++#Q_(&`qJGGq(-oADz5}*!j=3DTHCt>CS!ML*|rmq2ZlI#+_mZhzKu*
z!j%HvAvpf9137%P-dI0s$Q27w3{PR^rQ|eBIWI|Xw~0>VJxwaau_pFc{WBj|8#!r^
zl4lwcG!OS`*K}P?9XKW%yoQ3RxQE9u&+IeBPhH+M^K&ot9WtyhW81d0=3DHLPuAq~H+
z{?Bz-&;YU%08KTiru%0xICHZsml#ggFl>GozPvX+m%T|aab$4@bvkp1Z-82Oocqgk
zfN8=3D^Mx%+dvL`z+S_1$xk_E-B0(hJ=3DG%zqTF;OT<EiTb5NKDR7Oi$G{)Jx4_xSe+B
uUF!dBQJq^~ewTZGxuI`UycYm}9TY0o&aooGjhCAnv*jBU3g$JmE;3k}Mn7->
literal 0
HcmV?d00001
diff --git a/test/lisp/package-vc-resources/test-package-2.bundle b/test/li=
sp/package-vc-resources/test-package-2.bundle
new file mode 100644
index 0000000000000000000000000000000000000000..7b21f617b79d86a7d528d8af345=
d08373dbf3302
GIT binary patch
literal 763
zcmV<X0tEddAa*h!XK8dGVs&n0Y-I{$G%_?ZF=3D96}HZWo}G+{O}WHw}BV>2{mG&f^8
zG-769HDhKpIWlG-a%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J_4tSiM%smPM
zF%UrEKBq`8Nd7kg5qlfK6HF$Pb<ylDF(PZ}-Mp8gH?VuW;%k+Ndq~zqo2AT#6qqCt
zI|nj=3D6_k*awG@0-Y=3D%l>;}kFk9d$yC&KPt8Z8kDHFID!4KtXp}dj_|5nkqlk2bJae
zdcvLW>(W!@oB8~WU0-0htZ^z^E;}bWA-q?7C8QASbIZ^g{V%X1;WQ@xlh_*;E=3D#DL
z3wWHJ%s~pmFc3h|eNHiZK_*F?OhLqz8#i8IERz~Ev`iyXm)^~LDS88UpTBrjMSv~&
zo?BvU$a@hCE=3DA|lsp+EY0*NGviM`=3DlJ&y`UeMnj6*OTvX&}9&X&2;(3ZYZ3u>wYX-
zurXjnq?TZX7SVie$+gP=3Dg4t)CEBqky2A`%p%dG-<oHH~qFf%bxC`m0Y(Je?!&Q45E
z)iu&f&0*NvYCYxBQtL$;FAq)JU|;ml>E=3D!~0A{=3DriM<zioQ;q@Ps1<}hIjvpQ!>;+
zI+u^l8Cg13sA50jBe8JoU^^B4_t>RKfI6_9AHDCRJNJDLnN!AvhBq1+?-e^hL^u=3D*
z7YcZT;P}H1<nYCMWBsThS1d#^?83}T$!VB!UXtE!6CKHWnpB8mP3$lFCw^aT<fK7L
zo@q$XJlv|grt50znPalSYbdCSdw2}<%sx{*>GH0bpL?nAkYRlu+qR`O2N%c)Y4~;Z
zf3CxV29TWqXsSsy-9L-LnX6^F#Bj8RVe`B2<-PK`>`j7+Ba2UWymO6jfLeH*`^$8I
zX~IlKqlvS!Cp$4(0{}CU1;wobc$_mdFfcPQQ7B0*F3~MWOwLYBPt`TjOU+@ZZ~3vI
tBgE5l@w!t^)9sy#&Mw%g3jkq%5xOz0k$j;XmPz=3DsA!AOGOzWlF9ebFDSR4QV
literal 0
HcmV?d00001
diff --git a/test/lisp/package-vc-resources/test-package-3.bundle b/test/li=
sp/package-vc-resources/test-package-3.bundle
new file mode 100644
index 0000000000000000000000000000000000000000..a7ca66750db656b7fcc27204983=
8d9aceafc214e
GIT binary patch
literal 764
zcmV<Y0t5XcAa*h!XK8dGVs&n0Y-I{JF*i11HZ(V5G-fa|F=3DjY1F=3Dk>nV`efpW->T9
zHaRq5FkxajIX7e=3Da%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J_4tSiM%rOeW
zFc^m6J*UVnNYXY<e-LqZ5j;Wi=3DSwY`w#10k(YtvsMQ`Bt@(xeQfVA*n@=3DXop4TTn!
zL16DuJ2twq6g2tRMKQaKu}ITcsytf<3Iq;;sq+<D8$osC&^Z&SV<X(HoTe-f`GK@t
zUr%?J`@HnXax<U5vFno?E^D6BR%+WSt5mDCTq&)T_}ny<g8v0^1W#j-KS{g+{Ax_%
zoeOxJD=3DA7%RY)<hG_y=3DiN=3D-9J1R`VeB%_q%Bx5tnq!dHrM8o7X6Y~@!GqdCruEf%k
zjQk>nfTF6@+{)skO^M|S-bIz^sYMDl1=3D(PRLwasvW{zHRey*K@p}CoXxq*SHg@J;$
zfuVr`7f>`ev!o=3DId=3Dt3bGK-2!6d(q10RS>NJ(sNlc$_mdFfcPQQ7B0*F3~MWOwLYB
zPt`TnOU+?8{QsK66E4Och3_*yDxZ7#`d4InH~?-v6EVFPc$|%pu};G<5QcX@#VHx;
zAe{^9=3D8P<i6++#Q_(&`qJGGq(-oADz5}*!j=3DTHCt>CS!ML*|rmq2ZlI#+_mZhzKu*
z!j%HvAvpf9137%P-dI0s$Q27w3{PR^rQ|eBIWI|Xw~0>VJxwaau_pFc{WBj|8#!r^
zl4lwcG`oBC&~#l*9XKW%yoQ3RxQE9u&+IeBPhH+M^K&ot9WtyhW81d0=3DHLPuAq~H+
z{?Bz-&;YU%08KTiru%0xICHZsml#ggFl>GozPvX+m%T|aab$4@dOmZKZ-82Oocqgk
zfN8=3D^Mx%+dvL`z+S_1$xk_E-B0(hJ=3DG%zqTF;OT<EiTb5NKDR7Oi$G{)=3DSM{_|*7r
u)@}ylE0g<w=3DN^#d`mrn7Obq~SKoSRnmV8868k8_begWiOH93;r{Y0W%$xO2V
literal 0
HcmV?d00001
diff --git a/test/lisp/package-vc-resources/test-package-4.bundle b/test/li=
sp/package-vc-resources/test-package-4.bundle
new file mode 100644
index 0000000000000000000000000000000000000000..bbe907981201692e12ac226886c=
00fbdfb368179
GIT binary patch
literal 767
zcmV<b0s#FZAa*h!XK8dGVs&n0Y-I{&H!(RhW@0rqH#uT4VL4+kF*Y+bH!w6cH!?9Y
zGi5PhH#RUeVKHGKa%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J_4tSiE&N~VM
zF%*U2KC4JCNS-$dh}hc*t{{(_anQ^RF(PB>-rSdi;sWdrfAMizMWk9w3uto!shABY
zoHZdKk6Hjj$sBT%6=3DX8`ibJDT7|vt{&l5NSHlhL}1gfAt@Q{MwQ7Dy(zqQj?>7hQb
z%-7e`-|4>29ag%T&Y!XCitjJ$IF>Et1{gSFjiD>X86!(AeQWrqu-y9z<cM(`68%c#
z4b3b{ADs($oGU3xO;xZow@6AdN-{CCFf=3DhXH?uG{wXiTwwMb1&1agg&QVfku49rtg
zQ@9dKOEU6{6atE>QgbVdk2WQiD|i=3DGrl%Gu*c4=3Dg84l^WiJ3Wi$@#f<3Wnxp24+CB
zO)V6(4GawoxPYR$nI$Eu<eR|dmRVF>q5v_73jj%ZJX);+c$_mdFfcPQQ7B0*F3~MW
zOwLYBPt`TiOU+?8*!umO)HOBx!tNzkCLI@insxb;EdXuT6Ck}8c$|%pu};G<5QcX@
z#VHx;Ae{?>$r)KXR;Xe>;v=3Dze>|i?;eS7RuBtRY5&Y%AO)1CXihs-JCLc<%4j1P((
zAR-(Jg$o6|L2&$G2Xgpgy|I4OkSi9V7<OUirQ|eBIWI|Xw~3DAJxwaau_pEx{S&{h
zHgeJ+CC@Y@Xzp*-UDI_n^~^EZ;58If#XUTRd1jv}o^*NF%+I~lcgV0lk8Ru1nu7~u
zgf#rR`ajoUK?BH605sL4n(m*);LO#sTw*v{!?5{X`0`%)T=3Dpix#F51(e86*;Z-82O
zocqgkfN8=3D^Mx%+dvL`z+S_1$xk_E-B0(hJ=3DG%zqTF;OT<EiTb5NKDR7Oi$G{(M!!?
x$dsHgjlm{}Pht@ti(5(G-38flk^nL^4d7>+=3DuOEN5Y#?NZ~O8I;v<$%y$7D{N^1ZB
literal 0
HcmV?d00001
diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
new file mode 100644
index 00000000000..d7385b33e2f
--- /dev/null
+++ b/test/lisp/package-vc-tests.el
@@ -0,0 +1,454 @@
+;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
+
+;; Copyright (C) 2025 Free Software Foundation, Inc.
+
+;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
+;; Keywords: package
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These tests focus on verifying post conditions for `package-vc'
+;; operations on packages. Since installing a package changes the state
+;; of running process these tests are ment to be executed in order, as
+;; denoted by digits in their name. Also in many cases the subsequent
+;; test often depends on the passing of the previous test.
+
+;; It is recommended to run this suite in a separate process, for
+;; example, in root of Emacs source directory:
+
+;; ./src/emacs -batch \
+;; -l ../test/lisp/package-vc-tests.el \
+;; -f ert-run-tests-batch-and-exit
+
+;;; Code:
+
+(require 'package-vc)
+(require 'package)
+(require 'vc-git)
+(require 'vc)
+(require 'cl-lib)
+(require 'ert)
+
+(defvar package-vc-tests-dir
+ (make-temp-file "package-vc-tests-" t (format-time-string "-%Y%m%d.%H%M%=
S")))
+
+;; Test packages sources are stored in bundle files produced by git-bundle=
(1)
+;; and are stored in directory package-vc-resources. Make sure that:
+;;
+;; - tests know path to the directory:
+(defvar package-vc-tests-resources-dir
+ (file-name-concat (file-name-directory (or load-file-name buffer-file-na=
me))
+ "package-vc-resources"))
+;; - test packages are recognised by `package' and `package-vc' internals:
+(setq package-archives nil)
+(package-initialize)
+(push (list 'test-package-1
+ (package-desc-create :name 'test-package-1
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras (list
+ `(:url . ,(format "%s/test-packa=
ge-1.bundle"
+ package-vc-tes=
ts-resources-dir))
+ '(:commit . "7b8e3322055287ef158=
0432014de3a2d5f383d79")
+ '(:revdesc . "7b8e33220552"))))
+ package-archive-contents)
+(push (list 'test-package-3
+ (package-desc-create :name 'test-package-3
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras (list
+ `(:url . ,(format "%s/test-packa=
ge-3.bundle"
+ package-vc-tes=
ts-resources-dir))
+ '(:commit . "7176b647c4f021f811f=
b7cf27f288694a0ab997d")
+ '(:revdesc . "7176b647c4f0"))))
+ package-archive-contents)
+(push (list 'test-elpa
+ (list 'test-package-1
+ :url (format "%s/test-package-1.bundle"
+ package-vc-tests-resources-dir)
+ :branch "master")
+ (list 'test-package-3
+ :url (format "%s/test-package-3.bundle"
+ package-vc-tests-resources-dir)
+ :branch "master"))
+ package-vc--archive-spec-alists)
+(push (list 'test-elpa :version 1 :default-vc 'Git)
+ package-vc--archive-data-alist)
+;; - `vc-guess-backend-url' is recognising bundles as `Git' repositories.
+(push (cons (rx-to-string `(seq ,package-vc-tests-resources-dir "/"
+ (one-or-more any) ".bundle"
+ string-end))
+ 'Git)
+ vc-clone-heuristic-alist)
+
+(setq package-user-dir (expand-file-name "elpa" package-vc-tests-dir))
+
+(defvar package-vc-tests-packages
+ `(;; checkout and install with `package-vc-install' (on ELPA)
+ (test-package-1 . ,(expand-file-name "test-package-1" package-user-dir=
))
+ ;; checkout and install with `package-vc-install' (not on ELPA)
+ (test-package-2 . ,(expand-file-name "test-package-2" package-user-dir=
))
+ ;; checkout with `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-3 . ,(expand-file-name "test-package-3" package-vc-tests=
-dir))
+ ;; checkout with git and install with `package-vc-install-from-checkou=
t'
+ (test-package-4 . ,(expand-file-name "test-package-4" package-vc-tests=
-dir))
+ ;; TODO: a package with source files in lisp/ directory (both methods =
of
+ ;; installation)
+
+ ;; TODO: a package with source files in a non-standard :lisp-dir (both
+ ;; methods of installation)
+ ))
+
+;; TODO: add test for deleting packages, with asserting
+;; `package-vc-selected-packages'
+
+;; TODO: clarify `package-vc-install-all' behaviour with regards to packag=
es
+;; installed with `package-vc' but not stored in `package-vc-selected-pack=
ages'
+;; i.e., packages from ELPAs
+
+(defun package-vc-tests-package-desc (package &optional installed)
+ "Return descriptor of PACKAGE.
+When INSTALLED is non-nil the descriptor will come from `package-alist'.
+Otherwise the descriptor will be from `package-archive-contents'. This
+is to mimic `package-vc--read-package-desc'."
+ (cadr (assoc (if (stringp package) package (symbol-name package))
+ (if installed package-alist package-archive-contents)
+ #'string=3D)))
+
+(defun package-vc-tests-package-main-file (pkg-checkout-dir)
+ "Return a main file of PKG-CHECKOUT-DIR."
+ (format "%s/%s.el" (cdr pkg-checkout-dir) (car pkg-checkout-dir)))
+
+(defun package-vc-tests-load-history-position (pkg type)
+ "Return a PKG's position in `load-history'.
+If TYPE is `:autoloads' return a position of a PKG autoloads file.
+Otherwise, if TYPE is `:main' return a position of PKG main file (not
+compiled). Otherwise, if TYPE is `:main-compiled' return a position of
+PKG compiled main file. Otherwise, if TYPE is `:marker' return a
+position of a marker PKG."
+ (let ((pkg-file (pcase type
+ (:autoloads
+ (rx-to-string
+ `(seq ,(format "%s/%s/%s-autoloads.el"
+ package-user-dir pkg pkg)
+ string-end)))
+ (:main
+ (rx-to-string
+ `(seq ,(format "%s"
+ (package-vc-tests-package-main-file
+ (assoc pkg package-vc-tests-packages=
)))
+ string-end)))
+ (:main-compiled
+ (rx-to-string
+ `(seq ,(format "%s"
+ (package-vc-tests-package-main-file
+ (assoc pkg package-vc-tests-packages=
)))
+ "c"
+ string-end)))
+ (:marker
+ (rx-to-string `(seq "/" ,(format "%s" pkg))))))
+ (interesting-entry
+ (rx-to-string `(seq string-start
+ ,(file-truename package-vc-tests-dir)))))
+ (cl-position-if
+ (lambda (file)
+ (string-match pkg-file file))
+ (cl-remove-if-not (lambda (file-name)
+ (string-match interesting-entry file-name))
+ (mapcar #'file-truename
+ (cl-remove-if-not #'stringp
+ (mapcar #'car load-histor=
y)))))))
+
+(defun package-vc-tests-assert-delete-elc ()
+ "Assert that .elc files are in expected directories and delete them.
+When ALL is non nil, check all packages under test."
+ (dolist (pkg-checkout-dir package-vc-tests-packages)
+ (let* ((dir (cdr pkg-checkout-dir))
+ (elc-files (directory-files dir nil (rx ".elc" string-end)))
+ (autoloads-rx (rx-to-string
+ `(seq ,(format "%s" (car pkg-checkout-dir))
+ "-autoloads.elc"
+ string-end))))
+ (should-not (equal (cons dir elc-files)
+ (list dir)))
+ (should-not (cl-find-if (lambda (elc)
+ (string-match autoloads-rx elc))
+ elc-files))
+ (dolist (elc-file elc-files)
+ (delete-file (expand-file-name elc-file dir))))))
+
+(defun package-vc-tests-assert-package-alist (version)
+ "Assert that entries in `package-alist' have correct VERSION and dir."
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
+ (should (equal (file-name-as-directory
+ (expand-file-name (format "%s" pkg)
+ package-user-dir))
+ (file-name-as-directory
+ (package-desc-dir pkg-desc))))
+ (should (equal (list pkg version)
+ (list pkg (package-desc-version pkg-desc)))))))
+
+(defun package-vc-tests-reset-heads ()
+ "Reset to HEAD^ checkouts `package-vc-tests-packages'."
+ (mapcar (lambda (pkg-checkout-dir)
+ (let ((default-directory (cdr pkg-checkout-dir)))
+ (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))
+ package-vc-tests-packages))
+
+(defun package-vc-tests-packages-heads ()
+ "Return HEAD revisions of `package-vc-tests-packages'."
+ (mapcar (lambda (pkg-checkout-dir)
+ (let ((default-directory (cdr pkg-checkout-dir)))
+ (cons (car pkg-checkout-dir)
+ (vc-git-working-revision nil))))
+ package-vc-tests-packages))
+
+(ert-deftest package-vc-tests-000-install ()
+ (package-refresh-contents)
+ (package-vc--archives-initialize)
+ (push (list (format "%s/install-begin" package-vc-tests-dir))
+ load-history)
+ (package-vc-install 'test-package-1)
+ (should-not (alist-get "test-package-1" package-vc-selected-packages
+ nil nil #'string=3D))
+
+ (let ((bundle (format "%s/test-package-2.bundle" package-vc-tests-resour=
ces-dir)))
+ (package-vc-install `(test-package-2
+ :url ,bundle
+ :branch "master"))
+ (should (equal bundle
+ (plist-get (alist-get "test-package-2"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-3" package-vc-tests-=
dir)))
+ (package-vc-checkout (package-vc-tests-package-desc 'test-package-3)
+ checkout-dir)
+ (package-vc-install-from-checkout checkout-dir)
+ (should (equal (format "file://%s" checkout-dir)
+ (plist-get (alist-get "test-package-3"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-4" package-vc-tests-=
dir)))
+ (shell-command
+ (format "git clone -b master %s/test-package-4.bundle %s"
+ package-vc-tests-resources-dir
+ checkout-dir))
+ (package-vc-install-from-checkout checkout-dir "test-package-4")
+ (should (equal (format "file://%s" checkout-dir)
+ (plist-get (alist-get "test-package-4"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (push (list (format "%s/install-end" package-vc-tests-dir))
+ load-history)
+
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc))
+
+(ert-deftest package-vc-tests-001-main-file ()
+ (dolist (pkg-checkout-dir package-vc-tests-packages)
+ (should (equal (package-vc--main-file
+ (package-vc-tests-package-desc (car pkg-checkout-dir) t=
))
+ (package-vc-tests-package-main-file pkg-checkout-dir)))))
+
+(ert-deftest package-vc-tests-002-commit ()
+ (dolist (pkg-checkout-dir package-vc-tests-packages)
+ (let ((pkg (car pkg-checkout-dir))
+ (commit (package-vc-commit
+ (package-vc-tests-package-desc (car pkg-checkout-dir) t)=
)))
+ (should-not (equal (cons pkg commit)
+ (list pkg)))
+ (should-not (equal (list pkg "unknown")
+ (list pkg commit))))))
+
+(ert-deftest package-vc-tests-003-load-history-after-install ()
+ (let ((install-begin (should (package-vc-tests-load-history-position
+ 'install-begin :marker)))
+ (install-end (should (package-vc-tests-load-history-position
+ 'install-end :marker))))
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position pkg :autoload=
s))))
+ (should (< install-end autoloads-pos install-begin)))
+ (should-not (package-vc-tests-load-history-position pkg :main))
+ (should-not (package-vc-tests-load-history-position pkg :main-compil=
ed)))))
+
+(defmacro package-vc-tests-package-vc-upgrade-wait (seconds count &rest bo=
dy)
+ "Wait up to SECONDS for COUNT packages upgrading BODY.
+Return nil on timeout or non nil otherwise."
+ (declare (indent 2))
+ `(letrec ((packages-count ,count)
+ (post-vc-command (lambda (command _ flags)
+ ;; A crude filter for vc commands
+ (when (and (equal command "git")
+ (string-prefix-p "*vc-git" (buff=
er-name)))
+ (cl-decf packages-count)))))
+ (add-hook 'vc-post-command-functions post-vc-command 100)
+ (unwind-protect
+ (progn
+ ,@body
+ (catch 'done
+ (dotimes (i (* 10 ,seconds))
+ (sleep-for 0.1)
+ (when (eql packages-count 0)
+ (throw 'done t)))))
+ (remove-hook 'vc-post-command-functions post-vc-command))))
+
+(ert-deftest package-vc-tests-004-upgrade-all ()
+ (push (list (format "%s/upgrade-all-begin" package-vc-tests-dir))
+ load-history)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (package-vc-tests-reset-heads)
+ (should
+ (package-vc-tests-package-vc-upgrade-wait
+ 5 (length package-vc-tests-packages)
+ (package-vc-upgrade-all)))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (push (list (format "%s/upgrade-all-end" package-vc-tests-dir))
+ load-history)
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc))
+
+(ert-deftest package-vc-tests-005-load-history-after-upgrade-all ()
+ (let ((upgrade-all-begin (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-all-end (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker))))
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position pkg :autoload=
s))))
+ (should (< upgrade-all-end autoloads-pos upgrade-all-begin))
+ (should-not (package-vc-tests-load-history-position pkg :main))
+ (should-not (package-vc-tests-load-history-position pkg :main-compil=
ed))))))
+
+(ert-deftest package-vc-tests-006-require ()
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should (autoloadp (symbol-function (intern (format "%s-func" pkg)))))
+ (should (require pkg))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp (symbol-function (intern (format "%s-func" pkg)=
))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg)))))
+ (let ((upgrade-all-end (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker))))
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (let ((main-pos (should (package-vc-tests-load-history-position pkg =
:main))))
+ (should (< main-pos upgrade-all-end)))
+ (should-not (package-vc-tests-load-history-position pkg :main-compil=
ed)))))
+
+(ert-deftest package-vc-tests-007-upgrade ()
+ (push (list (format "%s/upgrade-begin" package-vc-tests-dir))
+ load-history)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (package-vc-tests-reset-heads)
+ (should
+ (package-vc-tests-package-vc-upgrade-wait
+ 5 (length package-vc-tests-packages)
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (package-vc-upgrade
+ (package-vc-tests-package-desc pkg t))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp (symbol-function (intern (format "%s-func"=
pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg)))))))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (push (list (format "%s/upgrade-end" package-vc-tests-dir))
+ load-history)
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc))
+
+(ert-deftest package-vc-tests-008-load-history-after-upgrade ()
+ (let ((upgrade-begin (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker))))
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position pkg :autoload=
s)))
+ (main-pos
+ (should (package-vc-tests-load-history-position pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position pkg :main-com=
piled))))
+ (should (< upgrade-end autoloads-pos upgrade-begin))
+ (should (< upgrade-end main-pos upgrade-begin))
+ (should (< upgrade-end main-compiled-pos upgrade-begin))))))
+
+(ert-deftest package-vc-tests-009-rebuild ()
+ (package-vc-tests-reset-heads)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp (symbol-function (intern (format "%s-func" pk=
g)))))
+ (should (fboundp (intern (format "%s-old-func" pkg))))
+ (should-not (autoloadp (symbol-function (intern (format "%s-old-func=
" pkg))))))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (package-vc-tests-assert-package-alist '(0 1))
+ (package-vc-tests-assert-delete-elc))
+
+(ert-deftest package-vc-tests-010-prepare-patch ()
+ (dolist (pkg-checkout-dir package-vc-tests-packages)
+ (cl-letf* ((call-count 0)
+ ((symbol-function #'package-maintainers)
+ (lambda (&rest _)
+ "test-maintainers"))
+ ((symbol-function #'vc-prepare-patch)
+ (lambda (addressee subject revisions)
+ (should (equal (file-name-as-directory default-directory)
+ (file-name-as-directory (cdr pkg-checkout=
-dir))))
+ (should (equal "test-maintainers" addressee))
+ (should (equal "test-subject" subject))
+ (should (equal "test-revisions" revisions))
+ (cl-incf call-count))))
+ (package-vc-prepare-patch (package-vc-tests-package-desc
+ (car pkg-checkout-dir)
+ t)
+ "test-subject"
+ "test-revisions")
+ (should (eql 1 call-count)))))
+
+(ert-deftest package-vc-tests-011-log-incoming ()
+ (dolist (pkg-checkout-dir package-vc-tests-packages)
+ (cl-letf* ((call-count 0)
+ ((symbol-function #'vc-log-incoming)
+ (lambda ()
+ (interactive)
+ (should (equal (file-name-as-directory default-directory)
+ (file-name-as-directory (cdr pkg-checkout=
-dir))))
+ (cl-incf call-count))))
+ (package-vc-log-incoming (package-vc-tests-package-desc
+ (car pkg-checkout-dir) t))
+ (should (eql 1 call-count)))))
+
+(provide 'package-vc-tests)
+
+;;; package-vc-tests.el ends here
--=20
2.51.0
--=-=-=
Content-Type: text/plain
[1] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=79188#49
[2] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=79188#55
[3] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=79188#64
Cheers,
PK
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Sun, 19 Oct 2025 19:20:01 +0000
Resent-Message-ID: <handler.79188.B79188.176090154522358 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176090154522358
(code B ref 79188); Sun, 19 Oct 2025 19:20:01 +0000
Received: (at 79188) by debbugs.gnu.org; 19 Oct 2025 19:19:05 +0000
Received: from localhost ([127.0.0.1]:38222 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vAYvn-0005oC-8B
for submit <at> debbugs.gnu.org; Sun, 19 Oct 2025 15:19:05 -0400
Received: from mout01.posteo.de ([185.67.36.65]:36175)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1vAYvj-0005nR-Rt
for 79188 <at> debbugs.gnu.org; Sun, 19 Oct 2025 15:19:01 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout01.posteo.de (Postfix) with ESMTPS id 7C3D5240027
for <79188 <at> debbugs.gnu.org>; Sun, 19 Oct 2025 21:18:52 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1760901532; bh=mFfAeGndDq+IPgDKY/BPr+5+5nC/Yeat1/j87fLjFrg=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:Content-Transfer-Encoding:From;
b=g7N2KdsU6uWdkaHzyWk0zmgXpGV15rc50PH5fwJs3WauN/KcEpxvUy+8XWlcpq1yc
8rw4UQpUTnkDZCvojG1a3x4ANvL99h81XIRdy7KcIXEVKusz47NGl1RemuptEeO1np
aoWJp4FLtJkpjiIiSOJejNU9udQFrOKvxH1/CyNXakGdAOxDGIRRa2/byUmLTCmaew
/rrFfNBsfs2o8Ct50A3eLYYWogza3AE2HaBOgeHXAnRDZCMl/2ghJRwQ5xIBvgT2+f
RGR0GBstLOx3PRbOCQSIGykf7kfOScFh9zrMyg+sWBzI/w8eWLRfvoLdHLLbxJOZgA
V6CPKdxL45stw==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4cqSyz61bQz6v00;
Sun, 19 Oct 2025 21:18:51 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2ldlax0jr.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Sun, 19 Oct 2025 19:18:52 +0000
Message-ID: <87plaiya21.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -0.7 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.7 (-)
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> I have found a bit of time and took a look on some of the issues
> highlighted below. To my understanding some of fixes are needed.
> Please see below.
>
> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>> [...]
>> Do you have any comments on the other issues I highlighted in previous
>> message? Repeating them for convenience:
>>
>> [...]
>>
>> 1. In `package-vc--unpack-1' there are calls to `package-activate-1' and
>> `package--reload-previously-loaded' (just around where compilation
>> happens). But I am not convinced these calls will result in expected
>> side effects when a package has been installed with
>> `package-vc-install-from-checkout'.
>>
>> 2. In `package-vc-unpack-1' there are calls to `package-vc--make' and
>> `package-vc--build-documentation' which, again may be not doing what is
>> expected for packages installed with `package-vc-install-from-checkout'.
>
> So as I suspected not everything was all right. With the patches up to
> this message, when a user installed a package with
> `package-install-from-checkout' and then subsequently upgraded it with
> `package-upgrade' then the pkg-desc entry for the package in
> `package-alist' become corrupted. After the installation the `dir' slot
> in `pkg-desc' has been pointing to the `pkg-dir', i.e., a directory
> under `package-user-dir' that contains "-pkg.el" and forwarding
> "-autoloads.el" files. However, after the upgrade the slot `dir' points
> to checkout directory. To my understanding this is undesirable, as for
> example a subsequent call to `package-delete' will delete the checkout
> directory leaving the `pkg-dir' with forwarding "-autoloads.el" file
> that tries load non existent "-autoloads.el".
I am not sure if I have mentioned this before, I have been thinking
about deprecating `package-install-from-checkout' because of
complications like these. I don't mean to be ungrateful for the work
you have put in until now (even if we do deprecate from-checkout your
tests are still a great addition), but in retrospect it seems that we
shouldn't have made this feature a part of package-vc.el. To replace
it, I have been thinking about taking something like site-lisp from ELPA
and reworking it into the core. What do you think of that? The
functionality would stay the same, just that instead of having to
install a specific package by using a command, you can just throw a
git-clone into a ~/.config/emacs/site-lisp/ directory. You would still
get byte-compilation, autoload scraping, but loose automatic dependency
resolution and the building of documentation. Considering the target
audience of package-vc-install-from-checkout, I don't think that this is
unreasonable.
> Please find a patch for that:
>
> From 2b3375490fba5dc00ba7305e670286fb41401cbc Mon Sep 17 00:00:00 2001
> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
> Date: Wed, 15 Oct 2025 08:00:02 +0100
> Subject: [PATCH] Fix incorrect pkg-desc after package-vc-upgrade
>
> After installing a package with
> `package-vc-install-from-checkout' and subsequently upgrading it
> with `package-vc-upgrade' the pkg-desc for the package becomes
> corrupted. After the upgrade the pkg-desc's dir (a.k.a
> `pkg-dir') points to checkout directory. This will cause the
> subsequent `package-delete' to delete the checkout directory and
> leaving incorrect forwarding autoloads file in
> `package-user-directory'.
>
> * lisp/emacs-lisp/package-vc.el (package-vc--unpack-1): Remove
> superfluous `pkg-dir' argument. After calling
> `package-activate-1', ensure that source files are reloaded when
> `lisp-dir' is not a subdirectory of `pkg-dir' and call
> `package--add-info-node' when `checkoud-dir' is different than
> `pkg-dir'.
> (package-vc--unpack, package-vc-upgrade)
> (package-vc-install-from-checkout, package-vc-rebuild): Remove
> `pkg-dir' argument from `package-vc--unpack-1' calls.
> * lisp/emacs-lisp/package.el (package--add-info-node): New
> function to install info node for package. Extracted from
> `package-activate-1'.
> (package-activate-1): Call `package--add-info-node'.
> ---
> lisp/emacs-lisp/package-vc.el | 56 ++++++++++++++++++++++-------------
> lisp/emacs-lisp/package.el | 15 ++++++----
> 2 files changed, 45 insertions(+), 26 deletions(-)
>
> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
> index d99bdb1813c..21bdf3e401f 100644
> --- a/lisp/emacs-lisp/package-vc.el
> +++ b/lisp/emacs-lisp/package-vc.el
> @@ -467,13 +467,15 @@ package-vc-install-dependencies
> (mapc #'package-install-from-archive to-install)
> missing))
>=20=20
> -(defun package-vc--unpack-1 (pkg-desc pkg-dir)
> - "Prepare PKG-DESC that is already checked-out in PKG-DIR.
> -This includes downloading missing dependencies, generating
> -autoloads, generating a package description file (used to
> -identify a package as a VC package later on), building
> -documentation and marking the package as installed."
> - (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> +(defun package-vc--unpack-1 (pkg-desc)
I just went over all the call-sites of this function, and the change
make sense regardless of what we decide w.r.t. the above, as we only
needed the distinction between the two due to -from-checkout.
> + "Prepare PKG-DESC that is already checked-out.
> +The checkout directory is determined by relevant pkg-spec or from `dir'
> +slot of PKG-DESC. This includes downloading missing dependencies,
> +generating autoloads, generating a package description file (used to
> +identify a package as a VC package later on), building documentation and
> +marking the package as installed."
> + (let* ((pkg-dir (package-desc-dir pkg-desc))
> + (pkg-spec (package-vc--desc->spec pkg-desc))
> (checkout-dir (package-vc--checkout-dir pkg-desc))
We should really write down (in a comment) what the different
directories mean, just to make it easier to read this stuff.
> (lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
> missing)
> @@ -567,12 +569,24 @@ package-vc--unpack-1
> (setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
>=20=20
> ;; Update package-alist.
> - (let ((new-desc (package-load-descriptor pkg-dir))
> - (compile-desc (package-desc-create :dir lisp-dir)))
> + (let* ((new-desc (package-load-descriptor pkg-dir))
> + (compile-desc (package-desc-create :name (package-desc-name n=
ew-desc)
Why do we need the :name here?
> + :dir lisp-dir)))
> ;; Activation has to be done before compilation, so that if we're
> ;; upgrading and macros have changed we load the new definitions
> ;; before compiling.
> (when (package-activate-1 new-desc :reload :deps)
> + ;; `package-activate-1' will reload all necessary package files
> + ;; as long as they are locate in a subdirectory of `pkg-dir'.
> + ;; If that's not the case, we want to reload all package files
> + ;; from the `lisp-dir' before compilation.
> + (unless (file-in-directory-p lisp-dir pkg-dir)
> + (package--reload-previously-loaded compile-desc))
> + ;; `package-activate-1' will add info node as long as dir file
> + ;; exists in `pkg-dir'. We need to manually add it when
> + ;; `checkout-dir' is in different location.
> + (unless (file-equal-p pkg-dir checkout-dir)
> + (package--add-info-node checkout-dir))
> ;; FIXME: Compilation should be done as a separate, optional, st=
ep.
> ;; E.g. for multi-package installs, we should first install all =
packages
> ;; and then compile them.
> @@ -580,8 +594,10 @@ package-vc--unpack-1
> (when package-native-compile
> (package--native-compile-async compile-desc))
> ;; After compilation, load again any files loaded by
> - ;; `activate-1', so that we use the byte-compiled definitions.
> - (package--reload-previously-loaded new-desc)))
> + ;; `package-activate-1', so that we use the byte-compiled
> + ;; definitions. This time we'll use `compile-desc' straight
> + ;; away.
> + (package--reload-previously-loaded compile-desc)))
>=20=20
> ;; Mark package as selected
> (let ((name (package-desc-name pkg-desc)))
> @@ -714,7 +730,7 @@ package-vc--unpack
> (when (null (package-vc--desc->spec pkg-desc name))
> (package-vc--save-selected-packages name pkg-spec))
>=20=20
> - (package-vc--unpack-1 pkg-desc pkg-dir)))
> + (package-vc--unpack-1 pkg-desc)))
>=20=20
> (defun package-vc--read-package-name (prompt &optional allow-url install=
ed)
> "Query the user for a VC package and return a name with PROMPT.
> @@ -782,7 +798,7 @@ package-vc-upgrade
> ;;
> ;; If there is a better way to do this, it should be done.
> (cl-assert (package-vc-p pkg-desc))
> - (letrec ((pkg-dir (package-vc--checkout-dir pkg-desc))
> + (letrec ((checkout-dir (package-vc--checkout-dir pkg-desc))
I would avoid renaming variables if it is not necessary, as it pollutes
the Git log.
> (vc-flags)
> (vc-filter-command-function
> (lambda (command file-or-list flags)
> @@ -790,18 +806,19 @@ package-vc-upgrade
> (list command file-or-list flags)))
> (post-upgrade
> (lambda (_command _file-or-list flags)
> - (when (and (file-equal-p pkg-dir default-directory)
> + (when (and (file-equal-p checkout-dir default-directory)
> (eq flags vc-flags))
> (unwind-protect
> (with-demoted-errors "Failed to activate: %S"
> - (package-vc--unpack-1 pkg-desc pkg-dir))
> + (package-vc--unpack-1 pkg-desc))
> (remove-hook 'vc-post-command-functions post-upgrade))=
))))
> (add-hook 'vc-post-command-functions post-upgrade)
> (with-demoted-errors "Failed to fetch: %S"
> (require 'vc-dir)
> (with-current-buffer (vc-dir-prepare-status-buffer
> - (format " *package-vc-dir: %s*" pkg-dir)
> - pkg-dir (vc-responsible-backend pkg-dir))
> + (format " *package-vc-dir: %s*" checkout-dir)
> + checkout-dir
> + (vc-responsible-backend checkout-dir))
> (vc-pull)))))
>=20=20
> (defun package-vc--archives-initialize ()
> @@ -980,8 +997,7 @@ package-vc-install-from-checkout
> (package-desc-create
> :name (intern name)
> :dir pkg-dir
> - :kind 'vc)
> - (file-name-as-directory pkg-dir))))
> + :kind 'vc))))
>=20=20
> ;;;###autoload
> (defun package-vc-rebuild (pkg-desc)
> @@ -993,7 +1009,7 @@ package-vc-rebuild
> is the responsibility of `package-vc-upgrade'. Interactively,
> prompt for the name of the package to rebuild."
> (interactive (list (package-vc--read-package-desc "Rebuild package: " =
t)))
> - (package-vc--unpack-1 pkg-desc (package-vc--checkout-dir pkg-desc)))
> + (package-vc--unpack-1 pkg-desc))
>=20=20
> ;;;###autoload
> (defun package-vc-prepare-patch (pkg-desc subject revisions)
> diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
> index ba9999c20e6..fb073579bc1 100644
> --- a/lisp/emacs-lisp/package.el
> +++ b/lisp/emacs-lisp/package.el
> @@ -903,6 +903,14 @@ package--reload-previously-loaded
> (mapc (lambda (c) (load (car c) nil t))
> (sort result (lambda (x y) (< (cdr x) (cdr y))))))))
>=20=20
> +(defun package--add-info-node (pkg-dir)
> + "Add info node located in PKG-DIR."
> + (when (file-exists-p (expand-file-name "dir" pkg-dir))
> + ;; FIXME: not the friendliest, but simple.
> + (require 'info)
> + (info-initialize)
> + (add-to-list 'Info-directory-list pkg-dir)))
LGTM!
> (defun package-activate-1 (pkg-desc &optional reload deps)
> "Activate package given by PKG-DESC, even if it was already active.
> If DEPS is non-nil, also activate its dependencies (unless they
> @@ -934,12 +942,7 @@ package-activate-1
> The following files have already been loaded: %S")))
> (with-demoted-errors "Error loading autoloads: %s"
> (load (package--autoloads-file-name pkg-desc) nil t)))
> - ;; Add info node.
> - (when (file-exists-p (expand-file-name "dir" pkg-dir))
> - ;; FIXME: not the friendliest, but simple.
> - (require 'info)
> - (info-initialize)
> - (add-to-list 'Info-directory-list pkg-dir))
> + (package--add-info-node pkg-dir)
> (push name package-activated-list)
> ;; Don't return nil.
> t)))
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Sun, 19 Oct 2025 19:48:06 +0000
Resent-Message-ID: <handler.79188.B79188.176090326431732 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176090326431732
(code B ref 79188); Sun, 19 Oct 2025 19:48:06 +0000
Received: (at 79188) by debbugs.gnu.org; 19 Oct 2025 19:47:44 +0000
Received: from localhost ([127.0.0.1]:38621 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vAZNX-0008Fh-Gw
for submit <at> debbugs.gnu.org; Sun, 19 Oct 2025 15:47:44 -0400
Received: from mout01.posteo.de ([185.67.36.65]:56035)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1vAZNU-0008F4-39
for 79188 <at> debbugs.gnu.org; Sun, 19 Oct 2025 15:47:41 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout01.posteo.de (Postfix) with ESMTPS id 63623240027
for <79188 <at> debbugs.gnu.org>; Sun, 19 Oct 2025 21:47:33 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1760903253; bh=d01GLiekqAGb1ruktHL/QDj5FrIC8xKkakI0O7IRAuc=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:Content-Transfer-Encoding:From;
b=GspLFETXdGLsWZNQdymw7dW7aE3eu8pCL8kUIYXbmxW+aMebInBe/tdhEuuBRkZ9L
TZIBM1eqvlESPosKQ2LFJOdYVcw/kvgFBEyVQ0k6bl+9HqZLJI7IGbrsJGDSrYWf1Q
QUQmMDt8wErJHbsQwB3BqVNqtVxfpk0ijWLpIDIVLzRisHMRe4hpVeYhQHuf+FmZAv
VG8R+Y7ugReGjdUA9gAXS4/szI2tufWkCt9IZNFjyvUDVUTORkEdBZCbEgnZln1hQQ
U7BBqlPoESgW+1hhZc5O7ld4heGc/lGHDFMAjYbSfYJ4fwPYb9FJPIkmDlvKSSZ0oZ
RvABOXPU7Q6/w==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4cqTc45mP7z9rxP;
Sun, 19 Oct 2025 21:47:32 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2ldlax0jr.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Sun, 19 Oct 2025 19:47:32 +0000
Message-ID: <87ikgay8q8.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -0.7 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.7 (-)
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
[...]
> Please find a patch for that:
Gnus cut of the remaining response so I sent my previous message to early!
>
>
> And upgraded test file with extra assertions to ensure `package-alist'
> and `load-history' contain correct entries:
>
> ;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
>
> ;;; Code:
>
> (require 'package-vc)
> (require 'package)
> (require 'vc-git)
> (require 'cl-lib)
> (require 'ert)
>
> (defvar package-vc-tests-dir
> (make-temp-file "package-vc-tests-" t (format-time-string "-%Y%m%d.%H%M=
%S")))
Should the global variable have a side-effect at declaration-time? I
don't think we can be sure that the file will still exist if you load
the file at one point and run the tests later (even if you re-load the
file, the "new" value won't get re-evaluated).
>
> (setq package-user-dir (expand-file-name "elpa" package-vc-tests-dir))
Please don't use setq on the top-level.
>
> (defvar package-vc-tests-packages
> `(;; checkout and install with `package-vc-install' (on ELPA)
> (diminish . ,(expand-file-name "diminish" package-user-dir))
> ;; checkout and install with `package-vc-install' (not on ELPA)
> (ultra-scroll . ,(expand-file-name "ultra-scroll" package-user-dir))
> ;; checkout with `package-vc-checktout' and install with
> ;; `package-vc-install-from-checkout'
> (gcmh . ,(expand-file-name "gcmh" package-vc-tests-dir))
> ;; checkout with git and install with `package-vc-install-from-checko=
ut'
> (basic-stats . ,(expand-file-name "basic-stats.el" package-vc-tests-d=
ir))
> ;; TODO: a package with source files in lisp/ directory (both methods=
of
> ;; installation)
>
> ;; TODO: a package with source files in a non-standard :lisp-dir (both
> ;; methods of installation)
> ))
>
> ;; TODO: add test for deleting packages, with asserting
> ;; `package-vc-selected-packages'
>
> ;; TODO: clarify `package-vc-install-all' behaviour with regards to packa=
ges
> ;; installed with `package-vc' but not stored in `package-vc-selected-pac=
kages'
> ;; i.e., packages from ELPAs
>
> (defun package-vc-tests-package-desc (package &optional installed)
> "Return descriptor of PACKAGE.
> When INSTALLED is non-nil the descriptor will come from `package-alist'.
> Otherwise the descriptor will be from `package-archive-contents'. This
> is to mimic `package-vc--read-package-desc'."
> (cadr (assoc (if (stringp package) package (symbol-name package))
> (if installed package-alist package-archive-contents)
> #'string=3D)))
>
> (defun package-vc-tests-package-main-file (pkg-checkout-dir)
> "Return a main file of PKG-CHECKOUT-DIR."
> (format "%s/%s.el" (cdr pkg-checkout-dir) (car pkg-checkout-dir)))
>
> (defun package-vc-tests-load-history-position (pkg type)
> "Return a PKG's position in `load-history'.
> If TYPE is `:autoloads' return a position of a PKG autoloads file.
> Otherwise, if TYPE is `:main' return a position of PKG main file (not
> compiled). Otherwise, if TYPE is `:main-compiled' return a position of
> PKG compiled main file. Otherwise, if TYPE is `:marker' return a
> position of a marker PKG."
> (let ((pkg-file (pcase type
> (:autoloads
> (rx-to-string
BTW, you don't need rx-to-string here, you can also write
(rx (literal (format ...)) string-end)
which will also avoid quoting issues.
> `(seq ,(format "%s/%s/%s-autoloads.el"
> package-user-dir pkg pkg)
> string-end)))
> (:main
> (rx-to-string
> `(seq ,(format "%s"
> (package-vc-tests-package-main-file
> (assoc pkg package-vc-tests-package=
s)))
> string-end)))
> (:main-compiled
> (rx-to-string
> `(seq ,(format "%s"
> (package-vc-tests-package-main-file
> (assoc pkg package-vc-tests-package=
s)))
> "c"
> string-end)))
> (:marker
> (rx-to-string `(seq "/" ,(format "%s" pkg))))))
> (interesting-entry
> (rx-to-string `(seq string-start
> ,(file-truename package-vc-tests-dir)))))
> (cl-position-if
> (lambda (file)
> (string-match pkg-file file))
> (cl-remove-if-not (lambda (file-name)
> (string-match interesting-entry file-name))
> (mapcar #'file-truename
> (cl-remove-if-not #'stringp
> (mapcar #'car load-histo=
ry)))))))
>
> (defun package-vc-tests-assert-delete-elc ()
> "Assert that .elc files are in expected directories and delete them.
> When ALL is non nil, check all packages under test."
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (let* ((dir (cdr pkg-checkout-dir))
> (elc-files (directory-files dir nil (rx ".elc" string-end)))
> (autoloads-rx (rx-to-string
> `(seq ,(format "%s" (car pkg-checkout-dir))
> "-autoloads.elc"
> string-end))))
> (should-not (equal (cons dir elc-files)
> (list dir)))
> (should-not (cl-find-if (lambda (elc)
> (string-match autoloads-rx elc))
> elc-files))
> (dolist (elc-file elc-files)
> (delete-file (expand-file-name elc-file dir))))))
>
> (defun package-vc-tests-assert-packge-alist ()
> "Assert that entries in `package-alist' are correct."
> (dolist (pkg (mapcar #'car package-vc-tests-packages))
> (let ((pkg-spec (should (cadr (assq pkg package-alist)))))
> (should (equal (file-name-as-directory
> (package-desc-dir pkg-spec))
> (file-name-as-directory
> (expand-file-name (format "%s" pkg)
> package-user-dir)))))))
>
> (defun package-vc-tests-packages-heads (reset)
> "Return HEAD revisions of `package-vc-tests-packages'.
> When RESET is non-nil also reset to a previous version."
> (mapcar (lambda (pkg-checkout-dir)
> (let ((default-directory (cdr pkg-checkout-dir)))
> (prog1
> (cons (car pkg-checkout-dir)
> (vc-git-working-revision nil))
> (when reset
> (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")
> ;; FIXME: compilation of tests loads basic-stats.el
> (when (file-exists-p "test")
> (shell-command (format "rm -rf test")))))))
> package-vc-tests-packages))
>
> (ert-deftest package-vc-tests-000-install ()
> (package-refresh-contents)
> (package-vc--archives-initialize)
> (push (list (format "%s/install-begin" package-vc-tests-dir))
> load-history)
> (package-vc-install 'diminish)
> (should-not (alist-get "diminish" package-vc-selected-packages
> nil nil #'string=3D))
>
> (package-vc-install '(ultra-scroll
> :url "https://github.com/jdtsmith/ultra-scroll.gi=
t"))
> (should (equal "https://github.com/jdtsmith/ultra-scroll.git"
> (plist-get (alist-get "ultra-scroll"
> package-vc-selected-packages
> nil nil #'string=3D)
> :url)))
I feel like we should test more than just the :url.
>
> (let ((checkout-dir (expand-file-name "gcmh" package-vc-tests-dir)))
> (package-vc-checkout (package-vc-tests-package-desc 'gcmh)
> checkout-dir)
> (package-vc-install-from-checkout checkout-dir)
> (should (equal (format "file://%s" checkout-dir)
> (plist-get (alist-get "gcmh"
> package-vc-selected-packages
> nil nil #'string=3D)
> :url))))
These should also be separate tests, because they are not all testing
the same thing and it would be better if ERT can give you a better idea
to what went wrong if the tests are smaller.
> (let ((checkout-dir (expand-file-name "basic-stats.el" package-vc-tests=
-dir)))
> (shell-command
> (format "git clone https://github.com/pkryger/basic-stats.el.git %s"
> checkout-dir))
> ;; FIXME: compilation of tests loads basic-stats.el
> (shell-command (format "rm -rf %s/test" checkout-dir))
> (package-vc-install-from-checkout checkout-dir "basic-stats")
> (should (equal (format "file://%s" checkout-dir)
> (plist-get (alist-get "basic-stats"
> package-vc-selected-packages
> nil nil #'string=3D)
> :url))))
> (push (list (format "%s/install-end" package-vc-tests-dir))
> load-history)
>
> (dolist (package package-alist)
> (dolist (pkg-desc (cdr package))
> (when (package-vc-p pkg-desc)
> (message "*** installed %s" pkg-desc))))
Why do we need this?
> (package-vc-tests-assert-packge-alist)
> (package-vc-tests-assert-delete-elc))
>
> (ert-deftest package-vc-tests-001-main-file ()
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (should (equal (package-vc--main-file
> (package-vc-tests-package-desc (car pkg-checkout-dir) =
t))
> (package-vc-tests-package-main-file pkg-checkout-dir)))=
))
>
> (ert-deftest package-vc-tests-002-commit ()
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (let ((pkg (car pkg-checkout-dir))
> (commit (package-vc-commit
> (package-vc-tests-package-desc (car pkg-checkout-dir) t=
))))
> (should-not (equal (cons pkg commit)
> (list pkg)))
So (null commit)?
> (should-not (equal (list pkg "unknown")
> (list pkg commit))))))
>
> (ert-deftest package-vc-tests-003-load-history-after-install ()
> (let ((install-begin (should (package-vc-tests-load-history-position
> 'install-begin :marker)))
> (install-end (should (package-vc-tests-load-history-position
> 'install-end :marker))))
> (dolist (pkg (mapcar #'car package-vc-tests-packages))
> (let ((autoloads-pos
> (should (package-vc-tests-load-history-position pkg :autoloa=
ds))))
> (should (< install-end autoloads-pos install-begin)))
> (should-not (package-vc-tests-load-history-position pkg :main))
> (should-not (package-vc-tests-load-history-position pkg :main-compi=
led)))))
>
> (ert-deftest package-vc-tests-004-require ()
> (dolist (pkg (mapcar #'car package-vc-tests-packages))
> (should (require pkg)))
Shouldn't this be called with NOERROR.
> (let ((install-end (should (package-vc-tests-load-history-position
> 'install-end :marker))))
> (dolist (pkg (mapcar #'car package-vc-tests-packages))
> (let ((main-pos (should (package-vc-tests-load-history-position pkg=
:main))))
> (should (< main-pos install-end)))
> (should-not (package-vc-tests-load-history-position pkg :main-compi=
led)))))
Why are we interested in the position in load-list?
> (defmacro package-vc-tests-package-vc-upgrade-wait (seconds count &rest b=
ody)
> "Wait up to SECONDS for COUNT packages upgrading BODY.
> Return nil on timeout or non nil otherwise."
> (declare (indent 2))
> `(letrec ((packages-count ,count)
> (post-vc-command (lambda (command _ flags)
> ;; A crude filter for vc commands
> (when (and (equal command "git")
> (string-prefix-p "*vc-git" (buf=
fer-name)))
> (cl-decf packages-count)))))
> (add-hook 'vc-post-command-functions post-vc-command 100)
> (unwind-protect
> (progn
> ,@body
> (catch 'done
Do you want with-timeout?
> (dotimes (i (* 10 ,seconds))
> (sleep-for 0.1)
> (when (eql packages-count 0)
> (throw 'done t)))))
> (remove-hook 'vc-post-command-functions post-vc-command))))
>
> (ert-deftest package-vc-tests-005-upgrade-all ()
> (push (list (format "%s/upgrade-all-begin" package-vc-tests-dir))
> load-history)
> (let ((heads (package-vc-tests-packages-heads t)))
> (should
> (package-vc-tests-package-vc-upgrade-wait
> 5 (length package-vc-tests-packages)
> (package-vc-upgrade-all)))
> (should (equal heads
> (package-vc-tests-packages-heads nil))))
> (push (list (format "%s/upgrade-all-end" package-vc-tests-dir))
> load-history)
> (package-vc-tests-assert-packge-alist)
> (package-vc-tests-assert-delete-elc))
>
> (ert-deftest package-vc-tests-006-load-history-after-upgrade-all ()
> (let ((upgrade-all-begin (should (package-vc-tests-load-history-position
> 'upgrade-all-begin :marker)))
> (upgrade-all-end (should (package-vc-tests-load-history-position
> 'upgrade-all-end :marker))))
> (dolist (pkg (mapcar #'car package-vc-tests-packages))
> (let ((autoloads-pos (should (package-vc-tests-load-history-positio=
n pkg :autoloads)))
> (main-pos (should (package-vc-tests-load-history-position pkg=
:main)))
> (main-compiled-pos (should (package-vc-tests-load-history-pos=
ition pkg :main-compiled))))
> (should (< upgrade-all-end autoloads-pos upgrade-all-begin))
> (should (< upgrade-all-end main-pos upgrade-all-begin))
> (should (< upgrade-all-end main-compiled-pos upgrade-all-begin)))=
)))
>
> (ert-deftest package-vc-tests-007-upgrade ()
> (push (list (format "%s/upgrade-begin" package-vc-tests-dir))
> load-history)
> (let ((heads (package-vc-tests-packages-heads t)))
> (should
> (package-vc-tests-package-vc-upgrade-wait
> 5 (length package-vc-tests-packages)
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (package-vc-upgrade
> (package-vc-tests-package-desc (car pkg-checkout-dir) t)))))
> (should (equal heads
> (package-vc-tests-packages-heads nil))))
> (push (list (format "%s/upgrade-end" package-vc-tests-dir))
> load-history)
> (package-vc-tests-assert-packge-alist)
> (package-vc-tests-assert-delete-elc))
>
> (ert-deftest package-vc-tests-008-load-history-after-upgrade ()
> (let ((upgrade-begin (should (package-vc-tests-load-history-position
> 'upgrade-begin :marker)))
> (upgrade-end (should (package-vc-tests-load-history-position
> 'upgrade-end :marker))))
> (dolist (pkg (mapcar #'car package-vc-tests-packages))
> (let ((autoloads-pos
> (should (package-vc-tests-load-history-position pkg :autoloa=
ds)))
> (main-pos
> (should (package-vc-tests-load-history-position pkg :main)))
> (main-compiled-pos
> (should (package-vc-tests-load-history-position pkg :main-co=
mpiled))))
> (should (< upgrade-end autoloads-pos upgrade-begin))
> (should (< upgrade-end main-pos upgrade-begin))
> (should (< upgrade-end main-compiled-pos upgrade-begin))))))
>
> (ert-deftest package-vc-tests-009-rebuild ()
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (package-vc-rebuild
> (package-vc-tests-package-desc (car pkg-checkout-dir) t)))
> (package-vc-tests-assert-packge-alist)
> (package-vc-tests-assert-delete-elc))
>
> (ert-deftest package-vc-tests-010-prepare-patch ()
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (cl-letf* ((call-count 0)
> ((symbol-function #'package-maintainers)
> (lambda (&rest _)
> "test-maintainers"))
> ((symbol-function #'vc-prepare-patch)
> (lambda (addressee subject revisions)
> (should (equal (file-name-as-directory default-director=
y)
> (file-name-as-directory (cdr pkg-checkou=
t-dir))))
> (should (equal "test-maintainers" addressee))
> (should (equal "test-subject" subject))
> (should (equal "test-revisions" revisions))
> (cl-incf call-count))))
> (package-vc-prepare-patch (package-vc-tests-package-desc
> (car pkg-checkout-dir)
> t)
> "test-subject"
> "test-revisions")
> (should (eql 1 call-count)))))
I don't think we need to test the specific internal behaviour. IMO the
tests should ensure that user-facing behaviour doesn't regress.
> (ert-deftest package-vc-tests-011-log-incoming ()
> (dolist (pkg-checkout-dir package-vc-tests-packages)
> (cl-letf* ((call-count 0)
> ((symbol-function #'vc-log-incoming)
> (lambda ()
> (interactive)
> (should (equal (file-name-as-directory default-director=
y)
> (file-name-as-directory (cdr pkg-checkou=
t-dir))))
> (cl-incf call-count))))
> (package-vc-log-incoming (package-vc-tests-package-desc
> (car pkg-checkout-dir) t))
> (should (eql 1 call-count)))))
>
> (provide 'package-vc-tests)
>
> ;;; package-vc-tests.el ends here
>
>
>
>> 3. I am not sure what will happen when someone checkouts a repository to
>> `package-user-dir' making it so the 'package-vc-install-from-checkout'
>> calculates `pkg-dir' that is the same as a checkout dir. I know it's
>> not the smartest thing to do, but perhaps detect it and raise an error?
>>
>> 4. I struggle to understand how the value of `:lisp-dir' calculated in
>> `package-vc-unpack' (lines 701-711) is used in further code. Will need
>> to find a package that specifies that and try to debug it further.
>>
>> 5. Perhaps the `package-vc-install-from-checkout' could be extended in
>> such a way to allow user to specify their `pkg-spec'. That should
>> include the checkout directory, as well as other values from spec
>> (lisp-dir, make, doc)?
>
> I have not looked at these yet. Perhaps will find some time in next
> couple of weeks. With my current understanding these are unlikely to
> make things any worse than what is here today. I have a one more
> question:
>
> 6. Perhaps `package-vc-rebuild' should delete all *.elc files, such that
> subsequent `package--reload-previously-loaded' calls will certainly pick
> up what is in the code, such that downgrades are supported (i.e., the
> *.el file will become older than *.elc).
>
>> 5. I am not sure how `package-delete' will work with these changes. I
>> guess it should at least remove the pkg-dir as well as entry from
>> `package-vc-selected-packages'.
>
> I guess this will be question 7 now ;). I am thinking about adding a
> hook, say `package-delete-hook' that will be called with a `pkg-desc' of
> the package being deleted. `package-vc' could register it's own handler
> and delete such an entry.
>
> And last but not least:
>
> 8. I have noticed that `package-reinstall' allows to reinstall a VC
> package. But that will certainly won't do the right thing - it will
> delete the package, but the subsequent installation will either happen
> from an ELPA or will fail if no ELPA exists. I am thinking about of two
> options:
>
> a. Remove VC packages from completion offers, and block the function,
> asking user to use `package-vc-rebuild'.
>
> b. Forward the call to `package-vc-rebuild' for VC packages. Perhaps
> after asking user if they want to do so. The question could be
> suppress-able with a new variable
> (e.g. `package-reinstall-vc-package-forward' with values `always',
> `ask', `never'). And the `package-vc-rebuild' could be also set as a
> variable (e.g., `package-reinstall-vc-package-function').
My preference would be towards a., just like how I think that adding
VC packages to package-upgrade was a mistake in retrospect.
>> [...]
>
> Cheers,
> PK
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Sun, 19 Oct 2025 19:50:02 +0000
Resent-Message-ID: <handler.79188.B79188.176090336032462 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176090336032462
(code B ref 79188); Sun, 19 Oct 2025 19:50:02 +0000
Received: (at 79188) by debbugs.gnu.org; 19 Oct 2025 19:49:20 +0000
Received: from localhost ([127.0.0.1]:38652 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vAZP5-0008RS-19
for submit <at> debbugs.gnu.org; Sun, 19 Oct 2025 15:49:20 -0400
Received: from mout01.posteo.de ([185.67.36.65]:42031)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1vAZOy-0008PF-2t
for 79188 <at> debbugs.gnu.org; Sun, 19 Oct 2025 15:49:17 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout01.posteo.de (Postfix) with ESMTPS id E1EED240027
for <79188 <at> debbugs.gnu.org>; Sun, 19 Oct 2025 21:49:05 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1760903345; bh=ZuQ/yoDh7ybpj8hVvmf9+GKLx0LNYKqxiT1fdblEqU0=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:Content-Transfer-Encoding:From;
b=eD/8IQyYbYsEF1OvfTR4DefstcOGbqLm9mcz5S8RDin5yiQ9tkdGTDAL8Q99DnROg
wrxuYzhdT5ZBEugUt5eanzVfk648eB0vtszMQZ1CYUGxE0LOovaCxHIzpLXTgNemxv
0zrNCeWJkyvXUloqfamZjcRFC5fAmbRgo98kyZZRPIRM3F1pMrZLpjMcXaVljEsN4C
BHAkeMcQcHc0RN/Yj68ubBJsLPvET1/C310GpRKjE8KuUnBev9/+QjOoVz2nfRhz+a
vUz/rLZP8N0YrGhYLInZnAeckc0IQHEb3dvUVmq4ZLrWpOfAo/kGQLQOnO/t2SJzao
fOyZYj3zAZvtg==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4cqTds3qM2z9rxG;
Sun, 19 Oct 2025 21:49:05 +0200 (CEST)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2h5vxwp5j.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m2h5vxwp5j.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Sun, 19 Oct 2025 19:49:05 +0000
Message-ID: <87ecqyy8nj.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -0.7 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.7 (-)
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> Philip Kaludercic <philipk@HIDDEN> writes:
>
>> [...]
>> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>>
>>> Philip Kaludercic <philipk@HIDDEN> writes:
>>>
>>> [...]
>>> ;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t =
-*-
>>>
>>> ;;; Code:
>>>
>>> (require 'package-vc)
>>> (require 'package)
>>
>> The latter shouldn't be necessary, as package-vc depends on package?
>>
>>> (require 'vc-git)
>>> (require 'cl-lib)
>>> (require 'ert)
>>>
>>> (defvar package-vc-tests-dir
>>> (make-temp-file "package-vc-tests-" t (format-time-string "-%Y%m%d.%H=
%M%S")))
>>>
>>> (setq package-user-dir (expand-file-name "elpa" package-vc-tests-dir))
>>>
>>> (defvar package-vc-tests-packages
>>> `(;; checkout and install with `package-vc-install' (on ELPA)
>>> (diminish . ,(expand-file-name "diminish" package-user-dir))
>>> ;; checkout and install with `package-vc-install' (not on ELPA)
>>> (ultra-scroll . ,(expand-file-name "ultra-scroll" package-user-dir))
>>> ;; checkout with `package-vc-checktout' and install with
>>> ;; `package-vc-install-from-checkout'
>>> (gcmh . ,(expand-file-name "gcmh" package-vc-tests-dir))
>>> ;; checkout with git and install with `package-vc-install-from-chec=
kout'
>>> (basic-stats . ,(expand-file-name "basic-stats.el" package-vc-tests=
-dir))
>>> ;; TODO: a package with source files in lisp/ directory (both metho=
ds of
>>> ;; installation)
>>>
>>> ;; TODO: a package with source files in a non-standard :lisp-dir (b=
oth
>>> ;; methods of installation)
>>> ))
>>
>> Part of me is uncomfortable with the idea of having our tests depend on
>> the package structure of packages that are not under our control. Would
>> it be possible to restrict the tests to packages that are on GNU ELPA
>> and are versioned inside of elpa.git (i.e. have ":url nil")?
>>
>> Alternatively, we could consider git-bundle(1) files as test data to
>> emacs.git.
>> [...]
>
> So I went for the git-bundle(1) approach, and I think this is the way to
> go. Mainly because the bundle files can be easily developed as
> required, as well as they can be trivially kept in sync with the test
> code as well as the code under test. This is just a single commit after
> all. Not withstanding is the fact that it eliminates a need to fetch
> anything from ELPAs over network speeding the execution time by a factor
> of 10 (from 12-17sec to 1-2sec on my laptop).
>
> Attached please find the test file altogether with required resources. I
> have tested it on a code with patches that you have sent on Fri, 19 Sep
> 2025 [1] and subsequent two that I have sent on Fri, 26 Sep 2025 [2] and
> Thu, 16 Oct 2025 [3]. Please let me know what you think.
The results sound very good.
> From a9b4328b1314f326be8a8c8164793d918cc7a78e Mon Sep 17 00:00:00 2001
> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
> Date: Tue, 2 Sep 2025 09:28:13 +0100
> Subject: [PATCH] Add tests for package-vc
>
> * test/lisp/package-vc-tests.el (package-vc-tests-dir):
> Temporary directory to store `package' and test data during the
> test.
> (package-vc-tests-resources-dir): Directory where bundle files
> (repositories with test packages): are located.
> (package-vc-tests-packages): List of packages to tests, together
> with their checkout locations.
> (package-vc-tests-package-desc): Retrieve a `package-desc' for
> tested package.
> (package-vc-tests-package-main-file): Calculate expected
> location of package's main file.
> (package-vc-tests-load-history-position): Calculate a position
> in load-history of a file. The position only accounts for
> interesting files, that is only files that are in
> `package-vc-tests-dir'.
> (package-vc-tests-assert-delete-elc): Assert that .elc files
> have been gernerated for a package and delete them.
> (package-vc-tests-assert-package-alist): Assert that
> `pakcage-alist' contains a `package-desc' for package, and that
> the `pakcage-desc' has correct slot `version' and slot `dir'.
> (package-vc-tests-reset-heads): Reset heads of checkouts of
> tested packages to a HEAD^.
> (package-vc-tests-packages-heads): Return a list of checkouts of
> tested packages current HEAD revisions.
> (package-vc-tests-000-install): Test that packages can be
> installed with `package-vc-install' and
> `package-vc-install-from-checkout', including
> `package-vc-checkout'.
> (package-vc-tests-001-main-file): Test that
> `package-vc--main-file' return main file in expected locations.
> (package-vc-tests-002-commit): Test that `package-vc-commit' is
> returning a revision.
> (package-vc-tests-003-load-history-after-install): Test that
> `load-history' has entries for autoloads of tested packages.
> (package-vc-tests-package-vc-upgrade-wait): Helper function to
> wait for a package being upgraded. This is needed due to
> asynchronous nature of `vc-pull'.
> (package-vc-tests-004-upgrade-all): Test that
> `package-vc-upgrade-all' indeed upgrades all packages.
> (package-vc-tests-005-load-history-after-upgrade-all): Test that
> `load-history' has entries for autoloads of tested packages.
> (package-vc-tests-006-require): Test that packages can be
> `require'd, and that `load-history' has entries for non-compiled
> package main files.
> (package-vc-tests-007-upgrade): Test that `package-vc-upgrade'
> upgrades a package.
> (package-vc-tests-008-load-history-after-upgrade): Test that
> `load-history' has entries for autoloads, non-compiled main
> files, and compiled main files after a package has been
> upgraded.
> (package-vc-tests-009-rebuild): Test that a downgraded package
> can be rebuild with `package-vc-rebuild', and that appropriate
> files are reloaded.
> (package-vc-tests-010-prepare-patch): Test that
> `package-vc-prepare-patch' calls `vc-prepare-patch' with
> expected arguments.
> (package-vc-tests-011-log-incoming): Test that
> `package-vc-log-incoming' calls `vc-log-incoming' with expected
> arguments.
> ---
> .../test-package-1.bundle | Bin 0 -> 764 bytes
> .../test-package-2.bundle | Bin 0 -> 763 bytes
> .../test-package-3.bundle | Bin 0 -> 764 bytes
> .../test-package-4.bundle | Bin 0 -> 767 bytes
I was afraid that the files would be a lot larger, but this seems
acceptable. Did you do a shallow clone and run git-gc(1)? Either way,
I would prefer to ask a maintainer before we apply these patches, just
to be on the safe side.
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Tue, 21 Oct 2025 10:53:01 +0000
Resent-Message-ID: <handler.79188.B79188.17610439785874 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17610439785874
(code B ref 79188); Tue, 21 Oct 2025 10:53:01 +0000
Received: (at 79188) by debbugs.gnu.org; 21 Oct 2025 10:52:58 +0000
Received: from localhost ([127.0.0.1]:50265 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vB9z4-0001WY-86
for submit <at> debbugs.gnu.org; Tue, 21 Oct 2025 06:52:58 -0400
Received: from mail-wr1-x429.google.com ([2a00:1450:4864:20::429]:60720)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1vB9yx-0001VY-Ss
for 79188 <at> debbugs.gnu.org; Tue, 21 Oct 2025 06:52:52 -0400
Received: by mail-wr1-x429.google.com with SMTP id
ffacd0b85a97d-3ece0e4c5faso5368231f8f.1
for <79188 <at> debbugs.gnu.org>; Tue, 21 Oct 2025 03:52:47 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1761043961; x=1761648761; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=elCzAaPoYgGVUtOgmi94/BAuTyNqBG+Vm4apwwKXVhQ=;
b=fLyzNr1aGasELSOh7mFq5qiL7EO5iLr+UIwl+PV3w1DxF6gj8Jm1Z+51k28mlYGPCv
cK9fUg1vpBLjAaZWtRirT5utbOutEJwHBNiGTA5cWOtYTtwirY1rUcJbwlTLqqDbcEZj
7qI6HB+0sOpChI0734XIcy8PhwR6BMPfOnbOP+pLLqaHxW2DssxWGIYx8rS37WT+2pdE
JTA/MH6qOQjFBtIQjcw8YJL9IjpklHNFbrul3N/13+qTHgVhd/ZptGvTf9Ayxm4zMutR
qccISKrsJQztDPYV+1UaxzmdqqK0BFUpiDPa7zGQzh0MidmDdrvGY6S4HGVNtq+yLcGv
/cxQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1761043961; x=1761648761;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to;
bh=elCzAaPoYgGVUtOgmi94/BAuTyNqBG+Vm4apwwKXVhQ=;
b=qhp1F6/HEgnx7jRndACKibjWWcTOgOgz1DNnXT+70crICWZCd7qdhb+W5Vq/jC0VxF
f5fyfB1aKy/rXyDujtypKOopvzh9PAnGVD/ijh9MvxFyHROz0PUw30Du+a6M1vS8wCEt
hn0oA/m7ZmVbkF0rQmD+hULRk+mhoOX8zUBs8OOxwc1d43G7QOi/W1Z9a14Bel59anlG
ZQdpM10e+D90igDfjiYleKzwZ9O5CAhl2eHUgqkdn/1RTr1qQyK4vstA5wDaaZDLN+s5
CNzj9j3GMdfW1+fXAVR53z62Ro06zvqZ8oVXnXko3Y3raCNt0DlrbDEYyLTzHHXACJM4
L04g==
X-Gm-Message-State: AOJu0YyuBPd6Gh3dMmtBjl0J2FOkXWq9jeP88gYAJ7uUc6SlKBAFvUWy
BRyp3Ey/EYPfR7SZiCirSVVocrByP0lLUA4qKTp2VytuX8hi29l6sa4YxWnatw==
X-Gm-Gg: ASbGncuuXG88eiR3j+aTmnhRnbNGbhZEBQB7mDKZv+mM5f79UrFn8YCUdOnnMky8oWm
lNp9zYKs4XSDjtJOC/4KUvONsXcDjVkK+uDHAoaUV474akQrFQ1IEMOhBEbCIlz1g8G5StA8FTc
jgLigCMMUxQZK/7tHJBEXD7BlQJvGNsEvrpZxaLXp8iYrneXCAR7RfncFK9ZKvp/J8LPnPvVS2F
LQyefpNBNc0YNCNlYYnT9YvIf2RcF6TeVkv8RJEFOfqDf/qDgRBRhVyvIofsiGsFxPofaTI50AI
T7Q09T8hfe12wKxeUyEQUteetDDEkiw6hGh+4FV6b28ZJUvSzFX8DBBDN2xlA1eqMcxGloMLH6e
TwnI/lN2Xaas0AU9KANvbrSt7L4CcqR+NfCKGrgEv2phXu72UTEeanyivfjp/ctdY6okP8/stHp
dKL6xa+4PDHbUEGd5O/PVgkCtF0Q8K26m96tm/DRT3Krzh8u5RKdY=
X-Google-Smtp-Source: AGHT+IFIfAHVlti9Z6JeOd4j/U4EFVgngZxV6QiCHCQ0MW7q7WwPhUP/COO2HOinqnHwsbpW3LoLtA==
X-Received: by 2002:a05:6000:1ac5:b0:3ee:141a:ede5 with SMTP id
ffacd0b85a97d-42704dc6d3cmr9998966f8f.57.1761043960413;
Tue, 21 Oct 2025 03:52:40 -0700 (PDT)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:d1c9:f38c:bb6b:25d1])
by smtp.gmail.com with ESMTPSA id
ffacd0b85a97d-427ea5b3c34sm19692470f8f.17.2025.10.21.03.52.38
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Tue, 21 Oct 2025 03:52:39 -0700 (PDT)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <87plaiya21.fsf@HIDDEN> (Philip Kaludercic's message of "Sun,
19 Oct 2025 19:18:52 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
Date: Tue, 21 Oct 2025 11:52:38 +0100
Message-ID: <m2a51k4jd5.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Philip Kaludercic <philipk@HIDDEN> writes:
> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>
> [...]
>>
>> So as I suspected not everything was all right. With the patches up to
>> this message, when a user installed a package with
>> `package-install-from-checkout' and then subsequently upgraded it with
>> `package-upgrade' then the pkg-desc entry for the package in
>> `package-alist' become corrupted. After the installation the `dir' slot
>> in `pkg-desc' has been pointing to the `pkg-dir', i.e., a directory
>> under `package-user-dir' that contains "-pkg.el" and forwarding
>> "-autoloads.el" files. However, after the upgrade the slot `dir' points
>> to checkout directory. To my understanding this is undesirable, as for
>> example a subsequent call to `package-delete' will delete the checkout
>> directory leaving the `pkg-dir' with forwarding "-autoloads.el" file
>> that tries load non existent "-autoloads.el".
>
> I am not sure if I have mentioned this before, I have been thinking
> about deprecating `package-install-from-checkout' because of
> complications like these. I don't mean to be ungrateful for the work
> you have put in until now (even if we do deprecate from-checkout your
> tests are still a great addition), but in retrospect it seems that we
> shouldn't have made this feature a part of package-vc.el. To replace
> it, I have been thinking about taking something like site-lisp from ELPA
> and reworking it into the core. What do you think of that? The
> functionality would stay the same, just that instead of having to
> install a specific package by using a command, you can just throw a
> git-clone into a ~/.config/emacs/site-lisp/ directory. You would still
> get byte-compilation, autoload scraping, but loose automatic dependency
> resolution and the building of documentation. Considering the target
> audience of package-vc-install-from-checkout, I don't think that this is
> unreasonable.
Removal of `package-vc-install-from-checkout' is not something I would
like to see. I really liked it since I discovered it a few years ago
and organised my workflow around it [1]. I liked the simplicity of it
and picked up it instead of going a route of straight etc. I am using a
custom Emacs configuration, where I developed an extension to
`use-package' such that the shared configuration of packages can be
used, allowing for ad hoc replacement of chosen packages with
development versions [2]. Reorganising everything, while technically
feasible will likely be a major undertaking from my side. Could you
give me some more details on the ~/.config/emacs/site-lisp approach, and
I could see how easy/difficult it could be to switch?
>> Please find a patch for that:
>>
>> From 2b3375490fba5dc00ba7305e670286fb41401cbc Mon Sep 17 00:00:00 2001
>> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
>> Date: Wed, 15 Oct 2025 08:00:02 +0100
>> Subject: [PATCH] Fix incorrect pkg-desc after package-vc-upgrade
>>
> [...]
>>=20=20
>> -(defun package-vc--unpack-1 (pkg-desc pkg-dir)
>> - "Prepare PKG-DESC that is already checked-out in PKG-DIR.
>> -This includes downloading missing dependencies, generating
>> -autoloads, generating a package description file (used to
>> -identify a package as a VC package later on), building
>> -documentation and marking the package as installed."
>> - (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>> +(defun package-vc--unpack-1 (pkg-desc)
>
> I just went over all the call-sites of this function, and the change
> make sense regardless of what we decide w.r.t. the above, as we only
> needed the distinction between the two due to -from-checkout.
I am not sure that I understood what you meant by "we only needed the
distinction between the two due to -from-checkout.", but I gather the
sentiment is that the argument removal was a good idea. I think that
tests are executing reasonable amount of scenarios to give extra
confidence it won't break Emacs code.
>
>> + "Prepare PKG-DESC that is already checked-out.
>> +The checkout directory is determined by relevant pkg-spec or from `dir'
>> +slot of PKG-DESC. This includes downloading missing dependencies,
>> +generating autoloads, generating a package description file (used to
>> +identify a package as a VC package later on), building documentation and
>> +marking the package as installed."
>> + (let* ((pkg-dir (package-desc-dir pkg-desc))
>> + (pkg-spec (package-vc--desc->spec pkg-desc))
>> (checkout-dir (package-vc--checkout-dir pkg-desc))
>
> We should really write down (in a comment) what the different
> directories mean, just to make it easier to read this stuff.
I added some in a new patch. Please let me know what you think.
>> (lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
>> missing)
>> @@ -567,12 +569,24 @@ package-vc--unpack-1
>> (setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
>>=20=20
>> ;; Update package-alist.
>> - (let ((new-desc (package-load-descriptor pkg-dir))
>> - (compile-desc (package-desc-create :dir lisp-dir)))
>> + (let* ((new-desc (package-load-descriptor pkg-dir))
>> + (compile-desc (package-desc-create :name (package-desc-name =
new-desc)
>
> Why do we need the :name here?
This is because `package--reload-previously-loaded' uses that slot when
calculating autoload file name [3] as well as to display warnings [4].
> [...]
>> (defun package-vc--read-package-name (prompt &optional allow-url instal=
led)
>> "Query the user for a VC package and return a name with PROMPT.
>> @@ -782,7 +798,7 @@ package-vc-upgrade
>> ;;
>> ;; If there is a better way to do this, it should be done.
>> (cl-assert (package-vc-p pkg-desc))
>> - (letrec ((pkg-dir (package-vc--checkout-dir pkg-desc))
>> + (letrec ((checkout-dir (package-vc--checkout-dir pkg-desc))
>
> I would avoid renaming variables if it is not necessary, as it pollutes
> the Git log.
I understand that sentiment. I changed the variable name, such that the
name consistently reflects semantic meaning of it across the file. For
that reason I have chosen to not update it in the attached patch, but
will change it if you think that sacrificing semantic meaning is a
better compromise than polluting Git log.
> [...]
>> diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
>> index ba9999c20e6..fb073579bc1 100644
>> --- a/lisp/emacs-lisp/package.el
>> +++ b/lisp/emacs-lisp/package.el
>> @@ -903,6 +903,14 @@ package--reload-previously-loaded
>> (mapc (lambda (c) (load (car c) nil t))
>> (sort result (lambda (x y) (< (cdr x) (cdr y))))))))
>>=20=20
>> +(defun package--add-info-node (pkg-dir)
>> + "Add info node located in PKG-DIR."
>> + (when (file-exists-p (expand-file-name "dir" pkg-dir))
>> + ;; FIXME: not the friendliest, but simple.
>> + (require 'info)
>> + (info-initialize)
>> + (add-to-list 'Info-directory-list pkg-dir)))
>
> LGTM!
=F0=9F=98=8E
> [...]
> Gnus cut of the remaining response so I sent my previous message to early!
No problem. Consolidating here.
> [...]
>> (defvar package-vc-tests-dir
>> (make-temp-file "package-vc-tests-" t (format-time-string "-%Y%m%d.%H%=
M%S")))
>
> Should the global variable have a side-effect at declaration-time? I
> don't think we can be sure that the file will still exist if you load
> the file at one point and run the tests later (even if you re-load the
> file, the "new" value won't get re-evaluated).
>>
>> (setq package-user-dir (expand-file-name "elpa" package-vc-tests-dir))
>
> Please don't use setq on the top-level.
>
I have updated the whole test environment approach. I added a new macro
to wrap up the whole setup, with a few extra checks before running any
test. This has a drawback of increasing the indentation depth by 2. Do
thing this is a good approach, or perhaps you can recommend a different
technique?
Thanks for that =F0=9F=92=AF!
> [...]
>> (package-vc-install '(ultra-scroll
>> :url "https://github.com/jdtsmith/ultra-scroll.g=
it"))
>> (should (equal "https://github.com/jdtsmith/ultra-scroll.git"
>> (plist-get (alist-get "ultra-scroll"
>> package-vc-selected-packages
>> nil nil #'string=3D)
>> :url)))
>
> I feel like we should test more than just the :url.
In this particular case this is the only value set.
>> (let ((checkout-dir (expand-file-name "gcmh" package-vc-tests-dir)))
>> (package-vc-checkout (package-vc-tests-package-desc 'gcmh)
>> checkout-dir)
>> (package-vc-install-from-checkout checkout-dir)
>> (should (equal (format "file://%s" checkout-dir)
>> (plist-get (alist-get "gcmh"
>> package-vc-selected-packages
>> nil nil #'string=3D)
>> :url))))
>
> These should also be separate tests, because they are not all testing
> the same thing and it would be better if ERT can give you a better idea
> to what went wrong if the tests are smaller.
>
I understand the idea (see comment below), but in this case ERT nicely
prints a failing package name in every assertion, so I decided to keep
it in a single test, as it nicely inserts the markers into
`load-history' within a single function. Can work on breaking it down
if you insist.
> [...]
>> (dolist (package package-alist)
>> (dolist (pkg-desc (cdr package))
>> (when (package-vc-p pkg-desc)
>> (message "*** installed %s" pkg-desc))))
>
> Why do we need this?
Good catch! We don't. This is some of my extra tracing code. Removed.
> [...]
>> (ert-deftest package-vc-tests-002-commit ()
>> (dolist (pkg-checkout-dir package-vc-tests-packages)
>> (let ((pkg (car pkg-checkout-dir))
>> (commit (package-vc-commit
>> (package-vc-tests-package-desc (car pkg-checkout-dir) =
t))))
>> (should-not (equal (cons pkg commit)
>> (list pkg)))
>
> So (null commit)?
Or even simpler (should commit). But that will only print a commit name
in case of failure. I did the list trick on purpose, such that on
failure it prints the affected package name. I know that one option is
to write a custom ert-explainer, but that seems like an overkill. Or
create a custom assertion that would `message' before failure, yet this
one seems odd to me. I wish `should' could take extra context. Do you
have a better idea how to ensure package name is printed?
>> (should-not (equal (list pkg "unknown")
>> (list pkg commit))))))
>>
>> (ert-deftest package-vc-tests-003-load-history-after-install ()
>> (let ((install-begin (should (package-vc-tests-load-history-position
>> 'install-begin :marker)))
>> (install-end (should (package-vc-tests-load-history-position
>> 'install-end :marker))))
>> (dolist (pkg (mapcar #'car package-vc-tests-packages))
>> (let ((autoloads-pos
>> (should (package-vc-tests-load-history-position pkg :autolo=
ads))))
>> (should (< install-end autoloads-pos install-begin)))
>> (should-not (package-vc-tests-load-history-position pkg :main))
>> (should-not (package-vc-tests-load-history-position pkg :main-comp=
iled)))))
>>
>> (ert-deftest package-vc-tests-004-require ()
>> (dolist (pkg (mapcar #'car package-vc-tests-packages))
>> (should (require pkg)))
>
> Shouldn't this be called with NOERROR.
It could, but I don't really understand a benefit. Either case `should'
will abort the loop and in consequence the test.
>> (let ((install-end (should (package-vc-tests-load-history-position
>> 'install-end :marker))))
>> (dolist (pkg (mapcar #'car package-vc-tests-packages))
>> (let ((main-pos (should (package-vc-tests-load-history-position pk=
g :main))))
>> (should (< main-pos install-end)))
>> (should-not (package-vc-tests-load-history-position pkg :main-comp=
iled)))))
>
> Why are we interested in the position in load-list?
This is to ensure that files are reloaded. It has proven very helpful
as it caught that code was not reloaded for a package, that:
- has it's Lisp code in a sub directory called "lisp",
- and has been installed with `package-vc-install',
- and has been upgraded with `package-vc-upgrade'.
For posterity, this was test-package-5, to be found in the most recent
patch.
>> (defmacro package-vc-tests-package-vc-upgrade-wait (seconds count &rest =
body)
>> "Wait up to SECONDS for COUNT packages upgrading BODY.
>> Return nil on timeout or non nil otherwise."
>> (declare (indent 2))
>> `(letrec ((packages-count ,count)
>> (post-vc-command (lambda (command _ flags)
>> ;; A crude filter for vc commands
>> (when (and (equal command "git")
>> (string-prefix-p "*vc-git" (bu=
ffer-name)))
>> (cl-decf packages-count)))))
>> (add-hook 'vc-post-command-functions post-vc-command 100)
>> (unwind-protect
>> (progn
>> ,@body
>> (catch 'done
>
> Do you want with-timeout?
It turns out I want that. Thanks for pointing out!
> [...]
>> (ert-deftest package-vc-tests-010-prepare-patch ()
>> (dolist (pkg-checkout-dir package-vc-tests-packages)
>> (cl-letf* ((call-count 0)
>> ((symbol-function #'package-maintainers)
>> (lambda (&rest _)
>> "test-maintainers"))
>> ((symbol-function #'vc-prepare-patch)
>> (lambda (addressee subject revisions)
>> (should (equal (file-name-as-directory default-directo=
ry)
>> (file-name-as-directory (cdr pkg-checko=
ut-dir))))
>> (should (equal "test-maintainers" addressee))
>> (should (equal "test-subject" subject))
>> (should (equal "test-revisions" revisions))
>> (cl-incf call-count))))
>> (package-vc-prepare-patch (package-vc-tests-package-desc
>> (car pkg-checkout-dir)
>> t)
>> "test-subject"
>> "test-revisions")
>> (should (eql 1 call-count)))))
>
> I don't think we need to test the specific internal behaviour. IMO the
> tests should ensure that user-facing behaviour doesn't regress.
I have chosen to go the mocking route for this (and the following) test.
Otherwise writing assertions for them may be a bit complicated. But I
can try to update if you think the extra work justifies the benefit.
>>> 3. I am not sure what will happen when someone checkouts a repository to
>>> `package-user-dir' making it so the 'package-vc-install-from-checkout'
>>> calculates `pkg-dir' that is the same as a checkout dir. I know it's
>>> not the smartest thing to do, but perhaps detect it and raise an error?
If we agree to keep `package-vc-install-from-checkout' (which I still
have hopes for) I will create a patch for it.
>>> 4. I struggle to understand how the value of `:lisp-dir' calculated in
>>> `package-vc-unpack' (lines 701-711) is used in further code. Will need
>>> to find a package that specifies that and try to debug it further.
So this one turns out to be an issue. Caught by one of `load-history'
tests (as mentioned above). It doesn't do anything for
`package-vc-install', and the logic is omitted for
`package-vc-install-from-chekcout'. I have added a fix for it in the
attached patches.
>>> 5. Perhaps the `package-vc-install-from-checkout' could be extended in
>>> such a way to allow user to specify their `pkg-spec'. That should
>>> include the checkout directory, as well as other values from spec
>>> (lisp-dir, make, doc)?
>> 6. Perhaps `package-vc-rebuild' should delete all *.elc files, such that
>> subsequent `package--reload-previously-loaded' calls will certainly pick
>> up what is in the code, such that downgrades are supported (i.e., the
>> *.el file will become older than *.elc).
Although I have done some work around that area and it seems to work as
it should I still need to do some experiments to convince myself this
indeed works as expected. I will update if I find anything.
>>> 5. I am not sure how `package-delete' will work with these changes. I
>>> guess it should at least remove the pkg-dir as well as entry from
>>> `package-vc-selected-packages'.
>>
>> I guess this will be question 7 now ;). I am thinking about adding a
>> hook, say `package-delete-hook' that will be called with a `pkg-desc' of
>> the package being deleted. `package-vc' could register it's own handler
>> and delete such an entry.
>>
>> And last but not least:
>>
>> 8. I have noticed that `package-reinstall' allows to reinstall a VC
>> package. But that will certainly won't do the right thing - it will
>> delete the package, but the subsequent installation will either happen
>> from an ELPA or will fail if no ELPA exists. I am thinking about of two
>> options:
>>
>> a. Remove VC packages from completion offers, and block the function,
>> asking user to use `package-vc-rebuild'.
>>
>> b. Forward the call to `package-vc-rebuild' for VC packages. Perhaps
>> after asking user if they want to do so. The question could be
>> suppress-able with a new variable
>> (e.g. `package-reinstall-vc-package-forward' with values `always',
>> `ask', `never'). And the `package-vc-rebuild' could be also set as a
>> variable (e.g., `package-reinstall-vc-package-function').
>
> My preference would be towards a., just like how I think that adding
> VC packages to package-upgrade was a mistake in retrospect.
How about creating a new bug for issues 7 (package-delete) and 8
(package-reinstall) and discuss patches there?
>> .../test-package-1.bundle | Bin 0 -> 764 bytes
>> .../test-package-2.bundle | Bin 0 -> 763 bytes
>> .../test-package-3.bundle | Bin 0 -> 764 bytes
>> .../test-package-4.bundle | Bin 0 -> 767 bytes
>
> I was afraid that the files would be a lot larger, but this seems
> acceptable. Did you do a shallow clone and run git-gc(1)? Either way,
> I would prefer to ask a maintainer before we apply these patches, just
> to be on the safe side.
These are not the packages I used as specimens earlier. Instead I opted
for creating a minimal viable package repositories with just a two
commits to exercise upgrade/downgrade test scenarios. That's why the
bundles are so small. You can clone one of these bundles to see what's
inside.
Here are the new patches, that include additional fix for the Lisp sub
directory as well as addressing comments. This time, I consolidated
them, so they apply on the directly on top of the patch you sent Fri, 19
Sep 2025 [5]. If you prefer incremental changes (I guess on a cost of
managing applying them in right order), please let me know and will send
them in smaller chunks. Please let me know what you think.
--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment;
filename=0001-Fix-upgrading-and-rebuilding-of-VC-packages.patch
Content-Description: patch
From 2ccc2463a714d8f7ab91eef0813c615bba5e1251 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Przemys=C5=82aw=20Kryger?= <pkryger@HIDDEN>
Date: Fri, 26 Sep 2025 17:24:44 +0100
Subject: [PATCH 1/2] Fix upgrading and rebuilding of VC packages
There are a few issues addressed in this patch:
1. Compilation (including native compilation) should happen in
directory that contains package's Lisp code.
2. After installing a package with
`package-vc-install-from-checkout' and subsequently upgrading it
with `package-vc-upgrade' the pkg-desc for the package becomes
corrupted. After the upgrade the pkg-desc's dir (a.k.a
`pkg-dir') points to checkout directory. This will cause the
subsequent `package-delete' to delete the checkout directory and
leaving incorrect forwarding autoloads file in
`package-user-directory'.
3. The detection of package's Lisp directory has been not
effective for packages installed with `package-vc-install' and
not existent for packages installed with
`package-install-from-checkout'.
* lisp/emacs-lisp/package-vc.el (package-vc--checkout-dir):
Detect standard lisp sub directory if called with non-nil
`lisp-dir'.
(package-vc--unpack-1): Remove superfluous `pkg-dir' argument.
Use a `package' with `:dir' pointing to where package code is.
After calling `package-activate-1' ensure that source files are
reloaded when `lisp-dir' is a sub directory and call
`package--add-info-node' when `checkout-dir' is different than
`pkg-dir'.
(package-vc-install-from-checkout): Remove superfluous
`package-vc-selected-packages' binding. Remove `pkg-dir'
argument from `package-vc--unpack-1' calls.
(package-vc--unpack): Remove superfluous Lisp code sub directory
detection - logic moved to `package-vc--checkout-dir'. Remove
`pkg-dir' argument from `package-vc--unpack-1' call.
(package-vc-upgrade, package-vc-rebuild): Remove `pkg-dir'
argument from `package-vc--unpack-1' calls.
* lisp/emacs-lisp/package.el (package--add-info-node): New
function to install info node for package. Extracted from
`package-activate-1'.
(package-activate-1): Call `package--add-info-node'.
(Bug#79188)
---
lisp/emacs-lisp/package-vc.el | 154 ++++++++++++++++++++--------------
lisp/emacs-lisp/package.el | 15 ++--
2 files changed, 102 insertions(+), 67 deletions(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 078a7bd8136..10b198961be 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -31,8 +31,7 @@
;; aren't interested in activating a package, you can use
;; `package-vc-checkout' instead, which will prompt you for a target
;; directory. If you wish to reuse an existing checkout, the command
-;; `package-vc-install-from-checkout' will create a symbolic link and
-;; prepare the package.
+;; `package-vc-install-from-checkout' will prepare the package.
;;
;; If you make local changes that you wish to share with an upstream
;; maintainer, the command `package-vc-prepare-patch' can prepare
@@ -180,16 +179,37 @@ package-vc--checkout-dir
that case the package redirects to the actual VC checkout. If the
optional LISP-DIR argument is non-nil, then check if a related package
specification has a `:lisp-dir' field to indicate that Lisp files are
-located in a sub directory of a checkout and return that instead."
+located in a sub directory of the checkout, or the checkout has a sub
+directory named \"lisp\" or \"src\" that contains .el files and return
+that instead."
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
- (url (plist-get pkg-spec :url)))
+ (url (plist-get pkg-spec :url))
+ (pkg-dir (cond
+ ((save-match-data
+ (and url (string-match (rx "file://" (group (+ any))) url)
+ (match-string 1 url))))
+ (t (package-desc-dir pkg-desc)))))
(expand-file-name
- (or (and (not lisp-dir) (plist-get pkg-spec :lisp-dir)) ".")
- (cond
- ((save-match-data
- (and url (string-match (rx "file://" (group (+ any))) url)
- (match-string 1 url))))
- (t (package-desc-dir pkg-desc))))))
+ (or (when lisp-dir
+ (or (plist-get pkg-spec :lisp-dir)
+ ;; When nothing is specified about a `lisp-dir', then should
+ ;; heuristically check if there is a sub-directory with lisp
+ ;; files. These are conventionally just called "lisp" or "src".
+ ;; If this directory exists and contains non-zero number of lisp
+ ;; files, we will use that instead of `pkg-dir'.
+ (catch 'done
+ (dolist (name '("lisp" "src"))
+ (when-let* ((dir (expand-file-name name pkg-dir))
+ ((file-directory-p dir))
+ ((directory-files dir nil "\\`[^.].+\\.el\\'" t 1)))
+ ;; We won't use `dir', since dir is an absolute path and we
+ ;; don't want `lisp-dir' to depend on the current location of
+ ;; the package installation, ie. to break if moved around the
+ ;; file system or between installations.
+ (throw 'done name))))
+ ))
+ ".")
+ pkg-dir)))
(defun package-vc--read-archive-data (archive)
"Update `package-vc--archive-spec-alists' for ARCHIVE.
@@ -468,14 +488,24 @@ package-vc-install-dependencies
(mapc #'package-install-from-archive to-install)
missing))
-(defun package-vc--unpack-1 (pkg-desc pkg-dir)
- "Prepare PKG-DESC that is already checked-out in PKG-DIR.
-This includes downloading missing dependencies, generating
-autoloads, generating a package description file (used to
-identify a package as a VC package later on), building
-documentation and marking the package as installed."
- (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
+(defun package-vc--unpack-1 (pkg-desc)
+ "Prepare PKG-DESC that is already checked-out.
+The checkout directory is determined by relevant pkg-spec or from `dir'
+slot of PKG-DESC. This includes downloading missing dependencies,
+generating autoloads, generating a package description file (used to
+identify a package as a VC package later on), building documentation and
+marking the package as installed."
+ (let* (;; Main package directory, under `package-user-dir'. This is
+ ;; the same `checkout-dir' when package has been installed with
+ ;; `package-vc-install'.
+ (pkg-dir (package-desc-dir pkg-desc))
+ (pkg-spec (package-vc--desc->spec pkg-desc))
+ ;; Directory where the package repository has been checked out.
+ ;; This is the `dir' argument of
+ ;; `package-vc-install-from-checkout'.
(checkout-dir (package-vc--checkout-dir pkg-desc))
+ ;; Directory where package's Lisp code resides. It may be
+ ;; equal to `checkout-dir' or be a subdirectory of it.
(lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
missing)
@@ -518,13 +548,17 @@ package-vc--unpack-1
(auto-name (format "%s-autoloads.el" name)))
(package-generate-autoloads name lisp-dir)
;; There are two cases when we wish to "indirect" the loading of
- ;; autoload files: 1. a package specification has a `:lisp-dir'
- ;; entry listing indicting that the actual Lisp code is located in
- ;; a subdirectory of the checkout, 2. the package has been
- ;; installed using `package-vc-install-from-checkout' and we want
- ;; to load the other directory instead -- which is outside of the
- ;; checkout. We can therefore take file inequality as a sign that
- ;; we have to set up an indirection.
+ ;; autoload files:
+ ;;
+ ;; 1. a package specification has a `:lisp-dir' entry listing
+ ;; indicting that the actual Lisp code is located in a
+ ;; subdirectory of the checkout,
+ ;;
+ ;; 2. the package has been installed using
+ ;; `package-vc-install-from-checkout' and we want to load the
+ ;; other directory instead -- which is outside of the checkout.
+ ;; We can therefore take file inequality as a sign that we have to
+ ;; set up an indirection.
(unless (file-equal-p lisp-dir pkg-dir)
(write-region
(concat
@@ -568,20 +602,37 @@ package-vc--unpack-1
(setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
;; Update package-alist.
- (let ((new-desc (package-load-descriptor pkg-dir)))
+ (let* ((new-desc (package-load-descriptor pkg-dir))
+ (compile-desc (package-desc-create :name (package-desc-name new-desc)
+ :dir lisp-dir)))
;; Activation has to be done before compilation, so that if we're
;; upgrading and macros have changed we load the new definitions
;; before compiling.
(when (package-activate-1 new-desc :reload :deps)
+ ;; `package-activate-1' will reload all necessary package files
+ ;; as long as their stems are relative to of `pkg-dir'. If
+ ;; that's not the case (for example for packages with different
+ ;; `checkout-dir' or with source files in a sub directory of
+ ;; `pkg-dir'), we want to reload package files from the
+ ;; `lisp-dir' before compilation.
+ (unless (file-equal-p lisp-dir pkg-dir)
+ (package--reload-previously-loaded compile-desc))
+ ;; `package-activate-1' will add info node as long as dir file
+ ;; exists in `pkg-dir'. We need to manually add it when
+ ;; `checkout-dir' is in different location.
+ (unless (file-equal-p pkg-dir checkout-dir)
+ (package--add-info-node checkout-dir))
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
- (package--compile (package-desc-create :dir lisp-dir))
+ (package--compile compile-desc)
(when package-native-compile
- (package--native-compile-async new-desc))
+ (package--native-compile-async compile-desc))
;; After compilation, load again any files loaded by
- ;; `activate-1', so that we use the byte-compiled definitions.
- (package--reload-previously-loaded new-desc)))
+ ;; `package-activate-1', so that we use the byte-compiled
+ ;; definitions. This time we'll use `compile-desc' straight
+ ;; away.
+ (package--reload-previously-loaded compile-desc)))
;; Mark package as selected
(let ((name (package-desc-name pkg-desc)))
@@ -693,28 +744,11 @@ package-vc--unpack
(delete-directory pkg-dir t)
(user-error "Installation aborted")))
- ;; When nothing is specified about a `lisp-dir', then should
- ;; heuristically check if there is a sub-directory with lisp
- ;; files. These are conventionally just called "lisp" or "src".
- ;; If this directory exists and contains non-zero number of lisp
- ;; files, we will use that instead of `pkg-dir'.
- (catch 'done
- (dolist (name '("lisp" "src"))
- (when-let* (((null lisp-dir))
- (dir (expand-file-name name pkg-dir))
- ((file-directory-p dir))
- ((directory-files dir nil "\\`[^.].+\\.el\\'" t 1)))
- ;; We won't use `dir', since dir is an absolute path and we
- ;; don't want `lisp-dir' to depend on the current location of
- ;; the package installation, ie. to break if moved around the
- ;; file system or between installations.
- (throw 'done (setq lisp-dir name)))))
-
;; Ensure we have a copy of the package specification
(when (null (package-vc--desc->spec pkg-desc name))
(package-vc--save-selected-packages name pkg-spec))
- (package-vc--unpack-1 pkg-desc pkg-dir)))
+ (package-vc--unpack-1 pkg-desc)))
(defun package-vc--read-package-name (prompt &optional allow-url installed)
"Query the user for a VC package and return a name with PROMPT.
@@ -782,7 +816,7 @@ package-vc-upgrade
;;
;; If there is a better way to do this, it should be done.
(cl-assert (package-vc-p pkg-desc))
- (letrec ((pkg-dir (package-vc--checkout-dir pkg-desc))
+ (letrec ((checkout-dir (package-vc--checkout-dir pkg-desc))
(vc-flags)
(vc-filter-command-function
(lambda (command file-or-list flags)
@@ -790,18 +824,19 @@ package-vc-upgrade
(list command file-or-list flags)))
(post-upgrade
(lambda (_command _file-or-list flags)
- (when (and (file-equal-p pkg-dir default-directory)
+ (when (and (file-equal-p checkout-dir default-directory)
(eq flags vc-flags))
(unwind-protect
(with-demoted-errors "Failed to activate: %S"
- (package-vc--unpack-1 pkg-desc pkg-dir))
+ (package-vc--unpack-1 pkg-desc))
(remove-hook 'vc-post-command-functions post-upgrade))))))
(add-hook 'vc-post-command-functions post-upgrade)
(with-demoted-errors "Failed to fetch: %S"
(require 'vc-dir)
(with-current-buffer (vc-dir-prepare-status-buffer
- (format " *package-vc-dir: %s*" pkg-dir)
- pkg-dir (vc-responsible-backend pkg-dir))
+ (format " *package-vc-dir: %s*" checkout-dir)
+ checkout-dir
+ (vc-responsible-backend checkout-dir))
(vc-pull)))))
(defun package-vc--archives-initialize ()
@@ -966,24 +1001,21 @@ package-vc-install-from-checkout
(package-vc--archives-initialize)
(let* ((dir (if interactive dir (expand-file-name dir))) ;avoid double expansion
(name (or name (file-name-base (directory-file-name dir))))
- (pkg-dir (file-name-concat package-user-dir name))
- (package-vc-selected-packages
- (cons (list name :lisp-dir dir)
- package-vc-selected-packages)))
+ (pkg-dir (file-name-concat package-user-dir name)))
(when (file-exists-p pkg-dir)
(if (yes-or-no-p (format "Overwrite previous checkout for package `%s'?" name))
(package--delete-directory pkg-dir)
(error "There already exists a checkout for %s" name)))
(make-directory pkg-dir t)
- ;; We store a custom package specification so that
- ;; `package-vc--checkout-dir' can later retrieve the actual checkout.
+ ;; We store a custom package specification so that it is available
+ ;; for `package-vc--unpack-1' as well as `package-vc--checkout-dir'
+ ;; can later retrieve the actual checkout.
(package-vc--save-selected-packages name (list :url (concat "file://" dir)))
(package-vc--unpack-1
(package-desc-create
:name (intern name)
:dir pkg-dir
- :kind 'vc)
- (file-name-as-directory pkg-dir))))
+ :kind 'vc))))
;;;###autoload
(defun package-vc-rebuild (pkg-desc)
@@ -995,7 +1027,7 @@ package-vc-rebuild
is the responsibility of `package-vc-upgrade'. Interactively,
prompt for the name of the package to rebuild."
(interactive (list (package-vc--read-package-desc "Rebuild package: " t)))
- (package-vc--unpack-1 pkg-desc (package-vc--checkout-dir pkg-desc)))
+ (package-vc--unpack-1 pkg-desc))
;;;###autoload
(defun package-vc-prepare-patch (pkg-desc subject revisions)
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index ba9999c20e6..fb073579bc1 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -903,6 +903,14 @@ package--reload-previously-loaded
(mapc (lambda (c) (load (car c) nil t))
(sort result (lambda (x y) (< (cdr x) (cdr y))))))))
+(defun package--add-info-node (pkg-dir)
+ "Add info node located in PKG-DIR."
+ (when (file-exists-p (expand-file-name "dir" pkg-dir))
+ ;; FIXME: not the friendliest, but simple.
+ (require 'info)
+ (info-initialize)
+ (add-to-list 'Info-directory-list pkg-dir)))
+
(defun package-activate-1 (pkg-desc &optional reload deps)
"Activate package given by PKG-DESC, even if it was already active.
If DEPS is non-nil, also activate its dependencies (unless they
@@ -934,12 +942,7 @@ package-activate-1
The following files have already been loaded: %S")))
(with-demoted-errors "Error loading autoloads: %s"
(load (package--autoloads-file-name pkg-desc) nil t)))
- ;; Add info node.
- (when (file-exists-p (expand-file-name "dir" pkg-dir))
- ;; FIXME: not the friendliest, but simple.
- (require 'info)
- (info-initialize)
- (add-to-list 'Info-directory-list pkg-dir))
+ (package--add-info-node pkg-dir)
(push name package-activated-list)
;; Don't return nil.
t)))
--
2.51.0
--=-=-=
Content-Type: text/x-patch; charset=utf-8
Content-Disposition: attachment;
filename=0002-Add-tests-for-package-vc.patch
Content-Transfer-Encoding: quoted-printable
Content-Description: patch
From c82c03957f5f1fab6fbbff39ef1ea49792581e6f Mon Sep 17 00:00:00 2001
From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
Date: Tue, 2 Sep 2025 09:28:13 +0100
Subject: [PATCH 2/2] Add tests for package-vc
* test/lisp/package-vc-tests.el (package-vc-tests-dir):
Temporary directory to store `package' and test data during the
test.
(package-vc-tests-resources-dir): Directory where bundle files
(repositories with test packages): are located.
(package-vc-tests-packages): List of packages to tests, together
with their checkout locations.
(with-package-vc-tests-enviroment): Setup environment for test,
that includes configuring `package', `package-vc', and `vc'
variables, as well as defining test packages.
(package-vc-tests-package-desc): Retrieve a `package-desc' for
tested package.
(package-vc-tests-package-main-file): Calculate expected
location of package's main file.
(package-vc-tests-load-history-position): Calculate a position
in load-history of a file. The position only accounts for
interesting files, that is only files that are in
`package-vc-tests-dir'.
(package-vc-tests-assert-delete-elc): Assert that .elc files
have been gernerated for a package and delete them.
(package-vc-tests-assert-package-alist): Assert that
`pakcage-alist' contains a `package-desc' for package, and that
the `pakcage-desc' has correct slot `version' and slot `dir'.
(package-vc-tests-reset-heads): Reset heads of checkouts of
tested packages to a HEAD^.
(package-vc-tests-packages-heads): Return a list of checkouts of
tested packages current HEAD revisions.
(package-vc-tests-000-install): Test that packages can be
installed with `package-vc-install' and
`package-vc-install-from-checkout', including
`package-vc-checkout'.
(package-vc-tests-001-main-file): Test that
`package-vc--main-file' return main file in expected locations.
(package-vc-tests-002-commit): Test that `package-vc-commit' is
returning a revision.
(package-vc-tests-003-load-history-after-install): Test that
`load-history' has entries for autoloads of tested packages.
(package-vc-tests-package-vc-upgrade-wait): Helper function to
wait for a package being upgraded. This is needed due to
asynchronous nature of `vc-pull'.
(package-vc-tests-004-upgrade-all): Test that
`package-vc-upgrade-all' indeed upgrades all packages.
(package-vc-tests-005-load-history-after-upgrade-all): Test that
`load-history' has entries for autoloads of tested packages.
(package-vc-tests-006-require): Test that packages can be
`require'd, and that `load-history' has entries for non-compiled
package main files.
(package-vc-tests-007-upgrade): Test that `package-vc-upgrade'
upgrades a package.
(package-vc-tests-008-load-history-after-upgrade): Test that
`load-history' has entries for autoloads, non-compiled main
files, and compiled main files after a package has been
upgraded.
(package-vc-tests-009-rebuild): Test that a downgraded package
can be rebuild with `package-vc-rebuild', and that appropriate
files are reloaded.
(package-vc-tests-010-prepare-patch): Test that
`package-vc-prepare-patch' calls `vc-prepare-patch' with
expected arguments.
(package-vc-tests-011-log-incoming): Test that
`package-vc-log-incoming' calls `vc-log-incoming' with expected
arguments.
---
.../test-package-1.bundle | Bin 0 -> 764 bytes
.../test-package-2.bundle | Bin 0 -> 763 bytes
.../test-package-3.bundle | Bin 0 -> 764 bytes
.../test-package-4.bundle | Bin 0 -> 767 bytes
.../test-package-5.bundle | Bin 0 -> 845 bytes
.../test-package-6.bundle | Bin 0 -> 843 bytes
test/lisp/package-vc-tests.el | 601 ++++++++++++++++++
7 files changed, 601 insertions(+)
create mode 100644 test/lisp/package-vc-resources/test-package-1.bundle
create mode 100644 test/lisp/package-vc-resources/test-package-2.bundle
create mode 100644 test/lisp/package-vc-resources/test-package-3.bundle
create mode 100644 test/lisp/package-vc-resources/test-package-4.bundle
create mode 100644 test/lisp/package-vc-resources/test-package-5.bundle
create mode 100644 test/lisp/package-vc-resources/test-package-6.bundle
create mode 100644 test/lisp/package-vc-tests.el
diff --git a/test/lisp/package-vc-resources/test-package-1.bundle b/test/li=
sp/package-vc-resources/test-package-1.bundle
new file mode 100644
index 0000000000000000000000000000000000000000..1ba31bb56c8a4e78c04ced881f6=
8aa56113e5258
GIT binary patch
literal 764
zcmV<Y0t5XcAa*h!XK8dGVs&n0Y-I{JVmM_pGcqzTH8nCgH)UoqH8?OdGcqtSG-PEn
zVKQVjW-~Z5WH&h=3Da%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J_4tSiM%s~nQ
zArye&y{B*=3Dg!*(;h-lv?=3DmbxFPD42}m=3DV*myLGRkZqV-MUwo|+aYNR5p@=3D|diD;cs
z&SLTcr8G7K2r2oPGn=3Du}*f=3DJT5sU{&I=3DUdTk6tV3QL7X*I4y$#fXwjLPE+NF`k=3DC0
zUr)UAeO-F0d^4ZFvFi&Cmvx-VmP^|SE3|hVUkND$``j|LM*j=3D!NO2ky|4Hl(VDn1C
zoeOxJD=3DA7%RWLV5Gc+-_NU^lEOind7OR}&uFf}wYFix{HGDu0aFiJH}u}m>BG2%)r
zEy>6)QV1xjO3ke-KH8L6uHao%nVwptU{jC{W;mqhCT8a7CFkebDHxiY8JHWGSelwE
zXd4(B7;phab2CdyQpq=3Dg%Pq60xI_VB5ElS2>^vQ<0(hJ=3DG%zqTF;OT<EiTb5NKDR7
zOi$G{)Jx4_D7YLrk)dQyz>^)-HM+(gZut*A>j70B5Tv~qc$|%pu};G<5QcX@#VHx;
zAe~Fa=3D8P<i6++#Q_(&`qJGGq(-oADz5}*!j=3DTHCt>CS!ML*|rmq2ZlI#+_mZhzKu*
z!j%HvAvpf9137%P-dI0s$Q27w3{PR^rQ|eBIWI|Xw~0>VJxwaau_pFc{WBj|8#!r^
zl4lwcG!OS`*K}P?9XKW%yoQ3RxQE9u&+IeBPhH+M^K&ot9WtyhW81d0=3DHLPuAq~H+
z{?Bz-&;YU%08KTiru%0xICHZsml#ggFl>GozPvX+m%T|aab$4@bvkp1Z-82Oocqgk
zfN8=3D^Mx%+dvL`z+S_1$xk_E-B0(hJ=3DG%zqTF;OT<EiTb5NKDR7Oi$G{)Jx4_xSe+B
uUF!dBQJq^~ewTZGxuI`UycYm}9TY0o&aooGjhCAnv*jBU3g$JmE;3k}Mn7->
literal 0
HcmV?d00001
diff --git a/test/lisp/package-vc-resources/test-package-2.bundle b/test/li=
sp/package-vc-resources/test-package-2.bundle
new file mode 100644
index 0000000000000000000000000000000000000000..7b21f617b79d86a7d528d8af345=
d08373dbf3302
GIT binary patch
literal 763
zcmV<X0tEddAa*h!XK8dGVs&n0Y-I{$G%_?ZF=3D96}HZWo}G+{O}WHw}BV>2{mG&f^8
zG-769HDhKpIWlG-a%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J_4tSiM%smPM
zF%UrEKBq`8Nd7kg5qlfK6HF$Pb<ylDF(PZ}-Mp8gH?VuW;%k+Ndq~zqo2AT#6qqCt
zI|nj=3D6_k*awG@0-Y=3D%l>;}kFk9d$yC&KPt8Z8kDHFID!4KtXp}dj_|5nkqlk2bJae
zdcvLW>(W!@oB8~WU0-0htZ^z^E;}bWA-q?7C8QASbIZ^g{V%X1;WQ@xlh_*;E=3D#DL
z3wWHJ%s~pmFc3h|eNHiZK_*F?OhLqz8#i8IERz~Ev`iyXm)^~LDS88UpTBrjMSv~&
zo?BvU$a@hCE=3DA|lsp+EY0*NGviM`=3DlJ&y`UeMnj6*OTvX&}9&X&2;(3ZYZ3u>wYX-
zurXjnq?TZX7SVie$+gP=3Dg4t)CEBqky2A`%p%dG-<oHH~qFf%bxC`m0Y(Je?!&Q45E
z)iu&f&0*NvYCYxBQtL$;FAq)JU|;ml>E=3D!~0A{=3DriM<zioQ;q@Ps1<}hIjvpQ!>;+
zI+u^l8Cg13sA50jBe8JoU^^B4_t>RKfI6_9AHDCRJNJDLnN!AvhBq1+?-e^hL^u=3D*
z7YcZT;P}H1<nYCMWBsThS1d#^?83}T$!VB!UXtE!6CKHWnpB8mP3$lFCw^aT<fK7L
zo@q$XJlv|grt50znPalSYbdCSdw2}<%sx{*>GH0bpL?nAkYRlu+qR`O2N%c)Y4~;Z
zf3CxV29TWqXsSsy-9L-LnX6^F#Bj8RVe`B2<-PK`>`j7+Ba2UWymO6jfLeH*`^$8I
zX~IlKqlvS!Cp$4(0{}CU1;wobc$_mdFfcPQQ7B0*F3~MWOwLYBPt`TjOU+@ZZ~3vI
tBgE5l@w!t^)9sy#&Mw%g3jkq%5xOz0k$j;XmPz=3DsA!AOGOzWlF9ebFDSR4QV
literal 0
HcmV?d00001
diff --git a/test/lisp/package-vc-resources/test-package-3.bundle b/test/li=
sp/package-vc-resources/test-package-3.bundle
new file mode 100644
index 0000000000000000000000000000000000000000..a7ca66750db656b7fcc27204983=
8d9aceafc214e
GIT binary patch
literal 764
zcmV<Y0t5XcAa*h!XK8dGVs&n0Y-I{JF*i11HZ(V5G-fa|F=3DjY1F=3Dk>nV`efpW->T9
zHaRq5FkxajIX7e=3Da%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J_4tSiM%rOeW
zFc^m6J*UVnNYXY<e-LqZ5j;Wi=3DSwY`w#10k(YtvsMQ`Bt@(xeQfVA*n@=3DXop4TTn!
zL16DuJ2twq6g2tRMKQaKu}ITcsytf<3Iq;;sq+<D8$osC&^Z&SV<X(HoTe-f`GK@t
zUr%?J`@HnXax<U5vFno?E^D6BR%+WSt5mDCTq&)T_}ny<g8v0^1W#j-KS{g+{Ax_%
zoeOxJD=3DA7%RY)<hG_y=3DiN=3D-9J1R`VeB%_q%Bx5tnq!dHrM8o7X6Y~@!GqdCruEf%k
zjQk>nfTF6@+{)skO^M|S-bIz^sYMDl1=3D(PRLwasvW{zHRey*K@p}CoXxq*SHg@J;$
zfuVr`7f>`ev!o=3DId=3Dt3bGK-2!6d(q10RS>NJ(sNlc$_mdFfcPQQ7B0*F3~MWOwLYB
zPt`TnOU+?8{QsK66E4Och3_*yDxZ7#`d4InH~?-v6EVFPc$|%pu};G<5QcX@#VHx;
zAe{^9=3D8P<i6++#Q_(&`qJGGq(-oADz5}*!j=3DTHCt>CS!ML*|rmq2ZlI#+_mZhzKu*
z!j%HvAvpf9137%P-dI0s$Q27w3{PR^rQ|eBIWI|Xw~0>VJxwaau_pFc{WBj|8#!r^
zl4lwcG`oBC&~#l*9XKW%yoQ3RxQE9u&+IeBPhH+M^K&ot9WtyhW81d0=3DHLPuAq~H+
z{?Bz-&;YU%08KTiru%0xICHZsml#ggFl>GozPvX+m%T|aab$4@dOmZKZ-82Oocqgk
zfN8=3D^Mx%+dvL`z+S_1$xk_E-B0(hJ=3DG%zqTF;OT<EiTb5NKDR7Oi$G{)=3DSM{_|*7r
u)@}ylE0g<w=3DN^#d`mrn7Obq~SKoSRnmV8868k8_begWiOH93;r{Y0W%$xO2V
literal 0
HcmV?d00001
diff --git a/test/lisp/package-vc-resources/test-package-4.bundle b/test/li=
sp/package-vc-resources/test-package-4.bundle
new file mode 100644
index 0000000000000000000000000000000000000000..bbe907981201692e12ac226886c=
00fbdfb368179
GIT binary patch
literal 767
zcmV<b0s#FZAa*h!XK8dGVs&n0Y-I{&H!(RhW@0rqH#uT4VL4+kF*Y+bH!w6cH!?9Y
zGi5PhH#RUeVKHGKa%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J_4tSiE&N~VM
zF%*U2KC4JCNS-$dh}hc*t{{(_anQ^RF(PB>-rSdi;sWdrfAMizMWk9w3uto!shABY
zoHZdKk6Hjj$sBT%6=3DX8`ibJDT7|vt{&l5NSHlhL}1gfAt@Q{MwQ7Dy(zqQj?>7hQb
z%-7e`-|4>29ag%T&Y!XCitjJ$IF>Et1{gSFjiD>X86!(AeQWrqu-y9z<cM(`68%c#
z4b3b{ADs($oGU3xO;xZow@6AdN-{CCFf=3DhXH?uG{wXiTwwMb1&1agg&QVfku49rtg
zQ@9dKOEU6{6atE>QgbVdk2WQiD|i=3DGrl%Gu*c4=3Dg84l^WiJ3Wi$@#f<3Wnxp24+CB
zO)V6(4GawoxPYR$nI$Eu<eR|dmRVF>q5v_73jj%ZJX);+c$_mdFfcPQQ7B0*F3~MW
zOwLYBPt`TiOU+?8*!umO)HOBx!tNzkCLI@insxb;EdXuT6Ck}8c$|%pu};G<5QcX@
z#VHx;Ae{?>$r)KXR;Xe>;v=3Dze>|i?;eS7RuBtRY5&Y%AO)1CXihs-JCLc<%4j1P((
zAR-(Jg$o6|L2&$G2Xgpgy|I4OkSi9V7<OUirQ|eBIWI|Xw~3DAJxwaau_pEx{S&{h
zHgeJ+CC@Y@Xzp*-UDI_n^~^EZ;58If#XUTRd1jv}o^*NF%+I~lcgV0lk8Ru1nu7~u
zgf#rR`ajoUK?BH605sL4n(m*);LO#sTw*v{!?5{X`0`%)T=3Dpix#F51(e86*;Z-82O
zocqgkfN8=3D^Mx%+dvL`z+S_1$xk_E-B0(hJ=3DG%zqTF;OT<EiTb5NKDR7Oi$G{(M!!?
x$dsHgjlm{}Pht@ti(5(G-38flk^nL^4d7>+=3DuOEN5Y#?NZ~O8I;v<$%y$7D{N^1ZB
literal 0
HcmV?d00001
diff --git a/test/lisp/package-vc-resources/test-package-5.bundle b/test/li=
sp/package-vc-resources/test-package-5.bundle
new file mode 100644
index 0000000000000000000000000000000000000000..b64e154c91c898f8fabec2aad27=
954c78b61cc54
GIT binary patch
literal 845
zcmY#ZC^J$>&n!_$D$PsDN#!!LOf#`eOtVN!Nli2|FgCR`OExk$NlUggH83+wG%`#|
zHL<ibFgH*rN=3D+-)&qz&7Db~+TEG|hc;^GQ$boORoU|<4bj(L0)bLO6L<T_*^;Bc|l
zZ{l8snOi*76dv8{eZYC?%#yBUx`s-nFYoS|?wbGL-DmOjVriXfTiuuiCAo9o*knH!
z@O-^Q$;9g?#}z4|U=3D5p)mj_D1*x!VFkdU?DmWwTF^i|=3DxSC!PQ*;%lD`Nk8@l|}RN
z--lP6sGV7@S7aQ!Z{zD?i}>q>XQFpnoN|0EJw=3D<<tMloz;<bPFEA+`6Z+zk}Brmwy
zt7R@X$dR^Oha3bP9@hCA?o}|pxxro`DK+`As9K?!-YylNFqLWd&Q@zyG4DREy>FG0
z!y)zCk@5xs$umzbZIF<Dd1L!J$HJ3EuWo)=3DJI}p!vE34#&#zCGTf8vpIFz=3DlCfQu%
z-1SoXX}S~2U##qvNNjD%u-pD5>S_JKH=3DECi)=3Dj8nUVhEy_Ik#OImU(zOs#XyJYr(|
z7^xS&{KMJX(=3DL|Zot1t5rp&oePGN=3D>hj`4_G6B_@7#J8E25NZf>Rr_J@Hyw_<A2rk
zs`uH%4>vCUjEY%QelDhe#<SZ^ll$}6#mr}B2!9~hzE`|rPVa<`euoVN+RE*ZYD&IR
zn9J>?bMC~YjZUJ!1?4+ili6>td~rK@x)S5717-id{Gb2s&Uf1sKS^<^dl@M;0dE)t
z9|mZ|XguI;ddzP<;jsAY-mi<>Vm1mK-N0?Euev<(RHbLtZr>7>_nAS8eWn}tznK4{
zcI(8+Y?_tJ6djA}SHGLJZuQFazLRY07cS6x_t5Z+@o%4xOHS`jt9!R}pL5&S%ADKN
zuF1qGC@*<<{p$aneB4qFWlRfJs$DJlufvwUZrW3!!xyF6&b~i1{rjoso6I@Y`gH6V
z>z#_{<TpfD%=3Dvw~q#^T=3DkK5wT&70J%4WpPDj3=3D=3DkMG4imGn?%BLrW#!JxwXgzf+~-
zu;<M+&M=3D0J*LY6i4b>BZNxOaq9rMh5_vpvEzprjTS{&v!mx;k6L!ey1XmU&(Q}qV3
QpO%k*%lPhdDEspY0DfPAh5!Hn
literal 0
HcmV?d00001
diff --git a/test/lisp/package-vc-resources/test-package-6.bundle b/test/li=
sp/package-vc-resources/test-package-6.bundle
new file mode 100644
index 0000000000000000000000000000000000000000..4294c885a0b7d5bd5bf665aa727=
4988f3692d36b
GIT binary patch
literal 843
zcmY#ZC^J$>&n!_$D$PsDN##mSG)+lNN=3Di1hG%!w0u{1C>H#Ij&O*2kQF-}W1N-{Ds
zG%!gvGBZ>tN=3D+-)&qz&7Db~+TEG|hc;^GQ$boORoU|<4bj(L0)bLRFqavd@dV0d5Y
z`mX8Ct(3_P9p(B>`X1YFN15by3a)hj|7^d`FXrbaXA-@{E^<iUcZuHa;?Od$=3D_7Zp
z=3D+UO{ci6ObIag?=3DNp_hv-dwPQ_j;U+l?co02|DI&P7h8w%UW*g`d%cr+3wl$B|pE_
z9c{OJvUBp9?U$cw|JFPDZ`U)!w<cCh?P9CE)-y0(2?~zy`cogE{;)9P%ljpEkG;K2
z=3D5kle(bn|x4fQZJ-{@gv<ZJ5h>1AwYXy9$^WoEKzgNcu?x3`y%p{K8pp@*NRp~*8Z
z9o>^B^n*AwR(YLWt7CU-O2oPcu^}_(MJ-7Pp1_-CvE;d0+Orp`&!6AYl$bSJa)$IQ
zDG4d93~31|i2_E~Vq<Twpp)i}r*${4*x|yMBp}Y9y2iF=3DJ!8cjV?zd});VV$F|qM7
zhTBydZ`~j4GWD{NoG0sM(~f;?3=3DK;-?bk8^)tML=3D7#jv^c<Sn1)b;Q=3D=3DjY>p)%3FW
z*~A|Pk2f8BGiUcRKYQO#PvrcHta7#*h%%%$2p-uhUNNV4!bZQt1_Ev6_D3}(Un$Jx
zc1kL6o7N|~>PG($4;>ln8-A|$<#vm32C#4Yy!`+FlIQ#0D;A&Hap8lT^5f<t_70AA
zr-x3A`2sTaHyUO3MdYuMH+|C8s?ioZqf*n7H~5_QrQ5lSlq>xwa}}=3DX{OkJv$otj3
zb4)x=3D8uN0_`W;<*y(HGxw%Et4f|oV4kiS21-p%wb_1Jr+pNsXs${MXXpL~1UmS+!`
zBo%r0ulsktG~xooCSe9&)0NA9ryE)nZ`GMD(Ra-tr%rs|o^ZSAdp!*bQ$BJw9w}a!
z-w<6f=3DlAK7hRj1gZi_oNZ&J55jACXmp2T_-B~;ta&GXg%%JeRK^VhXGcHejWJ@V|w
z%cTrkS$G%Y4b>N4j6Ckv2HbiZFtg-fZ+uaezU%8E2LJg2m3l=3DroAjc2{>v0T*!+!6
KWx7=3D8tB(L0@n)L<
literal 0
HcmV?d00001
diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
new file mode 100644
index 00000000000..1e9b96df866
--- /dev/null
+++ b/test/lisp/package-vc-tests.el
@@ -0,0 +1,601 @@
+;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
+
+;; Copyright (C) 2025 Free Software Foundation, Inc.
+
+;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
+;; Keywords: package
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These tests focus on verifying post conditions for `package-vc'
+;; operations on packages. Since installing a package changes the state
+;; of running process these tests are ment to be executed in order, as
+;; denoted by digits in their name. Also in many cases the subsequent
+;; test often depends on the passing of the previous test.
+
+;; It is recommended to run this suite in a separate process, for
+;; example, in root of Emacs source directory:
+
+;; ./src/emacs -batch \
+;; -l ../test/lisp/package-vc-tests.el \
+;; -f ert-run-tests-batch-and-exit
+
+;;; Code:
+
+(require 'package-vc)
+(require 'package)
+(require 'vc-git)
+(require 'vc)
+(require 'cl-lib)
+(require 'ert)
+
+(defvar package-vc-tests-dir nil)
+
+(defvar package-vc-tests-resources-dir
+ (file-name-concat (file-name-directory
+ (or load-file-name buffer-file-name))
+ "package-vc-resources"))
+(defvar package-vc-tests-packages nil)
+
+(defmacro with-package-vc-tests-enviroment (&rest body)
+ "Eval BODY with test environment."
+ (declare (debug t))
+ ;; Test packages sources are stored in bundle files produced by
+ ;; git-bundle(1) and are stored in directory package-vc-resources.
+ ;; Before executing body make sure that:
+ `(let* (package-archives
+ (package-user-dir (expand-file-name "elpa"
+ package-vc-tests-dir))
+ ;; - test packages are recognised by `package' and
+ ;; `package-vc' internals:
+ (package-archive-contents
+ (list
+ (list 'test-package-1
+ (package-desc-create
+ :name 'test-package-1
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras
+ (list
+ `(:url
+ . ,(format "%s/test-package-1.bundle"
+ package-vc-tests-resources-dir))
+ '(:commit
+ . "7b8e3322055287ef1580432014de3a2d5f383d79")
+ '(:revdesc
+ . "7b8e33220552"))))
+ (list 'test-package-3
+ (package-desc-create
+ :name 'test-package-3
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras
+ (list
+ `(:url
+ . ,(format "%s/test-package-3.bundle"
+ package-vc-tests-resources-dir))
+ '(:commit
+ . "7176b647c4f021f811fb7cf27f288694a0ab997d")
+ '(:revdesc
+ . "7176b647c4f0"))))))
+ (package-vc--archive-spec-alists
+ (list
+ (list 'test-elpa
+ (list 'test-package-1
+ :url (format "%s/test-package-1.bundle"
+ package-vc-tests-resources-dir)
+ :branch "master")
+ (list 'test-package-3
+ :url (format "%s/test-package-3.bundle"
+ package-vc-tests-resources-dir)
+ :branch "master"))))
+ (package-vc--archive-data-alist
+ (list
+ (list 'test-elpa :version 1 :default-vc 'Git)))
+ ;; - `vc-guess-backend-url' is recognising bundles as `Git'
+ ;; repositories:
+ (vc-clone-heuristic-alist
+ (cons
+ (cons (rx (literal package-vc-tests-resources-dir) "/"
+ (one-or-more any) ".bundle"
+ string-end)
+ 'Git)
+ vc-clone-heuristic-alist))
+ ;; - define test packages and their checkout locations
+ (package-vc-tests-packages
+ `(;; checkout and install with `package-vc-install' (on ELPA)
+ (test-package-1
+ . ,(expand-file-name "test-package-1"
+ package-user-dir))
+ ;; checkout and install with `package-vc-install' (not on
+ ;; ELPA)
+ (test-package-2
+ . ,(expand-file-name "test-package-2"
+ package-user-dir))
+ ;; checkout with `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-3
+ . ,(expand-file-name "test-package-3"
+ package-vc-tests-dir))
+ ;; checkout with git and install with
+ ;; `package-vc-install-from-checkout'
+ (test-package-4
+ . ,(expand-file-name "test-package-4"
+ package-vc-tests-dir))
+ ;; sources in "lisp" sub directory, checkout and install
+ ;; with `package-vc-install'
+ (test-package-5
+ . ,(expand-file-name "test-package-5"
+ package-user-dir))
+ ;; sources in "lisp" sub directory, checkout with git and
+ ;; install with `package-vc-install-from-checkout'
+ (test-package-6
+ . ,(expand-file-name "test-package-6"
+ package-vc-tests-dir))
+
+ ;; TODO: a package with source files in a non-standard
+ ;; :lisp-dir, a custom Makefile and non-standard :doc (both
+ ;; methods of installation)
+ )))
+ ;; - test directory exists:
+ (should package-vc-tests-dir)
+ (should (file-directory-p package-vc-tests-dir))
+ ;; - resources are available:
+ (should package-vc-tests-resources-dir)
+ (should (file-directory-p package-vc-tests-resources-dir))
+ ;; - `package' has been initialised:
+ (should package--initialized)
+
+ ,@body))
+
+
+;; TODO: add test for deleting packages, with asserting
+;; `package-vc-selected-packages'
+
+;; TODO: clarify `package-vc-install-all' behaviour with regards to
+;; packages installed with `package-vc' but not stored in
+;; `package-vc-selected-packages' i.e., packages from ELPAs
+
+(defun package-vc-tests-package-desc (package &optional installed)
+ "Return descriptor of PACKAGE.
+When INSTALLED is non-nil the descriptor will come from `package-alist'.
+Otherwise the descriptor will be from `package-archive-contents'. This
+is to mimic `package-vc--read-package-desc'."
+ (cadr (assoc (if (stringp package) package (symbol-name package))
+ (if installed package-alist package-archive-contents)
+ #'string=3D)))
+
+(defun package-vc-tests-package-lisp-dir (pkg)
+ "Return a Lisp directory of PKG."
+ (when-let* ((checkout-dir (alist-get pkg package-vc-tests-packages)))
+ (cond
+ ((member pkg '(test-package-5 test-package-6))
+ (expand-file-name "lisp" checkout-dir))
+ (t checkout-dir))))
+
+(defun package-vc-tests-package-main-file (pkg)
+ "Return a main file of PKG."
+ (format "%s/%s.el" (package-vc-tests-package-lisp-dir pkg) pkg))
+
+(defun package-vc-tests-load-history-position (pkg type)
+ "Return a PKG's position in `load-history'.
+If TYPE is `:autoloads' return a position of a PKG autoloads file.
+Otherwise, if TYPE is `:main' return a position of PKG main file (not
+compiled). Otherwise, if TYPE is `:main-compiled' return a position of
+PKG compiled main file. Otherwise, if TYPE is `:marker' return a
+position of a marker PKG."
+ (let ((pkg-file (pcase type
+ (:autoloads
+ (rx (literal
+ (format "%s/%s/%s-autoloads.el"
+ package-user-dir pkg pkg))
+ string-end))
+ (:main
+ (rx
+ (literal
+ (format "%s"
+ (package-vc-tests-package-main-file pkg)))
+ string-end))
+ (:main-compiled
+ (rx
+ (literal
+ (format "%s"
+ (package-vc-tests-package-main-file pkg)))
+ "c"
+ string-end))
+ (:marker
+ (rx "/" (literal (format "%s" pkg))))))
+ (interesting-entry
+ (rx string-start
+ (literal (file-truename package-vc-tests-dir)))))
+ (cl-position-if
+ (lambda (file)
+ (string-match pkg-file file))
+ (cl-remove-if-not
+ (lambda (file-name)
+ (string-match interesting-entry file-name))
+ (mapcar
+ #'file-truename
+ (cl-remove-if-not
+ #'stringp
+ (mapcar #'car load-history)))))))
+
+(defun package-vc-tests-assert-delete-elc ()
+ "Assert that .elc files are in expected directories and delete them.
+When ALL is non nil, check all packages under test."
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (let* ((dir (package-vc-tests-package-lisp-dir pkg))
+ (elc-files (directory-files dir nil (rx ".elc" string-end)))
+ (autoloads-rx (rx
+ (literal (format "%s-autoloads.el" pkg))
+ string-end)))
+ (should-not (equal (cons dir elc-files)
+ (list dir)))
+ (should-not (cl-find-if (lambda (elc)
+ (string-match autoloads-rx elc))
+ elc-files))
+ (dolist (elc-file elc-files)
+ (delete-file (expand-file-name elc-file dir))))))
+
+(defun package-vc-tests-assert-package-alist (version)
+ "Assert that entries in `package-alist' have correct VERSION and dir."
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
+ (should (equal (file-name-as-directory
+ (expand-file-name (format "%s" pkg)
+ package-user-dir))
+ (file-name-as-directory
+ (package-desc-dir pkg-desc))))
+ (should (equal (list pkg version)
+ (list pkg (package-desc-version pkg-desc)))))))
+
+(defun package-vc-tests-reset-heads ()
+ "Reset to HEAD^ checkouts `package-vc-tests-packages'."
+ (mapcar (lambda (pkg-checkout-dir)
+ (let ((default-directory (cdr pkg-checkout-dir)))
+ (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))
+ package-vc-tests-packages))
+
+(defun package-vc-tests-packages-heads ()
+ "Return HEAD revisions of `package-vc-tests-packages'."
+ (mapcar (lambda (pkg-checkout-dir)
+ (let ((default-directory (cdr pkg-checkout-dir)))
+ (cons (car pkg-checkout-dir)
+ (vc-git-working-revision nil))))
+ package-vc-tests-packages))
+
+(ert-deftest package-vc-tests-000-install ()
+ (setq package-vc-tests-dir
+ (make-temp-file "package-vc-tests-"
+ t
+ (format-time-string "-%Y%m%d.%H%M%S")))
+ (package-initialize)
+ (package-vc--archives-initialize)
+ (eval
+ '(with-package-vc-tests-enviroment
+ (push (list (format "%s/install-begin" package-vc-tests-dir))
+ load-history)
+ (package-vc-install 'test-package-1)
+ (should-not (alist-get "test-package-1"
+ package-vc-selected-packages
+ nil nil #'string=3D))
+
+ (let ((bundle (format "%s/test-package-2.bundle"
+ package-vc-tests-resources-dir)))
+ (package-vc-install `(test-package-2
+ :url ,bundle
+ :branch "master"))
+ (should (equal bundle
+ (plist-get (alist-get "test-package-2"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-3"
+ package-vc-tests-dir)))
+ (package-vc-checkout (package-vc-tests-package-desc
+ 'test-package-3)
+ checkout-dir)
+ (package-vc-install-from-checkout checkout-dir)
+ (should (equal (format "file://%s" checkout-dir)
+ (plist-get (alist-get "test-package-3"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-4"
+ package-vc-tests-dir)))
+ (shell-command
+ (format "git clone -b master %s/test-package-4.bundle %s"
+ package-vc-tests-resources-dir
+ checkout-dir))
+ (package-vc-install-from-checkout checkout-dir "test-package-4")
+ (should (equal (format "file://%s" checkout-dir)
+ (plist-get (alist-get "test-package-4"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((bundle (format "%s/test-package-5.bundle"
+ package-vc-tests-resources-dir)))
+ (package-vc-install `(test-package-5
+ :url ,bundle
+ :branch "master"))
+ (should (equal bundle
+ (plist-get (alist-get "test-package-5"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-6"
+ package-vc-tests-dir)))
+ (shell-command
+ (format "git clone -b master %s/test-package-6.bundle %s"
+ package-vc-tests-resources-dir
+ checkout-dir))
+ (package-vc-install-from-checkout checkout-dir "test-package-6")
+ (should (equal (format "file://%s" checkout-dir)
+ (plist-get (alist-get "test-package-6"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (push (list (format "%s/install-end" package-vc-tests-dir))
+ load-history)
+
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc))))
+
+(ert-deftest package-vc-tests-001-main-file ()
+ (eval
+ '(with-package-vc-tests-enviroment
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (should (equal (package-vc--main-file
+ (package-vc-tests-package-desc pkg t))
+ (package-vc-tests-package-main-file pkg)))))))
+
+(ert-deftest package-vc-tests-002-commit ()
+ (eval
+ '(with-package-vc-tests-enviroment
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (let ((commit (package-vc-commit
+ (package-vc-tests-package-desc pkg t))))
+ (should-not (equal (cons pkg commit)
+ (list pkg)))
+ (should-not (equal (list pkg "unknown")
+ (list pkg commit))))))))
+
+(ert-deftest package-vc-tests-003-load-history-after-install ()
+ (eval
+ '(with-package-vc-tests-enviroment
+ (let ((install-begin
+ (should (package-vc-tests-load-history-position
+ 'install-begin :marker)))
+ (install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker))))
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (< install-end autoloads-pos install-begin)))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled)))))))
+
+(defmacro package-vc-tests-package-vc-upgrade-wait (seconds count &rest bo=
dy)
+ "Wait up to SECONDS for COUNT packages upgrading BODY.
+Return nil on timeout or the value of last form in BODY."
+ (declare (indent 2))
+ `(letrec ((packages-count ,count)
+ (post-vc-command
+ (lambda (command _ flags)
+ ;; A crude filter for vc commands
+ (when (and (equal command "git")
+ (string-prefix-p "*vc-git" (buffer-name)))
+ (cl-decf packages-count)))))
+ (add-hook 'vc-post-command-functions post-vc-command 100)
+ (unwind-protect
+ (with-timeout (,seconds nil)
+ (prog1
+ (progn ,@body)
+ (while (not (eql packages-count 0))
+ (sleep-for 0.1))))
+ (remove-hook 'vc-post-command-functions post-vc-command))))
+
+(ert-deftest package-vc-tests-004-upgrade-all ()
+ (eval
+ '(with-package-vc-tests-enviroment
+ (push (list (format "%s/upgrade-all-begin" package-vc-tests-dir))
+ load-history)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (package-vc-tests-reset-heads)
+ (should
+ (package-vc-tests-package-vc-upgrade-wait
+ 5 (length package-vc-tests-packages)
+ (package-vc-upgrade-all)
+ t))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (push (list (format "%s/upgrade-all-end" package-vc-tests-dir))
+ load-history)
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc))))
+
+(ert-deftest package-vc-tests-005-load-history-after-upgrade-all ()
+ (eval
+ '(with-package-vc-tests-enviroment
+ (let ((upgrade-all-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-all-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker))))
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (< upgrade-all-end autoloads-pos upgrade-all-begin))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))))))))
+
+(ert-deftest package-vc-tests-006-require ()
+ (eval
+ '(with-package-vc-tests-enviroment
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should (require pkg))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg)))))
+ (let ((upgrade-all-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker))))
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (let ((main-pos (should (package-vc-tests-load-history-position
+ pkg :main))))
+ (should (< main-pos upgrade-all-end)))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled)))))))
+
+(ert-deftest package-vc-tests-007-upgrade ()
+ (eval
+ '(with-package-vc-tests-enviroment
+ (push (list (format "%s/upgrade-begin" package-vc-tests-dir))
+ load-history)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (package-vc-tests-reset-heads)
+ (should
+ (package-vc-tests-package-vc-upgrade-wait
+ 5 (length package-vc-tests-packages)
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (package-vc-upgrade
+ (package-vc-tests-package-desc pkg t))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function
+ (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg)))))
+ t))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (push (list (format "%s/upgrade-end" package-vc-tests-dir))
+ load-history)
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc))))
+
+(ert-deftest package-vc-tests-008-load-history-after-upgrade ()
+ (eval
+ '(with-package-vc-tests-enviroment
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker))))
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (< upgrade-end autoloads-pos upgrade-begin))
+ (should (< upgrade-end main-pos upgrade-begin))
+ (should
+ (< upgrade-end main-compiled-pos upgrade-begin))))))))
+
+(ert-deftest package-vc-tests-009-rebuild ()
+ (eval
+ '(with-package-vc-tests-enviroment
+ (package-vc-tests-reset-heads)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (dolist (pkg (mapcar #'car package-vc-tests-packages))
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function
+ (intern (format "%s-func" pkg)))))
+ (should (fboundp (intern (format "%s-old-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function
+ (intern (format "%s-old-func" pkg))))))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (package-vc-tests-assert-package-alist '(0 1))
+ (package-vc-tests-assert-delete-elc))))
+
+(ert-deftest package-vc-tests-010-prepare-patch ()
+ (eval
+ '(with-package-vc-tests-enviroment
+ (dolist (pkg-checkout-dir package-vc-tests-packages)
+ (cl-letf* ((call-count 0)
+ ((symbol-function #'package-maintainers)
+ (lambda (&rest _)
+ "test-maintainers"))
+ ((symbol-function #'vc-prepare-patch)
+ (lambda (addressee subject revisions)
+ (should (equal (file-name-as-directory
+ default-directory)
+ (file-name-as-directory
+ (cdr pkg-checkout-dir))))
+ (should (equal "test-maintainers" addressee))
+ (should (equal "test-subject" subject))
+ (should (equal "test-revisions" revisions))
+ (cl-incf call-count))))
+ (package-vc-prepare-patch (package-vc-tests-package-desc
+ (car pkg-checkout-dir)
+ t)
+ "test-subject"
+ "test-revisions")
+ (should (eql 1 call-count)))))))
+
+(ert-deftest package-vc-tests-011-log-incoming ()
+ (eval
+ '(with-package-vc-tests-enviroment
+ (dolist (pkg-checkout-dir package-vc-tests-packages)
+ (cl-letf* ((call-count 0)
+ ((symbol-function #'vc-log-incoming)
+ (lambda ()
+ (interactive)
+ (should (equal (file-name-as-directory
+ default-directory)
+ (file-name-as-directory
+ (cdr pkg-checkout-dir))))
+ (cl-incf call-count))))
+ (package-vc-log-incoming (package-vc-tests-package-desc
+ (car pkg-checkout-dir) t))
+ (should (eql 1 call-count)))))))
+
+(provide 'package-vc-tests)
+
+;;; package-vc-tests.el ends here
--=20
2.51.0
--=-=-=
Content-Type: text/plain
Cheers,
PK
[1] https://xkcd.com/1172/
[2] https://github.com/emacs-exordium/exordium/blob/4e4d49db3495f625faf734736b4d19396387b105/modules/init-vc-checkout.el
[3] https://gitweb.git.savannah.gnu.org/gitweb/?p=emacs.git;a=blob;f=lisp/emacs-lisp/package.el;h=c39c8bf24cc8525c1e5e2d6cc617016991291ad3;hb=11915c6acb9f5463515d4f3891ad8d7134685838#l897
[4] https://gitweb.git.savannah.gnu.org/gitweb/?p=emacs.git;a=blob;f=lisp/emacs-lisp/package.el;h=c39c8bf24cc8525c1e5e2d6cc617016991291ad3;hb=11915c6acb9f5463515d4f3891ad8d7134685838#l901
[5] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=79188#49
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Sun, 26 Oct 2025 12:45:02 +0000
Resent-Message-ID: <handler.79188.B79188.17614826653191 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17614826653191
(code B ref 79188); Sun, 26 Oct 2025 12:45:02 +0000
Received: (at 79188) by debbugs.gnu.org; 26 Oct 2025 12:44:25 +0000
Received: from localhost ([127.0.0.1]:44581 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vD06d-0000pH-2d
for submit <at> debbugs.gnu.org; Sun, 26 Oct 2025 08:44:25 -0400
Received: from mout02.posteo.de ([185.67.36.66]:33565)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1vD06M-0000nW-NQ
for 79188 <at> debbugs.gnu.org; Sun, 26 Oct 2025 08:44:16 -0400
Received: from submission (posteo.de [185.67.36.169])
by mout02.posteo.de (Postfix) with ESMTPS id BEB87240101
for <79188 <at> debbugs.gnu.org>; Sun, 26 Oct 2025 13:43:55 +0100 (CET)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1761482635; bh=1mgeg1m96cMGE3v4Ml0LZ/qJcCFMF6Z3LwrLamJHdCY=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:Content-Transfer-Encoding:From;
b=m8ZQn1sXrTvBxWqY66S0t0P1nJL2UyxsAaAYTQRU8LLjD0KryIoZQqlbOLZXKH3fo
TUbEuAxgiZxl4kEOOYKHjihm/eT4O6l0oLfrIjnfQ5TUJgCfH24N7Rg7+dBjc6RdhU
yiIKbNyXi9v6Ee3qP12MeqmQhKuobZKECikuJ65hzS7A9RL5aqQtphtGAw097JFKaD
X3ywgkTNpnLk3/F7z/BrPihdNaYKsVH5qIxgCDIPijgWN1Q3FjmCs8Kcl2IaF6j/kD
aMzfLQk8pR8WBSEhW8b3S+ezkR+YUqW6RatrAT965PA8RQKtn/bzDevcQLwinLf6ut
yz12QctzSj9kw==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4cvbt30zb1z9rxW;
Sun, 26 Oct 2025 13:43:55 +0100 (CET)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2a51k4jd5.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<87jz3f2svk.fsf@HIDDEN> <m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
<m2a51k4jd5.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Sun, 26 Oct 2025 12:43:55 +0000
Message-ID: <87a51du92y.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -0.7 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.7 (-)
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> Philip Kaludercic <philipk@HIDDEN> writes:
>
>> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>>
>> [...]
>>>
>>> So as I suspected not everything was all right. With the patches up to
>>> this message, when a user installed a package with
>>> `package-install-from-checkout' and then subsequently upgraded it with
>>> `package-upgrade' then the pkg-desc entry for the package in
>>> `package-alist' become corrupted. After the installation the `dir' slot
>>> in `pkg-desc' has been pointing to the `pkg-dir', i.e., a directory
>>> under `package-user-dir' that contains "-pkg.el" and forwarding
>>> "-autoloads.el" files. However, after the upgrade the slot `dir' points
>>> to checkout directory. To my understanding this is undesirable, as for
>>> example a subsequent call to `package-delete' will delete the checkout
>>> directory leaving the `pkg-dir' with forwarding "-autoloads.el" file
>>> that tries load non existent "-autoloads.el".
>>
>> I am not sure if I have mentioned this before, I have been thinking
>> about deprecating `package-install-from-checkout' because of
>> complications like these. I don't mean to be ungrateful for the work
>> you have put in until now (even if we do deprecate from-checkout your
>> tests are still a great addition), but in retrospect it seems that we
>> shouldn't have made this feature a part of package-vc.el. To replace
>> it, I have been thinking about taking something like site-lisp from ELPA
>> and reworking it into the core. What do you think of that? The
>> functionality would stay the same, just that instead of having to
>> install a specific package by using a command, you can just throw a
>> git-clone into a ~/.config/emacs/site-lisp/ directory. You would still
>> get byte-compilation, autoload scraping, but loose automatic dependency
>> resolution and the building of documentation. Considering the target
>> audience of package-vc-install-from-checkout, I don't think that this is
>> unreasonable.
>
> Removal of `package-vc-install-from-checkout' is not something I would
> like to see.=20=20
We would of course begin by deprecating it, revising my previous
message, your changes should all be welcome, but then in two or three
versions I would vote to remove it.
> I really liked it since I discovered it a few years ago
> and organised my workflow around it [1]. I liked the simplicity of it
> and picked up it instead of going a route of straight etc. I am using a
> custom Emacs configuration, where I developed an extension to
> `use-package' such that the shared configuration of packages can be
> used, allowing for ad hoc replacement of chosen packages with
> development versions [2]. Reorganising everything, while technically
> feasible will likely be a major undertaking from my side. Could you
> give me some more details on the ~/.config/emacs/site-lisp approach, and
> I could see how easy/difficult it could be to switch?
Skimming over the source code, it might just be that you would have to
replace `package-vc-install-from-checkout' with a `make-symbolic-link'
(I am consciously ignoring systems where this is a problem) and perhaps
a call to site-lisp to compile everything.
>>> Please find a patch for that:
>>>
>>> From 2b3375490fba5dc00ba7305e670286fb41401cbc Mon Sep 17 00:00:00 2001
>>> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
>>> Date: Wed, 15 Oct 2025 08:00:02 +0100
>>> Subject: [PATCH] Fix incorrect pkg-desc after package-vc-upgrade
>>>
>> [...]
>>>=20=20
>>> -(defun package-vc--unpack-1 (pkg-desc pkg-dir)
>>> - "Prepare PKG-DESC that is already checked-out in PKG-DIR.
>>> -This includes downloading missing dependencies, generating
>>> -autoloads, generating a package description file (used to
>>> -identify a package as a VC package later on), building
>>> -documentation and marking the package as installed."
>>> - (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>>> +(defun package-vc--unpack-1 (pkg-desc)
>>
>> I just went over all the call-sites of this function, and the change
>> make sense regardless of what we decide w.r.t. the above, as we only
>> needed the distinction between the two due to -from-checkout.
>
> I am not sure that I understood what you meant by "we only needed the
> distinction between the two due to -from-checkout.", but I gather the
> sentiment is that the argument removal was a good idea.=20=20
I meant the distinction between pkg-desc's directory and pkg-dir.
> I think that
> tests are executing reasonable amount of scenarios to give extra
> confidence it won't break Emacs code.
Presently I am cautious, because there seems to be a lot of small things
that can break that affect just one persons workflow.
>>> + "Prepare PKG-DESC that is already checked-out.
>>> +The checkout directory is determined by relevant pkg-spec or from `dir'
>>> +slot of PKG-DESC. This includes downloading missing dependencies,
>>> +generating autoloads, generating a package description file (used to
>>> +identify a package as a VC package later on), building documentation a=
nd
>>> +marking the package as installed."
>>> + (let* ((pkg-dir (package-desc-dir pkg-desc))
>>> + (pkg-spec (package-vc--desc->spec pkg-desc))
>>> (checkout-dir (package-vc--checkout-dir pkg-desc))
>>
>> We should really write down (in a comment) what the different
>> directories mean, just to make it easier to read this stuff.
>
> I added some in a new patch. Please let me know what you think.
>
>>> (lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
>>> missing)
>>> @@ -567,12 +569,24 @@ package-vc--unpack-1
>>> (setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
>>>=20=20
>>> ;; Update package-alist.
>>> - (let ((new-desc (package-load-descriptor pkg-dir))
>>> - (compile-desc (package-desc-create :dir lisp-dir)))
>>> + (let* ((new-desc (package-load-descriptor pkg-dir))
>>> + (compile-desc (package-desc-create :name (package-desc-name=
new-desc)
>>
>> Why do we need the :name here?
>
> This is because `package--reload-previously-loaded' uses that slot when
> calculating autoload file name [3] as well as to display warnings [4].
OK!
>
>> [...]
>>> (defun package-vc--read-package-name (prompt &optional allow-url insta=
lled)
>>> "Query the user for a VC package and return a name with PROMPT.
>>> @@ -782,7 +798,7 @@ package-vc-upgrade
>>> ;;
>>> ;; If there is a better way to do this, it should be done.
>>> (cl-assert (package-vc-p pkg-desc))
>>> - (letrec ((pkg-dir (package-vc--checkout-dir pkg-desc))
>>> + (letrec ((checkout-dir (package-vc--checkout-dir pkg-desc))
>>
>> I would avoid renaming variables if it is not necessary, as it pollutes
>> the Git log.
>
> I understand that sentiment. I changed the variable name, such that the
> name consistently reflects semantic meaning of it across the file. For
> that reason I have chosen to not update it in the attached patch, but
> will change it if you think that sacrificing semantic meaning is a
> better compromise than polluting Git log.
Thanks!
>> [...]
>>> diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
>>> index ba9999c20e6..fb073579bc1 100644
>>> --- a/lisp/emacs-lisp/package.el
>>> +++ b/lisp/emacs-lisp/package.el
>>> @@ -903,6 +903,14 @@ package--reload-previously-loaded
>>> (mapc (lambda (c) (load (car c) nil t))
>>> (sort result (lambda (x y) (< (cdr x) (cdr y))))))))
>>>=20=20
>>> +(defun package--add-info-node (pkg-dir)
>>> + "Add info node located in PKG-DIR."
>>> + (when (file-exists-p (expand-file-name "dir" pkg-dir))
>>> + ;; FIXME: not the friendliest, but simple.
>>> + (require 'info)
>>> + (info-initialize)
>>> + (add-to-list 'Info-directory-list pkg-dir)))
>>
>> LGTM!
>
> =F0=9F=98=8E
>
>> [...]
>> Gnus cut of the remaining response so I sent my previous message to earl=
y!
>
> No problem. Consolidating here.
>
>> [...]
>>> (defvar package-vc-tests-dir
>>> (make-temp-file "package-vc-tests-" t (format-time-string "-%Y%m%d.%H=
%M%S")))
>>
>> Should the global variable have a side-effect at declaration-time? I
>> don't think we can be sure that the file will still exist if you load
>> the file at one point and run the tests later (even if you re-load the
>> file, the "new" value won't get re-evaluated).
>>>
>>> (setq package-user-dir (expand-file-name "elpa" package-vc-tests-dir))
>>
>> Please don't use setq on the top-level.
>>
>
> I have updated the whole test environment approach. I added a new macro
> to wrap up the whole setup, with a few extra checks before running any
> test. This has a drawback of increasing the indentation depth by 2. Do
> thing this is a good approach, or perhaps you can recommend a different
> technique?
Sounds good, will comment on it below.
> Thanks for that =F0=9F=92=AF!
>
>> [...]
>>> (package-vc-install '(ultra-scroll
>>> :url "https://github.com/jdtsmith/ultra-scroll.=
git"))
>>> (should (equal "https://github.com/jdtsmith/ultra-scroll.git"
>>> (plist-get (alist-get "ultra-scroll"
>>> package-vc-selected-packages
>>> nil nil #'string=3D)
>>> :url)))
>>
>> I feel like we should test more than just the :url.
>
> In this particular case this is the only value set.
Ah yes, nevermind then.
>>> (let ((checkout-dir (expand-file-name "gcmh" package-vc-tests-dir)))
>>> (package-vc-checkout (package-vc-tests-package-desc 'gcmh)
>>> checkout-dir)
>>> (package-vc-install-from-checkout checkout-dir)
>>> (should (equal (format "file://%s" checkout-dir)
>>> (plist-get (alist-get "gcmh"
>>> package-vc-selected-packages
>>> nil nil #'string=3D)
>>> :url))))
>>
>> These should also be separate tests, because they are not all testing
>> the same thing and it would be better if ERT can give you a better idea
>> to what went wrong if the tests are smaller.
>>
>
> I understand the idea (see comment below), but in this case ERT nicely
> prints a failing package name in every assertion, so I decided to keep
> it in a single test, as it nicely inserts the markers into
> `load-history' within a single function. Can work on breaking it down
> if you insist.
No, if ERT helps us out here, then it should be fine.
>> [...]
>>> (dolist (package package-alist)
>>> (dolist (pkg-desc (cdr package))
>>> (when (package-vc-p pkg-desc)
>>> (message "*** installed %s" pkg-desc))))
>>
>> Why do we need this?
>
> Good catch! We don't. This is some of my extra tracing code. Removed.
1+
>> [...]
>>> (ert-deftest package-vc-tests-002-commit ()
>>> (dolist (pkg-checkout-dir package-vc-tests-packages)
>>> (let ((pkg (car pkg-checkout-dir))
>>> (commit (package-vc-commit
>>> (package-vc-tests-package-desc (car pkg-checkout-dir)=
t))))
>>> (should-not (equal (cons pkg commit)
>>> (list pkg)))
>>
>> So (null commit)?
>
> Or even simpler (should commit). But that will only print a commit name
> in case of failure. I did the list trick on purpose, such that on
> failure it prints the affected package name. I know that one option is
> to write a custom ert-explainer, but that seems like an overkill. Or
> create a custom assertion that would `message' before failure, yet this
> one seems odd to me. I wish `should' could take extra context. Do you
> have a better idea how to ensure package name is printed?
The only idea I have would be to write (and pkg (null commit))...
>>> (should-not (equal (list pkg "unknown")
>>> (list pkg commit))))))
>>>
>>> (ert-deftest package-vc-tests-003-load-history-after-install ()
>>> (let ((install-begin (should (package-vc-tests-load-history-position
>>> 'install-begin :marker)))
>>> (install-end (should (package-vc-tests-load-history-position
>>> 'install-end :marker))))
>>> (dolist (pkg (mapcar #'car package-vc-tests-packages))
>>> (let ((autoloads-pos
>>> (should (package-vc-tests-load-history-position pkg :autol=
oads))))
>>> (should (< install-end autoloads-pos install-begin)))
>>> (should-not (package-vc-tests-load-history-position pkg :main))
>>> (should-not (package-vc-tests-load-history-position pkg :main-com=
piled)))))
>>>
>>> (ert-deftest package-vc-tests-004-require ()
>>> (dolist (pkg (mapcar #'car package-vc-tests-packages))
>>> (should (require pkg)))
>>
>> Shouldn't this be called with NOERROR.
>
> It could, but I don't really understand a benefit. Either case `should'
> will abort the loop and in consequence the test.
Ah right, I forgot how should works ^^
>>> (let ((install-end (should (package-vc-tests-load-history-position
>>> 'install-end :marker))))
>>> (dolist (pkg (mapcar #'car package-vc-tests-packages))
>>> (let ((main-pos (should (package-vc-tests-load-history-position p=
kg :main))))
>>> (should (< main-pos install-end)))
>>> (should-not (package-vc-tests-load-history-position pkg :main-com=
piled)))))
>>
>> Why are we interested in the position in load-list?
>
> This is to ensure that files are reloaded. It has proven very helpful
> as it caught that code was not reloaded for a package, that:
>
> - has it's Lisp code in a sub directory called "lisp",
> - and has been installed with `package-vc-install',
> - and has been upgraded with `package-vc-upgrade'.
>
> For posterity, this was test-package-5, to be found in the most recent
> patch.
Ah, OK! Unless I missed it somewhere, and this is actually a reliable
way of testing this, I would add a comment somewhere to explain this.
>>> (defmacro package-vc-tests-package-vc-upgrade-wait (seconds count &rest=
body)
>>> "Wait up to SECONDS for COUNT packages upgrading BODY.
>>> Return nil on timeout or non nil otherwise."
>>> (declare (indent 2))
>>> `(letrec ((packages-count ,count)
>>> (post-vc-command (lambda (command _ flags)
>>> ;; A crude filter for vc commands
>>> (when (and (equal command "git")
>>> (string-prefix-p "*vc-git" (b=
uffer-name)))
>>> (cl-decf packages-count)))))
>>> (add-hook 'vc-post-command-functions post-vc-command 100)
>>> (unwind-protect
>>> (progn
>>> ,@body
>>> (catch 'done
>>
>> Do you want with-timeout?
>
> It turns out I want that. Thanks for pointing out!
>
>> [...]
>>> (ert-deftest package-vc-tests-010-prepare-patch ()
>>> (dolist (pkg-checkout-dir package-vc-tests-packages)
>>> (cl-letf* ((call-count 0)
>>> ((symbol-function #'package-maintainers)
>>> (lambda (&rest _)
>>> "test-maintainers"))
>>> ((symbol-function #'vc-prepare-patch)
>>> (lambda (addressee subject revisions)
>>> (should (equal (file-name-as-directory default-direct=
ory)
>>> (file-name-as-directory (cdr pkg-check=
out-dir))))
>>> (should (equal "test-maintainers" addressee))
>>> (should (equal "test-subject" subject))
>>> (should (equal "test-revisions" revisions))
>>> (cl-incf call-count))))
>>> (package-vc-prepare-patch (package-vc-tests-package-desc
>>> (car pkg-checkout-dir)
>>> t)
>>> "test-subject"
>>> "test-revisions")
>>> (should (eql 1 call-count)))))
>>
>> I don't think we need to test the specific internal behaviour. IMO the
>> tests should ensure that user-facing behaviour doesn't regress.
>
> I have chosen to go the mocking route for this (and the following) test.
> Otherwise writing assertions for them may be a bit complicated. But I
> can try to update if you think the extra work justifies the benefit.
My only concern is that this might break if we make changes in the
future, and I don't want to expose (or imply to expose) the specific
internal details as something that any third party should rely on.
>>>> 3. I am not sure what will happen when someone checkouts a repository =
to
>>>> `package-user-dir' making it so the 'package-vc-install-from-checkout'
>>>> calculates `pkg-dir' that is the same as a checkout dir. I know it's
>>>> not the smartest thing to do, but perhaps detect it and raise an error?
>
> If we agree to keep `package-vc-install-from-checkout' (which I still
> have hopes for) I will create a patch for it.
I am sorry to say, but my inclination towards deprecation and eventual
removal is just increasing due to the complications we see that arise in
having that feature in package-vc.
>>>> 4. I struggle to understand how the value of `:lisp-dir' calculated in
>>>> `package-vc-unpack' (lines 701-711) is used in further code. Will need
>>>> to find a package that specifies that and try to debug it further.
>
> So this one turns out to be an issue. Caught by one of `load-history'
> tests (as mentioned above). It doesn't do anything for
> `package-vc-install', and the logic is omitted for
> `package-vc-install-from-chekcout'. I have added a fix for it in the
> attached patches.
>
>>>> 5. Perhaps the `package-vc-install-from-checkout' could be extended in
>>>> such a way to allow user to specify their `pkg-spec'. That should
>>>> include the checkout directory, as well as other values from spec
>>>> (lisp-dir, make, doc)?
>
>
>
>>> 6. Perhaps `package-vc-rebuild' should delete all *.elc files, such that
>>> subsequent `package--reload-previously-loaded' calls will certainly pick
>>> up what is in the code, such that downgrades are supported (i.e., the
>>> *.el file will become older than *.elc).
>
> Although I have done some work around that area and it seems to work as
> it should I still need to do some experiments to convince myself this
> indeed works as expected. I will update if I find anything.
>
>>>> 5. I am not sure how `package-delete' will work with these changes. I
>>>> guess it should at least remove the pkg-dir as well as entry from
>>>> `package-vc-selected-packages'.
>>>
>>> I guess this will be question 7 now ;). I am thinking about adding a
>>> hook, say `package-delete-hook' that will be called with a `pkg-desc' of
>>> the package being deleted. `package-vc' could register it's own handler
>>> and delete such an entry.
>>>
>>> And last but not least:
>>>
>>> 8. I have noticed that `package-reinstall' allows to reinstall a VC
>>> package. But that will certainly won't do the right thing - it will
>>> delete the package, but the subsequent installation will either happen
>>> from an ELPA or will fail if no ELPA exists. I am thinking about of two
>>> options:
>>>
>>> a. Remove VC packages from completion offers, and block the function,
>>> asking user to use `package-vc-rebuild'.
>>>
>>> b. Forward the call to `package-vc-rebuild' for VC packages. Perhaps
>>> after asking user if they want to do so. The question could be
>>> suppress-able with a new variable
>>> (e.g. `package-reinstall-vc-package-forward' with values `always',
>>> `ask', `never'). And the `package-vc-rebuild' could be also set as a
>>> variable (e.g., `package-reinstall-vc-package-function').
>>
>> My preference would be towards a., just like how I think that adding
>> VC packages to package-upgrade was a mistake in retrospect.
>
> How about creating a new bug for issues 7 (package-delete) and 8
> (package-reinstall) and discuss patches there?
Sounds good!
>>> .../test-package-1.bundle | Bin 0 -> 764 bytes
>>> .../test-package-2.bundle | Bin 0 -> 763 bytes
>>> .../test-package-3.bundle | Bin 0 -> 764 bytes
>>> .../test-package-4.bundle | Bin 0 -> 767 bytes
>>
>> I was afraid that the files would be a lot larger, but this seems
>> acceptable. Did you do a shallow clone and run git-gc(1)? Either way,
>> I would prefer to ask a maintainer before we apply these patches, just
>> to be on the safe side.
>
> These are not the packages I used as specimens earlier. Instead I opted
> for creating a minimal viable package repositories with just a two
> commits to exercise upgrade/downgrade test scenarios. That's why the
> bundles are so small. You can clone one of these bundles to see what's
> inside.
Ah, I haven't applied the patch yet so I didn't know what was inside.
> Here are the new patches, that include additional fix for the Lisp sub
> directory as well as addressing comments. This time, I consolidated
> them, so they apply on the directly on top of the patch you sent Fri, 19
> Sep 2025 [5]. If you prefer incremental changes (I guess on a cost of
> managing applying them in right order), please let me know and will send
> them in smaller chunks. Please let me know what you think.
>
> From 2ccc2463a714d8f7ab91eef0813c615bba5e1251 Mon Sep 17 00:00:00 2001
> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
> Date: Fri, 26 Sep 2025 17:24:44 +0100
> Subject: [PATCH 1/2] Fix upgrading and rebuilding of VC packages
>
> There are a few issues addressed in this patch:
>
> 1. Compilation (including native compilation) should happen in
> directory that contains package's Lisp code.
>
> 2. After installing a package with
> `package-vc-install-from-checkout' and subsequently upgrading it
> with `package-vc-upgrade' the pkg-desc for the package becomes
> corrupted. After the upgrade the pkg-desc's dir (a.k.a
> `pkg-dir') points to checkout directory. This will cause the
> subsequent `package-delete' to delete the checkout directory and
> leaving incorrect forwarding autoloads file in
> `package-user-directory'.
>
> 3. The detection of package's Lisp directory has been not
> effective for packages installed with `package-vc-install' and
> not existent for packages installed with
> `package-install-from-checkout'.
>
> * lisp/emacs-lisp/package-vc.el (package-vc--checkout-dir):
> Detect standard lisp sub directory if called with non-nil
> `lisp-dir'.
> (package-vc--unpack-1): Remove superfluous `pkg-dir' argument.
> Use a `package' with `:dir' pointing to where package code is.
> After calling `package-activate-1' ensure that source files are
> reloaded when `lisp-dir' is a sub directory and call
> `package--add-info-node' when `checkout-dir' is different than
> `pkg-dir'.
> (package-vc-install-from-checkout): Remove superfluous
> `package-vc-selected-packages' binding. Remove `pkg-dir'
> argument from `package-vc--unpack-1' calls.
> (package-vc--unpack): Remove superfluous Lisp code sub directory
> detection - logic moved to `package-vc--checkout-dir'. Remove
> `pkg-dir' argument from `package-vc--unpack-1' call.
> (package-vc-upgrade, package-vc-rebuild): Remove `pkg-dir'
> argument from `package-vc--unpack-1' calls.
> * lisp/emacs-lisp/package.el (package--add-info-node): New
> function to install info node for package. Extracted from
> `package-activate-1'.
> (package-activate-1): Call `package--add-info-node'.
>
> (Bug#79188)
> ---
> lisp/emacs-lisp/package-vc.el | 154 ++++++++++++++++++++--------------
> lisp/emacs-lisp/package.el | 15 ++--
> 2 files changed, 102 insertions(+), 67 deletions(-)
>
> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
> index 078a7bd8136..10b198961be 100644
> --- a/lisp/emacs-lisp/package-vc.el
> +++ b/lisp/emacs-lisp/package-vc.el
> @@ -31,8 +31,7 @@
> ;; aren't interested in activating a package, you can use
> ;; `package-vc-checkout' instead, which will prompt you for a target
> ;; directory. If you wish to reuse an existing checkout, the command
> -;; `package-vc-install-from-checkout' will create a symbolic link and
> -;; prepare the package.
> +;; `package-vc-install-from-checkout' will prepare the package.
> ;;
> ;; If you make local changes that you wish to share with an upstream
> ;; maintainer, the command `package-vc-prepare-patch' can prepare
> @@ -180,16 +179,37 @@ package-vc--checkout-dir
> that case the package redirects to the actual VC checkout. If the
> optional LISP-DIR argument is non-nil, then check if a related package
> specification has a `:lisp-dir' field to indicate that Lisp files are
> -located in a sub directory of a checkout and return that instead."
> +located in a sub directory of the checkout, or the checkout has a sub
> +directory named \"lisp\" or \"src\" that contains .el files and return
> +that instead."
> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> - (url (plist-get pkg-spec :url)))
> + (url (plist-get pkg-spec :url))
> + (pkg-dir (cond
> + ((save-match-data
> + (and url (string-match (rx "file://" (group (+ any=
))) url)
> + (match-string 1 url))))
BTW, did you know that you can also use `pcase' here:
(pcase url
((rx "file://" (let file (+ any))) file)
(_ (package-desc-dir pkg-desc)))
I only recently discovered this myself.
> + (t (package-desc-dir pkg-desc)))))
> (expand-file-name
> - (or (and (not lisp-dir) (plist-get pkg-spec :lisp-dir)) ".")
> - (cond
> - ((save-match-data
> - (and url (string-match (rx "file://" (group (+ any))) url)
> - (match-string 1 url))))
> - (t (package-desc-dir pkg-desc))))))
> + (or (when lisp-dir
Please don't use `when' if we are interested in the return value.
> + (or (plist-get pkg-spec :lisp-dir)
> + ;; When nothing is specified about a `lisp-dir', then sho=
uld
> + ;; heuristically check if there is a sub-directory with l=
isp
> + ;; files. These are conventionally just called "lisp" or=
"src".
> + ;; If this directory exists and contains non-zero number =
of lisp
> + ;; files, we will use that instead of `pkg-dir'.
> + (catch 'done
> + (dolist (name '("lisp" "src"))
> + (when-let* ((dir (expand-file-name name pkg-dir))
> + ((file-directory-p dir))
> + ((directory-files dir nil "\\`[^.].+\\.el=
\\'" t 1)))
> + ;; We won't use `dir', since dir is an absolute pat=
h and we
> + ;; don't want `lisp-dir' to depend on the current l=
ocation of
> + ;; the package installation, ie. to break if moved =
around the
> + ;; file system or between installations.
> + (throw 'done name))))
> + ))
I think you should fold these parentheses onto the previous line.
> + ".")
> + pkg-dir)))
>=20=20
> (defun package-vc--read-archive-data (archive)
> "Update `package-vc--archive-spec-alists' for ARCHIVE.
> @@ -468,14 +488,24 @@ package-vc-install-dependencies
> (mapc #'package-install-from-archive to-install)
> missing))
>=20=20
> -(defun package-vc--unpack-1 (pkg-desc pkg-dir)
> - "Prepare PKG-DESC that is already checked-out in PKG-DIR.
> -This includes downloading missing dependencies, generating
> -autoloads, generating a package description file (used to
> -identify a package as a VC package later on), building
> -documentation and marking the package as installed."
> - (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> +(defun package-vc--unpack-1 (pkg-desc)
> + "Prepare PKG-DESC that is already checked-out.
> +The checkout directory is determined by relevant pkg-spec or from `dir'
(Not critical, but if you can think of a nice way to avoid the passive
tense here, that would be nice)
> +slot of PKG-DESC. This includes downloading missing dependencies,
> +generating autoloads, generating a package description file (used to
> +identify a package as a VC package later on), building documentation and
> +marking the package as installed."
> + (let* (;; Main package directory, under `package-user-dir'. This is
> + ;; the same `checkout-dir' when package has been installed with
> + ;; `package-vc-install'.
> + (pkg-dir (package-desc-dir pkg-desc))
> + (pkg-spec (package-vc--desc->spec pkg-desc))
> + ;; Directory where the package repository has been checked out.
> + ;; This is the `dir' argument of
> + ;; `package-vc-install-from-checkout'.
> (checkout-dir (package-vc--checkout-dir pkg-desc))
> + ;; Directory where package's Lisp code resides. It may be
> + ;; equal to `checkout-dir' or be a subdirectory of it.
> (lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
> missing)
>=20=20
> @@ -518,13 +548,17 @@ package-vc--unpack-1
> (auto-name (format "%s-autoloads.el" name)))
> (package-generate-autoloads name lisp-dir)
> ;; There are two cases when we wish to "indirect" the loading of
> - ;; autoload files: 1. a package specification has a `:lisp-dir'
> - ;; entry listing indicting that the actual Lisp code is located in
> - ;; a subdirectory of the checkout, 2. the package has been
> - ;; installed using `package-vc-install-from-checkout' and we want
> - ;; to load the other directory instead -- which is outside of the
> - ;; checkout. We can therefore take file inequality as a sign that
> - ;; we have to set up an indirection.
> + ;; autoload files:
> + ;;
> + ;; 1. a package specification has a `:lisp-dir' entry listing
> + ;; indicting that the actual Lisp code is located in a
> + ;; subdirectory of the checkout,
> + ;;
> + ;; 2. the package has been installed using
> + ;; `package-vc-install-from-checkout' and we want to load the
> + ;; other directory instead -- which is outside of the checkout.
> + ;; We can therefore take file inequality as a sign that we have to
> + ;; set up an indirection.
> (unless (file-equal-p lisp-dir pkg-dir)
> (write-region
> (concat
> @@ -568,20 +602,37 @@ package-vc--unpack-1
> (setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
>=20=20
> ;; Update package-alist.
> - (let ((new-desc (package-load-descriptor pkg-dir)))
> + (let* ((new-desc (package-load-descriptor pkg-dir))
> + (compile-desc (package-desc-create :name (package-desc-name n=
ew-desc)
> + :dir lisp-dir)))
> ;; Activation has to be done before compilation, so that if we're
> ;; upgrading and macros have changed we load the new definitions
> ;; before compiling.
> (when (package-activate-1 new-desc :reload :deps)
> + ;; `package-activate-1' will reload all necessary package files
> + ;; as long as their stems are relative to of `pkg-dir'. If
> + ;; that's not the case (for example for packages with different
> + ;; `checkout-dir' or with source files in a sub directory of
> + ;; `pkg-dir'), we want to reload package files from the
> + ;; `lisp-dir' before compilation.
> + (unless (file-equal-p lisp-dir pkg-dir)
> + (package--reload-previously-loaded compile-desc))
> + ;; `package-activate-1' will add info node as long as dir file
> + ;; exists in `pkg-dir'. We need to manually add it when
> + ;; `checkout-dir' is in different location.
> + (unless (file-equal-p pkg-dir checkout-dir)
Minor nit-pick if you are going to revise the patch anyway, it would be
nice to swap the argument here or above so that pkg-dir is on the same side.
> + (package--add-info-node checkout-dir))
> ;; FIXME: Compilation should be done as a separate, optional, st=
ep.
> ;; E.g. for multi-package installs, we should first install all =
packages
> ;; and then compile them.
> - (package--compile (package-desc-create :dir lisp-dir))
> + (package--compile compile-desc)
> (when package-native-compile
> - (package--native-compile-async new-desc))
> + (package--native-compile-async compile-desc))
> ;; After compilation, load again any files loaded by
> - ;; `activate-1', so that we use the byte-compiled definitions.
> - (package--reload-previously-loaded new-desc)))
> + ;; `package-activate-1', so that we use the byte-compiled
> + ;; definitions. This time we'll use `compile-desc' straight
> + ;; away.
> + (package--reload-previously-loaded compile-desc)))
>=20=20
> ;; Mark package as selected
> (let ((name (package-desc-name pkg-desc)))
> @@ -693,28 +744,11 @@ package-vc--unpack
> (delete-directory pkg-dir t)
> (user-error "Installation aborted")))
>=20=20
> - ;; When nothing is specified about a `lisp-dir', then should
> - ;; heuristically check if there is a sub-directory with lisp
> - ;; files. These are conventionally just called "lisp" or "src".
> - ;; If this directory exists and contains non-zero number of lisp
> - ;; files, we will use that instead of `pkg-dir'.
> - (catch 'done
> - (dolist (name '("lisp" "src"))
> - (when-let* (((null lisp-dir))
> - (dir (expand-file-name name pkg-dir))
> - ((file-directory-p dir))
> - ((directory-files dir nil "\\`[^.].+\\.el\\'" t 1)))
> - ;; We won't use `dir', since dir is an absolute path and we
> - ;; don't want `lisp-dir' to depend on the current location of
> - ;; the package installation, ie. to break if moved around the
> - ;; file system or between installations.
> - (throw 'done (setq lisp-dir name)))))
> -
> ;; Ensure we have a copy of the package specification
> (when (null (package-vc--desc->spec pkg-desc name))
> (package-vc--save-selected-packages name pkg-spec))
>=20=20
> - (package-vc--unpack-1 pkg-desc pkg-dir)))
> + (package-vc--unpack-1 pkg-desc)))
>=20=20
> (defun package-vc--read-package-name (prompt &optional allow-url install=
ed)
> "Query the user for a VC package and return a name with PROMPT.
> @@ -782,7 +816,7 @@ package-vc-upgrade
> ;;
> ;; If there is a better way to do this, it should be done.
> (cl-assert (package-vc-p pkg-desc))
> - (letrec ((pkg-dir (package-vc--checkout-dir pkg-desc))
> + (letrec ((checkout-dir (package-vc--checkout-dir pkg-desc))
> (vc-flags)
> (vc-filter-command-function
> (lambda (command file-or-list flags)
> @@ -790,18 +824,19 @@ package-vc-upgrade
> (list command file-or-list flags)))
> (post-upgrade
> (lambda (_command _file-or-list flags)
> - (when (and (file-equal-p pkg-dir default-directory)
> + (when (and (file-equal-p checkout-dir default-directory)
> (eq flags vc-flags))
> (unwind-protect
> (with-demoted-errors "Failed to activate: %S"
> - (package-vc--unpack-1 pkg-desc pkg-dir))
> + (package-vc--unpack-1 pkg-desc))
> (remove-hook 'vc-post-command-functions post-upgrade))=
))))
> (add-hook 'vc-post-command-functions post-upgrade)
> (with-demoted-errors "Failed to fetch: %S"
> (require 'vc-dir)
> (with-current-buffer (vc-dir-prepare-status-buffer
> - (format " *package-vc-dir: %s*" pkg-dir)
> - pkg-dir (vc-responsible-backend pkg-dir))
> + (format " *package-vc-dir: %s*" checkout-dir)
> + checkout-dir
> + (vc-responsible-backend checkout-dir))
> (vc-pull)))))
>=20=20
> (defun package-vc--archives-initialize ()
> @@ -966,24 +1001,21 @@ package-vc-install-from-checkout
> (package-vc--archives-initialize)
> (let* ((dir (if interactive dir (expand-file-name dir))) ;avoid double=
expansion
> (name (or name (file-name-base (directory-file-name dir))))
> - (pkg-dir (file-name-concat package-user-dir name))
> - (package-vc-selected-packages
> - (cons (list name :lisp-dir dir)
> - package-vc-selected-packages)))
> + (pkg-dir (file-name-concat package-user-dir name)))
> (when (file-exists-p pkg-dir)
> (if (yes-or-no-p (format "Overwrite previous checkout for package =
`%s'?" name))
> (package--delete-directory pkg-dir)
> (error "There already exists a checkout for %s" name)))
> (make-directory pkg-dir t)
> - ;; We store a custom package specification so that
> - ;; `package-vc--checkout-dir' can later retrieve the actual checkout.
> + ;; We store a custom package specification so that it is available
> + ;; for `package-vc--unpack-1' as well as `package-vc--checkout-dir'
> + ;; can later retrieve the actual checkout.
> (package-vc--save-selected-packages name (list :url (concat "file://=
" dir)))
> (package-vc--unpack-1
> (package-desc-create
> :name (intern name)
> :dir pkg-dir
> - :kind 'vc)
> - (file-name-as-directory pkg-dir))))
> + :kind 'vc))))
>=20=20
> ;;;###autoload
> (defun package-vc-rebuild (pkg-desc)
> @@ -995,7 +1027,7 @@ package-vc-rebuild
> is the responsibility of `package-vc-upgrade'. Interactively,
> prompt for the name of the package to rebuild."
> (interactive (list (package-vc--read-package-desc "Rebuild package: " =
t)))
> - (package-vc--unpack-1 pkg-desc (package-vc--checkout-dir pkg-desc)))
> + (package-vc--unpack-1 pkg-desc))
>=20=20
> ;;;###autoload
> (defun package-vc-prepare-patch (pkg-desc subject revisions)
> diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
> index ba9999c20e6..fb073579bc1 100644
> --- a/lisp/emacs-lisp/package.el
> +++ b/lisp/emacs-lisp/package.el
> @@ -903,6 +903,14 @@ package--reload-previously-loaded
> (mapc (lambda (c) (load (car c) nil t))
> (sort result (lambda (x y) (< (cdr x) (cdr y))))))))
>=20=20
> +(defun package--add-info-node (pkg-dir)
> + "Add info node located in PKG-DIR."
> + (when (file-exists-p (expand-file-name "dir" pkg-dir))
> + ;; FIXME: not the friendliest, but simple.
> + (require 'info)
> + (info-initialize)
> + (add-to-list 'Info-directory-list pkg-dir)))
> +
> (defun package-activate-1 (pkg-desc &optional reload deps)
> "Activate package given by PKG-DESC, even if it was already active.
> If DEPS is non-nil, also activate its dependencies (unless they
> @@ -934,12 +942,7 @@ package-activate-1
> The following files have already been loaded: %S")))
> (with-demoted-errors "Error loading autoloads: %s"
> (load (package--autoloads-file-name pkg-desc) nil t)))
> - ;; Add info node.
> - (when (file-exists-p (expand-file-name "dir" pkg-dir))
> - ;; FIXME: not the friendliest, but simple.
> - (require 'info)
> - (info-initialize)
> - (add-to-list 'Info-directory-list pkg-dir))
> + (package--add-info-node pkg-dir)
> (push name package-activated-list)
> ;; Don't return nil.
> t)))
> --=20
> 2.51.0
This is a pretty big patch, so I hope you understand that it takes me a
while to review it and my hesitance to changing so much of the code.
Please tell me, if we revert the change that replaced the symbolic links
with the current "indirect" package loading approach, would that also
resolve the issue you had? If so, we could consider that along with
deprecating package-vc-install-from-checkout in favour of site-lisp.
> From c82c03957f5f1fab6fbbff39ef1ea49792581e6f Mon Sep 17 00:00:00 2001
> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
> Date: Tue, 2 Sep 2025 09:28:13 +0100
> Subject: [PATCH 2/2] Add tests for package-vc
>
> * test/lisp/package-vc-tests.el (package-vc-tests-dir):
> Temporary directory to store `package' and test data during the
> test.
> (package-vc-tests-resources-dir): Directory where bundle files
> (repositories with test packages): are located.
> (package-vc-tests-packages): List of packages to tests, together
> with their checkout locations.
> (with-package-vc-tests-enviroment): Setup environment for test,
> that includes configuring `package', `package-vc', and `vc'
> variables, as well as defining test packages.
> (package-vc-tests-package-desc): Retrieve a `package-desc' for
> tested package.
> (package-vc-tests-package-main-file): Calculate expected
> location of package's main file.
> (package-vc-tests-load-history-position): Calculate a position
> in load-history of a file. The position only accounts for
> interesting files, that is only files that are in
> `package-vc-tests-dir'.
> (package-vc-tests-assert-delete-elc): Assert that .elc files
> have been gernerated for a package and delete them.
> (package-vc-tests-assert-package-alist): Assert that
> `pakcage-alist' contains a `package-desc' for package, and that
> the `pakcage-desc' has correct slot `version' and slot `dir'.
> (package-vc-tests-reset-heads): Reset heads of checkouts of
> tested packages to a HEAD^.
> (package-vc-tests-packages-heads): Return a list of checkouts of
> tested packages current HEAD revisions.
> (package-vc-tests-000-install): Test that packages can be
> installed with `package-vc-install' and
> `package-vc-install-from-checkout', including
> `package-vc-checkout'.
> (package-vc-tests-001-main-file): Test that
> `package-vc--main-file' return main file in expected locations.
> (package-vc-tests-002-commit): Test that `package-vc-commit' is
> returning a revision.
> (package-vc-tests-003-load-history-after-install): Test that
> `load-history' has entries for autoloads of tested packages.
> (package-vc-tests-package-vc-upgrade-wait): Helper function to
> wait for a package being upgraded. This is needed due to
> asynchronous nature of `vc-pull'.
> (package-vc-tests-004-upgrade-all): Test that
> `package-vc-upgrade-all' indeed upgrades all packages.
> (package-vc-tests-005-load-history-after-upgrade-all): Test that
> `load-history' has entries for autoloads of tested packages.
> (package-vc-tests-006-require): Test that packages can be
> `require'd, and that `load-history' has entries for non-compiled
> package main files.
> (package-vc-tests-007-upgrade): Test that `package-vc-upgrade'
> upgrades a package.
> (package-vc-tests-008-load-history-after-upgrade): Test that
> `load-history' has entries for autoloads, non-compiled main
> files, and compiled main files after a package has been
> upgraded.
> (package-vc-tests-009-rebuild): Test that a downgraded package
> can be rebuild with `package-vc-rebuild', and that appropriate
> files are reloaded.
> (package-vc-tests-010-prepare-patch): Test that
> `package-vc-prepare-patch' calls `vc-prepare-patch' with
> expected arguments.
> (package-vc-tests-011-log-incoming): Test that
> `package-vc-log-incoming' calls `vc-log-incoming' with expected
> arguments.
> ---
> .../test-package-1.bundle | Bin 0 -> 764 bytes
> .../test-package-2.bundle | Bin 0 -> 763 bytes
> .../test-package-3.bundle | Bin 0 -> 764 bytes
> .../test-package-4.bundle | Bin 0 -> 767 bytes
> .../test-package-5.bundle | Bin 0 -> 845 bytes
> .../test-package-6.bundle | Bin 0 -> 843 bytes
> test/lisp/package-vc-tests.el | 601 ++++++++++++++++++
> 7 files changed, 601 insertions(+)
> create mode 100644 test/lisp/package-vc-resources/test-package-1.bundle
> create mode 100644 test/lisp/package-vc-resources/test-package-2.bundle
> create mode 100644 test/lisp/package-vc-resources/test-package-3.bundle
> create mode 100644 test/lisp/package-vc-resources/test-package-4.bundle
> create mode 100644 test/lisp/package-vc-resources/test-package-5.bundle
> create mode 100644 test/lisp/package-vc-resources/test-package-6.bundle
I am sorry if I seem to be flip-flopping here, but thinking about this
again, but if you have constructed custom packages, why not store them
directly as test resources and have the tests convert them first into
git repositories under /tmp/, then git bundles and install those as
though they were remote? That would make it easier to track changes to
the test packages without having to update these opaque objects.
> create mode 100644 test/lisp/package-vc-tests.el
>
> diff --git a/test/lisp/package-vc-resources/test-package-1.bundle b/test/=
lisp/package-vc-resources/test-package-1.bundle
> new file mode 100644
> index 0000000000000000000000000000000000000000..1ba31bb56c8a4e78c04ced881=
f68aa56113e5258
> GIT binary patch
> literal 764
> zcmV<Y0t5XcAa*h!XK8dGVs&n0Y-I{JVmM_pGcqzTH8nCgH)UoqH8?OdGcqtSG-PEn
> zVKQVjW-~Z5WH&h=3Da%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J_4tSiM%s~nQ
> zArye&y{B*=3Dg!*(;h-lv?=3DmbxFPD42}m=3DV*myLGRkZqV-MUwo|+aYNR5p@=3D|diD;cs
> z&SLTcr8G7K2r2oPGn=3Du}*f=3DJT5sU{&I=3DUdTk6tV3QL7X*I4y$#fXwjLPE+NF`k=3DC0
> zUr)UAeO-F0d^4ZFvFi&Cmvx-VmP^|SE3|hVUkND$``j|LM*j=3D!NO2ky|4Hl(VDn1C
> zoeOxJD=3DA7%RWLV5Gc+-_NU^lEOind7OR}&uFf}wYFix{HGDu0aFiJH}u}m>BG2%)r
> zEy>6)QV1xjO3ke-KH8L6uHao%nVwptU{jC{W;mqhCT8a7CFkebDHxiY8JHWGSelwE
> zXd4(B7;phab2CdyQpq=3Dg%Pq60xI_VB5ElS2>^vQ<0(hJ=3DG%zqTF;OT<EiTb5NKDR7
> zOi$G{)Jx4_D7YLrk)dQyz>^)-HM+(gZut*A>j70B5Tv~qc$|%pu};G<5QcX@#VHx;
> zAe~Fa=3D8P<i6++#Q_(&`qJGGq(-oADz5}*!j=3DTHCt>CS!ML*|rmq2ZlI#+_mZhzKu*
> z!j%HvAvpf9137%P-dI0s$Q27w3{PR^rQ|eBIWI|Xw~0>VJxwaau_pFc{WBj|8#!r^
> zl4lwcG!OS`*K}P?9XKW%yoQ3RxQE9u&+IeBPhH+M^K&ot9WtyhW81d0=3DHLPuAq~H+
> z{?Bz-&;YU%08KTiru%0xICHZsml#ggFl>GozPvX+m%T|aab$4@bvkp1Z-82Oocqgk
> zfN8=3D^Mx%+dvL`z+S_1$xk_E-B0(hJ=3DG%zqTF;OT<EiTb5NKDR7Oi$G{)Jx4_xSe+B
> uUF!dBQJq^~ewTZGxuI`UycYm}9TY0o&aooGjhCAnv*jBU3g$JmE;3k}Mn7->
>
> literal 0
> HcmV?d00001
>
> diff --git a/test/lisp/package-vc-resources/test-package-2.bundle b/test/=
lisp/package-vc-resources/test-package-2.bundle
> new file mode 100644
> index 0000000000000000000000000000000000000000..7b21f617b79d86a7d528d8af3=
45d08373dbf3302
> GIT binary patch
> literal 763
> zcmV<X0tEddAa*h!XK8dGVs&n0Y-I{$G%_?ZF=3D96}HZWo}G+{O}WHw}BV>2{mG&f^8
> zG-769HDhKpIWlG-a%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J_4tSiM%smPM
> zF%UrEKBq`8Nd7kg5qlfK6HF$Pb<ylDF(PZ}-Mp8gH?VuW;%k+Ndq~zqo2AT#6qqCt
> zI|nj=3D6_k*awG@0-Y=3D%l>;}kFk9d$yC&KPt8Z8kDHFID!4KtXp}dj_|5nkqlk2bJae
> zdcvLW>(W!@oB8~WU0-0htZ^z^E;}bWA-q?7C8QASbIZ^g{V%X1;WQ@xlh_*;E=3D#DL
> z3wWHJ%s~pmFc3h|eNHiZK_*F?OhLqz8#i8IERz~Ev`iyXm)^~LDS88UpTBrjMSv~&
> zo?BvU$a@hCE=3DA|lsp+EY0*NGviM`=3DlJ&y`UeMnj6*OTvX&}9&X&2;(3ZYZ3u>wYX-
> zurXjnq?TZX7SVie$+gP=3Dg4t)CEBqky2A`%p%dG-<oHH~qFf%bxC`m0Y(Je?!&Q45E
> z)iu&f&0*NvYCYxBQtL$;FAq)JU|;ml>E=3D!~0A{=3DriM<zioQ;q@Ps1<}hIjvpQ!>;+
> zI+u^l8Cg13sA50jBe8JoU^^B4_t>RKfI6_9AHDCRJNJDLnN!AvhBq1+?-e^hL^u=3D*
> z7YcZT;P}H1<nYCMWBsThS1d#^?83}T$!VB!UXtE!6CKHWnpB8mP3$lFCw^aT<fK7L
> zo@q$XJlv|grt50znPalSYbdCSdw2}<%sx{*>GH0bpL?nAkYRlu+qR`O2N%c)Y4~;Z
> zf3CxV29TWqXsSsy-9L-LnX6^F#Bj8RVe`B2<-PK`>`j7+Ba2UWymO6jfLeH*`^$8I
> zX~IlKqlvS!Cp$4(0{}CU1;wobc$_mdFfcPQQ7B0*F3~MWOwLYBPt`TjOU+@ZZ~3vI
> tBgE5l@w!t^)9sy#&Mw%g3jkq%5xOz0k$j;XmPz=3DsA!AOGOzWlF9ebFDSR4QV
>
> literal 0
> HcmV?d00001
>
> diff --git a/test/lisp/package-vc-resources/test-package-3.bundle b/test/=
lisp/package-vc-resources/test-package-3.bundle
> new file mode 100644
> index 0000000000000000000000000000000000000000..a7ca66750db656b7fcc272049=
838d9aceafc214e
> GIT binary patch
> literal 764
> zcmV<Y0t5XcAa*h!XK8dGVs&n0Y-I{JF*i11HZ(V5G-fa|F=3DjY1F=3Dk>nV`efpW->T9
> zHaRq5FkxajIX7e=3Da%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J_4tSiM%rOeW
> zFc^m6J*UVnNYXY<e-LqZ5j;Wi=3DSwY`w#10k(YtvsMQ`Bt@(xeQfVA*n@=3DXop4TTn!
> zL16DuJ2twq6g2tRMKQaKu}ITcsytf<3Iq;;sq+<D8$osC&^Z&SV<X(HoTe-f`GK@t
> zUr%?J`@HnXax<U5vFno?E^D6BR%+WSt5mDCTq&)T_}ny<g8v0^1W#j-KS{g+{Ax_%
> zoeOxJD=3DA7%RY)<hG_y=3DiN=3D-9J1R`VeB%_q%Bx5tnq!dHrM8o7X6Y~@!GqdCruEf%k
> zjQk>nfTF6@+{)skO^M|S-bIz^sYMDl1=3D(PRLwasvW{zHRey*K@p}CoXxq*SHg@J;$
> zfuVr`7f>`ev!o=3DId=3Dt3bGK-2!6d(q10RS>NJ(sNlc$_mdFfcPQQ7B0*F3~MWOwLYB
> zPt`TnOU+?8{QsK66E4Och3_*yDxZ7#`d4InH~?-v6EVFPc$|%pu};G<5QcX@#VHx;
> zAe{^9=3D8P<i6++#Q_(&`qJGGq(-oADz5}*!j=3DTHCt>CS!ML*|rmq2ZlI#+_mZhzKu*
> z!j%HvAvpf9137%P-dI0s$Q27w3{PR^rQ|eBIWI|Xw~0>VJxwaau_pFc{WBj|8#!r^
> zl4lwcG`oBC&~#l*9XKW%yoQ3RxQE9u&+IeBPhH+M^K&ot9WtyhW81d0=3DHLPuAq~H+
> z{?Bz-&;YU%08KTiru%0xICHZsml#ggFl>GozPvX+m%T|aab$4@dOmZKZ-82Oocqgk
> zfN8=3D^Mx%+dvL`z+S_1$xk_E-B0(hJ=3DG%zqTF;OT<EiTb5NKDR7Oi$G{)=3DSM{_|*7r
> u)@}ylE0g<w=3DN^#d`mrn7Obq~SKoSRnmV8868k8_begWiOH93;r{Y0W%$xO2V
>
> literal 0
> HcmV?d00001
>
> diff --git a/test/lisp/package-vc-resources/test-package-4.bundle b/test/=
lisp/package-vc-resources/test-package-4.bundle
> new file mode 100644
> index 0000000000000000000000000000000000000000..bbe907981201692e12ac22688=
6c00fbdfb368179
> GIT binary patch
> literal 767
> zcmV<b0s#FZAa*h!XK8dGVs&n0Y-I{&H!(RhW@0rqH#uT4VL4+kF*Y+bH!w6cH!?9Y
> zGi5PhH#RUeVKHGKa%E<7FKA_9WOFZVVRLk4ataDiK|@Ob00062000J_4tSiE&N~VM
> zF%*U2KC4JCNS-$dh}hc*t{{(_anQ^RF(PB>-rSdi;sWdrfAMizMWk9w3uto!shABY
> zoHZdKk6Hjj$sBT%6=3DX8`ibJDT7|vt{&l5NSHlhL}1gfAt@Q{MwQ7Dy(zqQj?>7hQb
> z%-7e`-|4>29ag%T&Y!XCitjJ$IF>Et1{gSFjiD>X86!(AeQWrqu-y9z<cM(`68%c#
> z4b3b{ADs($oGU3xO;xZow@6AdN-{CCFf=3DhXH?uG{wXiTwwMb1&1agg&QVfku49rtg
> zQ@9dKOEU6{6atE>QgbVdk2WQiD|i=3DGrl%Gu*c4=3Dg84l^WiJ3Wi$@#f<3Wnxp24+CB
> zO)V6(4GawoxPYR$nI$Eu<eR|dmRVF>q5v_73jj%ZJX);+c$_mdFfcPQQ7B0*F3~MW
> zOwLYBPt`TiOU+?8*!umO)HOBx!tNzkCLI@insxb;EdXuT6Ck}8c$|%pu};G<5QcX@
> z#VHx;Ae{?>$r)KXR;Xe>;v=3Dze>|i?;eS7RuBtRY5&Y%AO)1CXihs-JCLc<%4j1P((
> zAR-(Jg$o6|L2&$G2Xgpgy|I4OkSi9V7<OUirQ|eBIWI|Xw~3DAJxwaau_pEx{S&{h
> zHgeJ+CC@Y@Xzp*-UDI_n^~^EZ;58If#XUTRd1jv}o^*NF%+I~lcgV0lk8Ru1nu7~u
> zgf#rR`ajoUK?BH605sL4n(m*);LO#sTw*v{!?5{X`0`%)T=3Dpix#F51(e86*;Z-82O
> zocqgkfN8=3D^Mx%+dvL`z+S_1$xk_E-B0(hJ=3DG%zqTF;OT<EiTb5NKDR7Oi$G{(M!!?
> x$dsHgjlm{}Pht@ti(5(G-38flk^nL^4d7>+=3DuOEN5Y#?NZ~O8I;v<$%y$7D{N^1ZB
>
> literal 0
> HcmV?d00001
>
> diff --git a/test/lisp/package-vc-resources/test-package-5.bundle b/test/=
lisp/package-vc-resources/test-package-5.bundle
> new file mode 100644
> index 0000000000000000000000000000000000000000..b64e154c91c898f8fabec2aad=
27954c78b61cc54
> GIT binary patch
> literal 845
> zcmY#ZC^J$>&n!_$D$PsDN#!!LOf#`eOtVN!Nli2|FgCR`OExk$NlUggH83+wG%`#|
> zHL<ibFgH*rN=3D+-)&qz&7Db~+TEG|hc;^GQ$boORoU|<4bj(L0)bLO6L<T_*^;Bc|l
> zZ{l8snOi*76dv8{eZYC?%#yBUx`s-nFYoS|?wbGL-DmOjVriXfTiuuiCAo9o*knH!
> z@O-^Q$;9g?#}z4|U=3D5p)mj_D1*x!VFkdU?DmWwTF^i|=3DxSC!PQ*;%lD`Nk8@l|}RN
> z--lP6sGV7@S7aQ!Z{zD?i}>q>XQFpnoN|0EJw=3D<<tMloz;<bPFEA+`6Z+zk}Brmwy
> zt7R@X$dR^Oha3bP9@hCA?o}|pxxro`DK+`As9K?!-YylNFqLWd&Q@zyG4DREy>FG0
> z!y)zCk@5xs$umzbZIF<Dd1L!J$HJ3EuWo)=3DJI}p!vE34#&#zCGTf8vpIFz=3DlCfQu%
> z-1SoXX}S~2U##qvNNjD%u-pD5>S_JKH=3DECi)=3Dj8nUVhEy_Ik#OImU(zOs#XyJYr(|
> z7^xS&{KMJX(=3DL|Zot1t5rp&oePGN=3D>hj`4_G6B_@7#J8E25NZf>Rr_J@Hyw_<A2rk
> zs`uH%4>vCUjEY%QelDhe#<SZ^ll$}6#mr}B2!9~hzE`|rPVa<`euoVN+RE*ZYD&IR
> zn9J>?bMC~YjZUJ!1?4+ili6>td~rK@x)S5717-id{Gb2s&Uf1sKS^<^dl@M;0dE)t
> z9|mZ|XguI;ddzP<;jsAY-mi<>Vm1mK-N0?Euev<(RHbLtZr>7>_nAS8eWn}tznK4{
> zcI(8+Y?_tJ6djA}SHGLJZuQFazLRY07cS6x_t5Z+@o%4xOHS`jt9!R}pL5&S%ADKN
> zuF1qGC@*<<{p$aneB4qFWlRfJs$DJlufvwUZrW3!!xyF6&b~i1{rjoso6I@Y`gH6V
> z>z#_{<TpfD%=3Dvw~q#^T=3DkK5wT&70J%4WpPDj3=3D=3DkMG4imGn?%BLrW#!JxwXgzf+~-
> zu;<M+&M=3D0J*LY6i4b>BZNxOaq9rMh5_vpvEzprjTS{&v!mx;k6L!ey1XmU&(Q}qV3
> QpO%k*%lPhdDEspY0DfPAh5!Hn
>
> literal 0
> HcmV?d00001
>
> diff --git a/test/lisp/package-vc-resources/test-package-6.bundle b/test/=
lisp/package-vc-resources/test-package-6.bundle
> new file mode 100644
> index 0000000000000000000000000000000000000000..4294c885a0b7d5bd5bf665aa7=
274988f3692d36b
> GIT binary patch
> literal 843
> zcmY#ZC^J$>&n!_$D$PsDN##mSG)+lNN=3Di1hG%!w0u{1C>H#Ij&O*2kQF-}W1N-{Ds
> zG%!gvGBZ>tN=3D+-)&qz&7Db~+TEG|hc;^GQ$boORoU|<4bj(L0)bLRFqavd@dV0d5Y
> z`mX8Ct(3_P9p(B>`X1YFN15by3a)hj|7^d`FXrbaXA-@{E^<iUcZuHa;?Od$=3D_7Zp
> z=3D+UO{ci6ObIag?=3DNp_hv-dwPQ_j;U+l?co02|DI&P7h8w%UW*g`d%cr+3wl$B|pE_
> z9c{OJvUBp9?U$cw|JFPDZ`U)!w<cCh?P9CE)-y0(2?~zy`cogE{;)9P%ljpEkG;K2
> z=3D5kle(bn|x4fQZJ-{@gv<ZJ5h>1AwYXy9$^WoEKzgNcu?x3`y%p{K8pp@*NRp~*8Z
> z9o>^B^n*AwR(YLWt7CU-O2oPcu^}_(MJ-7Pp1_-CvE;d0+Orp`&!6AYl$bSJa)$IQ
> zDG4d93~31|i2_E~Vq<Twpp)i}r*${4*x|yMBp}Y9y2iF=3DJ!8cjV?zd});VV$F|qM7
> zhTBydZ`~j4GWD{NoG0sM(~f;?3=3DK;-?bk8^)tML=3D7#jv^c<Sn1)b;Q=3D=3DjY>p)%3FW
> z*~A|Pk2f8BGiUcRKYQO#PvrcHta7#*h%%%$2p-uhUNNV4!bZQt1_Ev6_D3}(Un$Jx
> zc1kL6o7N|~>PG($4;>ln8-A|$<#vm32C#4Yy!`+FlIQ#0D;A&Hap8lT^5f<t_70AA
> zr-x3A`2sTaHyUO3MdYuMH+|C8s?ioZqf*n7H~5_QrQ5lSlq>xwa}}=3DX{OkJv$otj3
> zb4)x=3D8uN0_`W;<*y(HGxw%Et4f|oV4kiS21-p%wb_1Jr+pNsXs${MXXpL~1UmS+!`
> zBo%r0ulsktG~xooCSe9&)0NA9ryE)nZ`GMD(Ra-tr%rs|o^ZSAdp!*bQ$BJw9w}a!
> z-w<6f=3DlAK7hRj1gZi_oNZ&J55jACXmp2T_-B~;ta&GXg%%JeRK^VhXGcHejWJ@V|w
> z%cTrkS$G%Y4b>N4j6Ckv2HbiZFtg-fZ+uaezU%8E2LJg2m3l=3DroAjc2{>v0T*!+!6
> KWx7=3D8tB(L0@n)L<
>
> literal 0
> HcmV?d00001
>
> diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
> new file mode 100644
> index 00000000000..1e9b96df866
> --- /dev/null
> +++ b/test/lisp/package-vc-tests.el
> @@ -0,0 +1,601 @@
> +;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -=
*-
> +
> +;; Copyright (C) 2025 Free Software Foundation, Inc.
> +
> +;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
^
looks like a typo, unless you
have an alternative address?
> +;; Keywords: package
> +
> +;; This file is part of GNU Emacs.
> +
> +;; GNU Emacs is free software: you can redistribute it and/or modify
> +;; it under the terms of the GNU General Public License as published by
> +;; the Free Software Foundation, either version 3 of the License, or
> +;; (at your option) any later version.
> +
> +;; GNU Emacs is distributed in the hope that it will be useful,
> +;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +;; GNU General Public License for more details.
> +
> +;; You should have received a copy of the GNU General Public License
> +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
> +
> +;;; Commentary:
> +
> +;; These tests focus on verifying post conditions for `package-vc'
> +;; operations on packages. Since installing a package changes the state
> +;; of running process these tests are ment to be executed in order, as
> +;; denoted by digits in their name.=20=20
This was my worry, are you sure there is no way around this? It seems
to me that by forcing this constraint we will always be struggling
against ERT in the future.
> Also in many cases the subsequent
> +;; test often depends on the passing of the previous test.
> +
> +;; It is recommended to run this suite in a separate process, for
> +;; example, in root of Emacs source directory:
> +
> +;; ./src/emacs -batch \
> +;; -l ../test/lisp/package-vc-tests.el \
> +;; -f ert-run-tests-batch-and-exit
This is unpleasant... Can you explain why, it would be nice to just use
M-x ert.
> +;;; Code:
> +
> +(require 'package-vc)
> +(require 'package)
> +(require 'vc-git)
> +(require 'vc)
> +(require 'cl-lib)
> +(require 'ert)
> +
> +(defvar package-vc-tests-dir nil)
> +
> +(defvar package-vc-tests-resources-dir
> + (file-name-concat (file-name-directory
Why not use `expand-file-name'? Or other tests are using
`ert-resource-file', perhaps that might make sense for us as well?
> + (or load-file-name buffer-file-name))
> + "package-vc-resources"))
> +(defvar package-vc-tests-packages nil)
> +
> +(defmacro with-package-vc-tests-enviroment (&rest body)
It is not possible to have this as a function that `funcall's a closure?
> + "Eval BODY with test environment."
> + (declare (debug t))
> + ;; Test packages sources are stored in bundle files produced by
> + ;; git-bundle(1) and are stored in directory package-vc-resources.
> + ;; Before executing body make sure that:
> + `(let* (package-archives
> + (package-user-dir (expand-file-name "elpa"
> + package-vc-tests-dir))
> + ;; - test packages are recognised by `package' and
> + ;; `package-vc' internals:
> + (package-archive-contents
> + (list
> + (list 'test-package-1
> + (package-desc-create
> + :name 'test-package-1
> + :version '(0 2)
> + :reqs '((emacs (30.1)))
> + :kind 'tar
> + :archive "test-elpa"
> + :extras
> + (list
> + `(:url
> + . ,(format "%s/test-package-1.bundle"
> + package-vc-tests-resources-dir))
> + '(:commit
> + . "7b8e3322055287ef1580432014de3a2d5f383d79")
> + '(:revdesc
> + . "7b8e33220552"))))
> + (list 'test-package-3
> + (package-desc-create
> + :name 'test-package-3
> + :version '(0 2)
> + :reqs '((emacs (30.1)))
> + :kind 'tar
> + :archive "test-elpa"
> + :extras
> + (list
> + `(:url
> + . ,(format "%s/test-package-3.bundle"
> + package-vc-tests-resources-dir))
> + '(:commit
> + . "7176b647c4f021f811fb7cf27f288694a0ab997d")
> + '(:revdesc
> + . "7176b647c4f0"))))))
> + (package-vc--archive-spec-alists
> + (list
> + (list 'test-elpa
> + (list 'test-package-1
> + :url (format "%s/test-package-1.bundle"
> + package-vc-tests-resources-dir)
> + :branch "master")
> + (list 'test-package-3
> + :url (format "%s/test-package-3.bundle"
> + package-vc-tests-resources-dir)
> + :branch "master"))))
> + (package-vc--archive-data-alist
> + (list
> + (list 'test-elpa :version 1 :default-vc 'Git)))
> + ;; - `vc-guess-backend-url' is recognising bundles as `Git'
> + ;; repositories:
> + (vc-clone-heuristic-alist
> + (cons
> + (cons (rx (literal package-vc-tests-resources-dir) "/"
> + (one-or-more any) ".bundle"
> + string-end)
> + 'Git)
> + vc-clone-heuristic-alist))
> + ;; - define test packages and their checkout locations
> + (package-vc-tests-packages
> + `(;; checkout and install with `package-vc-install' (on ELPA)
> + (test-package-1
> + . ,(expand-file-name "test-package-1"
> + package-user-dir))
> + ;; checkout and install with `package-vc-install' (not on
> + ;; ELPA)
> + (test-package-2
> + . ,(expand-file-name "test-package-2"
> + package-user-dir))
> + ;; checkout with `package-vc-checktout' and install with
> + ;; `package-vc-install-from-checkout' (on ELPA)
> + (test-package-3
> + . ,(expand-file-name "test-package-3"
> + package-vc-tests-dir))
> + ;; checkout with git and install with
> + ;; `package-vc-install-from-checkout'
> + (test-package-4
> + . ,(expand-file-name "test-package-4"
> + package-vc-tests-dir))
> + ;; sources in "lisp" sub directory, checkout and install
> + ;; with `package-vc-install'
> + (test-package-5
> + . ,(expand-file-name "test-package-5"
> + package-user-dir))
> + ;; sources in "lisp" sub directory, checkout with git and
> + ;; install with `package-vc-install-from-checkout'
> + (test-package-6
> + . ,(expand-file-name "test-package-6"
> + package-vc-tests-dir))
> +
> + ;; TODO: a package with source files in a non-standard
> + ;; :lisp-dir, a custom Makefile and non-standard :doc (both
> + ;; methods of installation)
> + )))
> + ;; - test directory exists:
> + (should package-vc-tests-dir)
> + (should (file-directory-p package-vc-tests-dir))
These seem more like assertions w.r.t. the testing logic than tests of
the package-vc to me.
> + ;; - resources are available:
> + (should package-vc-tests-resources-dir)
> + (should (file-directory-p package-vc-tests-resources-dir))
> + ;; - `package' has been initialised:
> + (should package--initialized)
> +
> + ,@body))
> +
> +
> +;; TODO: add test for deleting packages, with asserting
> +;; `package-vc-selected-packages'
> +
> +;; TODO: clarify `package-vc-install-all' behaviour with regards to
> +;; packages installed with `package-vc' but not stored in
> +;; `package-vc-selected-packages' i.e., packages from ELPAs
> +
> +(defun package-vc-tests-package-desc (package &optional installed)
> + "Return descriptor of PACKAGE.
> +When INSTALLED is non-nil the descriptor will come from `package-alist'.
> +Otherwise the descriptor will be from `package-archive-contents'. This
> +is to mimic `package-vc--read-package-desc'."
> + (cadr (assoc (if (stringp package) package (symbol-name package))
> + (if installed package-alist package-archive-contents)
> + #'string=3D)))
> +
> +(defun package-vc-tests-package-lisp-dir (pkg)
> + "Return a Lisp directory of PKG."
> + (when-let* ((checkout-dir (alist-get pkg package-vc-tests-packages)))
> + (cond
> + ((member pkg '(test-package-5 test-package-6))
> + (expand-file-name "lisp" checkout-dir))
> + (t checkout-dir))))
> +
> +(defun package-vc-tests-package-main-file (pkg)
> + "Return a main file of PKG."
> + (format "%s/%s.el" (package-vc-tests-package-lisp-dir pkg) pkg))
Some more commentary here, or just the assurance that in all the tests,
this is in fact do all have main file names that fit this pattern.
> +
> +(defun package-vc-tests-load-history-position (pkg type)
> + "Return a PKG's position in `load-history'.
> +If TYPE is `:autoloads' return a position of a PKG autoloads file.
> +Otherwise, if TYPE is `:main' return a position of PKG main file (not
> +compiled). Otherwise, if TYPE is `:main-compiled' return a position of
> +PKG compiled main file. Otherwise, if TYPE is `:marker' return a
> +position of a marker PKG."
> + (let ((pkg-file (pcase type
> + (:autoloads
> + (rx (literal
> + (format "%s/%s/%s-autoloads.el"
> + package-user-dir pkg pkg))
> + string-end))
> + (:main
> + (rx
> + (literal
> + (format "%s"
^
this seems like a noop to me? the
same below...
> + (package-vc-tests-package-main-file pkg)))
> + string-end))
> + (:main-compiled
> + (rx
> + (literal
> + (format "%s"
> + (package-vc-tests-package-main-file pkg)))
> + "c"
> + string-end))
> + (:marker
> + (rx "/" (literal (format "%s" pkg))))))
> + (interesting-entry
> + (rx string-start
> + (literal (file-truename package-vc-tests-dir)))))
> + (cl-position-if
> + (lambda (file)
> + (string-match pkg-file file))
> + (cl-remove-if-not
> + (lambda (file-name)
> + (string-match interesting-entry file-name))
> + (mapcar
> + #'file-truename
> + (cl-remove-if-not
> + #'stringp
> + (mapcar #'car load-history)))))))
> +
> +(defun package-vc-tests-assert-delete-elc ()
> + "Assert that .elc files are in expected directories and delete them.
> +When ALL is non nil, check all packages under test."
> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
> + (let* ((dir (package-vc-tests-package-lisp-dir pkg))
> + (elc-files (directory-files dir nil (rx ".elc" string-end)))
> + (autoloads-rx (rx
> + (literal (format "%s-autoloads.el" pkg))
> + string-end)))
> + (should-not (equal (cons dir elc-files)
> + (list dir)))
> + (should-not (cl-find-if (lambda (elc)
> + (string-match autoloads-rx elc))
^
double space
> + elc-files))
> + (dolist (elc-file elc-files)
> + (delete-file (expand-file-name elc-file dir))))))
Are we sure that this functionality has not been implemented somewhere
else? It all seems a little finicky to me...
> +
> +(defun package-vc-tests-assert-package-alist (version)
> + "Assert that entries in `package-alist' have correct VERSION and dir."
> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
> + (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
> + (should (equal (file-name-as-directory
> + (expand-file-name (format "%s" pkg)
> + package-user-dir))
> + (file-name-as-directory
> + (package-desc-dir pkg-desc))))
> + (should (equal (list pkg version)
> + (list pkg (package-desc-version pkg-desc)))))))
I know we have been over this, but we could get someone with more ERT
experience to chime in to see if there is some way to avoid having to
write tests in this contrived way...
> +
> +(defun package-vc-tests-reset-heads ()
> + "Reset to HEAD^ checkouts `package-vc-tests-packages'."
> + (mapcar (lambda (pkg-checkout-dir)
This function is only used for its side-effects, so please use dolist
here!
> + (let ((default-directory (cdr pkg-checkout-dir)))
> + (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))
> + package-vc-tests-packages))
> +
> +(defun package-vc-tests-packages-heads ()
> + "Return HEAD revisions of `package-vc-tests-packages'."
> + (mapcar (lambda (pkg-checkout-dir)
> + (let ((default-directory (cdr pkg-checkout-dir)))
> + (cons (car pkg-checkout-dir)
> + (vc-git-working-revision nil))))
> + package-vc-tests-packages))
> +
> +(ert-deftest package-vc-tests-000-install ()
> + (setq package-vc-tests-dir
> + (make-temp-file "package-vc-tests-"
> + t
> + (format-time-string "-%Y%m%d.%H%M%S")))
> + (package-initialize)
> + (package-vc--archives-initialize)
> + (eval
Why are you evaluating the code like this??? (eval (quote x)) evaluates
to the same thing as x.
> + '(with-package-vc-tests-enviroment
> + (push (list (format "%s/install-begin" package-vc-tests-dir))
> + load-history)
> + (package-vc-install 'test-package-1)
> + (should-not (alist-get "test-package-1"
> + package-vc-selected-packages
> + nil nil #'string=3D))
> +
> + (let ((bundle (format "%s/test-package-2.bundle"
> + package-vc-tests-resources-dir)))
> + (package-vc-install `(test-package-2
> + :url ,bundle
> + :branch "master"))
> + (should (equal bundle
> + (plist-get (alist-get "test-package-2"
> + package-vc-selected-packages
> + nil nil #'string=3D)
> + :url))))
> +
> + (let ((checkout-dir (expand-file-name "test-package-3"
> + package-vc-tests-dir)))
> + (package-vc-checkout (package-vc-tests-package-desc
> + 'test-package-3)
> + checkout-dir)
> + (package-vc-install-from-checkout checkout-dir)
> + (should (equal (format "file://%s" checkout-dir)
> + (plist-get (alist-get "test-package-3"
> + package-vc-selected-packages
> + nil nil #'string=3D)
> + :url))))
> +
> + (let ((checkout-dir (expand-file-name "test-package-4"
> + package-vc-tests-dir)))
> + (shell-command
> + (format "git clone -b master %s/test-package-4.bundle %s"
> + package-vc-tests-resources-dir
> + checkout-dir))
> + (package-vc-install-from-checkout checkout-dir "test-package-4")
> + (should (equal (format "file://%s" checkout-dir)
> + (plist-get (alist-get "test-package-4"
> + package-vc-selected-packages
> + nil nil #'string=3D)
> + :url))))
> +
> + (let ((bundle (format "%s/test-package-5.bundle"
> + package-vc-tests-resources-dir)))
> + (package-vc-install `(test-package-5
> + :url ,bundle
> + :branch "master"))
> + (should (equal bundle
> + (plist-get (alist-get "test-package-5"
> + package-vc-selected-packages
> + nil nil #'string=3D)
> + :url))))
> +
> + (let ((checkout-dir (expand-file-name "test-package-6"
> + package-vc-tests-dir)))
> + (shell-command
> + (format "git clone -b master %s/test-package-6.bundle %s"
> + package-vc-tests-resources-dir
> + checkout-dir))
> + (package-vc-install-from-checkout checkout-dir "test-package-6")
> + (should (equal (format "file://%s" checkout-dir)
> + (plist-get (alist-get "test-package-6"
> + package-vc-selected-packages
> + nil nil #'string=3D)
> + :url))))
> +
> + (push (list (format "%s/install-end" package-vc-tests-dir))
> + load-history)
> +
> + (package-vc-tests-assert-package-alist '(0 2))
> + (package-vc-tests-assert-delete-elc))))
> +
> +(ert-deftest package-vc-tests-001-main-file ()
> + (eval
> + '(with-package-vc-tests-enviroment
> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
You can also use pcase-dolist if you want to pattern-match on each
element of the list, to avoid consing a new list. Not that that matters
much in tests, but it is less verbose.
> + (should (equal (package-vc--main-file
> + (package-vc-tests-package-desc pkg t))
> + (package-vc-tests-package-main-file pkg)))))))
> +
> +(ert-deftest package-vc-tests-002-commit ()
> + (eval
> + '(with-package-vc-tests-enviroment
> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
> + (let ((commit (package-vc-commit
> + (package-vc-tests-package-desc pkg t))))
> + (should-not (equal (cons pkg commit)
> + (list pkg)))
> + (should-not (equal (list pkg "unknown")
> + (list pkg commit))))))))
> +
> +(ert-deftest package-vc-tests-003-load-history-after-install ()
> + (eval
> + '(with-package-vc-tests-enviroment
> + (let ((install-begin
> + (should (package-vc-tests-load-history-position
> + 'install-begin :marker)))
> + (install-end
> + (should (package-vc-tests-load-history-position
> + 'install-end :marker))))
> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
> + (let ((autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads))))
> + (should (< install-end autoloads-pos install-begin)))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main-compiled)))))))
> +
> +(defmacro package-vc-tests-package-vc-upgrade-wait (seconds count &rest =
body)
> + "Wait up to SECONDS for COUNT packages upgrading BODY.
> +Return nil on timeout or the value of last form in BODY."
> + (declare (indent 2))
> + `(letrec ((packages-count ,count)
> + (post-vc-command
> + (lambda (command _ flags)
> + ;; A crude filter for vc commands
> + (when (and (equal command "git")
> + (string-prefix-p "*vc-git" (buffer-name)))
> + (cl-decf packages-count)))))
cl-decf is an alias for decf since Emacs 31.
> + (add-hook 'vc-post-command-functions post-vc-command 100)
> + (unwind-protect
> + (with-timeout (,seconds nil)
Having tests fail with hard-coded timeout values seems wrong as they can
depend on the specific decide and its available resources. Couldn't we
use something like `ert-skip' in this case?
> + (prog1
> + (progn ,@body)
> + (while (not (eql packages-count 0))
Or just /=3D, as you want package-count to be a number as well, right?
> + (sleep-for 0.1))))
> + (remove-hook 'vc-post-command-functions post-vc-command))))
> +
> +(ert-deftest package-vc-tests-004-upgrade-all ()
> + (eval
> + '(with-package-vc-tests-enviroment
> + (push (list (format "%s/upgrade-all-begin" package-vc-tests-dir))
> + load-history)
> + (let ((heads (package-vc-tests-packages-heads)))
> + (package-vc-tests-reset-heads)
> + (should
> + (package-vc-tests-package-vc-upgrade-wait
> + 5 (length package-vc-tests-packages)
> + (package-vc-upgrade-all)
> + t))
> + (should (equal heads
> + (package-vc-tests-packages-heads))))
> + (push (list (format "%s/upgrade-all-end" package-vc-tests-dir))
> + load-history)
> + (package-vc-tests-assert-package-alist '(0 2))
> + (package-vc-tests-assert-delete-elc))))
> +
> +(ert-deftest package-vc-tests-005-load-history-after-upgrade-all ()
> + (eval
> + '(with-package-vc-tests-enviroment
> + (let ((upgrade-all-begin
> + (should (package-vc-tests-load-history-position
> + 'upgrade-all-begin :marker)))
> + (upgrade-all-end
> + (should (package-vc-tests-load-history-position
> + 'upgrade-all-end :marker))))
> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
> + (let ((autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads))))
> + (should (< upgrade-all-end autoloads-pos upgrade-all-begin))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main-compiled))))))))
> +
> +(ert-deftest package-vc-tests-006-require ()
> + (eval
> + '(with-package-vc-tests-enviroment
> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
> + (should (fboundp (intern (format "%s-func" pkg))))
> + (should (autoloadp
> + (symbol-function (intern (format "%s-func" pkg)))))
> + (should (require pkg))
> + (should (fboundp (intern (format "%s-func" pkg))))
> + (should-not (autoloadp
> + (symbol-function (intern (format "%s-func" pkg)))))
> + (should-not (fboundp (intern (format "%s-old-func" pkg)))))
> + (let ((upgrade-all-end
> + (should (package-vc-tests-load-history-position
> + 'upgrade-all-end :marker))))
> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
> + (let ((main-pos (should (package-vc-tests-load-history-position
> + pkg :main))))
> + (should (< main-pos upgrade-all-end)))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main-compiled)))))))
> +
> +(ert-deftest package-vc-tests-007-upgrade ()
> + (eval
> + '(with-package-vc-tests-enviroment
> + (push (list (format "%s/upgrade-begin" package-vc-tests-dir))
> + load-history)
> + (let ((heads (package-vc-tests-packages-heads)))
> + (package-vc-tests-reset-heads)
> + (should
> + (package-vc-tests-package-vc-upgrade-wait
> + 5 (length package-vc-tests-packages)
> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
> + (package-vc-upgrade
> + (package-vc-tests-package-desc pkg t))
> + (should (fboundp (intern (format "%s-func" pkg))))
> + (should-not (autoloadp
> + (symbol-function
> + (intern (format "%s-func" pkg)))))
> + (should-not (fboundp (intern (format "%s-old-func" pkg)))))
> + t))
> + (should (equal heads
> + (package-vc-tests-packages-heads))))
> + (push (list (format "%s/upgrade-end" package-vc-tests-dir))
> + load-history)
> + (package-vc-tests-assert-package-alist '(0 2))
> + (package-vc-tests-assert-delete-elc))))
> +
> +(ert-deftest package-vc-tests-008-load-history-after-upgrade ()
> + (eval
> + '(with-package-vc-tests-enviroment
> + (let ((upgrade-begin
> + (should (package-vc-tests-load-history-position
> + 'upgrade-begin :marker)))
> + (upgrade-end
> + (should (package-vc-tests-load-history-position
> + 'upgrade-end :marker))))
> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
> + (let ((autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads)))
> + (main-pos
> + (should (package-vc-tests-load-history-position
> + pkg :main)))
> + (main-compiled-pos
> + (should (package-vc-tests-load-history-position
> + pkg :main-compiled))))
> + (should (< upgrade-end autoloads-pos upgrade-begin))
> + (should (< upgrade-end main-pos upgrade-begin))
> + (should
> + (< upgrade-end main-compiled-pos upgrade-begin))))))))
> +
> +(ert-deftest package-vc-tests-009-rebuild ()
> + (eval
> + '(with-package-vc-tests-enviroment
> + (package-vc-tests-reset-heads)
> + (let ((heads (package-vc-tests-packages-heads)))
> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
> + (package-vc-rebuild
> + (package-vc-tests-package-desc pkg t))
> + (should (fboundp (intern (format "%s-func" pkg))))
> + (should-not (autoloadp
> + (symbol-function
> + (intern (format "%s-func" pkg)))))
> + (should (fboundp (intern (format "%s-old-func" pkg))))
> + (should-not (autoloadp
> + (symbol-function
> + (intern (format "%s-old-func" pkg))))))
> + (should (equal heads
> + (package-vc-tests-packages-heads))))
> + (package-vc-tests-assert-package-alist '(0 1))
> + (package-vc-tests-assert-delete-elc))))
> +
> +(ert-deftest package-vc-tests-010-prepare-patch ()
> + (eval
> + '(with-package-vc-tests-enviroment
> + (dolist (pkg-checkout-dir package-vc-tests-packages)
> + (cl-letf* ((call-count 0)
> + ((symbol-function #'package-maintainers)
> + (lambda (&rest _)
> + "test-maintainers"))
> + ((symbol-function #'vc-prepare-patch)
> + (lambda (addressee subject revisions)
> + (should (equal (file-name-as-directory
> + default-directory)
> + (file-name-as-directory
> + (cdr pkg-checkout-dir))))
> + (should (equal "test-maintainers" addressee))
> + (should (equal "test-subject" subject))
> + (should (equal "test-revisions" revisions))
> + (cl-incf call-count))))
> + (package-vc-prepare-patch (package-vc-tests-package-desc
> + (car pkg-checkout-dir)
> + t)
> + "test-subject"
> + "test-revisions")
> + (should (eql 1 call-count)))))))
> +
> +(ert-deftest package-vc-tests-011-log-incoming ()
> + (eval
> + '(with-package-vc-tests-enviroment
> + (dolist (pkg-checkout-dir package-vc-tests-packages)
> + (cl-letf* ((call-count 0)
> + ((symbol-function #'vc-log-incoming)
> + (lambda ()
> + (interactive)
> + (should (equal (file-name-as-directory
> + default-directory)
> + (file-name-as-directory
> + (cdr pkg-checkout-dir))))
> + (cl-incf call-count))))
> + (package-vc-log-incoming (package-vc-tests-package-desc
> + (car pkg-checkout-dir) t))
> + (should (eql 1 call-count)))))))
> +
> +(provide 'package-vc-tests)
> +
> +;;; package-vc-tests.el ends here
Just for technical reasons I am opposed to applying the patch in the
current state. I don't understand some of your decisions, and am
generally not a fan of the things being tested or the approach of having
the tests depend on one another. If you don't want to rework it, that
is fine -- I can also take care of that, though it would be nice if I
could take over your demo packages.
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Thu, 06 Nov 2025 17:03:01 +0000
Resent-Message-ID: <handler.79188.B79188.176244853311169 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176244853311169
(code B ref 79188); Thu, 06 Nov 2025 17:03:01 +0000
Received: (at 79188) by debbugs.gnu.org; 6 Nov 2025 17:02:13 +0000
Received: from localhost ([127.0.0.1]:39388 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vH3NB-0002u3-80
for submit <at> debbugs.gnu.org; Thu, 06 Nov 2025 12:02:13 -0500
Received: from mail-wm1-x32d.google.com ([2a00:1450:4864:20::32d]:54650)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1vH3N4-0002ta-So
for 79188 <at> debbugs.gnu.org; Thu, 06 Nov 2025 12:02:07 -0500
Received: by mail-wm1-x32d.google.com with SMTP id
5b1f17b1804b1-4775ae5684fso6692955e9.1
for <79188 <at> debbugs.gnu.org>; Thu, 06 Nov 2025 09:02:02 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1762448516; x=1763053316; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=7oM7F8uAufnT4tzHbAqJvW9fkZErqvy4cdnLy/eT8DI=;
b=izApTP+Rr6V3nxW57B7pc4El5KkjQQp3d6TBYLb+F+99gzObGjLP92C21uxpvRT0jn
UFXdBlVLJy7tw1XKGS8VVi53Rlc7u0UzTQOdmY4dmp3x/+2X7ekSeXag3mRhEXIWkcsg
EgwQXSfwxl3vgtxpcl7Rj66n/3hJ9AUa8uUUVmtc8DsHom3MfqexO9BOBrXVY+AlZwS4
iAOztfhX7hMkqnzqfcmsFkAsfjC7muKAIdoVsxm0WE4TEBUc3odAaVYH/gWSTDjavmLY
NqWboIs1LjH3iKOgs5GsoCo9g9IP3NAH4XhYlK3pPm86/h426FzM6SikNPddfwLcJUa+
RNjg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1762448516; x=1763053316;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject
:date:message-id:reply-to;
bh=7oM7F8uAufnT4tzHbAqJvW9fkZErqvy4cdnLy/eT8DI=;
b=dwTfbvTKpun0kZmrHl09zOka0kfuftQrFJPf/qkrYL2oNlqEHburIs7+gZ57MMqI4J
GJ8jTpokshJX9YtjHC0WdkHcJSt/heg/eL4Gt+UNFcai2NJ7uASZ5Vow5tlSm6Iw+Aai
rVTM8512LdXdN7+IN4PWPDrK6lNRNWR71fFDMRlbEUdq7OJwxP3e+U7Qfw+5+YICqFGa
XkVKqSmHld2TGXDDl3OSU39+OK7/A1Q3vthCq7wk0ETnO3r8L1V3WHBLQD4VMu14BnB6
2fPADgmAIUo/N3sbXC2BGw1wGjAFJoYUkoVndIjYGF1qKpzjd672hdwbEzExH7TYarJw
jnsA==
X-Gm-Message-State: AOJu0Ywwa6JeUMOJeO/JX0pA7aoDrOTqkXf+OxNxPEWYUnPPqKQjaZgm
a9nubkSgaeFvMpI6/ti/FZjsf68JKG8rXBJlxNzRAo4N8ENpPdKb1d8eqGXSGQ==
X-Gm-Gg: ASbGnct2WoSPLHDpkZJjQMY5q9ytIkE4Ni+w7ErHMOO/TZwUyd/lnjgnNqZ2UjzaX4H
XRApzY5xZOpoKO1u2Dcg/VtvdGJGX7si4V6vozEjhphcKY5oaEOO9V6D77WdyplZDQSqrN+WL/4
b5Yu8oQytOI8sQcrxdebnPlVT3cHph018mAH+gxPP65iIUVl3osYbNjM4MxJMNDqshtWCejuUtx
84WzdNI11O9u1J2/Xxk0xyy7PGNz1bpuyYeoE/3y4RLaWGPdNcYQxC/BjMrRbr3Cp0bfjm3dcwh
rRD24LXqQLNSYDHMaAcnkz6qbGggt49yVOcrJvrlnR7fmsShPLCPVgPCTn/ZRjahQiY4N4YxEmi
kd+o92rRgwzAOcJ8HVHVfGwMOS0PjFig/Zi0jTQgqMJ1j3k8zAfvHvKi+KLrG7sDyxvnFEErSCQ
UUsIJSqN97RDza5YgAjmON8CcxsdoFY2hfnNblaRaaIZYYnE3SwdL0/lfQ
X-Google-Smtp-Source: AGHT+IG2YHXAJxeGYxZSqzRLOO4v1/BleYI5Vb4oDpY/81JVwwj/osaabubkHkc69MRj2X2BartYEQ==
X-Received: by 2002:a05:600c:1f91:b0:477:1ae1:fa5d with SMTP id
5b1f17b1804b1-4776bcb8986mr231915e9.20.1762448515984;
Thu, 06 Nov 2025 09:01:55 -0800 (PST)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:a18e:5efe:74c1:cc93])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-477625e88fasm73888595e9.15.2025.11.06.09.01.54
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Thu, 06 Nov 2025 09:01:54 -0800 (PST)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <87a51du92y.fsf@HIDDEN> (Philip Kaludercic's message of "Sun,
26 Oct 2025 12:43:55 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
<m2a51k4jd5.fsf@HIDDEN> <87a51du92y.fsf@HIDDEN>
Date: Thu, 06 Nov 2025 17:01:53 +0000
Message-ID: <m2bjlfrt6m.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain
Sorry for long time to respond. It took me some time to apply fixes and
reply. Attached are new patches, still keeping tests separate.
--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment;
filename=0001-Fix-upgrading-rebuilding-and-logging-of-VC-packages.patch
Content-Description: package-vc-patch
From 2e0fd674697843566de401ce45ba2e6e5a94e735 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Przemys=C5=82aw=20Kryger?= <pkryger@HIDDEN>
Date: Fri, 26 Sep 2025 17:24:44 +0100
Subject: [PATCH 1/2] Fix upgrading, rebuilding, and logging of VC packages
There are a few issues addressed in this patch:
1. Compilation (including native compilation) should happen in
directory that contains package's Lisp code.
2. After installing a package with
`package-vc-install-from-checkout' and subsequently upgrading it
with `package-vc-upgrade' the pkg-desc for the package becomes
corrupted. After the upgrade the pkg-desc's dir (a.k.a
`pkg-dir') points to checkout directory. This will cause the
subsequent `package-delete' to delete the checkout directory and
leaving incorrect forwarding autoloads file in
`package-user-directory'.
3. The detection of package's Lisp directory has been not
effective for packages installed with `package-vc-install' and
not existent for packages installed with
`package-install-from-checkout'.
4. Deduction of VC backend has been not working when called from
outside of deducing context.
* lisp/emacs-lisp/package-vc.el (package-vc--checkout-dir): Use
`pcase' to extract checkout directory from `pkg-spec'. Detect
standard lisp sub directory if called with non-nil `lisp-dir'.
(package-vc--unpack-1): Remove superfluous `pkg-dir' argument.
Use a `package' with `:dir' pointing to where package code is.
When `checkout-dir' is different than `pkg-dir' then call
`package--add-info-node' and after calling `package-activate-1'
ensure that source files are reloaded in case when `lisp-dir' is
a sub directory.
(package-vc-install-from-checkout): Remove superfluous
`package-vc-selected-packages' binding. Remove `pkg-dir'
argument from `package-vc--unpack-1' calls.
(package-vc--unpack): Remove `lisp-dir' variable and convert to
`let*'. Remove superfluous Lisp code sub directory detection -
logic moved to `package-vc--checkout-dir'. Remove `pkg-dir'
argument from `package-vc--unpack-1' call.
(package-vc-upgrade, package-vc-rebuild): Remove `pkg-dir'
argument from `package-vc--unpack-1' calls.
(package-vc-log-incoming): Endure VC backend can be deduced when
called from outside of default deducing context.
* lisp/emacs-lisp/package.el (package--add-info-node): New
function to install info node for package. Extracted from
`package-activate-1'.
(package-activate-1): Call `package--add-info-node'.
(Bug#79188)
---
lisp/emacs-lisp/package-vc.el | 166 ++++++++++++++++++++--------------
lisp/emacs-lisp/package.el | 15 +--
2 files changed, 109 insertions(+), 72 deletions(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 078a7bd8136..b2e1d28ff6f 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -31,8 +31,7 @@
;; aren't interested in activating a package, you can use
;; `package-vc-checkout' instead, which will prompt you for a target
;; directory. If you wish to reuse an existing checkout, the command
-;; `package-vc-install-from-checkout' will create a symbolic link and
-;; prepare the package.
+;; `package-vc-install-from-checkout' will prepare the package.
;;
;; If you make local changes that you wish to share with an upstream
;; maintainer, the command `package-vc-prepare-patch' can prepare
@@ -180,16 +179,39 @@ package-vc--checkout-dir
that case the package redirects to the actual VC checkout. If the
optional LISP-DIR argument is non-nil, then check if a related package
specification has a `:lisp-dir' field to indicate that Lisp files are
-located in a sub directory of a checkout and return that instead."
+located in a sub directory of the checkout, or the checkout has a sub
+directory named \"lisp\" or \"src\" that contains .el files and return
+that instead."
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
- (url (plist-get pkg-spec :url)))
+ (url (plist-get pkg-spec :url))
+ (pkg-dir (pcase url
+ ((rx "file://" (let checkout-dir (+ any)))
+ checkout-dir)
+ (_ (package-desc-dir pkg-desc)))))
(expand-file-name
- (or (and (not lisp-dir) (plist-get pkg-spec :lisp-dir)) ".")
- (cond
- ((save-match-data
- (and url (string-match (rx "file://" (group (+ any))) url)
- (match-string 1 url))))
- (t (package-desc-dir pkg-desc))))))
+ (or (and lisp-dir
+ (or (plist-get pkg-spec :lisp-dir)
+ ;; When nothing is specified about a `lisp-dir', then
+ ;; should heuristically check if there is a
+ ;; sub-directory with lisp files. These are
+ ;; conventionally just called "lisp" or "src". If
+ ;; this directory exists and contains non-zero number
+ ;; of lisp files, we will use that instead of
+ ;; `pkg-dir'.
+ (catch 'done
+ (dolist (name '("lisp" "src"))
+ (when-let* ((dir (expand-file-name name pkg-dir))
+ ((file-directory-p dir))
+ ((directory-files
+ dir nil "\\`[^.].+\\.el\\'" t 1)))
+ ;; We won't use `dir', since dir is an absolute
+ ;; path and we don't want `lisp-dir' to depend
+ ;; on the current location of the package
+ ;; installation, ie. to break if moved around
+ ;; the file system or between installations.
+ (throw 'done name))))))
+ ".")
+ pkg-dir)))
(defun package-vc--read-archive-data (archive)
"Update `package-vc--archive-spec-alists' for ARCHIVE.
@@ -468,14 +490,24 @@ package-vc-install-dependencies
(mapc #'package-install-from-archive to-install)
missing))
-(defun package-vc--unpack-1 (pkg-desc pkg-dir)
- "Prepare PKG-DESC that is already checked-out in PKG-DIR.
-This includes downloading missing dependencies, generating
-autoloads, generating a package description file (used to
-identify a package as a VC package later on), building
-documentation and marking the package as installed."
- (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
+(defun package-vc--unpack-1 (pkg-desc)
+ "Prepare PKG-DESC that is already checked-out.
+When there's a relevant pkg-spec it is used for checkout directory.
+Otherwise `dir' slot of PKG-SPEC is used. This includes downloading
+missing dependencies, generating autoloads, generating a package
+description file (used to identify a package as a VC package later on),
+building documentation and marking the package as installed."
+ (let* (;; Main package directory, under `package-user-dir'. This is
+ ;; the same `checkout-dir' when package has been installed with
+ ;; `package-vc-install'.
+ (pkg-dir (package-desc-dir pkg-desc))
+ (pkg-spec (package-vc--desc->spec pkg-desc))
+ ;; Directory where the package repository has been checked out.
+ ;; This is the `dir' argument of
+ ;; `package-vc-install-from-checkout'.
(checkout-dir (package-vc--checkout-dir pkg-desc))
+ ;; Directory where package's Lisp code resides. It may be
+ ;; equal to `checkout-dir' or be a subdirectory of it.
(lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
missing)
@@ -518,13 +550,17 @@ package-vc--unpack-1
(auto-name (format "%s-autoloads.el" name)))
(package-generate-autoloads name lisp-dir)
;; There are two cases when we wish to "indirect" the loading of
- ;; autoload files: 1. a package specification has a `:lisp-dir'
- ;; entry listing indicting that the actual Lisp code is located in
- ;; a subdirectory of the checkout, 2. the package has been
- ;; installed using `package-vc-install-from-checkout' and we want
- ;; to load the other directory instead -- which is outside of the
- ;; checkout. We can therefore take file inequality as a sign that
- ;; we have to set up an indirection.
+ ;; autoload files:
+ ;;
+ ;; 1. a package specification has a `:lisp-dir' entry listing
+ ;; indicting that the actual Lisp code is located in a
+ ;; subdirectory of the checkout,
+ ;;
+ ;; 2. the package has been installed using
+ ;; `package-vc-install-from-checkout' and we want to load the
+ ;; other directory instead -- which is outside of the checkout.
+ ;; We can therefore take file inequality as a sign that we have to
+ ;; set up an indirection.
(unless (file-equal-p lisp-dir pkg-dir)
(write-region
(concat
@@ -568,20 +604,37 @@ package-vc--unpack-1
(setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
;; Update package-alist.
- (let ((new-desc (package-load-descriptor pkg-dir)))
+ (let* ((new-desc (package-load-descriptor pkg-dir))
+ (compile-desc (package-desc-create :name (package-desc-name new-desc)
+ :dir lisp-dir)))
;; Activation has to be done before compilation, so that if we're
;; upgrading and macros have changed we load the new definitions
;; before compiling.
(when (package-activate-1 new-desc :reload :deps)
+ ;; `package-activate-1' will reload all necessary package files
+ ;; as long as their stems are relative to of `pkg-dir'. If
+ ;; that's not the case (for example for packages with different
+ ;; `checkout-dir' or with source files in a sub directory of
+ ;; `pkg-dir'), we want to reload package files from the
+ ;; `lisp-dir' before compilation.
+ (unless (file-equal-p lisp-dir pkg-dir)
+ (package--reload-previously-loaded compile-desc))
+ ;; `package-activate-1' will add info node as long as dir file
+ ;; exists in `pkg-dir'. We need to manually add it when
+ ;; `checkout-dir' is in different location.
+ (unless (file-equal-p checkout-dir pkg-dir)
+ (package--add-info-node checkout-dir))
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
- (package--compile (package-desc-create :dir lisp-dir))
+ (package--compile compile-desc)
(when package-native-compile
- (package--native-compile-async new-desc))
+ (package--native-compile-async compile-desc))
;; After compilation, load again any files loaded by
- ;; `activate-1', so that we use the byte-compiled definitions.
- (package--reload-previously-loaded new-desc)))
+ ;; `package-activate-1', so that we use the byte-compiled
+ ;; definitions. This time we'll use `compile-desc' straight
+ ;; away.
+ (package--reload-previously-loaded compile-desc)))
;; Mark package as selected
(let ((name (package-desc-name pkg-desc)))
@@ -669,10 +722,9 @@ package-vc--unpack
(let ((copy (copy-package-desc pkg-desc)))
(setf (package-desc-kind copy) 'vc
pkg-desc copy)))
- (pcase-let* (((map :lisp-dir) pkg-spec)
- (name (package-desc-name pkg-desc))
- (dirname (package-desc-full-name pkg-desc))
- (pkg-dir (file-name-as-directory (expand-file-name dirname package-user-dir))))
+ (let* ((name (package-desc-name pkg-desc))
+ (dirname (package-desc-full-name pkg-desc))
+ (pkg-dir (file-name-as-directory (expand-file-name dirname package-user-dir))))
(when (string-empty-p name)
(user-error "Empty package name"))
(setf (package-desc-dir pkg-desc) pkg-dir)
@@ -693,28 +745,11 @@ package-vc--unpack
(delete-directory pkg-dir t)
(user-error "Installation aborted")))
- ;; When nothing is specified about a `lisp-dir', then should
- ;; heuristically check if there is a sub-directory with lisp
- ;; files. These are conventionally just called "lisp" or "src".
- ;; If this directory exists and contains non-zero number of lisp
- ;; files, we will use that instead of `pkg-dir'.
- (catch 'done
- (dolist (name '("lisp" "src"))
- (when-let* (((null lisp-dir))
- (dir (expand-file-name name pkg-dir))
- ((file-directory-p dir))
- ((directory-files dir nil "\\`[^.].+\\.el\\'" t 1)))
- ;; We won't use `dir', since dir is an absolute path and we
- ;; don't want `lisp-dir' to depend on the current location of
- ;; the package installation, ie. to break if moved around the
- ;; file system or between installations.
- (throw 'done (setq lisp-dir name)))))
-
;; Ensure we have a copy of the package specification
(when (null (package-vc--desc->spec pkg-desc name))
(package-vc--save-selected-packages name pkg-spec))
- (package-vc--unpack-1 pkg-desc pkg-dir)))
+ (package-vc--unpack-1 pkg-desc)))
(defun package-vc--read-package-name (prompt &optional allow-url installed)
"Query the user for a VC package and return a name with PROMPT.
@@ -782,7 +817,7 @@ package-vc-upgrade
;;
;; If there is a better way to do this, it should be done.
(cl-assert (package-vc-p pkg-desc))
- (letrec ((pkg-dir (package-vc--checkout-dir pkg-desc))
+ (letrec ((checkout-dir (package-vc--checkout-dir pkg-desc))
(vc-flags)
(vc-filter-command-function
(lambda (command file-or-list flags)
@@ -790,18 +825,19 @@ package-vc-upgrade
(list command file-or-list flags)))
(post-upgrade
(lambda (_command _file-or-list flags)
- (when (and (file-equal-p pkg-dir default-directory)
+ (when (and (file-equal-p checkout-dir default-directory)
(eq flags vc-flags))
(unwind-protect
(with-demoted-errors "Failed to activate: %S"
- (package-vc--unpack-1 pkg-desc pkg-dir))
+ (package-vc--unpack-1 pkg-desc))
(remove-hook 'vc-post-command-functions post-upgrade))))))
(add-hook 'vc-post-command-functions post-upgrade)
(with-demoted-errors "Failed to fetch: %S"
(require 'vc-dir)
(with-current-buffer (vc-dir-prepare-status-buffer
- (format " *package-vc-dir: %s*" pkg-dir)
- pkg-dir (vc-responsible-backend pkg-dir))
+ (format " *package-vc-dir: %s*" checkout-dir)
+ checkout-dir
+ (vc-responsible-backend checkout-dir))
(vc-pull)))))
(defun package-vc--archives-initialize ()
@@ -966,24 +1002,21 @@ package-vc-install-from-checkout
(package-vc--archives-initialize)
(let* ((dir (if interactive dir (expand-file-name dir))) ;avoid double expansion
(name (or name (file-name-base (directory-file-name dir))))
- (pkg-dir (file-name-concat package-user-dir name))
- (package-vc-selected-packages
- (cons (list name :lisp-dir dir)
- package-vc-selected-packages)))
+ (pkg-dir (file-name-concat package-user-dir name)))
(when (file-exists-p pkg-dir)
(if (yes-or-no-p (format "Overwrite previous checkout for package `%s'?" name))
(package--delete-directory pkg-dir)
(error "There already exists a checkout for %s" name)))
(make-directory pkg-dir t)
- ;; We store a custom package specification so that
- ;; `package-vc--checkout-dir' can later retrieve the actual checkout.
+ ;; We store a custom package specification so that it is available
+ ;; for `package-vc--unpack-1' as well as `package-vc--checkout-dir'
+ ;; can later retrieve the actual checkout.
(package-vc--save-selected-packages name (list :url (concat "file://" dir)))
(package-vc--unpack-1
(package-desc-create
:name (intern name)
:dir pkg-dir
- :kind 'vc)
- (file-name-as-directory pkg-dir))))
+ :kind 'vc))))
;;;###autoload
(defun package-vc-rebuild (pkg-desc)
@@ -995,7 +1028,7 @@ package-vc-rebuild
is the responsibility of `package-vc-upgrade'. Interactively,
prompt for the name of the package to rebuild."
(interactive (list (package-vc--read-package-desc "Rebuild package: " t)))
- (package-vc--unpack-1 pkg-desc (package-vc--checkout-dir pkg-desc)))
+ (package-vc--unpack-1 pkg-desc))
;;;###autoload
(defun package-vc-prepare-patch (pkg-desc subject revisions)
@@ -1023,7 +1056,8 @@ package-vc-log-incoming
"Call `vc-log-incoming' for the package PKG-DESC."
(interactive
(list (package-vc--read-package-desc "Incoming log for package: " t)))
- (let ((default-directory (package-vc--checkout-dir pkg-desc)))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc))
+ (vc-deduce-backend-nonvc-modes t))
(call-interactively #'vc-log-incoming)))
(provide 'package-vc)
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index c39c8bf24cc..57167406e53 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -903,6 +903,14 @@ package--reload-previously-loaded
(mapc (lambda (c) (load (car c) nil t))
(sort result (lambda (x y) (< (cdr x) (cdr y))))))))
+(defun package--add-info-node (pkg-dir)
+ "Add info node located in PKG-DIR."
+ (when (file-exists-p (expand-file-name "dir" pkg-dir))
+ ;; FIXME: not the friendliest, but simple.
+ (require 'info)
+ (info-initialize)
+ (add-to-list 'Info-directory-list pkg-dir)))
+
(defun package-activate-1 (pkg-desc &optional reload deps)
"Activate package given by PKG-DESC, even if it was already active.
If DEPS is non-nil, also activate its dependencies (unless they
@@ -934,12 +942,7 @@ package-activate-1
The following files have already been loaded: %S")))
(with-demoted-errors "Error loading autoloads: %s"
(load (package--autoloads-file-name pkg-desc) nil t)))
- ;; Add info node.
- (when (file-exists-p (expand-file-name "dir" pkg-dir))
- ;; FIXME: not the friendliest, but simple.
- (require 'info)
- (info-initialize)
- (add-to-list 'Info-directory-list pkg-dir))
+ (package--add-info-node pkg-dir)
(push name package-activated-list)
;; Don't return nil.
t)))
--
2.51.2
--=-=-=
Content-Type: text/x-patch; charset=utf-8
Content-Disposition: attachment;
filename=0002-Add-tests-for-package-vc.patch
Content-Transfer-Encoding: quoted-printable
Content-Description: tests-patch
From 81528fe379effa08b2a9d12e7a1fe0b2534b2999 Mon Sep 17 00:00:00 2001
From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
Date: Tue, 2 Sep 2025 09:28:13 +0100
Subject: [PATCH 2/2] Add tests for package-vc
* test/lisp/package-vc-tests.el (package-vc-tests-dir):
Temporary directory to store `package' and test data during the
test.
(package-vc-tests-packages): List of packages to tests, together
with their checkout locations.
(package-vc-tessts-bundles): List of package bundles and their
most recent commits.
(package-vc-tests-checkin): Copy a an in file and create a new
file and create a new commit for a test package source.
(package-vc-tests-create-bundle): Create a package git
repository bundle with test package source.
(with-package-vc-tests-enviroment): Setup environment for test,
that includes configuring `package', `package-vc', and `vc'
variables, as well as defining test packages and creating their
bundles.
(package-vc-tests-package-desc): Retrieve a `package-desc' for
tested package.
(package-vc-tests-package-lisp-dir): Determine a lisp directory
for a package.
(package-vc-tests-package-main-file): Calculate expected
location of package's main file.
(package-vc-tests-load-history-position): Calculate a position
in load-history of a file. The position only accounts for
interesting files, that is only files that are in
`package-vc-tests-dir'.
(package-vc-tests-assert-delete-elc): Assert that .elc files
have been gernerated for a package and delete them.
(package-vc-tests-assert-package-alist): Assert that
`pakcage-alist' contains a `package-desc' for package, and that
the `pakcage-desc' has correct slot `version' and slot `dir'.
(package-vc-tests-reset-heads): Reset heads of checkouts of
tested packages to a HEAD^.
(package-vc-tests-packages-heads): Return a list of checkouts of
tested packages current HEAD revisions.
(package-vc-tests-000-install): Test that packages can be
installed with `package-vc-install' and
`package-vc-install-from-checkout', including
`package-vc-checkout'.
(package-vc-tests-001-main-file): Test that
`package-vc--main-file' return main file in expected locations.
(package-vc-tests-002-commit): Test that `package-vc-commit' is
returning a revision.
(package-vc-tests-003-load-history-after-install): Test that
`load-history' has entries for autoloads of tested packages.
(package-vc-tests-package-vc-async-wait): Helper function to
wait for an asynchronous VC command to finish. This is needed
due to asynchronous nature of `vc-pull' and `vc-log-incoming'.
(package-vc-tests-004-upgrade-all): Test that
`package-vc-upgrade-all' indeed upgrades all packages.
(package-vc-tests-005-load-history-after-upgrade-all): Test that
`load-history' has entries for autoloads of tested packages.
(package-vc-tests-006-require): Test that packages can be
`require'd, and that `load-history' has entries for non-compiled
package main files.
(package-vc-tests-007-upgrade): Test that `package-vc-upgrade'
upgrades a package.
(package-vc-tests-008-load-history-after-upgrade): Test that
`load-history' has entries for autoloads, non-compiled main
files, and compiled main files after a package has been
upgraded.
(package-vc-tests-009-rebuild): Test that a downgraded package
can be rebuild with `package-vc-rebuild', and that appropriate
files are reloaded.
(package-vc-tests-010-prepare-patch): Test that
`package-vc-prepare-patch' creates a new message buffer for a
package.
(package-vc-tests-011-log-incoming): Test that
`package-vc-log-incoming' creates a new log buffer for a
package.
* test/lisp/package-vc-resources/test-package-v0.1.el.in:
Skeleton of version 0.1 of a test package.
* test/lisp/package-vc-resources/test-package-v0.2.el.in:
Skeleton of version 0.2 of a test package.
---
.../test-package-v0.1.el.in | 24 +
.../test-package-v0.2.el.in | 20 +
test/lisp/package-vc-tests.el | 745 ++++++++++++++++++
3 files changed, 789 insertions(+)
create mode 100644 test/lisp/package-vc-resources/test-package-v0.1.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-v0.2.el.in
create mode 100644 test/lisp/package-vc-tests.el
diff --git a/test/lisp/package-vc-resources/test-package-v0.1.el.in b/test/=
lisp/package-vc-resources/test-package-v0.1.el.in
new file mode 100644
index 00000000000..8ee147a06a7
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-v0.1.el.in
@@ -0,0 +1,24 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-author@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.1
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+;;;###autoload
+(defun test-package-SUFFIX-func ()
+ "Test.")
+
+;;;###autoload
+(defun test-package-SUFFIX-old-func ()
+ "Test.")
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-v0.2.el.in b/test/=
lisp/package-vc-resources/test-package-v0.2.el.in
new file mode 100644
index 00000000000..3c84ba0b1ac
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-v0.2.el.in
@@ -0,0 +1,20 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-author@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.2
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+;;;###autoload
+(defun test-package-SUFFIX-func ()
+ "Test.")
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
new file mode 100644
index 00000000000..c5de5eef8a0
--- /dev/null
+++ b/test/lisp/package-vc-tests.el
@@ -0,0 +1,745 @@
+;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
+
+;; Copyright (C) 2025 Free Software Foundation, Inc.
+
+;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
+;; Keywords: package
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These tests focus on verifying post conditions for `package-vc'
+;; operations on packages. Since installing a package changes the state
+;; of running process these tests are ment to be executed in order, as
+;; denoted by digits in their name. Also in many cases the subsequent
+;; test often depends on the passing of the previous test.
+
+;; These tests load test packages with some test implementation, as well
+;; as `load-history' is being modified. This may contaminate the
+;; running Emacs instance. This, compounded with a need to run all
+;; tests in the order it is recommended to run this suite in a separate
+;; process, for example, in root of Emacs source directory:
+
+;; ./src/emacs -batch \
+;; -l ../test/lisp/package-vc-tests.el \
+;; -f ert-run-tests-batch-and-exit
+
+;;; Code:
+
+(require 'package-vc)
+(require 'package)
+(require 'vc-git)
+(require 'vc)
+(require 'cl-lib)
+(require 'ert-x)
+(require 'ert)
+
+(defvar package-vc-tests-dir nil)
+(defvar package-vc-tests-packages nil)
+(defvar package-vc-tests-bundles nil)
+
+(defun package-vc-tests-checkin (name suffix in commit-msg &optional lisp-=
dir)
+ "For package NAME copy IN file as main file.
+After copying update SUFFIX in the file and check it in with COMMIT-MSG.
+If LISP-DIR is non-nil place the file under LISP-DIR."
+ (let ((resource-dir (ert-resource-directory))
+ (main-file (format "%s.el" (if lisp-dir
+ (expand-file-name name lisp-dir)
+ name)))
+ (suffix (if (stringp suffix) suffix (format "%s" suffix))))
+ (copy-file (expand-file-name in resource-dir) main-file t)
+ (with-temp-buffer
+ (insert-file-contents main-file)
+ (goto-char (point-min))
+ (while (search-forward "SUFFIX" nil t)
+ (replace-match suffix))
+ (write-file main-file))
+ (vc-git-command nil 0 nil "add" ".")
+ (vc-git-command nil 0 nil "commit" "-m" commit-msg)))
+
+(defun package-vc-tests-create-bundle (suffix &optional lisp-dir)
+ "Create a test package bundle with SUFFIX.
+If LISP-DIR is non-nil place sources of the package in LISP-DIR."
+ (let* ((name (format "test-package-%s" suffix))
+ (src-dir (expand-file-name (format "src/%s" name)
+ package-vc-tests-dir)))
+ (make-directory (if lisp-dir
+ (expand-file-name lisp-dir src-dir)
+ src-dir)
+ :parents)
+ (let ((default-directory src-dir)
+ (bundle-file (expand-file-name (format "%s.bundle" name)
+ package-vc-tests-dir)))
+ (vc-git-command nil 0 nil "init" "-b" "master")
+ (package-vc-tests-checkin
+ name suffix "test-package-v0.1.el.in" "First commit" lisp-dir)
+ (package-vc-tests-checkin
+ name suffix "test-package-v0.2.el.in" "Second commit" lisp-dir)
+ (vc-git-command nil 0 nil
+ "bundle" "create" bundle-file "master")
+ (list (intern name)
+ bundle-file (vc-git-working-revision nil)))))
+
+(defmacro with-package-vc-tests-enviroment (&rest body)
+ "Eval BODY with test environment."
+ (declare (debug t))
+ ;; Test packages sources are stored in bundle files produced by
+ ;; git-bundle(1) and are stored in directory package-vc-resources.
+ ;; Before executing body make sure that:
+ `(let* (package-archives
+ ;; - temporary location for packages and test files is ready
+ (package-vc-tests-dir
+ (or package-vc-tests-dir
+ (setq package-vc-tests-dir
+ (make-temp-file "package-vc-tests-"
+ t
+ (format-time-string "-%Y%m%d.%H%M%S")=
))))
+ ;; - packages are installed into a test directory
+ (package-user-dir (expand-file-name "elpa"
+ package-vc-tests-dir))
+ ;; - create test package bundles if necessary and define test
+ ;; packages and their checkout locations
+ (package-vc-tests-bundles
+ (or package-vc-tests-bundles
+ (setq package-vc-tests-bundles
+ (mapcar (lambda (suffix)
+ (package-vc-tests-create-bundle
+ suffix (and (< 4 suffix) "lisp")))
+ '(1 2 3 4 5 6)))))
+ (package-vc-tests-packages
+ `(;; checkout and install with `package-vc-install' (on
+ ;; ELPA)
+ (test-package-1
+ . ,(expand-file-name "test-package-1"
+ package-user-dir))
+ ;; checkout and install with `package-vc-install' (not on
+ ;; ELPA)
+ (test-package-2
+ . ,(expand-file-name "test-package-2"
+ package-user-dir))
+ ;; checkout with `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-3
+ . ,(expand-file-name "test-package-3"
+ package-vc-tests-dir))
+ ;; checkout with git and install with
+ ;; `package-vc-install-from-checkout'
+ (test-package-4
+ . ,(expand-file-name "test-package-4"
+ package-vc-tests-dir))
+ ;; sources in "lisp" sub directory, checkout and install
+ ;; with `package-vc-install'
+ (test-package-5
+ . ,(expand-file-name "test-package-5"
+ package-user-dir))
+ ;; sources in "lisp" sub directory, checkout with git and
+ ;; install with `package-vc-install-from-checkout'
+ (test-package-6
+ . ,(expand-file-name "test-package-6"
+ package-vc-tests-dir))
+
+ ;; TODO: a package with source files in a non-standard
+ ;; :lisp-dir, a custom Makefile and non-standard :doc
+ ;; (both methods of installation)
+ ))
+ ;; - test packages are recognised by `package' and
+ ;; `package-vc' internals:
+ (package-archive-contents
+ (list
+ (let ((bundle (alist-get 'test-package-1
+ package-vc-tests-bundles)))
+ (list 'test-package-1
+ (package-desc-create
+ :name 'test-package-1
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras
+ (list
+ '(:maintainer
+ ("Test Maintainer" . "test-maintainer@test-domain.=
org"))
+ (cons :url (car bundle))
+ (cons :commit (cadr bundle))
+ (cons :revdesc (substring (cadr bundle) 0 12))))))
+ (let ((bundle (alist-get 'test-package-3
+ package-vc-tests-bundles)))
+ (list 'test-package-3
+ (package-desc-create
+ :name 'test-package-3
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras
+ (list
+ '(:maintainer
+ ("Test Maintainer" . "test-maintainer@test-domain.=
org"))
+ (cons :url (car bundle))
+ (cons :commit (cadr bundle))
+ (cons :revdesc (substring (cadr bundle) 0 12))))))))
+ (package-vc--archive-spec-alists
+ (list
+ (list 'test-elpa
+ (list 'test-package-1
+ :url (car (alist-get 'test-package-1
+ package-vc-tests-bundles))
+ :branch "master")
+ (list 'test-package-3
+ :url (car (alist-get 'test-package-3
+ package-vc-tests-bundles))
+ :branch "master"))))
+ (package-vc--archive-data-alist
+ (list
+ (list 'test-elpa :version 1 :default-vc 'Git)))
+ ;; - `vc-guess-backend-url' is recognising bundles as `Git'
+ ;; repositories:
+ (vc-clone-heuristic-alist
+ (cons
+ (cons (rx "test-package-" (one-or-more digit) ".bundle"
+ string-end)
+ 'Git)
+ vc-clone-heuristic-alist)))
+ ;; - `package' has been initialised:
+ (should package--initialized)
+
+ ,@body))
+
+
+;; TODO: add test for deleting packages, with asserting
+;; `package-vc-selected-packages'
+
+;; TODO: clarify `package-vc-install-all' behaviour with regards to
+;; packages installed with `package-vc' but not stored in
+;; `package-vc-selected-packages' i.e., packages from ELPAs
+
+(defun package-vc-tests-package-desc (package &optional installed)
+ "Return descriptor of PACKAGE.
+When INSTALLED is non-nil the descriptor will come from `package-alist'.
+Otherwise the descriptor will be from `package-archive-contents'. This
+is to mimic `package-vc--read-package-desc'."
+ (cadr (assoc (if (stringp package) package (symbol-name package))
+ (if installed package-alist package-archive-contents)
+ #'string=3D)))
+
+(defun package-vc-tests-package-lisp-dir (pkg)
+ "Return a Lisp directory of PKG."
+ (when-let* ((checkout-dir (alist-get pkg package-vc-tests-packages)))
+ (cond
+ ((member pkg '(test-package-5 test-package-6))
+ (expand-file-name "lisp" checkout-dir))
+ (t checkout-dir))))
+
+(defun package-vc-tests-package-main-file (pkg)
+ "Return a main file of PKG."
+ (format "%s/%s.el" (package-vc-tests-package-lisp-dir pkg) pkg))
+
+
+;; When a package source is being recompiled - for example as result of
+;; `pakckage-vc-upgrade' or `package-vc-rebuild' - it is also reloaded
+;; [1] to ensure that the most recent version of compiled code is
+;; available to Emacs. There are a few tests that add markers in
+;; `load-history' before executing such functions. And then follow up
+;; tests use these markers to assert that expected package files are in
+;; correct places in the `load-history'.
+;;
+;; [1] Only when a file has been loaded previously.
+(defun package-vc-tests-load-history-position (pkg type)
+ "Return a PKG's position in `load-history'.
+If TYPE is `:autoloads' return a position of a PKG autoloads file.
+Otherwise, if TYPE is `:main' return a position of PKG main file (not
+compiled). Otherwise, if TYPE is `:main-compiled' return a position of
+PKG compiled main file. Otherwise, if TYPE is `:marker' return a
+position of a marker PKG."
+ (let ((pkg-file (pcase type
+ (:autoloads
+ (rx (literal
+ (format "%s/%s/%s-autoloads.el"
+ package-user-dir pkg pkg))
+ string-end))
+ (:main
+ (rx
+ (literal
+ (package-vc-tests-package-main-file pkg))
+ string-end))
+ (:main-compiled
+ (rx
+ (literal
+ (package-vc-tests-package-main-file pkg))
+ "c"
+ string-end))
+ (:marker
+ (rx "/" (literal (format "%s" pkg))))))
+ (interesting-entry
+ (rx string-start
+ (literal (file-truename package-vc-tests-dir)))))
+ (cl-position-if
+ (lambda (file)
+ (string-match pkg-file file))
+ (cl-remove-if-not
+ (lambda (file-name)
+ (string-match interesting-entry file-name))
+ (mapcar
+ #'file-truename
+ (cl-remove-if-not
+ #'stringp
+ (mapcar #'car load-history)))))))
+
+(defun package-vc-tests-assert-delete-elc ()
+ "Assert that .elc files are in expected directories and delete them.
+When ALL is non nil, check all packages under test."
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let* ((dir (package-vc-tests-package-lisp-dir pkg))
+ (elc-files (directory-files dir nil (rx ".elc" string-end)))
+ (autoloads-rx (rx
+ (literal (format "%s-autoloads.el" pkg))
+ string-end)))
+ (should (equal (format "%s: has elc-files" dir)
+ (format "%s: %s elc-files"
+ dir (if elc-files "has" "has no"))))
+ (should-not (cl-find-if (lambda (elc)
+ (string-match autoloads-rx elc))
+ elc-files))
+ (dolist (elc-file elc-files)
+ (delete-file (expand-file-name elc-file dir))))))
+
+(defun package-vc-tests-assert-package-alist (version)
+ "Assert that entries in `package-alist' have correct VERSION and dir."
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
+ (should (equal (file-name-as-directory
+ (expand-file-name (format "%s" pkg)
+ package-user-dir))
+ (file-name-as-directory
+ (package-desc-dir pkg-desc))))
+ (should (equal (list pkg version)
+ (list pkg (package-desc-version pkg-desc)))))))
+
+(defun package-vc-tests-reset-heads ()
+ "Reset to HEAD^ checkouts `package-vc-tests-packages'."
+ (pcase-dolist (`(,_ . ,dir) package-vc-tests-packages)
+ (let ((default-directory dir))
+ (vc-git-command nil 0 nil "reset" "--hard" "HEAD^"))))
+
+(defun package-vc-tests-packages-heads ()
+ "Return HEAD revisions of `package-vc-tests-packages'."
+ (mapcar (lambda (pkg-checkout-dir)
+ (let ((default-directory (cdr pkg-checkout-dir)))
+ (cons (car pkg-checkout-dir)
+ (vc-git-working-revision nil))))
+ package-vc-tests-packages))
+
+(ert-deftest package-vc-tests-000-install ()
+ (package-initialize)
+ (package-vc--archives-initialize)
+ (with-package-vc-tests-enviroment
+ (push (list (format "%s/install-begin" package-vc-tests-dir))
+ load-history)
+ (package-vc-install 'test-package-1)
+ (should-not (alist-get "test-package-1"
+ package-vc-selected-packages
+ nil nil #'string=3D))
+
+ (let ((bundle (car (alist-get 'test-package-2
+ package-vc-tests-bundles))))
+ (package-vc-install `(test-package-2
+ :url ,bundle
+ :branch "master"))
+ (should (equal bundle
+ (plist-get (alist-get "test-package-2"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-3"
+ package-vc-tests-dir)))
+ (package-vc-checkout (package-vc-tests-package-desc
+ 'test-package-3)
+ checkout-dir)
+ (package-vc-install-from-checkout checkout-dir)
+ (should (equal (format "file://%s" checkout-dir)
+ (plist-get (alist-get "test-package-3"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-4"
+ package-vc-tests-dir)))
+ (vc-git-clone
+ (car (alist-get 'test-package-4
+ package-vc-tests-bundles))
+ checkout-dir
+ "master")
+ (package-vc-install-from-checkout checkout-dir "test-package-4")
+ (should (equal (format "file://%s" checkout-dir)
+ (plist-get (alist-get "test-package-4"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((bundle (car (alist-get 'test-package-5
+ package-vc-tests-bundles))))
+ (package-vc-install `(test-package-5
+ :url ,bundle
+ :branch "master"))
+ (should (equal bundle
+ (plist-get (alist-get "test-package-5"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-6"
+ package-vc-tests-dir)))
+ (vc-git-clone
+ (car (alist-get 'test-package-6
+ package-vc-tests-bundles))
+ checkout-dir
+ "master")
+ (package-vc-install-from-checkout checkout-dir "test-package-6")
+ (should (equal (format "file://%s" checkout-dir)
+ (plist-get (alist-get "test-package-6"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (push (list (format "%s/install-end" package-vc-tests-dir))
+ load-history)
+
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc)))
+
+(ert-deftest package-vc-tests-001-main-file ()
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (should (equal (package-vc--main-file
+ (package-vc-tests-package-desc pkg t))
+ (package-vc-tests-package-main-file pkg))))))
+
+(ert-deftest package-vc-tests-002-commit ()
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((commit (package-vc-commit
+ (package-vc-tests-package-desc pkg t))))
+ (should (equal (format "%s: has commit" pkg)
+ (format "%s: %s commit"
+ pkg (if commit "has" "has no"))))
+ (should-not (equal (format "%s: unknown commit" pkg)
+ (format "%s: %s commit" pkg commit)))))))
+
+(ert-deftest package-vc-tests-003-load-history-after-install ()
+ (with-package-vc-tests-enviroment
+ (let ((install-begin
+ (should (package-vc-tests-load-history-position
+ 'install-begin :marker)))
+ (install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker))))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (equal (format "%s: autoloads-pos between %s and %s"
+ pkg install-end install-begin)
+ (format "%s: autoloads-pos %s %s and %s"
+ pkg
+ (if (< install-end
+ autoloads-pos
+ install-begin)
+ "between"
+ "is not between")
+ install-end install-begin)
+ )))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))))))
+
+(defmacro package-vc-tests-package-vc-async-wait (seconds count flags &res=
t body)
+ "Wait up to SECONDS for COUNT async vc commands with FLAGS called by BOD=
Y.
+Return nil on timeout or the value of last form in BODY."
+ (declare (indent 3))
+ (let ((count-sym (make-symbol "count"))
+ (post-vc-command-sym (make-symbol "post-vc-command")))
+ `(letrec ((,count-sym ,count)
+ (,post-vc-command-sym
+ (lambda (command _ command-flags)
+ ;; A crude filter for vc commands
+ (when (and (equal command "git")
+ (cl-every (lambda (flag)
+ (member flag command-flags))
+ ,flags))
+ (decf ,count-sym)))))
+ (add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
+ (unwind-protect
+ (with-timeout (,seconds nil)
+ (prog1
+ (progn ,@body)
+ (while (/=3D ,count-sym 0)
+ (accept-process-output nil 0.01))))
+ (remove-hook 'vc-post-command-functions ,post-vc-command-sym)))))
+
+(ert-deftest package-vc-tests-004-upgrade-all ()
+ (with-package-vc-tests-enviroment
+ (push (list (format "%s/upgrade-all-begin" package-vc-tests-dir))
+ load-history)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (package-vc-tests-reset-heads)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 (length package-vc-tests-packages) '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (push (list (format "%s/upgrade-all-end" package-vc-tests-dir))
+ load-history)
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc)))
+
+(ert-deftest package-vc-tests-005-load-history-after-upgrade-all ()
+ (with-package-vc-tests-enviroment
+ (let ((upgrade-all-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-all-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker))))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (equal (format "%s: autoloads-pos between %s and %s"
+ pkg upgrade-all-end upgrade-all-begin)
+ (format "%s: autoloads-pos %s %s and %s"
+ pkg
+ (if (< upgrade-all-end
+ autoloads-pos
+ upgrade-all-begin)
+ "between"
+ "is not between")
+ upgrade-all-end upgrade-all-begin)))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled)))))))
+
+(ert-deftest package-vc-tests-006-require ()
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should (require pkg))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg)))))
+ (let ((upgrade-all-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker))))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((main-pos (should (package-vc-tests-load-history-position
+ pkg :main))))
+ (should (equal (format "%s: main-pos less than %s"
+ pkg upgrade-all-end)
+ (format "%s: main-pos %s than %s"
+ pkg
+ (if (< main-pos
+ upgrade-all-end)
+ "less"
+ "is not less")
+ upgrade-all-end))))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))))))
+
+(ert-deftest package-vc-tests-007-upgrade ()
+ (with-package-vc-tests-enviroment
+ (push (list (format "%s/upgrade-begin" package-vc-tests-dir))
+ load-history)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (package-vc-tests-reset-heads)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 (length package-vc-tests-packages) '("pull")
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (package-vc-upgrade
+ (package-vc-tests-package-desc pkg t))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function
+ (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg)))))
+ t))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (push (list (format "%s/upgrade-end" package-vc-tests-dir))
+ load-history)
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc)))
+
+(ert-deftest package-vc-tests-008-load-history-after-upgrade ()
+ (with-package-vc-tests-enviroment
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker))))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should
+ (equal (format "%s: autoloads-pos between %s and %s"
+ pkg upgrade-end upgrade-begin)
+ (format "%s: autoloads-pos %s %s and %s"
+ pkg
+ (if (< upgrade-end
+ autoloads-pos
+ upgrade-begin)
+ "between"
+ "is not between")
+ upgrade-end upgrade-begin)))
+ (should
+ (equal (format "%s: main-pos between %s and %s"
+ pkg upgrade-end upgrade-begin)
+ (format "%s: main-pos %s %s and %s"
+ pkg
+ (if (< upgrade-end
+ main-pos
+ upgrade-begin)
+ "between"
+ "is not between")
+ upgrade-end upgrade-begin)))
+ (should
+ (equal (format "%s: main-compiled-pos between %s and %s"
+ pkg upgrade-end upgrade-begin)
+ (format "%s: main-compiled-pos %s %s and %s"
+ pkg
+ (if (< upgrade-end
+ main-compiled-pos
+ upgrade-begin)
+ "between"
+ "is not between")
+ upgrade-end upgrade-begin))))))))
+
+(ert-deftest package-vc-tests-009-rebuild ()
+ (with-package-vc-tests-enviroment
+ (package-vc-tests-reset-heads)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function
+ (intern (format "%s-func" pkg)))))
+ (should (fboundp (intern (format "%s-old-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function
+ (intern (format "%s-old-func" pkg))))))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (package-vc-tests-assert-package-alist '(0 1))
+ (package-vc-tests-assert-delete-elc)))
+
+(ert-deftest package-vc-tests-010-prepare-patch ()
+ (let (vc-prepare-patches-separately)
+ ;; Ensure `vc-prepare-patch' respects subject from function
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ ;; FIXME: Currently `package-vc-prepare-patch' only works only
+ ;; for a package installed with `package-vc-install'. No other
+ ;; `package-vc' installation method is supported. Likely,
+ ;; because package maintainer are not set in generated pkg-file.
+ (when (memq pkg '(test-package-1))
+ (package-vc-prepare-patch (package-vc-tests-package-desc pkg t)
+ "test-subject"
+ (cdr (alist-get
+ pkg package-vc-tests-bundles)))
+ (let ((message-buffer
+ (get-buffer "*unsent mail to Test Maintainer*")))
+ (should (equal (format "%s: message-buffer" pkg)
+ (format "%s: %s"
+ pkg (if (bufferp message-buffer)
+ "message-buffer"
+ "no message-buffer"))))
+ (switch-to-buffer message-buffer)
+ (goto-char (point-min))
+ (should
+ (equal (format
+ "%s: To: Test Maintainer <test-maintainer@test-domain.=
org>"
+ pkg)
+ (format
+ "%s: %s"
+ pkg (buffer-substring (point) (pos-eol)))))
+ (forward-line)
+ (should
+ (equal (format
+ "%s: Subject: test-subject" pkg)
+ (format
+ "%s: %s"
+ pkg (buffer-substring (point) (pos-eol)))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer message-buffer))))))))
+
+(ert-deftest package-vc-tests-011-log-incoming ()
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 1 '("log" "--decorate")
+ (package-vc-log-incoming (package-vc-tests-package-desc pkg t))
+ t))
+ (let ((incoming-buffer (get-buffer "*vc-incoming*"))
+ (pattern (rx (literal
+ (substring
+ (cadr (alist-get pkg
+ package-vc-tests-bundles))
+ 0 7))
+ (one-or-more any)
+ "Second commit"
+ line-end)))
+ (should (equal (format "%s: incoming-buffer" pkg)
+ (format "%s: %s"
+ pkg (if (bufferp incoming-buffer)
+ "incoming-buffer"
+ "no incoming-buffer"))))
+ (switch-to-buffer incoming-buffer)
+ (goto-char (point-min))
+ (should
+ (equal (format "%s: match" pkg)
+ (format "%s: %s"
+ pkg
+ (if (re-search-forward pattern (pos-eol) t)
+ "match"
+ (format "no match: %s %s"
+ pattern
+ (buffer-substring
+ (point-min) (pos-eol)))))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer incoming-buffer))))))
+
+(provide 'package-vc-tests)
+
+;;; package-vc-tests.el ends here
--=20
2.51.2
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
I will follow up on the thread in eamcs-devel in next few days. Please
find responses inline.
Philip Kaludercic <philipk@HIDDEN> writes:
> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>
>> Philip Kaludercic <philipk@HIDDEN> writes:
>>
>>> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>>>
> [...]
>> I think that
>> tests are executing reasonable amount of scenarios to give extra
>> confidence it won't break Emacs code.
>
> Presently I am cautious, because there seems to be a lot of small things
> that can break that affect just one persons workflow.
Indeed - given a sufficient number of users every unintended side effect
will be used as a feature.
> [...]
>>>> (ert-deftest package-vc-tests-002-commit ()
>>>> (dolist (pkg-checkout-dir package-vc-tests-packages)
>>>> (let ((pkg (car pkg-checkout-dir))
>>>> (commit (package-vc-commit
>>>> (package-vc-tests-package-desc (car pkg-checkout-dir=
) t))))
>>>> (should-not (equal (cons pkg commit)
>>>> (list pkg)))
>>>
>>> So (null commit)?
>>
>> Or even simpler (should commit). But that will only print a commit name
>> in case of failure. I did the list trick on purpose, such that on
>> failure it prints the affected package name. I know that one option is
>> to write a custom ert-explainer, but that seems like an overkill. Or
>> create a custom assertion that would `message' before failure, yet this
>> one seems odd to me. I wish `should' could take extra context. Do you
>> have a better idea how to ensure package name is printed?
>
> The only idea I have would be to write (and pkg (null commit))...
Unfortunately, this doesn't print value of pkg. The assertion:
(should (and pkg commit))
Prints on failure:
(ert-test-failed ((should (and pkg commit)) :form (and pkg commit) :value=
nil))
I tried slightly different mangling trick:
(should (equal (format "%s: has commit" pkg)
(format "%s: %s commit"
pkg (if commit "has" "has no"))))
Which yields the following diagnostic on failure (indentation is mine):
(ert-test-failed
((should (equal (format "%s: has commit" pkg)
(format "%s: %s commit"
pkg (if commit "has" "has no")))
:form
(equal "test-package-1: has commit"
"test-package-1: has no commit")
:value nil
:explanation
(arrays-of-different-length
26 29
"test-package-1: has commit"
"test-package-1: has no commit"
first-mismatch-at 20)))
I hope it reads better. I have updated other relevant assertions to use
this technique as well.
> [...]
>>>> (let ((install-end (should (package-vc-tests-load-history-position
>>>> 'install-end :marker))))
>>>> (dolist (pkg (mapcar #'car package-vc-tests-packages))
>>>> (let ((main-pos (should (package-vc-tests-load-history-position =
pkg :main))))
>>>> (should (< main-pos install-end)))
>>>> (should-not (package-vc-tests-load-history-position pkg :main-co=
mpiled)))))
>>>
>>> Why are we interested in the position in load-list?
>>
>> This is to ensure that files are reloaded. It has proven very helpful
>> as it caught that code was not reloaded for a package, that:
>>
>> - has it's Lisp code in a sub directory called "lisp",
>> - and has been installed with `package-vc-install',
>> - and has been upgraded with `package-vc-upgrade'.
>>
>> For posterity, this was test-package-5, to be found in the most recent
>> patch.
>
> Ah, OK! Unless I missed it somewhere, and this is actually a reliable
> way of testing this, I would add a comment somewhere to explain this.
Added.
> [...]
>>>> (ert-deftest package-vc-tests-010-prepare-patch ()
>>>> (dolist (pkg-checkout-dir package-vc-tests-packages)
>>>> (cl-letf* ((call-count 0)
>>>> ((symbol-function #'package-maintainers)
>>>> (lambda (&rest _)
>>>> "test-maintainers"))
>>>> ((symbol-function #'vc-prepare-patch)
>>>> (lambda (addressee subject revisions)
>>>> (should (equal (file-name-as-directory default-direc=
tory)
>>>> (file-name-as-directory (cdr pkg-chec=
kout-dir))))
>>>> (should (equal "test-maintainers" addressee))
>>>> (should (equal "test-subject" subject))
>>>> (should (equal "test-revisions" revisions))
>>>> (cl-incf call-count))))
>>>> (package-vc-prepare-patch (package-vc-tests-package-desc
>>>> (car pkg-checkout-dir)
>>>> t)
>>>> "test-subject"
>>>> "test-revisions")
>>>> (should (eql 1 call-count)))))
>>>
>>> I don't think we need to test the specific internal behaviour. IMO the
>>> tests should ensure that user-facing behaviour doesn't regress.
>>
>> I have chosen to go the mocking route for this (and the following) test.
>> Otherwise writing assertions for them may be a bit complicated. But I
>> can try to update if you think the extra work justifies the benefit.
>
> My only concern is that this might break if we make changes in the
> future, and I don't want to expose (or imply to expose) the specific
> internal details as something that any third party should rely on.
So you were right. I rewrote these tests and it seems that this
revealed couple issues.
The `package-vc-prepare-patch' works only when a package is installed
with `package-vc-install'. Any other method of installation is
unsupported ATM. I haven't got to a bottom of why this is the case, but
after a quick skimming I think this is because initial pkg-desc doesn't
populate :maintainer in extras. I guess that may deserve a patch as
long as the `package-vc-install-from-checkout' remains in code base.
As for the `package-vc-log-incoming' I think it should be possible to
call the function from outside the package. At least this is my guess
based on the setting of `default-directory'. I have updated the
function to work correctly, regardless where it was called from.
> [...]
>>>>
>>>> I guess this will be question 7 now ;). I am thinking about adding a
>>>> hook, say `package-delete-hook' that will be called with a `pkg-desc' =
of
>>>> the package being deleted. `package-vc' could register it's own handl=
er
>>>> and delete such an entry.
>>>>
>>>> And last but not least:
>>>>
>>>> 8. I have noticed that `package-reinstall' allows to reinstall a VC
>>>> package. But that will certainly won't do the right thing - it will
>>>> delete the package, but the subsequent installation will either happen
>>>> from an ELPA or will fail if no ELPA exists. I am thinking about of t=
wo
>>>> options:
>>>>
>>>> a. Remove VC packages from completion offers, and block the function,
>>>> asking user to use `package-vc-rebuild'.
>>>>
>>>> b. Forward the call to `package-vc-rebuild' for VC packages. Perhaps
>>>> after asking user if they want to do so. The question could be
>>>> suppress-able with a new variable
>>>> (e.g. `package-reinstall-vc-package-forward' with values `always',
>>>> `ask', `never'). And the `package-vc-rebuild' could be also set as a
>>>> variable (e.g., `package-reinstall-vc-package-function').
>>>
>>> My preference would be towards a., just like how I think that adding
>>> VC packages to package-upgrade was a mistake in retrospect.
>>
>> How about creating a new bug for issues 7 (package-delete) and 8
>> (package-reinstall) and discuss patches there?
>
> Sounds good!
Will submit once we install some fix for this bug as it should make
developing a fix more concise.
>>>> .../test-package-1.bundle | Bin 0 -> 764 bytes
>>>> .../test-package-2.bundle | Bin 0 -> 763 bytes
>>>> .../test-package-3.bundle | Bin 0 -> 764 bytes
>>>> .../test-package-4.bundle | Bin 0 -> 767 bytes
>>>
>>> I was afraid that the files would be a lot larger, but this seems
>>> acceptable. Did you do a shallow clone and run git-gc(1)? Either way,
>>> I would prefer to ask a maintainer before we apply these patches, just
>>> to be on the safe side.
>>
>> These are not the packages I used as specimens earlier. Instead I opted
>> for creating a minimal viable package repositories with just a two
>> commits to exercise upgrade/downgrade test scenarios. That's why the
>> bundles are so small. You can clone one of these bundles to see what's
>> inside.
>
> Ah, I haven't applied the patch yet so I didn't know what was inside.
NW. I updated tests to generate packages on fly from skeleton files.
>> Here are the new patches
>> [...]
>> @@ -180,16 +179,37 @@ package-vc--checkout-dir
>> that case the package redirects to the actual VC checkout. If the
>> optional LISP-DIR argument is non-nil, then check if a related package
>> specification has a `:lisp-dir' field to indicate that Lisp files are
>> -located in a sub directory of a checkout and return that instead."
>> +located in a sub directory of the checkout, or the checkout has a sub
>> +directory named \"lisp\" or \"src\" that contains .el files and return
>> +that instead."
>> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>> - (url (plist-get pkg-spec :url)))
>> + (url (plist-get pkg-spec :url))
>> + (pkg-dir (cond
>> + ((save-match-data
>> + (and url (string-match (rx "file://" (group (+ an=
y))) url)
>> + (match-string 1 url))))
>
> BTW, did you know that you can also use `pcase' here:
>
> (pcase url
> ((rx "file://" (let file (+ any))) file)
> (_ (package-desc-dir pkg-desc)))
>
> I only recently discovered this myself.
This is awesome!
>> + (t (package-desc-dir pkg-desc)))))
>> (expand-file-name
>> - (or (and (not lisp-dir) (plist-get pkg-spec :lisp-dir)) ".")
>> - (cond
>> - ((save-match-data
>> - (and url (string-match (rx "file://" (group (+ any))) url)
>> - (match-string 1 url))))
>> - (t (package-desc-dir pkg-desc))))))
>> + (or (when lisp-dir
>
> Please don't use `when' if we are interested in the return value.
OK.
>> + (or (plist-get pkg-spec :lisp-dir)
>> + ;; When nothing is specified about a `lisp-dir', then sh=
ould
>> + ;; heuristically check if there is a sub-directory with =
lisp
>> + ;; files. These are conventionally just called "lisp" o=
r "src".
>> + ;; If this directory exists and contains non-zero number=
of lisp
>> + ;; files, we will use that instead of `pkg-dir'.
>> + (catch 'done
>> + (dolist (name '("lisp" "src"))
>> + (when-let* ((dir (expand-file-name name pkg-dir))
>> + ((file-directory-p dir))
>> + ((directory-files dir nil "\\`[^.].+\\.e=
l\\'" t 1)))
>> + ;; We won't use `dir', since dir is an absolute pa=
th and we
>> + ;; don't want `lisp-dir' to depend on the current =
location of
>> + ;; the package installation, ie. to break if moved=
around the
>> + ;; file system or between installations.
>> + (throw 'done name))))
>> + ))
>
> I think you should fold these parentheses onto the previous line.
Done.
> [...]
>> -(defun package-vc--unpack-1 (pkg-desc pkg-dir)
>> - "Prepare PKG-DESC that is already checked-out in PKG-DIR.
>> -This includes downloading missing dependencies, generating
>> -autoloads, generating a package description file (used to
>> -identify a package as a VC package later on), building
>> -documentation and marking the package as installed."
>> - (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>> +(defun package-vc--unpack-1 (pkg-desc)
>> + "Prepare PKG-DESC that is already checked-out.
>> +The checkout directory is determined by relevant pkg-spec or from `dir'
>
> (Not critical, but if you can think of a nice way to avoid the passive
> tense here, that would be nice)
I rewrote it, but English is not my forte, so I am not sure if it is any
better.
> [...]
>> @@ -568,20 +602,37 @@ package-vc--unpack-1
>> [...]
>> + (unless (file-equal-p lisp-dir pkg-dir)
>> + (package--reload-previously-loaded compile-desc))
>> + ;; `package-activate-1' will add info node as long as dir file
>> + ;; exists in `pkg-dir'. We need to manually add it when
>> + ;; `checkout-dir' is in different location.
>> + (unless (file-equal-p pkg-dir checkout-dir)
>
> Minor nit-pick if you are going to revise the patch anyway, it would be
> nice to swap the argument here or above so that pkg-dir is on the same si=
de.
Done.
> [...]
> This is a pretty big patch, so I hope you understand that it takes me a
> while to review it and my hesitance to changing so much of the code.
I totally understand that.
> Please tell me, if we revert the change that replaced the symbolic links
> with the current "indirect" package loading approach, would that also
> resolve the issue you had? If so, we could consider that along with
> deprecating package-vc-install-from-checkout in favour of site-lisp.
In case when we revert to symbolic link I think a few fixes may be worth
porting. From the top of my head the fix to handle standard lisp sub
directories, fix for backend detection in log incoming, and perhaps fix
for extracting maintainers (to be developed, see comment in test below).
>> From c82c03957f5f1fab6fbbff39ef1ea49792581e6f Mon Sep 17 00:00:00 2001
>> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
>> Date: Tue, 2 Sep 2025 09:28:13 +0100
>> Subject: [PATCH 2/2] Add tests for package-vc
>>
>> [...]
>>
>> ---
>> .../test-package-1.bundle | Bin 0 -> 764 bytes
>> .../test-package-2.bundle | Bin 0 -> 763 bytes
>> .../test-package-3.bundle | Bin 0 -> 764 bytes
>> .../test-package-4.bundle | Bin 0 -> 767 bytes
>> .../test-package-5.bundle | Bin 0 -> 845 bytes
>> .../test-package-6.bundle | Bin 0 -> 843 bytes
>> test/lisp/package-vc-tests.el | 601 ++++++++++++++++++
>> 7 files changed, 601 insertions(+)
>> create mode 100644 test/lisp/package-vc-resources/test-package-1.bundle
>> create mode 100644 test/lisp/package-vc-resources/test-package-2.bundle
>> create mode 100644 test/lisp/package-vc-resources/test-package-3.bundle
>> create mode 100644 test/lisp/package-vc-resources/test-package-4.bundle
>> create mode 100644 test/lisp/package-vc-resources/test-package-5.bundle
>> create mode 100644 test/lisp/package-vc-resources/test-package-6.bundle
>
> I am sorry if I seem to be flip-flopping here, but thinking about this
> again, but if you have constructed custom packages, why not store them
> directly as test resources and have the tests convert them first into
> git repositories under /tmp/, then git bundles and install those as
> though they were remote? That would make it easier to track changes to
> the test packages without having to update these opaque objects.
I had thought about that, but wanted to avoid delaying a replay. This
time I implemented this solution, and I think I like it better.
> [...]
>> diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.=
el
>> new file mode 100644
>> index 00000000000..1e9b96df866
>> --- /dev/null
>> +++ b/test/lisp/package-vc-tests.el
>> @@ -0,0 +1,601 @@
>> +;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t =
-*-
>> +
>> +;; Copyright (C) 2025 Free Software Foundation, Inc.
>> +
>> +;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
> ^
> looks like a typo, unless you
> have an alternative address?
Indeed a typo. Thanks for catching!
> [...]
>> +;;; Commentary:
>> +
>> +;; These tests focus on verifying post conditions for `package-vc'
>> +;; operations on packages. Since installing a package changes the state
>> +;; of running process these tests are ment to be executed in order, as
>> +;; denoted by digits in their name.
>
> This was my worry, are you sure there is no way around this? It seems
> to me that by forcing this constraint we will always be struggling
> against ERT in the future.
Perhaps there could be a way around. I guess we can ensure packages are
installed before each test, and preconditions are met. But not sure how
much work it will take. If you think it's worth it, I can give it a go.
>> Also in many cases the subsequent
>> +;; test often depends on the passing of the previous test.
>> +
>> +;; It is recommended to run this suite in a separate process, for
>> +;; example, in root of Emacs source directory:
>> +
>> +;; ./src/emacs -batch \
>> +;; -l ../test/lisp/package-vc-tests.el \
>> +;; -f ert-run-tests-batch-and-exit
>
> This is unpleasant... Can you explain why, it would be nice to just use
> M-x ert.
>
To be fair, this is predominantly, because I am still on Emacs 30 and
this is the way I am running these tests. This issues is the blocker
for me before I can switch. I have added extra caveat directly to the
doc string.
> [...]
>> +(defvar package-vc-tests-resources-dir
>> + (file-name-concat (file-name-directory
>
> Why not use `expand-file-name'? Or other tests are using
> `ert-resource-file', perhaps that might make sense for us as well?
>
This is gone in new version (in favour of `ert-resource-directory').
>> + (or load-file-name buffer-file-name))
>> + "package-vc-resources"))
>> +(defvar package-vc-tests-packages nil)
>> +
>> +(defmacro with-package-vc-tests-enviroment (&rest body)
>
> It is not possible to have this as a function that `funcall's a closure?
>
>> [...]
>> + ;; - test directory exists:
>> + (should package-vc-tests-dir)
>> + (should (file-directory-p package-vc-tests-dir))
>
> These seem more like assertions w.r.t. the testing logic than tests of
> the package-vc to me.
I removed them.
> [...]
>> +(defun package-vc-tests-package-main-file (pkg)
>> + "Return a main file of PKG."
>> + (format "%s/%s.el" (package-vc-tests-package-lisp-dir pkg) pkg))
>
> Some more commentary here, or just the assurance that in all the tests,
> this is in fact do all have main file names that fit this pattern.
>
I wrote this function to satisfy DRY. Not sure what else can be commented.
>> +
>> +(defun package-vc-tests-load-history-position (pkg type)
>> + "Return a PKG's position in `load-history'.
>> +If TYPE is `:autoloads' return a position of a PKG autoloads file.
>> +Otherwise, if TYPE is `:main' return a position of PKG main file (not
>> +compiled). Otherwise, if TYPE is `:main-compiled' return a position of
>> +PKG compiled main file. Otherwise, if TYPE is `:marker' return a
>> +position of a marker PKG."
>> + (let ((pkg-file (pcase type
>> + (:autoloads
>> + (rx (literal
>> + (format "%s/%s/%s-autoloads.el"
>> + package-user-dir pkg pkg))
>> + string-end))
>> + (:main
>> + (rx
>> + (literal
>> + (format "%s"
> ^
> this seems like a noop to me? the
> same below...
>
Fixed. I think it was an aftermath of changing an approach a couple times.
>> [...]
>> +(defun package-vc-tests-assert-delete-elc ()
>> + "Assert that .elc files are in expected directories and delete them.
>> +When ALL is non nil, check all packages under test."
>> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
>> + (let* ((dir (package-vc-tests-package-lisp-dir pkg))
>> + (elc-files (directory-files dir nil (rx ".elc" string-end)))
>> + (autoloads-rx (rx
>> + (literal (format "%s-autoloads.el" pkg))
>> + string-end)))
>> + (should-not (equal (cons dir elc-files)
>> + (list dir)))
>> + (should-not (cl-find-if (lambda (elc)
>> + (string-match autoloads-rx elc))
> ^
> double
> space
Deleted.
>> + elc-files))
>> + (dolist (elc-file elc-files)
>> + (delete-file (expand-file-name elc-file dir))))))
>
> Are we sure that this functionality has not been implemented somewhere
> else? It all seems a little finicky to me...
>
I couldn't find anything similar.
>> +
>> +(defun package-vc-tests-assert-package-alist (version)
>> + "Assert that entries in `package-alist' have correct VERSION and dir."
>> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
>> + (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
>> + (should (equal (file-name-as-directory
>> + (expand-file-name (format "%s" pkg)
>> + package-user-dir))
>> + (file-name-as-directory
>> + (package-desc-dir pkg-desc))))
>> + (should (equal (list pkg version)
>> + (list pkg (package-desc-version pkg-desc)))))))
>
> I know we have been over this, but we could get someone with more ERT
> experience to chime in to see if there is some way to avoid having to
> write tests in this contrived way...
Per Info node (ert) Defining Explanation Functions, the recommended way
is to write own explainer, but this seems a bit inconvenient. I have
rewritten them with:
(should (equal (format ...) (format ...)))
Please see above for longer explanation.
>> +
>> +(defun package-vc-tests-reset-heads ()
>> + "Reset to HEAD^ checkouts `package-vc-tests-packages'."
>> + (mapcar (lambda (pkg-checkout-dir)
>
> This function is only used for its side-effects, so please use dolist
> here!
Done (using `pcase-dolist').
>> + (let ((default-directory (cdr pkg-checkout-dir)))
>> + (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))
>> + package-vc-tests-packages))
>> +
>> +(defun package-vc-tests-packages-heads ()
>> + "Return HEAD revisions of `package-vc-tests-packages'."
>> + (mapcar (lambda (pkg-checkout-dir)
>> + (let ((default-directory (cdr pkg-checkout-dir)))
>> + (cons (car pkg-checkout-dir)
>> + (vc-git-working-revision nil))))
>> + package-vc-tests-packages))
>> +
>> +(ert-deftest package-vc-tests-000-install ()
>> + (setq package-vc-tests-dir
>> + (make-temp-file "package-vc-tests-"
>> + t
>> + (format-time-string "-%Y%m%d.%H%M%S")))
>> + (package-initialize)
>> + (package-vc--archives-initialize)
>> + (eval
>
> Why are you evaluating the code like this??? (eval (quote x)) evaluates
> to the same thing as x.
I think this is no longer needed. I don't claim to understand exactly
why it was needed there, but in the previous version of the patch, some
of the variables (IIRC `package-vc-test-dir' and/or
`package-user-directory') were evaled when the ert-deftest were evaled.
While they should be evaled when tests were exectued. That caused tests
to fail. However, since I have refactored to have these assigned as a
part of test environment this is no longer needed.
> [...]
>> +(ert-deftest package-vc-tests-001-main-file ()
>> + (eval
>> + '(with-package-vc-tests-enviroment
>> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
>
> You can also use pcase-dolist if you want to pattern-match on each
> element of the list, to avoid consing a new list. Not that that matters
> much in tests, but it is less verbose.
Nice! Converting to that.
> [...]
>> +(defmacro package-vc-tests-package-vc-upgrade-wait (seconds count &rest=
body)
>> + "Wait up to SECONDS for COUNT packages upgrading BODY.
>> +Return nil on timeout or the value of last form in BODY."
>> + (declare (indent 2))
>> + `(letrec ((packages-count ,count)
>> + (post-vc-command
>> + (lambda (command _ flags)
>> + ;; A crude filter for vc commands
>> + (when (and (equal command "git")
>> + (string-prefix-p "*vc-git" (buffer-name)))
>> + (cl-decf packages-count)))))
>
> cl-decf is an alias for decf since Emacs 31.
Fixed.
>> + (add-hook 'vc-post-command-functions post-vc-command 100)
>> + (unwind-protect
>> + (with-timeout (,seconds nil)
>
> Having tests fail with hard-coded timeout values seems wrong as they can
> depend on the specific decide and its available resources. Couldn't we
> use something like `ert-skip' in this case?
I am afraid that skipping in case of failure is not a good option. Too
many times I have seen failing test that skip instead of failing being
ignored. Ultimately it's humans who are consumers of test reports and
they often lack of necessary context to judge if test is being skipped
for legitimate reason (like test not being valid on a particular OS or
configuration) vs. legitimate error.
The value of 5s (per operation!) is order of magnitude higher than what
the command is expected to execute and, from my experience. I used such
approach in automatic tests on a very, very busy machines (echo while
typing on SSH was in order of seconds [sic!]), where tests were run
dozens of times daily. The 5s caused the tests not to stall too much
when something was actually broken, yet I don't remember seeing false
positives. One alternative I can see is to hack around `vc' commands
and force them to run synchronously under test.
But if you really think it's better to skip or have a better idea,
please let me know I will update.
>> + (prog1
>> + (progn ,@body)
>> + (while (not (eql packages-count 0))
>
> Or just /=3D, as you want package-count to be a number as well, right?
Done
> [...]
> Just for technical reasons I am opposed to applying the patch in the
> current state. I don't understand some of your decisions, and am
> generally not a fan of the things being tested or the approach of having
> the tests depend on one another. If you don't want to rework it, that
> is fine -- I can also take care of that, though it would be nice if I
> could take over your demo packages.
I have been thinking how to rework these tests. Perhaps rewriting them
in such a manner that each test will create a package bundle, and then
use it to install the package. When writing these tests, I wanted to
ensure that a package is handled the same regardless a method of
installation - hence one test per `package-vc' functionality looping
over all packages. And this was easiest achieved with a shared
environment.
I have been thinking about adding a number of functions to create a full
test environment, including creating a bundle, cloning, installing,
setting up all necessary variables etc. Installation could be done with
`cl-defgeneric' et. al., as this is the only thing that really should
differ per package. Then each test will progress setting up the package
as it needs to (i.e., resetting package heads, pre-loading main-file,
etc.). WDYT?
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Thu, 06 Nov 2025 20:52:03 +0000
Resent-Message-ID: <handler.79188.B79188.176246231230810 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176246231230810
(code B ref 79188); Thu, 06 Nov 2025 20:52:03 +0000
Received: (at 79188) by debbugs.gnu.org; 6 Nov 2025 20:51:52 +0000
Received: from localhost ([127.0.0.1]:40819 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vH6xR-00080X-71
for submit <at> debbugs.gnu.org; Thu, 06 Nov 2025 15:51:52 -0500
Received: from mout01.posteo.de ([185.67.36.65]:48641)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1vH6xL-0007z6-Ts
for 79188 <at> debbugs.gnu.org; Thu, 06 Nov 2025 15:51:47 -0500
Received: from submission (posteo.de [185.67.36.169])
by mout01.posteo.de (Postfix) with ESMTPS id 808BB240027
for <79188 <at> debbugs.gnu.org>; Thu, 6 Nov 2025 21:51:37 +0100 (CET)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1762462297; bh=KXPgTqB2xH9SVZZyE+zls80xYstkPPvP72orsULd0Ho=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:Content-Transfer-Encoding:From;
b=bia08EzhwREhbI/5l9jG61RViyvmvpcm42wBNYmQyWLpHG7Bd+M/acPPTFPi6p6cE
zDQ8OK4hnYgncYtKfB5NMffXSVLn+2YpAmpQG/sNW+4gZz/xkP2VrS2AMkiz2AtVkq
idkVCymhdHBWFZSZyiDZ4EjIr+es/A67GK4p+HR/0EHmfb9RddR+NYL8RjbZ7X/OW8
yscL0i/APmEvt/Whz4u7ys+TQWn2u01DyHiJfrskaHnGj3tAUonxi6GZM+z6X5qk3y
+FbgJCiS/sPm+nliwZ/os+H9jnVG6rnK4E0lUffOrBJkEUOIt+NFHd5VDvCOoQORPC
lvSLU7yra1hbw==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4d2Z9h5tGMz6txT;
Thu, 6 Nov 2025 21:51:36 +0100 (CET)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2bjlfrt6m.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
<m2a51k4jd5.fsf@HIDDEN> <87a51du92y.fsf@HIDDEN>
<m2bjlfrt6m.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Thu, 06 Nov 2025 20:51:37 +0000
Message-ID: <87346qx4tj.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> Sorry for long time to respond. It took me some time to apply fixes and
> reply. Attached are new patches, still keeping tests separate.
No worries, I was afraid that my last message was too strong/negative
and that I had scared you away :x
[...]
>
>> [...]
>>>>> (ert-deftest package-vc-tests-002-commit ()
>>>>> (dolist (pkg-checkout-dir package-vc-tests-packages)
>>>>> (let ((pkg (car pkg-checkout-dir))
>>>>> (commit (package-vc-commit
>>>>> (package-vc-tests-package-desc (car pkg-checkout-di=
r) t))))
>>>>> (should-not (equal (cons pkg commit)
>>>>> (list pkg)))
>>>>
>>>> So (null commit)?
>>>
>>> Or even simpler (should commit). But that will only print a commit name
>>> in case of failure. I did the list trick on purpose, such that on
>>> failure it prints the affected package name. I know that one option is
>>> to write a custom ert-explainer, but that seems like an overkill. Or
>>> create a custom assertion that would `message' before failure, yet this
>>> one seems odd to me. I wish `should' could take extra context. Do you
>>> have a better idea how to ensure package name is printed?
>>
>> The only idea I have would be to write (and pkg (null commit))...
>
> Unfortunately, this doesn't print value of pkg. The assertion:
>
> (should (and pkg commit))
>
> Prints on failure:
>
> (ert-test-failed ((should (and pkg commit)) :form (and pkg commit) :val=
ue nil))
>
> I tried slightly different mangling trick:
>
> (should (equal (format "%s: has commit" pkg)
> (format "%s: %s commit"
> pkg (if commit "has" "has no"))))
>
> Which yields the following diagnostic on failure (indentation is mine):
>
> (ert-test-failed
> ((should (equal (format "%s: has commit" pkg)
> (format "%s: %s commit"
> pkg (if commit "has" "has no")))
> :form
> (equal "test-package-1: has commit"
> "test-package-1: has no commit")
> :value nil
> :explanation
> (arrays-of-different-length
> 26 29
> "test-package-1: has commit"
> "test-package-1: has no commit"
> first-mismatch-at 20)))
>
> I hope it reads better. I have updated other relevant assertions to use
> this technique as well.
I guess if that was wrapped in a macro it would be acceptable, but
looking into ert.el it seems like we could also have a custom function
with a 'ert-explainer annotation that can specify how to display a
failure. For instance:
(ert-deftest foo ()
(should (time-equal-p (current-time) (current-time))))
fails for me with:
--8<---------------cut here---------------start------------->8---
F foo
(ert-test-failed
((should (time-equal-p (current-time) (current-time))) :form
(time-equal-p (26893 179 232751 570000) (26893 179 232751 805000))
:value nil :explanation
(different-time-values "2025-11-06 20:10:27.232751570+0000"
"2025-11-06 20:10:27.232751805+0000"
difference "-1.999999765")))
--8<---------------cut here---------------end--------------->8---
and the explainer is defined in ert.el. I would suggest to define a
custom equality predicate in the test file (perhaps abbreviating it
using a shorthand) and add a ert-explainer property to it.
>> [...]
>>>>> (let ((install-end (should (package-vc-tests-load-history-position
>>>>> 'install-end :marker))))
>>>>> (dolist (pkg (mapcar #'car package-vc-tests-packages))
>>>>> (let ((main-pos (should (package-vc-tests-load-history-position=
pkg :main))))
>>>>> (should (< main-pos install-end)))
>>>>> (should-not (package-vc-tests-load-history-position pkg :main-c=
ompiled)))))
>>>>
>>>> Why are we interested in the position in load-list?
>>>
>>> This is to ensure that files are reloaded. It has proven very helpful
>>> as it caught that code was not reloaded for a package, that:
>>>
>>> - has it's Lisp code in a sub directory called "lisp",
>>> - and has been installed with `package-vc-install',
>>> - and has been upgraded with `package-vc-upgrade'.
>>>
>>> For posterity, this was test-package-5, to be found in the most recent
>>> patch.
>>
>> Ah, OK! Unless I missed it somewhere, and this is actually a reliable
>> way of testing this, I would add a comment somewhere to explain this.
>
> Added.
>
>> [...]
>>>>> (ert-deftest package-vc-tests-010-prepare-patch ()
>>>>> (dolist (pkg-checkout-dir package-vc-tests-packages)
>>>>> (cl-letf* ((call-count 0)
>>>>> ((symbol-function #'package-maintainers)
>>>>> (lambda (&rest _)
>>>>> "test-maintainers"))
>>>>> ((symbol-function #'vc-prepare-patch)
>>>>> (lambda (addressee subject revisions)
>>>>> (should (equal (file-name-as-directory default-dire=
ctory)
>>>>> (file-name-as-directory (cdr pkg-che=
ckout-dir))))
>>>>> (should (equal "test-maintainers" addressee))
>>>>> (should (equal "test-subject" subject))
>>>>> (should (equal "test-revisions" revisions))
>>>>> (cl-incf call-count))))
>>>>> (package-vc-prepare-patch (package-vc-tests-package-desc
>>>>> (car pkg-checkout-dir)
>>>>> t)
>>>>> "test-subject"
>>>>> "test-revisions")
>>>>> (should (eql 1 call-count)))))
>>>>
>>>> I don't think we need to test the specific internal behaviour. IMO the
>>>> tests should ensure that user-facing behaviour doesn't regress.
>>>
>>> I have chosen to go the mocking route for this (and the following) test.
>>> Otherwise writing assertions for them may be a bit complicated. But I
>>> can try to update if you think the extra work justifies the benefit.
>>
>> My only concern is that this might break if we make changes in the
>> future, and I don't want to expose (or imply to expose) the specific
>> internal details as something that any third party should rely on.
>
> So you were right. I rewrote these tests and it seems that this
> revealed couple issues.
>
> The `package-vc-prepare-patch' works only when a package is installed
> with `package-vc-install'. Any other method of installation is
> unsupported ATM. I haven't got to a bottom of why this is the case, but
> after a quick skimming I think this is because initial pkg-desc doesn't
> populate :maintainer in extras. I guess that may deserve a patch as
> long as the `package-vc-install-from-checkout' remains in code base.
>
> As for the `package-vc-log-incoming' I think it should be possible to
> call the function from outside the package. At least this is my guess
> based on the setting of `default-directory'. I have updated the
> function to work correctly, regardless where it was called from.
>
>> [...]
>>>>>
>>>>> I guess this will be question 7 now ;). I am thinking about adding a
>>>>> hook, say `package-delete-hook' that will be called with a `pkg-desc'=
of
>>>>> the package being deleted. `package-vc' could register it's own hand=
ler
>>>>> and delete such an entry.
>>>>>
>>>>> And last but not least:
>>>>>
>>>>> 8. I have noticed that `package-reinstall' allows to reinstall a VC
>>>>> package. But that will certainly won't do the right thing - it will
>>>>> delete the package, but the subsequent installation will either happen
>>>>> from an ELPA or will fail if no ELPA exists. I am thinking about of =
two
>>>>> options:
>>>>>
>>>>> a. Remove VC packages from completion offers, and block the function,
>>>>> asking user to use `package-vc-rebuild'.
>>>>>
>>>>> b. Forward the call to `package-vc-rebuild' for VC packages. Perhaps
>>>>> after asking user if they want to do so. The question could be
>>>>> suppress-able with a new variable
>>>>> (e.g. `package-reinstall-vc-package-forward' with values `always',
>>>>> `ask', `never'). And the `package-vc-rebuild' could be also set as a
>>>>> variable (e.g., `package-reinstall-vc-package-function').
>>>>
>>>> My preference would be towards a., just like how I think that adding
>>>> VC packages to package-upgrade was a mistake in retrospect.
>>>
>>> How about creating a new bug for issues 7 (package-delete) and 8
>>> (package-reinstall) and discuss patches there?
>>
>> Sounds good!
>
> Will submit once we install some fix for this bug as it should make
> developing a fix more concise.
>
>>>>> .../test-package-1.bundle | Bin 0 -> 764 bytes
>>>>> .../test-package-2.bundle | Bin 0 -> 763 bytes
>>>>> .../test-package-3.bundle | Bin 0 -> 764 bytes
>>>>> .../test-package-4.bundle | Bin 0 -> 767 bytes
>>>>
>>>> I was afraid that the files would be a lot larger, but this seems
>>>> acceptable. Did you do a shallow clone and run git-gc(1)? Either way,
>>>> I would prefer to ask a maintainer before we apply these patches, just
>>>> to be on the safe side.
>>>
>>> These are not the packages I used as specimens earlier. Instead I opted
>>> for creating a minimal viable package repositories with just a two
>>> commits to exercise upgrade/downgrade test scenarios. That's why the
>>> bundles are so small. You can clone one of these bundles to see what's
>>> inside.
>>
>> Ah, I haven't applied the patch yet so I didn't know what was inside.
>
> NW. I updated tests to generate packages on fly from skeleton files.
1+
[...]
>
>>> + (or (plist-get pkg-spec :lisp-dir)
>>> + ;; When nothing is specified about a `lisp-dir', then s=
hould
>>> + ;; heuristically check if there is a sub-directory with=
lisp
>>> + ;; files. These are conventionally just called "lisp" =
or "src".
>>> + ;; If this directory exists and contains non-zero numbe=
r of lisp
>>> + ;; files, we will use that instead of `pkg-dir'.
>>> + (catch 'done
>>> + (dolist (name '("lisp" "src"))
>>> + (when-let* ((dir (expand-file-name name pkg-dir))
>>> + ((file-directory-p dir))
>>> + ((directory-files dir nil "\\`[^.].+\\.=
el\\'" t 1)))
>>> + ;; We won't use `dir', since dir is an absolute p=
ath and we
>>> + ;; don't want `lisp-dir' to depend on the current=
location of
>>> + ;; the package installation, ie. to break if move=
d around the
>>> + ;; file system or between installations.
>>> + (throw 'done name))))
>>> + ))
>>
>> I think you should fold these parentheses onto the previous line.
>
> Done.
>
>> [...]
>>> -(defun package-vc--unpack-1 (pkg-desc pkg-dir)
>>> - "Prepare PKG-DESC that is already checked-out in PKG-DIR.
>>> -This includes downloading missing dependencies, generating
>>> -autoloads, generating a package description file (used to
>>> -identify a package as a VC package later on), building
>>> -documentation and marking the package as installed."
>>> - (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>>> +(defun package-vc--unpack-1 (pkg-desc)
>>> + "Prepare PKG-DESC that is already checked-out.
>>> +The checkout directory is determined by relevant pkg-spec or from `dir'
>>
>> (Not critical, but if you can think of a nice way to avoid the passive
>> tense here, that would be nice)
>
> I rewrote it, but English is not my forte, so I am not sure if it is any
> better.
I recommend the `writegood-mode' package that catches passive forms
(with some false positives, because it is just regexp-based). But
essentially this rule boils to being explicit about who is doing
something, as opposed to just saying that something is being done to
something, without naming it.
>> [...]
>>> @@ -568,20 +602,37 @@ package-vc--unpack-1
>>> [...]
>>> + (unless (file-equal-p lisp-dir pkg-dir)
>>> + (package--reload-previously-loaded compile-desc))
>>> + ;; `package-activate-1' will add info node as long as dir file
>>> + ;; exists in `pkg-dir'. We need to manually add it when
>>> + ;; `checkout-dir' is in different location.
>>> + (unless (file-equal-p pkg-dir checkout-dir)
>>
>> Minor nit-pick if you are going to revise the patch anyway, it would be
>> nice to swap the argument here or above so that pkg-dir is on the same s=
ide.
>
> Done.
>
>> [...]
>> This is a pretty big patch, so I hope you understand that it takes me a
>> while to review it and my hesitance to changing so much of the code.
>
> I totally understand that.
>
>> Please tell me, if we revert the change that replaced the symbolic links
>> with the current "indirect" package loading approach, would that also
>> resolve the issue you had? If so, we could consider that along with
>> deprecating package-vc-install-from-checkout in favour of site-lisp.
>
> In case when we revert to symbolic link I think a few fixes may be worth
> porting. From the top of my head the fix to handle standard lisp sub
> directories, fix for backend detection in log incoming, and perhaps fix
> for extracting maintainers (to be developed, see comment in test below).
That sounds reasonable.
>>> From c82c03957f5f1fab6fbbff39ef1ea49792581e6f Mon Sep 17 00:00:00 2001
>>> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
>>> Date: Tue, 2 Sep 2025 09:28:13 +0100
>>> Subject: [PATCH 2/2] Add tests for package-vc
>>>
>>> [...]
>>>
>>> ---
>>> .../test-package-1.bundle | Bin 0 -> 764 bytes
>>> .../test-package-2.bundle | Bin 0 -> 763 bytes
>>> .../test-package-3.bundle | Bin 0 -> 764 bytes
>>> .../test-package-4.bundle | Bin 0 -> 767 bytes
>>> .../test-package-5.bundle | Bin 0 -> 845 bytes
>>> .../test-package-6.bundle | Bin 0 -> 843 bytes
>>> test/lisp/package-vc-tests.el | 601 ++++++++++++++++++
>>> 7 files changed, 601 insertions(+)
>>> create mode 100644 test/lisp/package-vc-resources/test-package-1.bundle
>>> create mode 100644 test/lisp/package-vc-resources/test-package-2.bundle
>>> create mode 100644 test/lisp/package-vc-resources/test-package-3.bundle
>>> create mode 100644 test/lisp/package-vc-resources/test-package-4.bundle
>>> create mode 100644 test/lisp/package-vc-resources/test-package-5.bundle
>>> create mode 100644 test/lisp/package-vc-resources/test-package-6.bundle
>>
>> I am sorry if I seem to be flip-flopping here, but thinking about this
>> again, but if you have constructed custom packages, why not store them
>> directly as test resources and have the tests convert them first into
>> git repositories under /tmp/, then git bundles and install those as
>> though they were remote? That would make it easier to track changes to
>> the test packages without having to update these opaque objects.
>
> I had thought about that, but wanted to avoid delaying a replay. This
> time I implemented this solution, and I think I like it better.
>
>> [...]
>>> diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests=
.el
>>> new file mode 100644
>>> index 00000000000..1e9b96df866
>>> --- /dev/null
>>> +++ b/test/lisp/package-vc-tests.el
>>> @@ -0,0 +1,601 @@
>>> +;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t=
-*-
>>> +
>>> +;; Copyright (C) 2025 Free Software Foundation, Inc.
>>> +
>>> +;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
>> ^
>> looks like a typo, unless you
>> have an alternative address?
>
> Indeed a typo. Thanks for catching!
>
>> [...]
>>> +;;; Commentary:
>>> +
>>> +;; These tests focus on verifying post conditions for `package-vc'
>>> +;; operations on packages. Since installing a package changes the sta=
te
>>> +;; of running process these tests are ment to be executed in order, as
>>> +;; denoted by digits in their name.
>>
>> This was my worry, are you sure there is no way around this? It seems
>> to me that by forcing this constraint we will always be struggling
>> against ERT in the future.
>
> Perhaps there could be a way around. I guess we can ensure packages are
> installed before each test, and preconditions are met. But not sure how
> much work it will take. If you think it's worth it, I can give it a go.
It would be worth estimating at least. I can also take care of some of
the work, if we decide a priori who should take care of what.
>>> Also in many cases the subsequent
>>> +;; test often depends on the passing of the previous test.
>>> +
>>> +;; It is recommended to run this suite in a separate process, for
>>> +;; example, in root of Emacs source directory:
>>> +
>>> +;; ./src/emacs -batch \
>>> +;; -l ../test/lisp/package-vc-tests.el \
>>> +;; -f ert-run-tests-batch-and-exit
>>
>> This is unpleasant... Can you explain why, it would be nice to just use
>> M-x ert.
>>
>
> To be fair, this is predominantly, because I am still on Emacs 30 and
> this is the way I am running these tests. This issues is the blocker
> for me before I can switch. I have added extra caveat directly to the
> doc string.
OK, that is good to hear. I would like to have the tests directly
executable, but again, that is something I can take care of as long as
you don't take it as an assumption that the tester must run the tests in
batch mode.
>> [...]
>>> +(defvar package-vc-tests-resources-dir
>>> + (file-name-concat (file-name-directory
>>
>> Why not use `expand-file-name'? Or other tests are using
>> `ert-resource-file', perhaps that might make sense for us as well?
>>
>
> This is gone in new version (in favour of `ert-resource-directory').
>
>>> + (or load-file-name buffer-file-name))
>>> + "package-vc-resources"))
>>> +(defvar package-vc-tests-packages nil)
>>> +
>>> +(defmacro with-package-vc-tests-enviroment (&rest body)
>>
>> It is not possible to have this as a function that `funcall's a closure?
>>
>>> [...]
>>> + ;; - test directory exists:
>>> + (should package-vc-tests-dir)
>>> + (should (file-directory-p package-vc-tests-dir))
>>
>> These seem more like assertions w.r.t. the testing logic than tests of
>> the package-vc to me.
>
> I removed them.
>
>> [...]
>>> +(defun package-vc-tests-package-main-file (pkg)
>>> + "Return a main file of PKG."
>>> + (format "%s/%s.el" (package-vc-tests-package-lisp-dir pkg) pkg))
>>
>> Some more commentary here, or just the assurance that in all the tests,
>> this is in fact do all have main file names that fit this pattern.
>>
>
> I wrote this function to satisfy DRY. Not sure what else can be commente=
d.
Ah, I see. What I was most interested in was some motivation, or some
expectation on what the structure of the parameter PKG should be. I
would guess it is a string, right?
>>> +
>>> +(defun package-vc-tests-load-history-position (pkg type)
>>> + "Return a PKG's position in `load-history'.
>>> +If TYPE is `:autoloads' return a position of a PKG autoloads file.
>>> +Otherwise, if TYPE is `:main' return a position of PKG main file (not
>>> +compiled). Otherwise, if TYPE is `:main-compiled' return a position of
>>> +PKG compiled main file. Otherwise, if TYPE is `:marker' return a
>>> +position of a marker PKG."
>>> + (let ((pkg-file (pcase type
>>> + (:autoloads
>>> + (rx (literal
>>> + (format "%s/%s/%s-autoloads.el"
>>> + package-user-dir pkg pkg))
>>> + string-end))
>>> + (:main
>>> + (rx
>>> + (literal
>>> + (format "%s"
>> ^
>> this seems like a noop to me? the
>> same below...
>>
>
> Fixed. I think it was an aftermath of changing an approach a couple time=
s.
>
>>> [...]
>>> +(defun package-vc-tests-assert-delete-elc ()
>>> + "Assert that .elc files are in expected directories and delete them.
>>> +When ALL is non nil, check all packages under test."
>>> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
>>> + (let* ((dir (package-vc-tests-package-lisp-dir pkg))
>>> + (elc-files (directory-files dir nil (rx ".elc" string-end)))
>>> + (autoloads-rx (rx
>>> + (literal (format "%s-autoloads.el" pkg))
>>> + string-end)))
>>> + (should-not (equal (cons dir elc-files)
>>> + (list dir)))
>>> + (should-not (cl-find-if (lambda (elc)
>>> + (string-match autoloads-rx elc))
>> ^
>> double
>> space
>
> Deleted.
>
>>> + elc-files))
>>> + (dolist (elc-file elc-files)
>>> + (delete-file (expand-file-name elc-file dir))))))
>>
>> Are we sure that this functionality has not been implemented somewhere
>> else? It all seems a little finicky to me...
>
> I couldn't find anything similar.
>
>>> +
>>> +(defun package-vc-tests-assert-package-alist (version)
>>> + "Assert that entries in `package-alist' have correct VERSION and dir=
."
>>> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
>>> + (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
>>> + (should (equal (file-name-as-directory
>>> + (expand-file-name (format "%s" pkg)
>>> + package-user-dir))
>>> + (file-name-as-directory
>>> + (package-desc-dir pkg-desc))))
>>> + (should (equal (list pkg version)
>>> + (list pkg (package-desc-version pkg-desc)))))))
>>
>> I know we have been over this, but we could get someone with more ERT
>> experience to chime in to see if there is some way to avoid having to
>> write tests in this contrived way...
>
> Per Info node (ert) Defining Explanation Functions, the recommended way
> is to write own explainer, but this seems a bit inconvenient. I have
> rewritten them with:
>
> (should (equal (format ...) (format ...)))
>
> Please see above for longer explanation.
What is the issue with explainers in your view?
>>> +
>>> +(defun package-vc-tests-reset-heads ()
>>> + "Reset to HEAD^ checkouts `package-vc-tests-packages'."
>>> + (mapcar (lambda (pkg-checkout-dir)
>>
>> This function is only used for its side-effects, so please use dolist
>> here!
>
> Done (using `pcase-dolist').
>
>>> + (let ((default-directory (cdr pkg-checkout-dir)))
>>> + (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))
>>> + package-vc-tests-packages))
>>> +
>>> +(defun package-vc-tests-packages-heads ()
>>> + "Return HEAD revisions of `package-vc-tests-packages'."
>>> + (mapcar (lambda (pkg-checkout-dir)
>>> + (let ((default-directory (cdr pkg-checkout-dir)))
>>> + (cons (car pkg-checkout-dir)
>>> + (vc-git-working-revision nil))))
>>> + package-vc-tests-packages))
>>> +
>>> +(ert-deftest package-vc-tests-000-install ()
>>> + (setq package-vc-tests-dir
>>> + (make-temp-file "package-vc-tests-"
>>> + t
>>> + (format-time-string "-%Y%m%d.%H%M%S")))
>>> + (package-initialize)
>>> + (package-vc--archives-initialize)
>>> + (eval
>>
>> Why are you evaluating the code like this??? (eval (quote x)) evaluates
>> to the same thing as x.
>
> I think this is no longer needed. I don't claim to understand exactly
> why it was needed there, but in the previous version of the patch, some
> of the variables (IIRC `package-vc-test-dir' and/or
> `package-user-directory') were evaled when the ert-deftest were evaled.
> While they should be evaled when tests were exectued. That caused tests
> to fail. However, since I have refactored to have these assigned as a
> part of test environment this is no longer needed.
Thank god :)
>> [...]
>>> +(ert-deftest package-vc-tests-001-main-file ()
>>> + (eval
>>> + '(with-package-vc-tests-enviroment
>>> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
>>
>> You can also use pcase-dolist if you want to pattern-match on each
>> element of the list, to avoid consing a new list. Not that that matters
>> much in tests, but it is less verbose.
>
> Nice! Converting to that.
>
>> [...]
>>> +(defmacro package-vc-tests-package-vc-upgrade-wait (seconds count &res=
t body)
>>> + "Wait up to SECONDS for COUNT packages upgrading BODY.
>>> +Return nil on timeout or the value of last form in BODY."
>>> + (declare (indent 2))
>>> + `(letrec ((packages-count ,count)
>>> + (post-vc-command
>>> + (lambda (command _ flags)
>>> + ;; A crude filter for vc commands
>>> + (when (and (equal command "git")
>>> + (string-prefix-p "*vc-git" (buffer-name)))
>>> + (cl-decf packages-count)))))
>>
>> cl-decf is an alias for decf since Emacs 31.
>
> Fixed.
>
>>> + (add-hook 'vc-post-command-functions post-vc-command 100)
>>> + (unwind-protect
>>> + (with-timeout (,seconds nil)
>>
>> Having tests fail with hard-coded timeout values seems wrong as they can
>> depend on the specific decide and its available resources. Couldn't we
>> use something like `ert-skip' in this case?
>
> I am afraid that skipping in case of failure is not a good option. Too
> many times I have seen failing test that skip instead of failing being
> ignored. Ultimately it's humans who are consumers of test reports and
> they often lack of necessary context to judge if test is being skipped
> for legitimate reason (like test not being valid on a particular OS or
> configuration) vs. legitimate error.
>
> The value of 5s (per operation!) is order of magnitude higher than what
> the command is expected to execute and, from my experience. I used such
> approach in automatic tests on a very, very busy machines (echo while
> typing on SSH was in order of seconds [sic!]), where tests were run
> dozens of times daily. The 5s caused the tests not to stall too much
> when something was actually broken, yet I don't remember seeing false
> positives. One alternative I can see is to hack around `vc' commands
> and force them to run synchronously under test.
>
> But if you really think it's better to skip or have a better idea,
> please let me know I will update.
I don't have anything strictly better, I have just had too many
paper-cuts with these kinds of tests. But I also understand the point
that people are inclined to ignore skipped tests. Again, this might be
something we could collaborate with/contribute to ERT to add some notion
of timeout'ed tests.
>>> + (prog1
>>> + (progn ,@body)
>>> + (while (not (eql packages-count 0))
>>
>> Or just /=3D, as you want package-count to be a number as well, right?
>
> Done
>
>> [...]
>> Just for technical reasons I am opposed to applying the patch in the
>> current state. I don't understand some of your decisions, and am
>> generally not a fan of the things being tested or the approach of having
>> the tests depend on one another. If you don't want to rework it, that
>> is fine -- I can also take care of that, though it would be nice if I
>> could take over your demo packages.
>
> I have been thinking how to rework these tests. Perhaps rewriting them
> in such a manner that each test will create a package bundle, and then
> use it to install the package. When writing these tests, I wanted to
> ensure that a package is handled the same regardless a method of
> installation - hence one test per `package-vc' functionality looping
> over all packages. And this was easiest achieved with a shared
> environment.
>
> I have been thinking about adding a number of functions to create a full
> test environment, including creating a bundle, cloning, installing,
> setting up all necessary variables etc. Installation could be done with
> `cl-defgeneric' et. al., as this is the only thing that really should
> differ per package. Then each test will progress setting up the package
> as it needs to (i.e., resetting package heads, pre-loading main-file,
> etc.). WDYT?
What I had in mind was perhaps to extract the tests into separate
functions and invoke from multiple tests. So each test would start with
installing a package (or multiple), running some tests and then
uninstalling the package again, reverting Emacs back to the initial
state. I guess that it comparable to what you had in mind?
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Eli Zaretskii <eliz@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Fri, 07 Nov 2025 06:54:01 +0000
Resent-Message-ID: <handler.79188.B79188.176249842722882 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176249842722882
(code B ref 79188); Fri, 07 Nov 2025 06:54:01 +0000
Received: (at 79188) by debbugs.gnu.org; 7 Nov 2025 06:53:47 +0000
Received: from localhost ([127.0.0.1]:44826 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vHGLy-0005x0-W9
for submit <at> debbugs.gnu.org; Fri, 07 Nov 2025 01:53:47 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:41824)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1vHGLw-0005wu-U3
for 79188 <at> debbugs.gnu.org; Fri, 07 Nov 2025 01:53:45 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
id 1vHGLq-0004re-N4; Fri, 07 Nov 2025 01:53:38 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
Date; bh=qD+u7H+UPApBxwl1JslzZVBMwdelRbV6TQgqNPqly7E=; b=b8ayaw+h9L2O/EfOGxVR
iHEU9VR6by5C9e/Z/v/YobAwKbwSuAyk//d2/F/h8c9n9qElzwR5zSpHNpaECg7xjkjqdreJNvyrT
jgsM+ISUiVkv4tVg7lRwQGPDfbTBY982czeyOy5DLTOAmHuJpQ5hXvDTRNcrsb2B5s3cvyBDyrw6A
2+7Wqni8fcEyXryNMXKMD2rqurrJ2pEenFuUL7KnG8WXvMzZRO/8NloRGegJa0VJYd69DIQecQD4x
wFq/7ALA8CQfly0Ou9buyB3yTI/b1MAR9wTGPRPGREzsvomRiwhNXtGv6c22C6/0E0Mg1sORt/e28
L32Bis5yvNncIA==;
Date: Fri, 07 Nov 2025 08:53:35 +0200
Message-Id: <86h5v6bafk.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
In-Reply-To: <m2bjlfrt6m.fsf@HIDDEN> (message from =?UTF-8?Q?Przemys=C5=82aw?= Kryger on Thu, 06 Nov 2025 17:01:53 +0000)
References: <m2ectn9xif.fsf@HIDDEN>
<m2cy97w04t.fsf@HIDDEN>
<CAPXM7TwOm9fF_nUsAZoDgrchp4Eg_991NmuBZgN2VCqjsUuShQ@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
<m2a51k4jd5.fsf@HIDDEN> <87a51du92y.fsf@HIDDEN>
<m2bjlfrt6m.fsf@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
> Cc: 79188 <at> debbugs.gnu.org
> From: Przemysław Kryger <pkryger@HIDDEN>
> Date: Thu, 06 Nov 2025 17:01:53 +0000
>
>
> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> - (url (plist-get pkg-spec :url)))
> + (url (plist-get pkg-spec :url))
> + (pkg-dir (pcase url
> + ((rx "file://" (let checkout-dir (+ any)))
> + checkout-dir)
> + (_ (package-desc-dir pkg-desc)))))
Does this work on MS-Windows, where file:// URLs have an extra '/'
before the actual absolute file name?
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Fri, 07 Nov 2025 17:20:02 +0000
Resent-Message-ID: <handler.79188.B79188.176253599122891 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Eli Zaretskii <eliz@HIDDEN>
Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176253599122891
(code B ref 79188); Fri, 07 Nov 2025 17:20:02 +0000
Received: (at 79188) by debbugs.gnu.org; 7 Nov 2025 17:19:51 +0000
Received: from localhost ([127.0.0.1]:47145 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vHQ7r-0005x9-3k
for submit <at> debbugs.gnu.org; Fri, 07 Nov 2025 12:19:51 -0500
Received: from mail-wm1-x336.google.com ([2a00:1450:4864:20::336]:54329)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1vHQ7o-0005wz-AJ
for 79188 <at> debbugs.gnu.org; Fri, 07 Nov 2025 12:19:49 -0500
Received: by mail-wm1-x336.google.com with SMTP id
5b1f17b1804b1-4711b95226dso9976685e9.0
for <79188 <at> debbugs.gnu.org>; Fri, 07 Nov 2025 09:19:48 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1762535982; x=1763140782; darn=debbugs.gnu.org;
h=content-transfer-encoding:mime-version:user-agent:message-id:date
:references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date
:message-id:reply-to;
bh=mFiKdjV/GnLZcXYr7ZMtYL2Q+mlmWGmbW8/Mtvnjsy0=;
b=f8kJG5iIg1hk1ekWc+ELtYk/1insg9KSfUCMdPeAifFlfH/9y95bdIhpyBGDkEW5sd
VpYsifiTU+ohaheZeJokNm5cC2p6xAcK4feFxsfzfVfbIdCRtJ/vRdAw70h0q4lBAw9O
cfRcjwbtQQw4j/mrG3RqWNvzRjE08/AWg8AB8lEAXll6DH056WmXglGEcezzPKrSxpCT
3RrdxCpX23xE0voyAk+niL5uyGpC96EvQjY6glKhZmmowHjX5RxELex9TCvgcvtU4kU8
ecBTGPacGlqpD1waSosMuowx3chx1dRUd2EzKGIWNNp76dqs1I6bPCgtGJe3rE8SFA9+
4ifg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1762535982; x=1763140782;
h=content-transfer-encoding:mime-version:user-agent:message-id:date
:references:in-reply-to:subject:cc:to:from:x-gm-gg
:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
bh=mFiKdjV/GnLZcXYr7ZMtYL2Q+mlmWGmbW8/Mtvnjsy0=;
b=NiT4Lz2qlMjTKZAfdhDFYML4tkWJuA+4BdIU6a2SOxapzrdX048zEuRleQ5FlboVAI
9cVLNUQvZKb2zt+Jp30KHzI8eU1pr7u9sIYfDCkkT4FKSeH7YpcmXFelW/BPgGjx26BD
UktfHVlBdKaZZaLBhSm7vpDh6xlvge5wLM6lpZr1NBgTwdaJsSdPz6/bRC+t/1ng65/0
IlWmlOc0IETaTfF7vy6rQrosRYbeigJGyl4cSNCtVHMeroLm3634EnTjpF4LfDH8sUOS
Mh6ZcH4apoisTg/3V4ir9Wh2BAJFxKoNyuxNlyNLcw7cr+Meuw3mwnclaZRIBVGDQJLQ
INWQ==
X-Forwarded-Encrypted: i=1;
AJvYcCWD01/DVDMdcBZbmfEIDROZiQeYwKLwj9PEYVQCLlgQXIrGNx2xfY+F9BkWHPQxiIvLT/lxhg==@debbugs.gnu.org
X-Gm-Message-State: AOJu0YzeQl8Eis+BUSvbgDu/mW/mwUJaePUVGKNfzxfUgOImQZlUEPnN
25VgmYfd9h+w+YQaJ23rMq3RZwNQMQER/8RVcnUxWAdDc5jzck9A5lZARz4jWpz6
X-Gm-Gg: ASbGncunIc5zMvUk2Sk3nbv4bNBQDuTssEyT6AQ011BNSp+RLC7SGIK/8ONX2YtpUKX
pe3KWgZri9CCuvLY+WVLuUGEtUp8zHCPt24YfTtjUlTFgJi26HoREgbo7ska58ysIQV8EC3v8ot
A+YSDWMkEvYK/5KFEhXhS6Wd6TyyD4APVNp9xb5ZMCTnlV5ieTsE3ZlM8y+YCvlKumtPzTjsdz0
ZTrCohZ8AhzsSoTzYMj8QYBwh6qjgIPGxHL2OGRJrx/FuHbopHRC8b0RGfc1NXb1eBsivtMoYiL
6PB3Odf1WSk9PIdHpjvhr7/xd/fIYsjeGuQDo5Qx++xd47YxaTP0eHV0Aq7itIoHTxtrUJxk47k
d5xn4rSZZv+8KD1a5m+iVf3jCqGXRJdMaIpUr5uSAHfEV7vDelr9IbMc+51xekXsQA4HnkJs+WU
MZs1ltGiKAeVfFU1G7NtqvcvgqSAMSADF5u/eQdVVhgPHw
X-Google-Smtp-Source: AGHT+IF2Oviu6fI1Z86u9qkF9VLveDOj7RDAVzSUMYw2uxwzNRPQW8fm+CM5bKfYur3CL2KxBuAiLA==
X-Received: by 2002:a05:600c:350d:b0:471:7a:791a with SMTP id
5b1f17b1804b1-4776bc88b26mr30510795e9.7.1762535981595;
Fri, 07 Nov 2025 09:19:41 -0800 (PST)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:831:e806:28ea:3de9])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-4776c2aff72sm56801165e9.4.2025.11.07.09.19.40
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Fri, 07 Nov 2025 09:19:41 -0800 (PST)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <86h5v6bafk.fsf@HIDDEN> (Eli Zaretskii's message of "Fri, 07 Nov
2025 08:53:35 +0200")
References: <m2ectn9xif.fsf@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
<m2a51k4jd5.fsf@HIDDEN> <87a51du92y.fsf@HIDDEN>
<m2bjlfrt6m.fsf@HIDDEN> <86h5v6bafk.fsf@HIDDEN>
Date: Fri, 07 Nov 2025 17:19:40 +0000
Message-ID: <m27bw1sqtv.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
Eli Zaretskii <eliz@HIDDEN> writes:
>> Cc: 79188 <at> debbugs.gnu.org
>> From: Przemys=C5=82aw Kryger <pkryger@HIDDEN>
>> Date: Thu, 06 Nov 2025 17:01:53 +0000
>>=20
>>=20
>> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>> - (url (plist-get pkg-spec :url)))
>> + (url (plist-get pkg-spec :url))
>> + (pkg-dir (pcase url
>> + ((rx "file://" (let checkout-dir (+ any)))
>> + checkout-dir)
>> + (_ (package-desc-dir pkg-desc)))))
>
> Does this work on MS-Windows, where file:// URLs have an extra '/'
> before the actual absolute file name?
I am not really sure. I don't have access to a Windows computer in
person, that I can goof around. However, I managed to setup a GitHub
action runner and tests attached earlier pass [1]. I don't really know
what are various ways of installing Emacs on a Windows machine and when
Windows style paths come to play. This installation uses MSYS2.
Also, in the output from test run I can see the lines like:
Compiling d:/a/_temp/msys64/tmp/package-vc-tests-ngs6l6-20251107.170557/t=
est-package-3/test-package-3.el...
while test-package-3 is one of packages installed with
`package-vc-install-from-checkout'. I guess that's a good sign.
[1] Except the log incoming one, but I suspect this has something to do
with `vc-git' or git itself. You can see full log here:
https://github.com/pkryger/emacs-dev/actions/runs/19175148354/job/548178732=
27=20
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Fri, 07 Nov 2025 18:19:02 +0000
Resent-Message-ID: <handler.79188.B79188.17625395369878 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17625395369878
(code B ref 79188); Fri, 07 Nov 2025 18:19:02 +0000
Received: (at 79188) by debbugs.gnu.org; 7 Nov 2025 18:18:56 +0000
Received: from localhost ([127.0.0.1]:47490 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vHR2z-0002ZC-Qu
for submit <at> debbugs.gnu.org; Fri, 07 Nov 2025 13:18:56 -0500
Received: from mail-wr1-x42a.google.com ([2a00:1450:4864:20::42a]:46554)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1vHR2v-0002Z4-1z
for 79188 <at> debbugs.gnu.org; Fri, 07 Nov 2025 13:18:52 -0500
Received: by mail-wr1-x42a.google.com with SMTP id
ffacd0b85a97d-421851bca51so820521f8f.1
for <79188 <at> debbugs.gnu.org>; Fri, 07 Nov 2025 10:18:49 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1762539522; x=1763144322; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=4AiShADfEByM6PDYa1IyEU6z/jhbVc+LaMFSPAU7Vu8=;
b=QBF5kjb2+230rcnOyUQpuhxrtJ9G84hMhO0d8qZ+Do+QKueVuT4cF+cuGcdIhN2zC9
IWO9p3cBL5tjHJmwahOzpCVqjTJ+o/SokO5KBVCb3ZPVcXoly/CNYhz0Y11V/MpjQiJr
2gAVY4vKCj569KOt0kVc4fA/BaDHI0SWTSzRc2pB1DqzJPLVyQgvUadH4Ucojr/9t/ic
pGVJZ/X8tfhBm3BcQhJNZJt4m4nvEQftRcVHgTD/5dX/aAC57K9970B9e6++5peYlqOh
/IvGhrpqLNqFCmIUNvHBUEl/uaG6SOnRbmsiTXeIf4Ab8u2sNa1leKiRZS9IynSq7oZX
hhDA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1762539522; x=1763144322;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject
:date:message-id:reply-to;
bh=4AiShADfEByM6PDYa1IyEU6z/jhbVc+LaMFSPAU7Vu8=;
b=B9WLGo0vqFmp/H0mbTM1PwvVS3oLKA5nFfD7seBPmpQ79fvBYAR6B1XprZEjf1gKCZ
zKQrnGI+pVdiCCaNLkr7jDb6hEhUqZqS9avuLpnXSz88cUuzPpg0D1UxCzSvNqaWwNFM
ZXIF05gsRdIaDfkZ0et8SpJLf+LDOJfWKYTSAFN449Gf100k2k1ajTcbI8dE4JZze0+f
twl4vaufNIxwnhglRdD2uDJMbrqdtVaXQGDafct6Y7g+5tNYRi7W1AQWE85ZjjtuZkcm
aKXc7J2nqKYZQ/XxKPugyFdXiSZPdxqeGNvXTtolke3Sq/PW+/EPcmpR+zp/JIAZmJzo
bsyg==
X-Gm-Message-State: AOJu0Yys68Uv52F5Dfe61C1KYEw6R9ds9D0sjaNYtpP8h/5mjyYS5i/L
t9ra24CNOtFFiNz9fp8wXO4XQAbsPGnwfx7SGNE9eTCx7u45YPIZYmAH09UFxg==
X-Gm-Gg: ASbGncuoni1danNrYYnWnMiiIAFDPxYQTFHJRES8pOZjnyxmkhTicDKxDg/W57BnMyp
cQ4Pba1CBf+fh1ik3YYSwV//r+QJT/f4G8yb00YDpKVYajF5wFl5CDlHOW6b1Nd0I9gZ/sp10x/
aY8vjj6EkHHrMY0hIss4rQ+Qi1r//pPgkJeTfm9rt8stgqIJ9K/mb4bFTHssh4dWtMotJU6x2RH
XViHjRvJoGY6SkKM4lUfLvhuCdG1DiX+cQ4CHZpvA+mg3dmfj8h9iok5PVTAiVEkqwH+Bd/ZB1l
9rBZw9dAmISbQtGL7wD7lnO0OCxD0Id2HUneyKyw0svc2W5T0+i++63Fs0tzYugR+5KRBIgGdEQ
SrVDYLu+WcPRwqF0i+V8DPPYyRSZoEesQ3GZpeP92vBOcydQVZ0USadjh1L/jn+Ot46R9j/xM8/
98q/K1z1PFaBjZZgRBbhPMjWJHBofHVaH5BMqGPJ3CZhM/FothRhW7Ks0=
X-Google-Smtp-Source: AGHT+IGXSYWgm/KPttvoC28yy+OINdKt5xxsTR34PsAga8EhUdGayR3vBVf30RaHp8qiO81I+4oFpQ==
X-Received: by 2002:a05:6000:4282:b0:425:86f0:6817 with SMTP id
ffacd0b85a97d-42ae5af41fbmr3391661f8f.57.1762539522149;
Fri, 07 Nov 2025 10:18:42 -0800 (PST)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:831:e806:28ea:3de9])
by smtp.gmail.com with ESMTPSA id
ffacd0b85a97d-42ac677abeasm6639988f8f.33.2025.11.07.10.18.40
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Fri, 07 Nov 2025 10:18:41 -0800 (PST)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <87346qx4tj.fsf@HIDDEN> (Philip Kaludercic's message of "Thu,
06 Nov 2025 20:51:37 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
<m2a51k4jd5.fsf@HIDDEN> <87a51du92y.fsf@HIDDEN>
<m2bjlfrt6m.fsf@HIDDEN> <87346qx4tj.fsf@HIDDEN>
Date: Fri, 07 Nov 2025 18:18:40 +0000
Message-ID: <m2346pso3j.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Philip Kaludercic <philipk@HIDDEN> writes:
> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>
>> Sorry for long time to respond. It took me some time to apply fixes and
>> reply. Attached are new patches, still keeping tests separate.
>
> No worries, I was afraid that my last message was too strong/negative
> and that I had scared you away :x
Absolutely not! While I still have a hope for preserving install from
checkout functionality, I'd like to help as much as I can.
Attached please see updated patch with updated tests (only assertions, see =
below):
--=-=-=
Content-Type: text/x-patch; charset=utf-8
Content-Disposition: attachment;
filename=0001-Add-tests-for-package-vc.patch
Content-Transfer-Encoding: quoted-printable
Content-Description: tests
From 3f40f5f014b70239ca85a0fb0267a522e0d98883 Mon Sep 17 00:00:00 2001
From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
Date: Tue, 2 Sep 2025 09:28:13 +0100
Subject: [PATCH] Add tests for package-vc
* test/lisp/package-vc-tests.el (package-vc-tests-dir):
Temporary directory to store `package' and test data during the
test.
(package-vc-tests-packages): List of packages to tests, together
with their checkout locations.
(package-vc-tessts-bundles): List of package bundles and their
most recent commits.
(package-vc-tests-checkin): Copy a an in file and create a new
file and create a new commit for a test package source.
(package-vc-tests-create-bundle): Create a package git
repository bundle with test package source.
(with-package-vc-tests-enviroment): Setup environment for test,
that includes configuring `package', `package-vc', and `vc'
variables, as well as defining test packages and creating their
bundles.
(package-vc-tests-package-desc): Retrieve a `package-desc' for
tested package.
(package-vc-tests-package-lisp-dir): Determine a lisp directory
for a package.
(package-vc-tests-package-main-file): Calculate expected
location of package's main file.
(package-vc-tests-load-history-position): Calculate a position
in load-history of a file. The position only accounts for
interesting files, that is only files that are in
`package-vc-tests-dir'.
(package-vc-tests-valid-commit-p): Check that commit is a string
and it is not "unknown".
(package-vc-tests-in-strict-order-p): Check that args are in
strict order (each arg is less than the following args).
(package-vc-tests-match-p): Check that string matches a regexp.
(package-vc-tests-buffer-p): Check that object is a buffer.
(package-vc-tests-elc-files): Check that there are elc files and
that there is no compiled autoloads file amongst them.
(package-vc-tests-assert-delete-elc): Assert that .elc files
have been gernerated for a package and delete them.
(package-vc-tests-assert-package-alist): Assert that
`pakcage-alist' contains a `package-desc' for package, and that
the `pakcage-desc' has correct slot `version' and slot `dir'.
(package-vc-tests-reset-heads): Reset heads of checkouts of
tested packages to a HEAD^.
(package-vc-tests-packages-heads): Return a list of checkouts of
tested packages current HEAD revisions.
(package-vc-tests-000-install): Test that packages can be
installed with `package-vc-install' and
`package-vc-install-from-checkout', including
`package-vc-checkout'.
(package-vc-tests-001-main-file): Test that
`package-vc--main-file' return main file in expected locations.
(package-vc-tests-002-commit): Test that `package-vc-commit' is
returning a revision.
(package-vc-tests-003-load-history-after-install): Test that
`load-history' has entries for autoloads of tested packages.
(package-vc-tests-package-vc-async-wait): Helper function to
wait for an asynchronous VC command to finish. This is needed
due to asynchronous nature of `vc-pull' and `vc-log-incoming'.
(package-vc-tests-004-upgrade-all): Test that
`package-vc-upgrade-all' indeed upgrades all packages.
(package-vc-tests-005-load-history-after-upgrade-all): Test that
`load-history' has entries for autoloads of tested packages.
(package-vc-tests-006-require): Test that packages can be
`require'd, and that `load-history' has entries for non-compiled
package main files.
(package-vc-tests-007-upgrade): Test that `package-vc-upgrade'
upgrades a package.
(package-vc-tests-008-load-history-after-upgrade): Test that
`load-history' has entries for autoloads, non-compiled main
files, and compiled main files after a package has been
upgraded.
(package-vc-tests-009-rebuild): Test that a downgraded package
can be rebuild with `package-vc-rebuild', and that appropriate
files are reloaded.
(package-vc-tests-010-prepare-patch): Test that
`package-vc-prepare-patch' creates a new message buffer for a
package.
(package-vc-tests-011-log-incoming): Test that
`package-vc-log-incoming' creates a new log buffer for a
package.
* test/lisp/package-vc-resources/test-package-v0.1.el.in:
Skeleton of version 0.1 of a test package.
* test/lisp/package-vc-resources/test-package-v0.2.el.in:
Skeleton of version 0.2 of a test package.
---
.../test-package-v0.1.el.in | 24 +
.../test-package-v0.2.el.in | 20 +
test/lisp/package-vc-tests.el | 722 ++++++++++++++++++
3 files changed, 766 insertions(+)
create mode 100644 test/lisp/package-vc-resources/test-package-v0.1.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-v0.2.el.in
create mode 100644 test/lisp/package-vc-tests.el
diff --git a/test/lisp/package-vc-resources/test-package-v0.1.el.in b/test/=
lisp/package-vc-resources/test-package-v0.1.el.in
new file mode 100644
index 00000000000..8ee147a06a7
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-v0.1.el.in
@@ -0,0 +1,24 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-author@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.1
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+;;;###autoload
+(defun test-package-SUFFIX-func ()
+ "Test.")
+
+;;;###autoload
+(defun test-package-SUFFIX-old-func ()
+ "Test.")
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-v0.2.el.in b/test/=
lisp/package-vc-resources/test-package-v0.2.el.in
new file mode 100644
index 00000000000..3c84ba0b1ac
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-v0.2.el.in
@@ -0,0 +1,20 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-author@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.2
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+;;;###autoload
+(defun test-package-SUFFIX-func ()
+ "Test.")
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
new file mode 100644
index 00000000000..f6c03961eaa
--- /dev/null
+++ b/test/lisp/package-vc-tests.el
@@ -0,0 +1,722 @@
+;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
+
+;; Copyright (C) 2025 Free Software Foundation, Inc.
+
+;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
+;; Keywords: package
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These tests focus on verifying post conditions for `package-vc'
+;; operations on packages. Since installing a package changes the state
+;; of running process these tests are ment to be executed in order, as
+;; denoted by digits in their name. Also in many cases the subsequent
+;; test often depends on the passing of the previous test.
+
+;; These tests load test packages with some test implementation, as well
+;; as `load-history' is being modified. This may contaminate the
+;; running Emacs instance. This, compounded with a need to run all
+;; tests in the order it is recommended to run this suite in a separate
+;; process, for example, in root of Emacs source directory:
+
+;; ./src/emacs -batch \
+;; -l ../test/lisp/package-vc-tests.el \
+;; -f ert-run-tests-batch-and-exit
+
+;;; Code:
+
+(require 'package-vc)
+(require 'package)
+(require 'vc-git)
+(require 'vc)
+(require 'cl-lib)
+(require 'ert-x)
+(require 'ert)
+
+(defvar package-vc-tests-dir nil)
+(defvar package-vc-tests-packages nil)
+(defvar package-vc-tests-bundles nil)
+
+(defun package-vc-tests-checkin (name suffix in commit-msg &optional lisp-=
dir)
+ "For package NAME copy IN file as main file.
+After copying update SUFFIX in the file and check it in with COMMIT-MSG.
+If LISP-DIR is non-nil place the file under LISP-DIR."
+ (let ((resource-dir (ert-resource-directory))
+ (main-file (format "%s.el" (if lisp-dir
+ (expand-file-name name lisp-dir)
+ name)))
+ (suffix (if (stringp suffix) suffix (format "%s" suffix))))
+ (copy-file (expand-file-name in resource-dir) main-file t)
+ (with-temp-buffer
+ (insert-file-contents main-file)
+ (goto-char (point-min))
+ (while (search-forward "SUFFIX" nil t)
+ (replace-match suffix))
+ (write-file main-file))
+ (vc-git-command nil 0 nil "add" ".")
+ (vc-git-command nil 0 nil "commit" "-m" commit-msg)))
+
+(defun package-vc-tests-create-bundle (suffix &optional lisp-dir)
+ "Create a test package bundle with SUFFIX.
+If LISP-DIR is non-nil place sources of the package in LISP-DIR."
+ (let* ((name (format "test-package-%s" suffix))
+ (src-dir (expand-file-name (format "src/%s" name)
+ package-vc-tests-dir)))
+ (make-directory (if lisp-dir
+ (expand-file-name lisp-dir src-dir)
+ src-dir)
+ :parents)
+ (let ((default-directory src-dir)
+ (bundle-file (expand-file-name (format "%s.bundle" name)
+ package-vc-tests-dir)))
+ (vc-git-command nil 0 nil "init" "-b" "master")
+ (package-vc-tests-checkin
+ name suffix "test-package-v0.1.el.in" "First commit" lisp-dir)
+ (package-vc-tests-checkin
+ name suffix "test-package-v0.2.el.in" "Second commit" lisp-dir)
+ (vc-git-command nil 0 nil
+ "bundle" "create" bundle-file "master")
+ (list (intern name)
+ bundle-file (vc-git-working-revision nil)))))
+
+(defmacro with-package-vc-tests-enviroment (&rest body)
+ "Eval BODY with test environment."
+ (declare (debug t))
+ ;; Test packages sources are stored in bundle files produced by
+ ;; git-bundle(1) and are stored in directory package-vc-resources.
+ ;; Before executing body make sure that:
+ `(let* (package-archives
+ ;; - temporary location for packages and test files is ready
+ (package-vc-tests-dir
+ (or package-vc-tests-dir
+ (setq package-vc-tests-dir
+ (make-temp-file "package-vc-tests-"
+ t
+ (format-time-string "-%Y%m%d.%H%M%S")=
))))
+ ;; - packages are installed into a test directory
+ (package-user-dir (expand-file-name "elpa"
+ package-vc-tests-dir))
+ ;; - create test package bundles if necessary and define test
+ ;; packages and their checkout locations
+ (package-vc-tests-bundles
+ (or package-vc-tests-bundles
+ (setq package-vc-tests-bundles
+ (mapcar (lambda (suffix)
+ (package-vc-tests-create-bundle
+ suffix (and (< 4 suffix) "lisp")))
+ '(1 2 3 4 5 6)))))
+ (package-vc-tests-packages
+ `(;; checkout and install with `package-vc-install' (on
+ ;; ELPA)
+ (test-package-1
+ . ,(expand-file-name "test-package-1"
+ package-user-dir))
+ ;; checkout and install with `package-vc-install' (not on
+ ;; ELPA)
+ (test-package-2
+ . ,(expand-file-name "test-package-2"
+ package-user-dir))
+ ;; checkout with `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-3
+ . ,(expand-file-name "test-package-3"
+ package-vc-tests-dir))
+ ;; checkout with git and install with
+ ;; `package-vc-install-from-checkout'
+ (test-package-4
+ . ,(expand-file-name "test-package-4"
+ package-vc-tests-dir))
+ ;; sources in "lisp" sub directory, checkout and install
+ ;; with `package-vc-install'
+ (test-package-5
+ . ,(expand-file-name "test-package-5"
+ package-user-dir))
+ ;; sources in "lisp" sub directory, checkout with git and
+ ;; install with `package-vc-install-from-checkout'
+ (test-package-6
+ . ,(expand-file-name "test-package-6"
+ package-vc-tests-dir))
+
+ ;; TODO: a package with source files in a non-standard
+ ;; :lisp-dir, a custom Makefile and non-standard :doc
+ ;; (both methods of installation)
+ ))
+ ;; - test packages are recognised by `package' and
+ ;; `package-vc' internals:
+ (package-archive-contents
+ (list
+ (let ((bundle (alist-get 'test-package-1
+ package-vc-tests-bundles)))
+ (list 'test-package-1
+ (package-desc-create
+ :name 'test-package-1
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras
+ (list
+ '(:maintainer
+ ("Test Maintainer" . "test-maintainer@test-domain.=
org"))
+ (cons :url (car bundle))
+ (cons :commit (cadr bundle))
+ (cons :revdesc (substring (cadr bundle) 0 12))))))
+ (let ((bundle (alist-get 'test-package-3
+ package-vc-tests-bundles)))
+ (list 'test-package-3
+ (package-desc-create
+ :name 'test-package-3
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras
+ (list
+ '(:maintainer
+ ("Test Maintainer" . "test-maintainer@test-domain.=
org"))
+ (cons :url (car bundle))
+ (cons :commit (cadr bundle))
+ (cons :revdesc (substring (cadr bundle) 0 12))))))))
+ (package-vc--archive-spec-alists
+ (list
+ (list 'test-elpa
+ (list 'test-package-1
+ :url (car (alist-get 'test-package-1
+ package-vc-tests-bundles))
+ :branch "master")
+ (list 'test-package-3
+ :url (car (alist-get 'test-package-3
+ package-vc-tests-bundles))
+ :branch "master"))))
+ (package-vc--archive-data-alist
+ (list
+ (list 'test-elpa :version 1 :default-vc 'Git)))
+ ;; - `vc-guess-backend-url' is recognising bundles as `Git'
+ ;; repositories:
+ (vc-clone-heuristic-alist
+ (cons
+ (cons (rx "test-package-" (one-or-more digit) ".bundle"
+ string-end)
+ 'Git)
+ vc-clone-heuristic-alist)))
+ ;; - `package' has been initialised:
+ (should package--initialized)
+
+ ,@body))
+
+
+;; TODO: add test for deleting packages, with asserting
+;; `package-vc-selected-packages'
+
+;; TODO: clarify `package-vc-install-all' behaviour with regards to
+;; packages installed with `package-vc' but not stored in
+;; `package-vc-selected-packages' i.e., packages from ELPAs
+
+(defun package-vc-tests-package-desc (package &optional installed)
+ "Return descriptor of PACKAGE.
+When INSTALLED is non-nil the descriptor will come from `package-alist'.
+Otherwise the descriptor will be from `package-archive-contents'. This
+is to mimic `package-vc--read-package-desc'."
+ (cadr (assoc (if (stringp package) package (symbol-name package))
+ (if installed package-alist package-archive-contents)
+ #'string=3D)))
+
+(defun package-vc-tests-package-lisp-dir (pkg)
+ "Return a Lisp directory of PKG."
+ (when-let* ((checkout-dir (alist-get pkg package-vc-tests-packages)))
+ (cond
+ ((member pkg '(test-package-5 test-package-6))
+ (expand-file-name "lisp" checkout-dir))
+ (t checkout-dir))))
+
+(defun package-vc-tests-package-main-file (pkg)
+ "Return a main file of PKG."
+ (format "%s/%s.el" (package-vc-tests-package-lisp-dir pkg) pkg))
+
+
+;; When a package source is being recompiled - for example as result of
+;; `pakckage-vc-upgrade' or `package-vc-rebuild' - it is also reloaded
+;; [1] to ensure that the most recent version of compiled code is
+;; available to Emacs. There are a few tests that add markers in
+;; `load-history' before executing such functions. And then follow up
+;; tests use these markers to assert that expected package files are in
+;; correct places in the `load-history'.
+;;
+;; [1] Only when a file has been loaded previously.
+(defun package-vc-tests-load-history-position (pkg type)
+ "Return a PKG's position in `load-history'.
+If TYPE is `:autoloads' return a position of a PKG autoloads file.
+Otherwise, if TYPE is `:main' return a position of PKG main file (not
+compiled). Otherwise, if TYPE is `:main-compiled' return a position of
+PKG compiled main file. Otherwise, if TYPE is `:marker' return a
+position of a marker PKG."
+ (let ((pkg-file (pcase type
+ (:autoloads
+ (rx (literal
+ (format "%s/%s/%s-autoloads.el"
+ package-user-dir pkg pkg))
+ string-end))
+ (:main
+ (rx
+ (literal
+ (package-vc-tests-package-main-file pkg))
+ string-end))
+ (:main-compiled
+ (rx
+ (literal
+ (package-vc-tests-package-main-file pkg))
+ "c"
+ string-end))
+ (:marker
+ (rx "/" (literal (format "%s" pkg))))))
+ (interesting-entry
+ (rx string-start
+ (literal (file-truename package-vc-tests-dir)))))
+ (cl-position-if
+ (lambda (file)
+ (string-match pkg-file file))
+ (cl-remove-if-not
+ (lambda (file-name)
+ (string-match interesting-entry file-name))
+ (mapcar
+ #'file-truename
+ (cl-remove-if-not
+ #'stringp
+ (mapcar #'car load-history)))))))
+
+;; The following predicates and helper functions take an extra PKG
+;; argument. This is needed for ERT to print package name in case of
+;; failure.
+
+(defun package-vc-tests-valid-commit-p (_pkg commit)
+ "Return non-nil when COMMIT is a valid commit."
+ (and (stringp commit)
+ (not (string=3D commit "unknown"))))
+
+(defun package-vc-tests-in-strict-order-p (_pkg &rest args)
+ "Return non-nil when ARGS are in strict order."
+ (apply #'< args))
+
+(defun package-vc-tests-match-p (_pkg regexp string)
+ "Return non-nil when REGEXP matches STRING."
+ (string-match regexp string))
+
+(defun package-vc-tests-buffer-p (_pkg obj)
+ "Return non-nil when OBJ is a buffer."
+ (bufferp obj))
+
+(defun package-vc-tests-elc-files (pkg)
+ "Return elc files for PKG."
+ (when-let* ((dir (package-vc-tests-package-lisp-dir pkg))
+ (elc-files (directory-files
+ dir nil (rx ".elc" string-end))))
+ elc-files))
+
+(defun package-vc-tests-assert-delete-elc ()
+ "Assert that .elc files are in expected directories and delete them.
+When ALL is non nil, check all packages under test."
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let* ((dir (package-vc-tests-package-lisp-dir pkg))
+ (elc-files (should (package-vc-tests-elc-files pkg)))
+ (autoloads-rx (rx
+ (literal (format "%s-autoloads.elc" pkg))
+ string-end)))
+ (should-not (cl-find-if (lambda (elc)
+ (string-match autoloads-rx elc))
+ elc-files))
+ (dolist (elc-file elc-files)
+ (delete-file (expand-file-name elc-file dir))))))
+
+(defun package-vc-tests-assert-package-alist (version)
+ "Assert that entries in `package-alist' have correct VERSION and dir."
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
+ (should (equal (file-name-as-directory
+ (expand-file-name (format "%s" pkg)
+ package-user-dir))
+ (file-name-as-directory
+ (package-desc-dir pkg-desc))))
+ (should (equal (list pkg version)
+ (list pkg (package-desc-version pkg-desc)))))))
+
+(defun package-vc-tests-reset-heads ()
+ "Reset to HEAD^ checkouts `package-vc-tests-packages'."
+ (pcase-dolist (`(,_ . ,dir) package-vc-tests-packages)
+ (let ((default-directory dir))
+ (vc-git-command nil 0 nil "reset" "--hard" "HEAD^"))))
+
+(defun package-vc-tests-packages-heads ()
+ "Return HEAD revisions of `package-vc-tests-packages'."
+ (mapcar (lambda (pkg-checkout-dir)
+ (let ((default-directory (cdr pkg-checkout-dir)))
+ (cons (car pkg-checkout-dir)
+ (vc-git-working-revision nil))))
+ package-vc-tests-packages))
+
+(ert-deftest package-vc-tests-000-install ()
+ (package-initialize)
+ (package-vc--archives-initialize)
+ (with-package-vc-tests-enviroment
+ (push (list (format "%s/install-begin" package-vc-tests-dir))
+ load-history)
+ (package-vc-install 'test-package-1)
+ (should-not (alist-get "test-package-1"
+ package-vc-selected-packages
+ nil nil #'string=3D))
+
+ (let ((bundle (car (alist-get 'test-package-2
+ package-vc-tests-bundles))))
+ (package-vc-install `(test-package-2
+ :url ,bundle
+ :branch "master"))
+ (should (equal bundle
+ (plist-get (alist-get "test-package-2"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-3"
+ package-vc-tests-dir)))
+ (package-vc-checkout (package-vc-tests-package-desc
+ 'test-package-3)
+ checkout-dir)
+ (package-vc-install-from-checkout checkout-dir)
+ (should (equal (format "file://%s" checkout-dir)
+ (plist-get (alist-get "test-package-3"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-4"
+ package-vc-tests-dir)))
+ (vc-git-clone
+ (car (alist-get 'test-package-4
+ package-vc-tests-bundles))
+ checkout-dir
+ "master")
+ (package-vc-install-from-checkout checkout-dir "test-package-4")
+ (should (equal (format "file://%s" checkout-dir)
+ (plist-get (alist-get "test-package-4"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((bundle (car (alist-get 'test-package-5
+ package-vc-tests-bundles))))
+ (package-vc-install `(test-package-5
+ :url ,bundle
+ :branch "master"))
+ (should (equal bundle
+ (plist-get (alist-get "test-package-5"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-6"
+ package-vc-tests-dir)))
+ (vc-git-clone
+ (car (alist-get 'test-package-6
+ package-vc-tests-bundles))
+ checkout-dir
+ "master")
+ (package-vc-install-from-checkout checkout-dir "test-package-6")
+ (should (equal (format "file://%s" checkout-dir)
+ (plist-get (alist-get "test-package-6"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (push (list (format "%s/install-end" package-vc-tests-dir))
+ load-history)
+
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc)))
+
+(ert-deftest package-vc-tests-001-main-file ()
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (should (equal (package-vc--main-file
+ (package-vc-tests-package-desc pkg t))
+ (package-vc-tests-package-main-file pkg))))))
+
+(ert-deftest package-vc-tests-002-commit ()
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (should (package-vc-tests-valid-commit-p
+ pkg
+ (package-vc-commit
+ (package-vc-tests-package-desc pkg t)))))))
+
+(ert-deftest package-vc-tests-003-load-history-after-install ()
+ (with-package-vc-tests-enviroment
+ (let ((install-begin
+ (should (package-vc-tests-load-history-position
+ 'install-begin :marker)))
+ (install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker))))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ install-end
+ autoloads-pos
+ install-begin)))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))))))
+
+(defmacro package-vc-tests-package-vc-async-wait (seconds count flags &res=
t body)
+ "Wait up to SECONDS for COUNT async vc commands with FLAGS called by BOD=
Y.
+Return nil on timeout or the value of last form in BODY."
+ (declare (indent 3))
+ (let ((count-sym (make-symbol "count"))
+ (post-vc-command-sym (make-symbol "post-vc-command")))
+ `(letrec ((,count-sym ,count)
+ (,post-vc-command-sym
+ (lambda (command _ command-flags)
+ ;; A crude filter for vc commands
+ (when (and (equal command "git")
+ (cl-every (lambda (flag)
+ (member flag command-flags))
+ ,flags))
+ (decf ,count-sym)))))
+ (add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
+ (unwind-protect
+ (with-timeout (,seconds nil)
+ (prog1
+ (progn ,@body)
+ (while (/=3D ,count-sym 0)
+ (accept-process-output nil 0.01))))
+ (remove-hook 'vc-post-command-functions ,post-vc-command-sym)))))
+
+(ert-deftest package-vc-tests-004-upgrade-all ()
+ (with-package-vc-tests-enviroment
+ (push (list (format "%s/upgrade-all-begin" package-vc-tests-dir))
+ load-history)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (package-vc-tests-reset-heads)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 (length package-vc-tests-packages) '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (push (list (format "%s/upgrade-all-end" package-vc-tests-dir))
+ load-history)
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc)))
+
+(ert-deftest package-vc-tests-005-load-history-after-upgrade-all ()
+ (with-package-vc-tests-enviroment
+ (let ((upgrade-all-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-all-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker))))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-all-end
+ autoloads-pos
+ upgrade-all-begin))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled)))))))
+
+(ert-deftest package-vc-tests-006-require ()
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should (require pkg))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg)))))
+ (let ((upgrade-all-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker))))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((main-pos (should (package-vc-tests-load-history-position
+ pkg :main))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ main-pos
+ upgrade-all-end)))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))))))
+
+(ert-deftest package-vc-tests-007-upgrade ()
+ (with-package-vc-tests-enviroment
+ (push (list (format "%s/upgrade-begin" package-vc-tests-dir))
+ load-history)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (package-vc-tests-reset-heads)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 (length package-vc-tests-packages) '("pull")
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (package-vc-upgrade
+ (package-vc-tests-package-desc pkg t))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function
+ (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg)))))
+ t))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (push (list (format "%s/upgrade-end" package-vc-tests-dir))
+ load-history)
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc)))
+
+(ert-deftest package-vc-tests-008-load-history-after-upgrade ()
+ (with-package-vc-tests-enviroment
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker))))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ autoloads-pos
+ upgrade-begin))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ main-pos
+ upgrade-begin))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ main-compiled-pos
+ upgrade-begin)))))))
+
+(ert-deftest package-vc-tests-009-rebuild ()
+ (with-package-vc-tests-enviroment
+ (package-vc-tests-reset-heads)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function
+ (intern (format "%s-func" pkg)))))
+ (should (fboundp (intern (format "%s-old-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function
+ (intern (format "%s-old-func" pkg))))))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (package-vc-tests-assert-package-alist '(0 1))
+ (package-vc-tests-assert-delete-elc)))
+
+(ert-deftest package-vc-tests-010-prepare-patch ()
+ (let (vc-prepare-patches-separately)
+ ;; Ensure `vc-prepare-patch' respects subject from function
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ ;; FIXME: Currently `package-vc-prepare-patch' only works only
+ ;; for a package installed with `package-vc-install'. No other
+ ;; `package-vc' installation method is supported. Likely,
+ ;; because package maintainer are not set in generated pkg-file.
+ (when (memq pkg '(test-package-1))
+ (package-vc-prepare-patch (package-vc-tests-package-desc pkg t)
+ "test-subject"
+ (cdr (alist-get
+ pkg package-vc-tests-bundles)))
+ (let ((message-buffer
+ (get-buffer "*unsent mail to Test Maintainer*")))
+ (should (equal (format "%s: message-buffer" pkg)
+ (format "%s: %s"
+ pkg (if (bufferp message-buffer)
+ "message-buffer"
+ "no message-buffer"))))
+ (switch-to-buffer message-buffer)
+ (goto-char (point-min))
+ (should
+ (package-vc-tests-match-p
+ pkg
+ (rx
+ "To: Test Maintainer <test-maintainer@HIDDEN>")
+ (buffer-substring (point) (pos-eol))))
+ (forward-line)
+ (should
+ (package-vc-tests-match-p
+ pkg
+ (rx "Subject: test-subject")
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer message-buffer))))))))
+
+(ert-deftest package-vc-tests-011-log-incoming ()
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 1 '("log" "--decorate")
+ (package-vc-log-incoming (package-vc-tests-package-desc pkg t))
+ t))
+ (let ((incoming-buffer (get-buffer "*vc-incoming*"))
+ (pattern (rx (literal
+ (substring
+ (cadr (alist-get pkg
+ package-vc-tests-bundles))
+ 0 7))
+ (one-or-more any)
+ "Second commit"
+ line-end)))
+ (should (package-vc-tests-buffer-p pkg incoming-buffer))
+ (switch-to-buffer incoming-buffer)
+ (goto-char (point-min))
+ (should
+ (package-vc-tests-match-p
+ pkg
+ pattern
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer incoming-buffer))))))
+
+(provide 'package-vc-tests)
+
+;;; package-vc-tests.el ends here
--=20
2.51.2
--=-=-=
Content-Type: text/plain
>>> [...]
>>>>>> (ert-deftest package-vc-tests-002-commit ()
>>>>>> (dolist (pkg-checkout-dir package-vc-tests-packages)
>>>>>> (let ((pkg (car pkg-checkout-dir))
>>>>>> (commit (package-vc-commit
>>>>>> (package-vc-tests-package-desc (car pkg-checkout-dir) t))))
>>>>>> (should-not (equal (cons pkg commit)
>>>>>> (list pkg)))
>>>>>
>>>>> So (null commit)?
>>>>
>>>> Or even simpler (should commit). But that will only print a commit name
>>>> in case of failure. I did the list trick on purpose, such that on
>>>> failure it prints the affected package name. I know that one option is
>>>> to write a custom ert-explainer, but that seems like an overkill. Or
>>>> create a custom assertion that would `message' before failure, yet this
>>>> one seems odd to me. I wish `should' could take extra context. Do you
>>>> have a better idea how to ensure package name is printed?
>>>
>>> The only idea I have would be to write (and pkg (null commit))...
>>
>> Unfortunately, this doesn't print value of pkg. The assertion:
>>
>> (should (and pkg commit))
>>
>> Prints on failure:
>>
>> (ert-test-failed ((should (and pkg commit)) :form (and pkg commit) :value nil))
>>
>> I tried slightly different mangling trick:
>>
>> (should (equal (format "%s: has commit" pkg)
>> (format "%s: %s commit"
>> pkg (if commit "has" "has no"))))
>>
>> Which yields the following diagnostic on failure (indentation is mine):
>>
>> (ert-test-failed
>> ((should (equal (format "%s: has commit" pkg)
>> (format "%s: %s commit"
>> pkg (if commit "has" "has no")))
>> :form
>> (equal "test-package-1: has commit"
>> "test-package-1: has no commit")
>> :value nil
>> :explanation
>> (arrays-of-different-length
>> 26 29
>> "test-package-1: has commit"
>> "test-package-1: has no commit"
>> first-mismatch-at 20)))
>>
>> I hope it reads better. I have updated other relevant assertions to use
>> this technique as well.
>
> I guess if that was wrapped in a macro it would be acceptable, but
> looking into ert.el it seems like we could also have a custom function
> with a 'ert-explainer annotation that can specify how to display a
> failure. For instance:
>
> (ert-deftest foo ()
> (should (time-equal-p (current-time) (current-time))))
>
> fails for me with:
>
> F foo
> (ert-test-failed
> ((should (time-equal-p (current-time) (current-time))) :form
> (time-equal-p (26893 179 232751 570000) (26893 179 232751 805000))
> :value nil :explanation
> (different-time-values "2025-11-06 20:10:27.232751570+0000"
> "2025-11-06 20:10:27.232751805+0000"
> difference "-1.999999765")))
>
> and the explainer is defined in ert.el. I would suggest to define a
> custom equality predicate in the test file (perhaps abbreviating it
> using a shorthand) and add a ert-explainer property to it.
So I embarked to write custom predicates and explainers. It turns out
that the latter are not even needed as ERT is nice enough to print
evaluated arguments in output. So I ended up with just custom
predicates. Please let me know what you think.
[...]
>>>> -(defun package-vc--unpack-1 (pkg-desc pkg-dir)
>>>> - "Prepare PKG-DESC that is already checked-out in PKG-DIR.
>>>> -This includes downloading missing dependencies, generating
>>>> -autoloads, generating a package description file (used to
>>>> -identify a package as a VC package later on), building
>>>> -documentation and marking the package as installed."
>>>> - (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>>>> +(defun package-vc--unpack-1 (pkg-desc)
>>>> + "Prepare PKG-DESC that is already checked-out.
>>>> +The checkout directory is determined by relevant pkg-spec or from `dir'
>>>
>>> (Not critical, but if you can think of a nice way to avoid the passive
>>> tense here, that would be nice)
>>
>> I rewrote it, but English is not my forte, so I am not sure if it is any
>> better.
>
> I recommend the `writegood-mode' package that catches passive forms
> (with some false positives, because it is just regexp-based). But
> essentially this rule boils to being explicit about who is doing
> something, as opposed to just saying that something is being done to
> something, without naming it.
Will check that out.
[...]
>>>> +;;; Commentary:
>>>> +
>>>> +;; These tests focus on verifying post conditions for `package-vc'
>>>> +;; operations on packages. Since installing a package changes the state
>>>> +;; of running process these tests are ment to be executed in order, as
>>>> +;; denoted by digits in their name.
>>>
>>> This was my worry, are you sure there is no way around this? It seems
>>> to me that by forcing this constraint we will always be struggling
>>> against ERT in the future.
>>
>> Perhaps there could be a way around. I guess we can ensure packages are
>> installed before each test, and preconditions are met. But not sure how
>> much work it will take. If you think it's worth it, I can give it a go.
>
> It would be worth estimating at least. I can also take care of some of
> the work, if we decide a priori who should take care of what.
It's very hard for me to estimate. I guess I know to little about the
internals, so I never know how long it will take me to debug anything.
Could be a couple of hours if all goes relatively smooth. Could be a
few days if stuck on something.
>>>> Also in many cases the subsequent
>>>> +;; test often depends on the passing of the previous test.
>>>> +
>>>> +;; It is recommended to run this suite in a separate process, for
>>>> +;; example, in root of Emacs source directory:
>>>> +
>>>> +;; ./src/emacs -batch \
>>>> +;; -l ../test/lisp/package-vc-tests.el \
>>>> +;; -f ert-run-tests-batch-and-exit
>>>
>>> This is unpleasant... Can you explain why, it would be nice to just use
>>> M-x ert.
>>>
>>
>> To be fair, this is predominantly, because I am still on Emacs 30 and
>> this is the way I am running these tests. This issues is the blocker
>> for me before I can switch. I have added extra caveat directly to the
>> doc string.
>
> OK, that is good to hear. I would like to have the tests directly
> executable, but again, that is something I can take care of as long as
> you don't take it as an assumption that the tester must run the tests in
> batch mode.
Let me put it this way: I have not assumed that tests are run in a batch
mode. Only that they are executed in order. I tried to write them in
such a way to not clobber anything vital for a regular Emacs. Yet I
have never run them in such a way, so I cannot guarantee that I caught
up and isolated all contention points.
[...]
>>>> +(defun package-vc-tests-package-main-file (pkg)
>>>> + "Return a main file of PKG."
>>>> + (format "%s/%s.el" (package-vc-tests-package-lisp-dir pkg) pkg))
>>>
>>> Some more commentary here, or just the assurance that in all the tests,
>>> this is in fact do all have main file names that fit this pattern.
>>>
>>
>> I wrote this function to satisfy DRY. Not sure what else can be commented.
>
> Ah, I see. What I was most interested in was some motivation, or some
> expectation on what the structure of the parameter PKG should be. I
> would guess it is a string, right?
A symbol in this case. I tried to make PKG a symbol everywhere in
package-vc-tests.el. Please let me know if I missed anything.
[...]
>>>> +(defun package-vc-tests-assert-package-alist (version)
>>>> + "Assert that entries in `package-alist' have correct VERSION and dir."
>>>> + (dolist (pkg (mapcar #'car package-vc-tests-packages))
>>>> + (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
>>>> + (should (equal (file-name-as-directory
>>>> + (expand-file-name (format "%s" pkg)
>>>> + package-user-dir))
>>>> + (file-name-as-directory
>>>> + (package-desc-dir pkg-desc))))
>>>> + (should (equal (list pkg version)
>>>> + (list pkg (package-desc-version pkg-desc)))))))
>>>
>>> I know we have been over this, but we could get someone with more ERT
>>> experience to chime in to see if there is some way to avoid having to
>>> write tests in this contrived way...
>>
>> Per Info node (ert) Defining Explanation Functions, the recommended way
>> is to write own explainer, but this seems a bit inconvenient. I have
>> rewritten them with:
>>
>> (should (equal (format ...) (format ...)))
>>
>> Please see above for longer explanation.
>
> What is the issue with explainers in your view?
Just for posterity, as I have already switched to predicates (see
above). I think that these were just a bit too verbose for a single use
item that's sole purpose is to print value of a single variable. They
require a separate function and property assignment. While I appreciate
how flexible such an abstract mechanism is, I think it's just too
baroque for such a simple case. I like how googletest solves such an
issue: just stream extra context to assertion. I wish ERT had something
similar.
[...]
>>>> + (add-hook 'vc-post-command-functions post-vc-command 100)
>>>> + (unwind-protect
>>>> + (with-timeout (,seconds nil)
>>>
>>> Having tests fail with hard-coded timeout values seems wrong as they can
>>> depend on the specific decide and its available resources. Couldn't we
>>> use something like `ert-skip' in this case?
>>
>> I am afraid that skipping in case of failure is not a good option. Too
>> many times I have seen failing test that skip instead of failing being
>> ignored. Ultimately it's humans who are consumers of test reports and
>> they often lack of necessary context to judge if test is being skipped
>> for legitimate reason (like test not being valid on a particular OS or
>> configuration) vs. legitimate error.
>>
>> The value of 5s (per operation!) is order of magnitude higher than what
>> the command is expected to execute and, from my experience. I used such
>> approach in automatic tests on a very, very busy machines (echo while
>> typing on SSH was in order of seconds [sic!]), where tests were run
>> dozens of times daily. The 5s caused the tests not to stall too much
>> when something was actually broken, yet I don't remember seeing false
>> positives. One alternative I can see is to hack around `vc' commands
>> and force them to run synchronously under test.
>>
>> But if you really think it's better to skip or have a better idea,
>> please let me know I will update.
>
> I don't have anything strictly better, I have just had too many
> paper-cuts with these kinds of tests. But I also understand the point
> that people are inclined to ignore skipped tests. Again, this might be
> something we could collaborate with/contribute to ERT to add some notion
> of timeout'ed tests.
How would you advice to proceed?
[...]
>>> Just for technical reasons I am opposed to applying the patch in the
>>> current state. I don't understand some of your decisions, and am
>>> generally not a fan of the things being tested or the approach of having
>>> the tests depend on one another. If you don't want to rework it, that
>>> is fine -- I can also take care of that, though it would be nice if I
>>> could take over your demo packages.
>>
>> I have been thinking how to rework these tests. Perhaps rewriting them
>> in such a manner that each test will create a package bundle, and then
>> use it to install the package. When writing these tests, I wanted to
>> ensure that a package is handled the same regardless a method of
>> installation - hence one test per `package-vc' functionality looping
>> over all packages. And this was easiest achieved with a shared
>> environment.
>>
>> I have been thinking about adding a number of functions to create a full
>> test environment, including creating a bundle, cloning, installing,
>> setting up all necessary variables etc. Installation could be done with
>> `cl-defgeneric' et. al., as this is the only thing that really should
>> differ per package. Then each test will progress setting up the package
>> as it needs to (i.e., resetting package heads, pre-loading main-file,
>> etc.). WDYT?
>
> What I had in mind was perhaps to extract the tests into separate
> functions and invoke from multiple tests. So each test would start with
> installing a package (or multiple), running some tests and then
> uninstalling the package again, reverting Emacs back to the initial
> state. I guess that it comparable to what you had in mind?
I had though about something similar as well. The issue with
composition is that it is very easy to forget to run one of these
aspects for one of packages. And, because there's no assertion to fail
one won't know that. Maybe wrap each test body in a macro that would
fail if some assertions were not executed?
I think I originally thought about something along the lines
(pseud-code, all typos mine, p-v-t=package-vc-tests):
;; Specialised installer for each package
(cl-defun p-v-t-install ((pkg (symbol test-package-2)) bundle)
(let ((chekcout-dir (expand-file-name (format "%s" pkg) p-v-t-dir)))
(package-vc-checkout pkg checkout-dir)
(package-vc-install-from-checkout pkg checkout-dir)))
;; One macro to create full environment protecting all critical
;; variables
(defmacro p-v-t-with-environment (pkg &rest body)
`(let* ((p-v-t-dir (make-temp)) ;; per-invocation
(p-v-t-bunldle (p-v-t-create-bundle ,pkg))
(package-user-dir (expand-file-name elpa p-v-t-dir)) ;; per-invocation
(package-archives ...)
(package-archive-contents ...)
package-alist
package-selected-package
(package-vc--archive-spec-alists ...)
(package-vc--archive-data-alist ...)
package-vc-selected-packages
(load-path load-path)
(load-history load-history)
(vc-clone-heuristic-alist ...)
;;... figure out other variables
)
(p-v-t-install ,pkg)
,@body))
(ert-deftest p-v-t-rebuild
(pcase-dolist* ((`(,pkg . ,dir) p-v-t-packages))
(p-v-t-with-environment pkg
(p-v-t-reset-head dir)
(push load-path (list begin nil))
(package-vc-rebuild pkg)
(push load-path (list end nil))
(should ...))))
I would like to do it that way, so when developing these tests
accidental breakages won't break running Emacs session. Or at least
have a smaller chance to do so.
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Eli Zaretskii <eliz@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Sat, 08 Nov 2025 07:26:02 +0000
Resent-Message-ID: <handler.79188.B79188.176258671130887 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176258671130887
(code B ref 79188); Sat, 08 Nov 2025 07:26:02 +0000
Received: (at 79188) by debbugs.gnu.org; 8 Nov 2025 07:25:11 +0000
Received: from localhost ([127.0.0.1]:50412 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vHdJu-00081n-HO
for submit <at> debbugs.gnu.org; Sat, 08 Nov 2025 02:25:11 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:37494)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1vHdJs-0007wI-5p
for 79188 <at> debbugs.gnu.org; Sat, 08 Nov 2025 02:25:09 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
id 1vHdJm-0003nY-5a; Sat, 08 Nov 2025 02:25:02 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
Date; bh=yScRFFs4lmYb6v6Ko+afHCtZ0kLpjbIpshJRnjWGJ9w=; b=e/t4BFthiWGrbfxG4w1h
ICjN4I5kcCX3xjiSK146qN0HEUTb5lbrfcA7vjG7HtBlaufCYsklH7T08VCjCE8dJ9KRW+6crSfZ2
zla5Z/Vp5tiMgHbpyu4U20/SQWSck8xioX83g5k0gmbl8h9j15zQH+aAT3CDK9KDHGsUc7tKjM3iw
QmuzSBFW8IWmwRII4vnM+juQ9pSvJZsRNerWRQOi9QcVC/s0uL3INb7+wQIIDDlw+z142gHgsiF34
KPVgOs3ju+ixnI70WM8XViVCrAfgkgfMD7UujeYVDOuBoiM8W/5XXhK2P3izJFT423UbiI9EOgy0h
IDyQjwZLBMwqyw==;
Date: Sat, 08 Nov 2025 09:24:57 +0200
Message-Id: <86qzu97zqu.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
In-Reply-To: <m27bw1sqtv.fsf@HIDDEN> (message from =?UTF-8?Q?Przemys=C5=82aw?= Kryger on Fri, 07 Nov 2025 17:19:40 +0000)
References: <m2ectn9xif.fsf@HIDDEN>
<m2a54avzq5.fsf_-_@HIDDEN> <87h5ygyb28.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
<m2a51k4jd5.fsf@HIDDEN> <87a51du92y.fsf@HIDDEN>
<m2bjlfrt6m.fsf@HIDDEN> <86h5v6bafk.fsf@HIDDEN>
<m27bw1sqtv.fsf@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
> From: Przemysław Kryger <pkryger@HIDDEN>
> Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
> Date: Fri, 07 Nov 2025 17:19:40 +0000
>
> Eli Zaretskii <eliz@HIDDEN> writes:
>
> >> Cc: 79188 <at> debbugs.gnu.org
> >> From: Przemysław Kryger <pkryger@HIDDEN>
> >> Date: Thu, 06 Nov 2025 17:01:53 +0000
> >>
> >>
> >> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> >> - (url (plist-get pkg-spec :url)))
> >> + (url (plist-get pkg-spec :url))
> >> + (pkg-dir (pcase url
> >> + ((rx "file://" (let checkout-dir (+ any)))
> >> + checkout-dir)
> >> + (_ (package-desc-dir pkg-desc)))))
> >
> > Does this work on MS-Windows, where file:// URLs have an extra '/'
> > before the actual absolute file name?
>
> I am not really sure. I don't have access to a Windows computer in
> person, that I can goof around. However, I managed to setup a GitHub
> action runner and tests attached earlier pass [1]. I don't really know
> what are various ways of installing Emacs on a Windows machine and when
> Windows style paths come to play. This installation uses MSYS2.
> Also, in the output from test run I can see the lines like:
>
> Compiling d:/a/_temp/msys64/tmp/package-vc-tests-ngs6l6-20251107.170557/test-package-3/test-package-3.el...
>
> while test-package-3 is one of packages installed with
> `package-vc-install-from-checkout'. I guess that's a good sign.
Let me ask a question which might be easier for you to answer: does
the above code produce file:///c:/foo/bar URLs on MS-Windows (note the
3 slashes before the drive letter) in the variables you use thereafter
as a URL? Alternatively, does it correctly remove the 3 slashes from
file:// URLs on MS-Windows to produce local absolute file names? If
not, the code needs to be amended to produce the extra slash on
Windows, otherwise it will not work.
Thanks.
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Mon, 10 Nov 2025 13:26:01 +0000
Resent-Message-ID: <handler.79188.B79188.176278110619098 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Eli Zaretskii <eliz@HIDDEN>
Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176278110619098
(code B ref 79188); Mon, 10 Nov 2025 13:26:01 +0000
Received: (at 79188) by debbugs.gnu.org; 10 Nov 2025 13:25:06 +0000
Received: from localhost ([127.0.0.1]:37734 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vIRtJ-0004xy-EV
for submit <at> debbugs.gnu.org; Mon, 10 Nov 2025 08:25:06 -0500
Received: from mail-wm1-x32b.google.com ([2a00:1450:4864:20::32b]:44367)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1vIRtF-0004xM-Na
for 79188 <at> debbugs.gnu.org; Mon, 10 Nov 2025 08:25:03 -0500
Received: by mail-wm1-x32b.google.com with SMTP id
5b1f17b1804b1-47777000dadso11056995e9.1
for <79188 <at> debbugs.gnu.org>; Mon, 10 Nov 2025 05:25:01 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1762781095; x=1763385895; darn=debbugs.gnu.org;
h=content-transfer-encoding:mime-version:user-agent:message-id:date
:references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date
:message-id:reply-to;
bh=rmSVgZNeGedLSPrRBObnDEWYbQVUZ5lp1blzsSOy5t4=;
b=IX5rNCNUyMsggSlJg43dfPDa9RIZY95syfw4wytFNIxutEP35UTqvgxBFzc/Z+/ts/
9dLE5qlv5WL7gRZQMHQ2tNJQoCeJlM2fkZiGAi2D5P7p5GQrZsMq19NyJYOGfp+zZdEe
mEGnwbwqtO9m1da8bjr5J0902d0xRGIY/3Q+3hgo1qTIlw5YvkYnAhgUApObm07nRghS
R+L5qgSK/0D0w00+kcqX96jrAuNezKJ2T62f/JGniAS8xXO/YVKv+8VmVwV8KBA7zZ0g
eInqyDDDyMTQ1Z/+d9ikSMbOiGXQ8x+QVI8Ruqfxf9Fog095kCHj8NjVPeS4mRoUYLlu
D9JQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1762781095; x=1763385895;
h=content-transfer-encoding:mime-version:user-agent:message-id:date
:references:in-reply-to:subject:cc:to:from:x-gm-gg
:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
bh=rmSVgZNeGedLSPrRBObnDEWYbQVUZ5lp1blzsSOy5t4=;
b=FOTblZp5iUR34FwtwC2b/7CgimlQNY9s+rwtphHZTzTN4N+EEumxllBXh/ch6H+o1X
nnVTeO4v/Q9GDuyMpohLR8v4sZrvLWXN47RzbwjUlud9wKHNeg9XEtTHJPgigXzxdWsr
rhOMijMy2Bjl+CPLGy3vQ4yuQndscwm260etjKX8AEvVvtV8TGLiDRbiDdjvEOG4kvEV
8EqpZNbO5LZvIG5Ky5/9rXSylIBbTkd2mXG8AMJ3grw+wXUcXFmE52xIb7h5q9gJORt1
dviVJQv1IKcNwWxV2ZpphhyEiEWmIFDMDBMtjhxx2yG7cg1WELvrE0YgCRA0Mk6xfxzK
2kbg==
X-Forwarded-Encrypted: i=1;
AJvYcCULDAZ2RESK+h9/L9sCXeDem6Bs8fbZezlB0mGlSlMPHPc05sgFtCCILdDl2zbbWX4ngEh03A==@debbugs.gnu.org
X-Gm-Message-State: AOJu0Yw8UgnmoiQjDbhcb2q4jyh4objm2wtXPLHm4YpJaGfYgQS7OR5w
CvlyUKuRv/ixzvRaDCKuVUnohEAJwb4+po67tbTIWcFVEurI8OPBV47gzu7cEw==
X-Gm-Gg: ASbGncvaFKeCsiRNwDRTerTGVTkxznp65By8oqsWz2wtJf9rBF++iAjkEjyUhNXHspY
eI/5bgnRiwZHHxpRE+MJ9vHQUlcOfZPfFhnutY8UsYI9ObRLjWbM20XwTor0NCs2EFwJ2GWdgp7
iujx/WX6cAUDIKbqyoz9t0q42kup7nvD6zMe/k2RO7M1JDEwvfDuP/gn8P30CHsYr9pFIfVxEdV
4bf7d8/qZe2vYzDDtoV9oIbGghNCWalgzlr+9FBU4elTUkfXTZVqeK3rDa9OLtnLOijLdejJztQ
m5SUsK77Hm58Lu9mjPBL3GjqklslHAgFIhP4X8P/eWz6Oal8iz00g2YK+ynGm0RhoV6UhvjLcix
e95a3Q28ztlWn+ZC3PQ6a1i9eelixuXU0nJvJpWvnaTAUT+79+EJHdjpPj6o6ZYB5ionFU+C7W1
fyzdFWLBHWhLmX1IZ53jTCb7c3cqAmbzeT8ycv4ROo1zP1j9ZmEhWCrU8p
X-Google-Smtp-Source: AGHT+IGXgoGHnOPBF1PYuuCqi5mcyRS/dMjLLOx1G31ufS/9NjOQAC4A57WgQZ1qc1MA1I9fPzgIjg==
X-Received: by 2002:a05:600c:a49:b0:475:dd9a:f786 with SMTP id
5b1f17b1804b1-477732ab2femr73230005e9.40.1762781094909;
Mon, 10 Nov 2025 05:24:54 -0800 (PST)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:84fd:dde9:b8aa:46a9])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-47764ec7736sm107077145e9.6.2025.11.10.05.24.53
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Mon, 10 Nov 2025 05:24:54 -0800 (PST)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <86qzu97zqu.fsf@HIDDEN> (Eli Zaretskii's message of "Sat, 08 Nov
2025 09:24:57 +0200")
References: <m2ectn9xif.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
<m2a51k4jd5.fsf@HIDDEN> <87a51du92y.fsf@HIDDEN>
<m2bjlfrt6m.fsf@HIDDEN> <86h5v6bafk.fsf@HIDDEN>
<m27bw1sqtv.fsf@HIDDEN> <86qzu97zqu.fsf@HIDDEN>
Date: Mon, 10 Nov 2025 13:24:53 +0000
Message-ID: <m2ms4uqau2.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
Eli Zaretskii <eliz@HIDDEN> writes:
>> From: Przemys=C5=82aw Kryger <pkryger@HIDDEN>
>> Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
>> Date: Fri, 07 Nov 2025 17:19:40 +0000
>>
>> Eli Zaretskii <eliz@HIDDEN> writes:
>>
>> >> Cc: 79188 <at> debbugs.gnu.org
>> >> From: Przemys=C5=82aw Kryger <pkryger@HIDDEN>
>> >> Date: Thu, 06 Nov 2025 17:01:53 +0000
>> >>
>> >>
>> >> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>> >> - (url (plist-get pkg-spec :url)))
>> >> + (url (plist-get pkg-spec :url))
>> >> + (pkg-dir (pcase url
>> >> + ((rx "file://" (let checkout-dir (+ any)))
>> >> + checkout-dir)
>> >> + (_ (package-desc-dir pkg-desc)))))
>> >
>> > Does this work on MS-Windows, where file:// URLs have an extra '/'
>> > before the actual absolute file name?
>>
>> I am not really sure. I don't have access to a Windows computer in
>> person, that I can goof around. However, I managed to setup a GitHub
>> action runner and tests attached earlier pass [1]. I don't really know
>> what are various ways of installing Emacs on a Windows machine and when
>> Windows style paths come to play. This installation uses MSYS2.
>> Also, in the output from test run I can see the lines like:
>>
>> Compiling d:/a/_temp/msys64/tmp/package-vc-tests-ngs6l6-20251107.17055=
7/test-package-3/test-package-3.el...
>>
>> while test-package-3 is one of packages installed with
>> `package-vc-install-from-checkout'. I guess that's a good sign.
>
> Let me ask a question which might be easier for you to answer: does
> the above code produce file:///c:/foo/bar URLs on MS-Windows (note the
> 3 slashes before the drive letter) in the variables you use thereafter
> as a URL? Alternatively, does it correctly remove the 3 slashes from
> file:// URLs on MS-Windows to produce local absolute file names? If
> not, the code needs to be amended to produce the extra slash on
> Windows, otherwise it will not work.
Apologies to not answering directly to your question, but my Windows
skills become rusty after almost 10 years of not using it.
To directly answer to your question, the this code produces a value with
two extra slashes before expanded path. Such that the value stored in a
pkg-spec in `package-vc-selected-packages' looks like (from one of test
executions in GitHub action, build under MSYS2):
((:url "file://d:/a/_temp/msys64/tmp/package-vc-tests-7nJr9j-20251108.092=
527/test-package-3"))
For non interactive calls, the value of `:url' is obtained by calling
(collapsed all transformations):
(concat "file://" (expand-file-name dir))
While for interactive calls it is:
(concat "file://" (expand-file-name (read-directory-name "Directory: ")))
For non interactive case, this is how test code produces for `dir':
(expand-file-name "test-package-3"
(make-temp-file "package-vc-tests-"
t
(format-time-string "-%Y%m%d.%H%M%S")))
For the interactive case I checked with a tmate [1] on a Windows 2025
build on a GitHub runner, and I can see that typing (with backslashes):
M-: (expand-file-name (read-directory-name "Directory: ")) RET
d:\a\_temp\msys64\tmp\package-vc-tests-7nJr9j-20251108.092527\test-packag=
e-3 RET
yields:
"d:/a/_temp/msys64/tmp/package-vc-tests-7nJr9j-20251108.092527/test-packag=
e-3"
Likewise, typing (without drive letter, and use slashes):
M-: (expand-file-name (read-directory-name "Directory: ")) RET
/a/_temp/msys64/tmp/package-vc-tests-7nJr9j-20251108.092527/test-package-3
yields exactly the same:
"d:/a/_temp/msys64/tmp/package-vc-tests-7nJr9j-20251108.092527/test-packag=
e-3"
I am not sure what conditions need to be met for (expand-file-name) to
return a path with a leading slash before drive letter.
[1] https://github.com/mxschmitt/action-tmate
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Eli Zaretskii <eliz@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Mon, 10 Nov 2025 14:28:02 +0000
Resent-Message-ID: <handler.79188.B79188.176278483629044 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176278483629044
(code B ref 79188); Mon, 10 Nov 2025 14:28:02 +0000
Received: (at 79188) by debbugs.gnu.org; 10 Nov 2025 14:27:16 +0000
Received: from localhost ([127.0.0.1]:37862 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vISrS-0007YO-U6
for submit <at> debbugs.gnu.org; Mon, 10 Nov 2025 09:27:15 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:60402)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1vISrP-0007Y4-8U
for 79188 <at> debbugs.gnu.org; Mon, 10 Nov 2025 09:27:12 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
id 1vISrJ-0003iu-I5; Mon, 10 Nov 2025 09:27:05 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
Date; bh=qNm1owBduom7v6xcGkupK7DFF9W5L0Q7vA6zUo9AveE=; b=TjWXhy53jhR0PVULm7iA
4lPzcpPAzBGBr3AimKjoWVVQUZYNTW4zMwO5HvXGx9bog8oXX1p65k02BwNFkbZPHde7qrnoEPzP6
9DDludM1lucNTgLJ+vRQOf39IqIFPanmY78m77rgVtHSzc+yghjy4/NDyXRKgApKz+LdkqW62XMYX
E+PSDZfpQ0aSrmNYpyoBCZrsYPMFTifV129Tsk3QejS9xWe7x3Q+PcTze3h/bR/4u0OA1BKjkEmvp
qeyCHboReWIIzjpYu7CsafAZDqDnyCnR3KR+Dg1wQ0+i/NAjW9zaY5UfMn7+VduMYyu3SRBPdlthQ
QLMn2BKmrENA8Q==;
Date: Mon, 10 Nov 2025 16:26:13 +0200
Message-Id: <864ir23qwq.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
In-Reply-To: <m2ms4uqau2.fsf@HIDDEN> (message from =?UTF-8?Q?Przemys=C5=82aw?= Kryger on Mon, 10 Nov 2025 13:24:53 +0000)
References: <m2ectn9xif.fsf@HIDDEN>
<m2o6smup74.fsf@HIDDEN> <87cy8v2zcd.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
<m2a51k4jd5.fsf@HIDDEN> <87a51du92y.fsf@HIDDEN>
<m2bjlfrt6m.fsf@HIDDEN> <86h5v6bafk.fsf@HIDDEN>
<m27bw1sqtv.fsf@HIDDEN> <86qzu97zqu.fsf@HIDDEN>
<m2ms4uqau2.fsf@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
> From: Przemysław Kryger <pkryger@HIDDEN>
> Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
> Date: Mon, 10 Nov 2025 13:24:53 +0000
>
> Eli Zaretskii <eliz@HIDDEN> writes:
>
> > Let me ask a question which might be easier for you to answer: does
> > the above code produce file:///c:/foo/bar URLs on MS-Windows (note the
> > 3 slashes before the drive letter) in the variables you use thereafter
> > as a URL? Alternatively, does it correctly remove the 3 slashes from
> > file:// URLs on MS-Windows to produce local absolute file names? If
> > not, the code needs to be amended to produce the extra slash on
> > Windows, otherwise it will not work.
>
> Apologies to not answering directly to your question, but my Windows
> skills become rusty after almost 10 years of not using it.
>
> To directly answer to your question, the this code produces a value with
> two extra slashes before expanded path. Such that the value stored in a
> pkg-spec in `package-vc-selected-packages' looks like (from one of test
> executions in GitHub action, build under MSYS2):
>
> ((:url "file://d:/a/_temp/msys64/tmp/package-vc-tests-7nJr9j-20251108.092527/test-package-3"))
This is wrong for Windows. For file:// URLs to work on Windows, they
should have 3 slashes before the drive letter, as in
"file:///d:/a/_temp/msys64/tmp/....
> For non interactive calls, the value of `:url' is obtained by calling
> (collapsed all transformations):
>
> (concat "file://" (expand-file-name dir))
This is correct on Posix systems, where expand-file-name returns a
string that begins with a slash, and so there will be 3 slashes after
the colon. But on Windows, we need to prepend the 3rd slash by hand.
So the code should be different for MS-Windows and for the rest. See
https://en.wikipedia.org/wiki/File_URI_scheme for the details.
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Mon, 10 Nov 2025 17:19:02 +0000
Resent-Message-ID: <handler.79188.B79188.176279510224331 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Eli Zaretskii <eliz@HIDDEN>
Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176279510224331
(code B ref 79188); Mon, 10 Nov 2025 17:19:02 +0000
Received: (at 79188) by debbugs.gnu.org; 10 Nov 2025 17:18:22 +0000
Received: from localhost ([127.0.0.1]:38803 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vIVX3-0006KI-5I
for submit <at> debbugs.gnu.org; Mon, 10 Nov 2025 12:18:22 -0500
Received: from mail-wm1-x332.google.com ([2a00:1450:4864:20::332]:50208)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1vIVX0-0006Jl-Sv
for 79188 <at> debbugs.gnu.org; Mon, 10 Nov 2025 12:18:19 -0500
Received: by mail-wm1-x332.google.com with SMTP id
5b1f17b1804b1-47775fb6cb4so12980665e9.0
for <79188 <at> debbugs.gnu.org>; Mon, 10 Nov 2025 09:18:18 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1762795092; x=1763399892; darn=debbugs.gnu.org;
h=content-transfer-encoding:mime-version:user-agent:message-id:date
:references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date
:message-id:reply-to;
bh=wI72Nc52uRwL8srqymBZmHCMtxQNUIjjp2AWITl0g5U=;
b=kyktUXTYnn5WcCH6GHadWJVLyhKR5QPqFvbsy2r6tA/I0VwAWR4k5s7Kbo0i4tGWpg
7QbOMjj62krEmPbYJXsox3waVDp1J8jGeo+uQ11JKByKaU+JwNMSN31mZy77Y/DFSOZM
iNbcDyYuaq8AjJANJmyKi3/slJoL3OzuANZUr3xyHQ8P31yLxzGJ4KOa1qXxlR/o+fZY
4+qdvaE3pUNzIT0lNSYMA+7r6oGVYlIkILNHzhEB1JIfKJkqAuhuBevKNEz0XTaDpgYd
aawxX2s2ZQ5B5ulj1PBsyVUgUmqMYTTE8/9u1Ugdv8bFfKxTQBOPf9qQ2WswqyGeIR4B
HiAg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1762795092; x=1763399892;
h=content-transfer-encoding:mime-version:user-agent:message-id:date
:references:in-reply-to:subject:cc:to:from:x-gm-gg
:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
bh=wI72Nc52uRwL8srqymBZmHCMtxQNUIjjp2AWITl0g5U=;
b=wrry00LB1bU+CEflPZvWVr6JxCUU5JG3b2wAxPkXOHUzLnulWbPctqhjSPo4F//eXm
BJLHUR1mapRUVsz0HHHEciuwuNyspX/tIUhfM3wX8yx83PEWiL1NHe3yudFo+j0vShGr
4qL2lXcrJ0dLMCz1GIqC+io9HNXyGS9ik9NYxnqruCVbuTs+U5vv3FRXXAPXkIDFx/j+
AYfTmQYFpfdw/K588fGT8RkoMYY1s3uc32j1YwXEfzFS/U0Bx2G06dnK/L5g5H/ItdRb
yecQF5tFeElxfALfT6GwM2adTRQFpNmolIYUukSlIsa+HD95lcqxwfK89hVARuXMdVXH
bvcg==
X-Forwarded-Encrypted: i=1;
AJvYcCVQM83FdybtFZSbXyTcgZZN8G4ioftVYdFtyCVDH0MB/17NlSvRn1pggZAwMyNxEHRH03BZuw==@debbugs.gnu.org
X-Gm-Message-State: AOJu0YwnT9w2OeLuPQQus0Ci8QpB8XnCcWej75Pkw7F45/3HlcNak+Au
gEcMe2LA2yJGVpbljoCsqRBgQUUZ4JuF4YYDJFAcHs5y9ni5r9muqegD2lbsg16O
X-Gm-Gg: ASbGncs/SEJ1rXBu0rKaMLWFxJjWZ7bhFW7e3i6IS80v/qt5kvDZSOMcNhlx45LucKg
28DfKFyeLfX+JvL5AIJgYMuMl0LkKIRW2VB8aIBwQQNS8KKKQMTy3yDXjNF7IR6VURIVSBH5umX
XBbzDjSjsvWrHvkeUoJ+M9pU5iwRM1+3a3OXgHLs0BvPNFrAiwKkKFP5d6yehfnWuUw5QRunWJM
C1w20l9qhaStU9VmkCiXeIytySUD6VsSp9hWx7YZbo9ewFFLK5u2nLClDV23AVedYcnthqFwHzL
Qsse7VJ0WVZF2aGFdchrk0I+J4otaDBEKzQLxUnr+rLeP1S3braSMRYxWrEGpAmdlQYCt2X/MPn
H576vYDnm3EfAB/8AP78XWaOOoa/gjPYlR4ralk/7FndfgA3s0OXZbeKYyk9fcjzwZEKnC34C71
gqU1dTvZDbjFkgQ2XMiumVGut1ha9CNWd3NB5d9WC0kdKiR6qyNSjeF6fD
X-Google-Smtp-Source: AGHT+IHxQMCeSd69csP1TfstgkgX5cOM2iG7z2Rrngm96UBKjA7fQ6xB4A4XIXe2EpAieFYnW4OiBA==
X-Received: by 2002:a05:600c:1d0a:b0:475:e007:baf1 with SMTP id
5b1f17b1804b1-4777328740emr84848045e9.34.1762795092143;
Mon, 10 Nov 2025 09:18:12 -0800 (PST)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:84fd:dde9:b8aa:46a9])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-4775ce32653sm331458905e9.13.2025.11.10.09.18.11
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Mon, 10 Nov 2025 09:18:11 -0800 (PST)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <864ir23qwq.fsf@HIDDEN> (Eli Zaretskii's message of "Mon, 10 Nov
2025 16:26:13 +0200")
References: <m2ectn9xif.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
<m2a51k4jd5.fsf@HIDDEN> <87a51du92y.fsf@HIDDEN>
<m2bjlfrt6m.fsf@HIDDEN> <86h5v6bafk.fsf@HIDDEN>
<m27bw1sqtv.fsf@HIDDEN> <86qzu97zqu.fsf@HIDDEN>
<m2ms4uqau2.fsf@HIDDEN> <864ir23qwq.fsf@HIDDEN>
Date: Mon, 10 Nov 2025 17:18:10 +0000
Message-ID: <m2bjl9relp.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
Eli Zaretskii <eliz@HIDDEN> writes:
>> From: Przemys=C5=82aw Kryger <pkryger@HIDDEN>
>> Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
>> Date: Mon, 10 Nov 2025 13:24:53 +0000
>>=20
>> Eli Zaretskii <eliz@HIDDEN> writes:
>>=20
>> > Let me ask a question which might be easier for you to answer: does
>> > the above code produce file:///c:/foo/bar URLs on MS-Windows (note the
>> > 3 slashes before the drive letter) in the variables you use thereafter
>> > as a URL? Alternatively, does it correctly remove the 3 slashes from
>> > file:// URLs on MS-Windows to produce local absolute file names? If
>> > not, the code needs to be amended to produce the extra slash on
>> > Windows, otherwise it will not work.
>>=20
>> Apologies to not answering directly to your question, but my Windows
>> skills become rusty after almost 10 years of not using it.
>>=20
>> To directly answer to your question, the this code produces a value with
>> two extra slashes before expanded path. Such that the value stored in a
>> pkg-spec in `package-vc-selected-packages' looks like (from one of test
>> executions in GitHub action, build under MSYS2):
>>=20
>> ((:url "file://d:/a/_temp/msys64/tmp/package-vc-tests-7nJr9j-20251108.=
092527/test-package-3"))
>
> This is wrong for Windows. For file:// URLs to work on Windows, they
> should have 3 slashes before the drive letter, as in
>
> "file:///d:/a/_temp/msys64/tmp/....
>
>> For non interactive calls, the value of `:url' is obtained by calling
>> (collapsed all transformations):
>>=20
>> (concat "file://" (expand-file-name dir))
>
> This is correct on Posix systems, where expand-file-name returns a
> string that begins with a slash, and so there will be 3 slashes after
> the colon. But on Windows, we need to prepend the 3rd slash by hand.
>
> So the code should be different for MS-Windows and for the rest. See
> https://en.wikipedia.org/wiki/File_URI_scheme for the details.
I think I am getting where your argument comes from. However, I don't
think I fully understand how `expand-file-name' works on a Windows
system. From the limited testing (in previous e-mail), I can see it
prepends paths that start with a slash with a drive letter of
`default-directory', correct? I could add code that adds the extra
slash on Windows before storing value in a pkg-spec, and then strip it
before using. But that seems like en extra code just to satisfy the
RFC. Or do we need to consider some remote directories, but that I am
completely out of depth. I don't use remote directories almost at all,
even on *nix like systems, and would need some help to understand it.
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Eli Zaretskii <eliz@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Mon, 10 Nov 2025 20:00:02 +0000
Resent-Message-ID: <handler.79188.B79188.176280478117071 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176280478117071
(code B ref 79188); Mon, 10 Nov 2025 20:00:02 +0000
Received: (at 79188) by debbugs.gnu.org; 10 Nov 2025 19:59:41 +0000
Received: from localhost ([127.0.0.1]:39664 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vIY3B-0004RH-5d
for submit <at> debbugs.gnu.org; Mon, 10 Nov 2025 14:59:41 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:45466)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1vIY38-0004R1-1W
for 79188 <at> debbugs.gnu.org; Mon, 10 Nov 2025 14:59:39 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
id 1vIY31-0004JZ-52; Mon, 10 Nov 2025 14:59:31 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
Date; bh=4XNu2gJ/jiIPuZTFD5h/umGgM8H/ZyNEmZz9Nl4c0QA=; b=fMI7j6xOAcqJ5JRHVWaJ
GFtuK9d8y+Pss6qF9epTPz/84PXFL19iNYw4hGJmqi/8HnBUTIxSinsZpUDtptHkBrtVuQlj3J6PF
LWPWQFzKbZzqkDzBw4i8Yf52O87lmLUH83/9w+EFNKFg+YrmPOuzxIwxM4rUb9yiePoKlCmUvASiP
VekmJVUNta+NcjRKAEohwyfg3mwYEpN3DWJyqEbiWpAIP5nCul2q10nP+wFe2NBqOF0JwjUVG8kD6
5BpLXv2RS7ybRdRcx94LwPZboWZPaUgNyPNmr0/djjigHtgcVnPrjjOV6feMBgwL6hHh0O4Uuoz8z
AGTa0a0C92Y5Jw==;
Date: Mon, 10 Nov 2025 21:59:13 +0200
Message-Id: <86wm3x3bhq.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
In-Reply-To: <m2bjl9relp.fsf@HIDDEN> (message from =?UTF-8?Q?Przemys=C5=82aw?= Kryger on Mon, 10 Nov 2025 17:18:10 +0000)
References: <m2ectn9xif.fsf@HIDDEN>
<m2o6sc7mwc.fsf@HIDDEN> <878qjgwuwb.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
<m2a51k4jd5.fsf@HIDDEN> <87a51du92y.fsf@HIDDEN>
<m2bjlfrt6m.fsf@HIDDEN> <86h5v6bafk.fsf@HIDDEN>
<m27bw1sqtv.fsf@HIDDEN> <86qzu97zqu.fsf@HIDDEN>
<m2ms4uqau2.fsf@HIDDEN> <864ir23qwq.fsf@HIDDEN>
<m2bjl9relp.fsf@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
> From: Przemysław Kryger <pkryger@HIDDEN>
> Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
> Date: Mon, 10 Nov 2025 17:18:10 +0000
>
> Eli Zaretskii <eliz@HIDDEN> writes:
>
> >> ((:url "file://d:/a/_temp/msys64/tmp/package-vc-tests-7nJr9j-20251108.092527/test-package-3"))
> >
> > This is wrong for Windows. For file:// URLs to work on Windows, they
> > should have 3 slashes before the drive letter, as in
> >
> > "file:///d:/a/_temp/msys64/tmp/....
> >
> >> For non interactive calls, the value of `:url' is obtained by calling
> >> (collapsed all transformations):
> >>
> >> (concat "file://" (expand-file-name dir))
> >
> > This is correct on Posix systems, where expand-file-name returns a
> > string that begins with a slash, and so there will be 3 slashes after
> > the colon. But on Windows, we need to prepend the 3rd slash by hand.
> >
> > So the code should be different for MS-Windows and for the rest. See
> > https://en.wikipedia.org/wiki/File_URI_scheme for the details.
>
> I think I am getting where your argument comes from. However, I don't
> think I fully understand how `expand-file-name' works on a Windows
> system. From the limited testing (in previous e-mail), I can see it
> prepends paths that start with a slash with a drive letter of
> `default-directory', correct?
No, it produces Windows-style d:/foo/bar absolute file names, without
the leading slash. So we need to add an extra slash to have
file:///d:/foo/bar URLs.
> I could add code that adds the extra
> slash on Windows before storing value in a pkg-spec, and then strip it
> before using. But that seems like en extra code just to satisfy the
> RFC. Or do we need to consider some remote directories, but that I am
> completely out of depth. I don't use remote directories almost at all,
> even on *nix like systems, and would need some help to understand it.
Remote directories are not relevant here, they are not supported in
file:// URLs.
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: Patch proposal.
References: <m2ectn9xif.fsf@HIDDEN>
In-Reply-To: <m2ectn9xif.fsf@HIDDEN>
Resent-From: Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Wed, 12 Nov 2025 11:38:02 +0000
Resent-Message-ID: <handler.79188.B79188.176294745723584 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176294745723584
(code B ref 79188); Wed, 12 Nov 2025 11:38:02 +0000
Received: (at 79188) by debbugs.gnu.org; 12 Nov 2025 11:37:37 +0000
Received: from localhost ([127.0.0.1]:48889 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vJ9AO-00068I-TC
for submit <at> debbugs.gnu.org; Wed, 12 Nov 2025 06:37:37 -0500
Received: from mail-ej1-x62f.google.com ([2a00:1450:4864:20::62f]:45141)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <michelangelo.rodriguez@HIDDEN>)
id 1vJ9AM-00067l-Lx
for 79188 <at> debbugs.gnu.org; Wed, 12 Nov 2025 06:37:35 -0500
Received: by mail-ej1-x62f.google.com with SMTP id
a640c23a62f3a-b73161849e1so131920166b.2
for <79188 <at> debbugs.gnu.org>; Wed, 12 Nov 2025 03:37:34 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1762947448; x=1763552248; darn=debbugs.gnu.org;
h=mime-version:message-id:date:subject:to:from:from:to:cc:subject
:date:message-id:reply-to;
bh=Ah1ycnLyi88lTzd1LCS38KQLBtsrUpyuPFpe5mJ1PSM=;
b=fqC5fkbXJEOFWaefYAtOES9t2AVGbb83G6GUxyDXbhWN2Txz7U3cre8rtprVCaqWYt
gVnlI3yyOVE4qcx+KKb5s7pq7y15rUA/SVce3EfIYLZglP5A6RrWzEtI51B3RUQTP4X2
FnuNcM/cIjxg24atiP/o4CXM3KykdgHER/Hk2DmbcHwiUwpQ/0CZO6FHClm7oZWAOimj
P6BMJgsODK9j1up/XGbg4nEUbCqWzXI/amn61cuwSjXykLndph1tmOiQ7ZRyV9puJUOy
kqYFh7B/HkZ3skvo+eNkDOq+p5Hf7gvzCSGkobrFStKFYWy50TxiuGeFM8Hg4oZatahp
23vw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1762947448; x=1763552248;
h=mime-version:message-id:date:subject:to:from:x-gm-gg
:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
bh=Ah1ycnLyi88lTzd1LCS38KQLBtsrUpyuPFpe5mJ1PSM=;
b=clap9anfklGRAONDARGey0ySV9H/o3DR0UfR3v9lmpUgG4sCWNI03d4VyfxvmwD69w
tePQcdxlG0mAjmLD6AfJVlfAvQY4/huiEcsgdUra2wt1IOuMRBuEOxWLvajVEm0eploq
sQVGu0nkcMxe39YL7fZiaX9HZNd5a6eirNZ+5XWhLnqYIzHI4zPPnxzX2E2jCkIhaD0G
of1+SlHEY/tg0VlvwNL8NjOkSd05U/rtn/+Z13grcAn5nvPRn4B1KmSyP0R2rPjyg2cZ
punQ22lN3wqTCrNXO+ag9A9FV++HPsgeDnRAd3x8JNRsU5QjzCm027rt9ocnP9ZcVCxf
RGkA==
X-Gm-Message-State: AOJu0YzZ6fVb/J/3R3lydzHPRd6+vT+oJhKkO9UghZjDAGYLCFskNE75
QyM4CUuUNQVD5DktBpClC/bJbRPXBfjH9Aoj2jquBAcyegaPoG8USmpl/2+q0zG/
X-Gm-Gg: ASbGncsK9TJmDxIH98kVe11gCiO9qN5TFPClOr5vtIAeUJsY4CnhlvLsCVCNr184xoG
dDZ0NcNb376WTb7y9ygfx8kc3fRU8K11g+ImdDtry31V8egy3mgSLllZ8qxxrfMfdtkfOp+b+65
8MNdwE+t2i3TpZrXB0sPdGEU4CKSd1uIbM3oQ+SI2E4EQONBD1AJmeS3OURu0QKz6DR+iJHQqx1
9xt4vKLGo0LiUjAH2fdfxx8XTng6xFQFlXT35DiBRgHcMQmk9SP6YU81NY382uAZYTpOyrSzDtG
oX/WN0mIzoie2F+9LlZJJDhy2PjeH4xxuJjJNjXbOCrkxBq2O3c1W/qBY35gWyb6RnkbCgeKuWC
+m39CrNh00uK/SAz8zYiZ2KO6BqkIii3MTHzG03sHhu+ylXV5ZNUGJhS4J4PIW/+FnQX3n0beyo
SXgbZBKS8JyGcMYSbD13yOVF5OrLLHTw==
X-Google-Smtp-Source: AGHT+IEiYx4s0fK16W/eXyYkenE/iy+XI0jU428GcJHjS6XqEMQpprwRAg2cValZXwi/At0RS5TmxA==
X-Received: by 2002:a17:907:2d25:b0:b72:7a39:4416 with SMTP id
a640c23a62f3a-b7331aa8a8bmr264272966b.55.1762947447638;
Wed, 12 Nov 2025 03:37:27 -0800 (PST)
Received: from mac-mikey.local ([62.18.41.95])
by smtp.gmail.com with ESMTPSA id
a640c23a62f3a-b72bf97e54asm1574802266b.34.2025.11.12.03.37.26
for <79188 <at> debbugs.gnu.org>
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Wed, 12 Nov 2025 03:37:27 -0800 (PST)
From: Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Date: Wed, 12 Nov 2025 12:37:25 +0100
Message-ID: <m24iqzmqh6.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
Hello,
These days I tried to follow all the various phases of the discussion, but at a certain point, I lost track of the patches.
In any case, I propose a patch that takes into account the observations made in bug#79716.
At the end of the execution of `package-vc-install-from-checkout` we will find the files "package-autoloads.el" and "package-pkg.el" in the package directory.
In the vc directory, we will instead find "package.el", "package-autoloads.el", and "package.elc".
If this is correct then the following patch should resolve the inconsistencies:
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 7433fce2d89..8c1d7147b22 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -244,7 +244,9 @@ package-vc--main-file
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
(name (symbol-name (package-desc-name pkg-desc)))
(directory (expand-file-name
- (or (plist-get pkg-spec :lisp-dir) ".")
+ (or (plist-get pkg-spec :lisp-dir)
+ (alist-get :vc-dir (package-desc-extras pkg-desc))
+ ".")
(or (package-desc-dir pkg-desc)
(expand-file-name name package-user-dir))))
(file (expand-file-name
@@ -461,7 +463,7 @@ package-vc--unpack-1
identify a package as a VC package later on), building
documentation and marking the package as installed."
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
- (lisp-dir (plist-get pkg-spec :lisp-dir))
+ (lisp-dir (alist-get :vc-dir (package-desc-extras pkg-desc)))
(lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
missing)
@@ -546,9 +548,14 @@ package-vc--unpack-1
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
- (package--compile new-desc)
- (when package-native-compile
- (package--native-compile-async new-desc))
+
+ ;; we induce `package--compile' to look in the vc directory
+ (let ((pkg-desc new-desc))
+ (setf (package-desc-dir pkg-desc) (alist-get :vc-dir
+ (package-desc-extras pkg-desc)))
+ (package--compile pkg-desc)
+ (when package-native-compile
+ (package--native-compile-async pkg-desc)))
;; After compilation, load again any files loaded by
;; `activate-1', so that we use the byte-compiled definitions.
(package--reload-previously-loaded new-desc)))
@@ -946,6 +953,9 @@ package-vc-install-from-checkout
(package-desc-create
:name (intern name)
:dir pkg-dir
+ ;; We use the :extras slot of vc-desc to store the directory where the
+ ;; sources are actually located.
+ :extras (list (cons :vc-dir dir))
:kind 'vc)
(file-name-as-directory pkg-dir))))
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Wed, 12 Nov 2025 13:32:02 +0000
Resent-Message-ID: <handler.79188.B79188.176295428030482 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176295428030482
(code B ref 79188); Wed, 12 Nov 2025 13:32:02 +0000
Received: (at 79188) by debbugs.gnu.org; 12 Nov 2025 13:31:20 +0000
Received: from localhost ([127.0.0.1]:49159 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vJAwS-0007vY-0I
for submit <at> debbugs.gnu.org; Wed, 12 Nov 2025 08:31:20 -0500
Received: from mail-wm1-x335.google.com ([2a00:1450:4864:20::335]:58657)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1vJAwN-0007vO-Iv
for 79188 <at> debbugs.gnu.org; Wed, 12 Nov 2025 08:31:18 -0500
Received: by mail-wm1-x335.google.com with SMTP id
5b1f17b1804b1-4775638d819so4750525e9.1
for <79188 <at> debbugs.gnu.org>; Wed, 12 Nov 2025 05:31:15 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1762954269; x=1763559069; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=Cy1+RaIl+46QdRtaXF17rzkT+pyJSaz8iyCIoVsdteo=;
b=kqXhAeDYGfQh2WYXBSL6d249CQGzSk0Aog0REoJoDeJRGpUZbTPIHY6Gu8ip1PvQYh
FEtYNcI+aBU49Ce6R1WL2pl0lRdZ0hJ7AZSU4Dp6txMJdZs7K2IMdc1HopgCYu8LH4HL
mzwyz4GKtggDbejpHdeZ1wQk7a8AGA9bYZfxHgLgzsu/7hL6ZasKUgnYQpvvAnf6sCP+
aV+gnt40SwNKWnbRYY3f97d3hYnuX/t2Y+ZPO03COsw5e+oDI0vyseQ6RieJpYC+r0GI
VAsHGVIvrri52kBgwNZjTCIR6uawiLYohURGTBC9U1d5efEHpdcGHBZK35RkVpobWoMx
sgUQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1762954269; x=1763559069;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject
:date:message-id:reply-to;
bh=Cy1+RaIl+46QdRtaXF17rzkT+pyJSaz8iyCIoVsdteo=;
b=n3A2nnGZsgThnYG1Ot3WYudcJBWz5JaiGewrAYMLFnuzE/MmwxH6Qux2YthR9AjtlT
/PEC+TEmAJ48R8OFIKxhycUEZqI60X9aIE+sDN7DqgU+lIVy92e8ZyZn4k+eS+APmGN+
YYBp4y2hU+Eh/JDzGGZ+7mI+gLQUejVXXOgHOQBr5h2GcIdfRlOturQiBv7FkCKeBMIe
xCnyFlUPdk3Kze954BZhKSqkZlbwQ5KYKQEEtytye75TYT3DhRiyHhBol9b0oEYG0487
OZ6V8dslikkQGFqKde/qDHB4pdhqIOH5ovZgb0DgBycdbWHJEnnLUHWjSOWl3o8W3Sm3
34xw==
X-Gm-Message-State: AOJu0YzLceaWkf6faL+pSjpBAVaM7vw/+PULD7yAdlq0OxG0fkeINzZm
wzNY/0IIJEMXaCw9+uIb1x8JbKoiC4BvZXl63dvGqUX27ZgcZg3of400nbA7Qw==
X-Gm-Gg: ASbGnctUR2IdFNtYGwcVI7sBEP7t+IBItIpp1f3oJt/WNxfrKMNSO2wnkjuwDKNTjtU
J4uRWg5rkYJ7QlsNrXEOh4sR4FZnXDbYzKsX/W5nFrEaqsbQhENi05HDGKJqHlPptxeQKTSwQ5b
Kzb+lqhDWXL33NCXG4VgYFLR2Vbix8Mxw45r//QjmjuLUIoeBB7t4/2imNmgnhBj1my441u9EZg
xrkx2yXm0jHupzQVx7nTgMdO3kzAuMCx4t8YDoyCPqU1GArodmITd+tHjay/3eOFoAt7ZRou1Hn
UJnSEI67rYvpMIG7qG2pPeMktG+IWyd3yoAZPFZ1DazwhxZ4b/mxWV4P+h4tKf8B5eY6tX87vML
UAp0mkFcI7ulPq0QiIR0nvtJiJA7OXZzpeoULi4uEmNAnkLRKZRI7lCOCPEKywFAUbMqbI0OaTN
PeD3D6Pw/PN/4BWSzDjlAdjrFxd6iExSmfiVf+EMqfl9JGWA9QSqC5yjFY
X-Google-Smtp-Source: AGHT+IHSOxB78Nqb+RLC87QkOSAj9AUHPXPk0f1QMVqp5V7Fo9h8FIajGMXvpkK6hKpKwYubHQMzjA==
X-Received: by 2002:a05:600c:c4a1:b0:477:a9e:859a with SMTP id
5b1f17b1804b1-477870c5e55mr29075685e9.22.1762954268777;
Wed, 12 Nov 2025 05:31:08 -0800 (PST)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:85a5:5026:6123:80c2])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-47787e58501sm35859615e9.10.2025.11.12.05.31.07
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Wed, 12 Nov 2025 05:31:07 -0800 (PST)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <m24iqzmqh6.fsf@HIDDEN> (Michelangelo Rodriguez's message of
"Wed, 12 Nov 2025 12:37:25 +0100")
References: <m2ectn9xif.fsf@HIDDEN>
<m24iqzmqh6.fsf@HIDDEN>
Date: Wed, 12 Nov 2025 13:31:07 +0000
Message-ID: <m28qgbqsx0.fsf_-_@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN> writes:
> Hello,
> These days I tried to follow all the various phases of the discussion,
> but at a certain point, I lost track of the patches.
Yeah - it's kinda blew up when I tried to add some systematic testing,
and kept finding little kinks to iron out. I suggest to start with the
latest patches and see what they change. That should give you an idea
which bits of `package-vc' I found to require distinction between a
package directory (usually named `pkg-dir') and a checkout directory
(usually `checkout-dir' or - in your case - `vc-dir'). Perhaps you can
use tests to see if the patch covers all aspects (probably removing
unnecessary bits).
> In any case, I propose a patch that takes into account the
> observations made in bug#79716. At the end of the execution of
> `package-vc-install-from-checkout` we will find the files
> "package-autoloads.el" and "package-pkg.el" in the package directory.
> In the vc directory, we will instead find "package.el",
> "package-autoloads.el", and "package.elc". If this is correct then
> the following patch should resolve the inconsistencies:
I applied the patch below, and indeed - I could find the files were
correctly compiled on installation from directory.
However, this patch seems to break `package-vc-install'. For example,
evaling the following in emacs -Q:
(require 'vc-git)
(require 'package-vc)
(let ((package-user-dir (expand-file-name "~/tmp/elpa" )))
(package-vc-install "gcmh"))
Yields, the following backtrace:
Debugger entered--Lisp error: (wrong-type-argument stringp nil)
file-name-as-directory(nil)
package--parse-elpaignore(#s(package-desc :name gcmh :version (0 2 1) :summary "the Garbage Collector Magic Hack" :reqs ((emacs (24))) :kind vc :archive nil :dir nil :extras ((:commit . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9") (:authors ("Andrea Corallo" . "akrl@HIDDEN")) (:maintainer nil . "akrl@HIDDEN") (:keywords "internal") (:url . "https://gitlab.com/koral/gcmh")) :signed nil))
package--compile(#s(package-desc :name gcmh :version (0 2 1) :summary "the Garbage Collector Magic Hack" :reqs ((emacs (24))) :kind vc :archive nil :dir nil :extras ((:commit . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9") (:authors ("Andrea Corallo" . "akrl@HIDDEN")) (:maintainer nil . "akrl@HIDDEN") (:keywords "internal") (:url . "https://gitlab.com/koral/gcmh")) :signed nil))
package-vc--unpack-1(#s(package-desc :name gcmh :version (0 2 1) :summary "the Garbage Collector Magic Hack" :reqs ((emacs (24))) :kind vc :archive "gnu" :dir "/Users/pkryger/tmp/elpa/gcmh/" :extras ((:url . "https://gitlab.com/koral/gcmh") (:keywords "internal") (:maintainer nil . "akrl@HIDDEN") (:authors ("Andrea Corallo" . "akrl@HIDDEN")) (:commit . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9")) :signed nil) "/Users/pkryger/tmp/elpa/gcmh/")
package-vc--unpack(#s(package-desc :name gcmh :version (0 2 1) :summary "the Garbage Collector Magic Hack" :reqs ((emacs (24))) :kind tar :archive "gnu" :dir nil :extras ((:url . "https://gitlab.com/koral/gcmh") (:keywords "internal") (:maintainer nil . "akrl@HIDDEN") (:authors ("Andrea Corallo" . "akrl@HIDDEN")) (:commit . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9")) :signed nil) (:url "https://gitlab.com/koral/gcmh") nil)
package-vc-install("gcmh")
(let ((package-user-dir (expand-file-name "~/tmp/elpa"))) (package-vc-install "gcmh"))
(progn (let ((package-user-dir (expand-file-name "~/tmp/elpa"))) (package-vc-install "gcmh")))
eval((progn (let ((package-user-dir (expand-file-name "~/tmp/elpa"))) (package-vc-install "gcmh"))) t)
elisp--eval-last-sexp(nil)
#f(compiled-function () #<bytecode 0x1866f2fbe5b2>)()
handler-bind-1(#f(compiled-function () #<bytecode 0x1866f2fbe5b2>) (error) eval-expression--debug)
eval-last-sexp(nil)
funcall-interactively(eval-last-sexp nil)
call-interactively(eval-last-sexp nil nil)
command-execute(eval-last-sexp)
> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
> index 7433fce2d89..8c1d7147b22 100644
> --- a/lisp/emacs-lisp/package-vc.el
> +++ b/lisp/emacs-lisp/package-vc.el
> @@ -244,7 +244,9 @@ package-vc--main-file
> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> (name (symbol-name (package-desc-name pkg-desc)))
> (directory (expand-file-name
> - (or (plist-get pkg-spec :lisp-dir) ".")
> + (or (plist-get pkg-spec :lisp-dir)
> + (alist-get :vc-dir (package-desc-extras pkg-desc))
> + ".")
> (or (package-desc-dir pkg-desc)
> (expand-file-name name package-user-dir))))
> (file (expand-file-name
> @@ -461,7 +463,7 @@ package-vc--unpack-1
> identify a package as a VC package later on), building
> documentation and marking the package as installed."
> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> - (lisp-dir (plist-get pkg-spec :lisp-dir))
> + (lisp-dir (alist-get :vc-dir (package-desc-extras pkg-desc)))
> (lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
> missing)
>
> @@ -546,9 +548,14 @@ package-vc--unpack-1
> ;; FIXME: Compilation should be done as a separate, optional, step.
> ;; E.g. for multi-package installs, we should first install all packages
> ;; and then compile them.
> - (package--compile new-desc)
> - (when package-native-compile
> - (package--native-compile-async new-desc))
> +
> + ;; we induce `package--compile' to look in the vc directory
> + (let ((pkg-desc new-desc))
> + (setf (package-desc-dir pkg-desc) (alist-get :vc-dir
> + (package-desc-extras pkg-desc)))
> + (package--compile pkg-desc)
> + (when package-native-compile
> + (package--native-compile-async pkg-desc)))
When you're on it, you may want to fix the indentation.
> ;; After compilation, load again any files loaded by
> ;; `activate-1', so that we use the byte-compiled definitions.
> (package--reload-previously-loaded new-desc)))
> @@ -946,6 +953,9 @@ package-vc-install-from-checkout
> (package-desc-create
> :name (intern name)
> :dir pkg-dir
> + ;; We use the :extras slot of vc-desc to store the directory where the
> + ;; sources are actually located.
> + :extras (list (cons :vc-dir dir))
> :kind 'vc)
> (file-name-as-directory pkg-dir))))
>
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Wed, 12 Nov 2025 13:57:02 +0000
Resent-Message-ID: <handler.79188.B79188.17629557772944 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Eli Zaretskii <eliz@HIDDEN>
Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17629557772944
(code B ref 79188); Wed, 12 Nov 2025 13:57:02 +0000
Received: (at 79188) by debbugs.gnu.org; 12 Nov 2025 13:56:17 +0000
Received: from localhost ([127.0.0.1]:49246 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vJBKW-0000lQ-Q2
for submit <at> debbugs.gnu.org; Wed, 12 Nov 2025 08:56:16 -0500
Received: from mail-wr1-x42b.google.com ([2a00:1450:4864:20::42b]:50177)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1vJBKR-0000l7-94
for 79188 <at> debbugs.gnu.org; Wed, 12 Nov 2025 08:56:10 -0500
Received: by mail-wr1-x42b.google.com with SMTP id
ffacd0b85a97d-42b3ac40ae4so443669f8f.0
for <79188 <at> debbugs.gnu.org>; Wed, 12 Nov 2025 05:56:07 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1762955761; x=1763560561; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=zsRl4AXE0oliqOSi5zfhCm+FayWFXc4GVgU/KYGhLTU=;
b=TZuyfSNKg1nqG3sIfa7uCbsBk/CBCViTXREOjFYqqokNSA3OC3zNX7YCFbtVjqnBDq
ahqsL0cW3DK8Ea1KGquvlzEhS4qeAZgtEpRmPp7o7pt7rQciM6pGqv26Wv4kuZxOAx1k
Zfqnb/EW4DgVDPdKk94W9sb/OynsmESTjoL3L1/derJmR7CtZ+btvAOLMhnGGi5VW7d7
k1/DXYJaHCL9JTqIvZ3JrVEOvKJOclWWufHT84dVpXoBkww9uLva8UPdfTXOqFTGrfVm
iXBtQ3ssZKCewrGYdrRbdZwthCnhT4pexOdDIjPkSTbXvjhjEew7NdNxvIHXI2iUd0/Z
EraQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1762955761; x=1763560561;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject
:date:message-id:reply-to;
bh=zsRl4AXE0oliqOSi5zfhCm+FayWFXc4GVgU/KYGhLTU=;
b=U2w5lKCtrJ7Dx+RmkgnKeGn3vWjhAU665Ola4zuS5xUkHFcU+U9NrpxvAKAD0epC0w
DviLUykFJK9t1ian8FTUenQlb9ZBUvjGvxQhhRYDRgT0eTrWvH6L1d38JkXqtdqP0T1K
xytSfk0roHIxbtnC6pGq41svl4VmGnhRTWn0p55FE5wQL2oaJ54Hj4Cgg5oqeEeTWvJs
uFiAn9syp8bWuliUnmCt0M0gQVSzR0vXGwUgsnoeiVGrklX8kVr2roDGirYm2chSpchH
hDM8rKq5xUPrOLFmMQzptiDb4Lr1pfYp8DDxBF21F+zChawXacu/0eKrX6ckZUvDlqnj
mkBA==
X-Forwarded-Encrypted: i=1;
AJvYcCWoM8GhvJgrqNzjfUhSWvnCghY+W7JSUQRlRDs4cJkXU2Ar/JYm6eJ9O0ELNJPDnGN3hU7DuQ==@debbugs.gnu.org
X-Gm-Message-State: AOJu0YyWj+6YRsHfe7C8BpnX94RX/HUQ61DdMJZVVX2h6il8Z3d1tJp9
KlM5CDmh3WaLZfPGCm9iIvuOrunDeNqGjx1eM9/GW9Pxqu/Fz0lbKwWsJv79oU8A
X-Gm-Gg: ASbGnct4vuvNHu+NYdRpt8Un0ufduXLUB1F5Y4QhASgI6cF5xQb7Y20rQMM4XQqTLHK
kRHDL1flmtSb0nmLGANv0U9DpqtvRbZt2A5xJIE2p99Iqf8JgEfelBEm75sQi1W2jZgsWMz9D2u
JDP4r0NBIkRXonKIfIWrccPZxw4K2mvbgOcuQ7Ll3Ai6MCUQjVROWHbp+xgv8Q2SyyOEq8q09oy
HbXDBKpsX3oWQwwZ805Cvmr2MdO/dosX13ZScLWcKdcCd1rmIU3wmR0+C8Fh9q+k3VOhzivnROI
QQkJdajIRWfNRFHisdelWzEXku0NcP6HrdX7/MVHgZapSqh7vtguXmiGzDEpAo1YirFKFhxaavO
vrDaEZ01JnowEKNyOOJKFTw5FyheOMZSuFR/cFqkK3TEXn5qhx5QQWW4lOU1pTv6qYGdbsak/fD
pIuLzA2DAbRsZE2cBd31epznkpSvc9+tDwx8ZORKRSK9Dzog==
X-Google-Smtp-Source: AGHT+IEiDhp1oAzOFXs7mOZX+io8sr5HhE7X5ggTrhLCzwCWYCeWwFJQSrk6qNqf8gw3V2nJgoyF2g==
X-Received: by 2002:a05:6000:4012:b0:42b:3d7c:c7cf with SMTP id
ffacd0b85a97d-42b4bb98ea9mr3027553f8f.15.1762955760551;
Wed, 12 Nov 2025 05:56:00 -0800 (PST)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:85a5:5026:6123:80c2])
by smtp.gmail.com with ESMTPSA id
ffacd0b85a97d-42abe62bf35sm33714368f8f.7.2025.11.12.05.55.59
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Wed, 12 Nov 2025 05:55:59 -0800 (PST)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <86wm3x3bhq.fsf@HIDDEN> (Eli Zaretskii's message of "Mon, 10 Nov
2025 21:59:13 +0200")
References: <m2ectn9xif.fsf@HIDDEN>
<m2h5xm5ebm.fsf@HIDDEN> <87cy7ovfwd.fsf@HIDDEN>
<87bjn7wjmo.fsf@HIDDEN> <m21po26fry.fsf@HIDDEN>
<87tt0yc15u.fsf@HIDDEN> <m2bjmxgn9v.fsf@HIDDEN>
<87v7kl2mkx.fsf@HIDDEN> <m24is3dqht.fsf@HIDDEN>
<m2ldlax0jr.fsf@HIDDEN> <87plaiya21.fsf@HIDDEN>
<m2a51k4jd5.fsf@HIDDEN> <87a51du92y.fsf@HIDDEN>
<m2bjlfrt6m.fsf@HIDDEN> <86h5v6bafk.fsf@HIDDEN>
<m27bw1sqtv.fsf@HIDDEN> <86qzu97zqu.fsf@HIDDEN>
<m2ms4uqau2.fsf@HIDDEN> <864ir23qwq.fsf@HIDDEN>
<m2bjl9relp.fsf@HIDDEN> <86wm3x3bhq.fsf@HIDDEN>
Date: Wed, 12 Nov 2025 13:55:59 +0000
Message-ID: <m24iqzqrrk.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Eli Zaretskii <eliz@HIDDEN> writes:
>> From: Przemys=C5=82aw Kryger <pkryger@HIDDEN>
>> Cc: philipk@HIDDEN, 79188 <at> debbugs.gnu.org
>> Date: Mon, 10 Nov 2025 17:18:10 +0000
>>=20
>> Eli Zaretskii <eliz@HIDDEN> writes:
>>=20
>> >> ((:url "file://d:/a/_temp/msys64/tmp/package-vc-tests-7nJr9j-202511=
08.092527/test-package-3"))
>> >
>> > This is wrong for Windows. For file:// URLs to work on Windows, they
>> > should have 3 slashes before the drive letter, as in
>> >
>> > "file:///d:/a/_temp/msys64/tmp/....
>> >
>> >> For non interactive calls, the value of `:url' is obtained by calling
>> >> (collapsed all transformations):
>> >>=20
>> >> (concat "file://" (expand-file-name dir))
>> >
>> > This is correct on Posix systems, where expand-file-name returns a
>> > string that begins with a slash, and so there will be 3 slashes after
>> > the colon. But on Windows, we need to prepend the 3rd slash by hand.
>> >
>> > So the code should be different for MS-Windows and for the rest. See
>> > https://en.wikipedia.org/wiki/File_URI_scheme for the details.
>>=20
>> I think I am getting where your argument comes from. However, I don't
>> think I fully understand how `expand-file-name' works on a Windows
>> system. From the limited testing (in previous e-mail), I can see it
>> prepends paths that start with a slash with a drive letter of
>> `default-directory', correct?
>
> No, it produces Windows-style d:/foo/bar absolute file names, without
> the leading slash. So we need to add an extra slash to have
> file:///d:/foo/bar URLs.
Got it.
>> I could add code that adds the extra
>> slash on Windows before storing value in a pkg-spec, and then strip it
>> before using. But that seems like en extra code just to satisfy the
>> RFC. Or do we need to consider some remote directories, but that I am
>> completely out of depth. I don't use remote directories almost at all,
>> even on *nix like systems, and would need some help to understand it.
>
> Remote directories are not relevant here, they are not supported in
> file:// URLs.
This makes life easier!
I am attaching new patches, that include triple slash for Windows as well
as a fix to extract package maintainers.
FWIW, I managed to figure out a workaround for Windows and now all tests
pass there too!
--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment;
filename=0001-Fix-upgrading-rebuilding-and-logging-of-VC-packages.patch
Content-Description: package-vc and package fixes
From 7f2ec17c76589c2c25e9a526befc383e3271dcfc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Przemys=C5=82aw=20Kryger?= <pkryger@HIDDEN>
Date: Fri, 26 Sep 2025 17:24:44 +0100
Subject: [PATCH 1/2] Fix upgrading, rebuilding, and logging of VC packages
There are a few issues addressed in this patch:
1. Compilation (including native compilation) should happen in
directory that contains package's Lisp code.
2. After installing a package with
`package-vc-install-from-checkout' and subsequently upgrading it
with `package-vc-upgrade' the pkg-desc for the package becomes
corrupted. After the upgrade the pkg-desc's dir (a.k.a
`pkg-dir') points to checkout directory. This will cause the
subsequent `package-delete' to delete the checkout directory and
leaving incorrect forwarding autoloads file in
`package-user-directory'.
3. The detection of package's Lisp directory has been not
effective for packages installed with `package-vc-install' and
not existent for packages installed with
`package-install-from-checkout'.
4. Deduction of VC backend has been not working when called from
outside of deducing context.
5. Extract maintainers and store them in a package description
file when installing a package from a checkout.
* lisp/emacs-lisp/package-vc.el (package-vc--url-scheme): Define
scheme for `:url' property.
(package-vc--generate-description-file): Extract maintainers
from main package file and store them in generated description
file.
(package-vc--checkout-dir): Use `pcase' to extract checkout
directory from `pkg-spec'. Detect standard lisp sub directory
if called with non-nil `lisp-dir'.
(package-vc--unpack-1): Remove superfluous `pkg-dir' argument.
Use a `package' with `:dir' pointing to where package code is.
When `checkout-dir' is different than `pkg-dir' then call
`package--add-info-node' and after calling `package-activate-1'
reload source files in case when `lisp-dir' is a sub directory.
(package-vc-install-from-checkout): Remove superfluous
`package-vc-selected-packages' binding. Remove `pkg-dir'
argument from `package-vc--unpack-1' calls.
(package-vc--unpack): Remove `lisp-dir' variable and convert to
`let*'. Remove superfluous Lisp code sub directory detection -
logic moved to `package-vc--checkout-dir'. Remove `pkg-dir'
argument from `package-vc--unpack-1' call.
(package-vc-upgrade, package-vc-rebuild): Remove `pkg-dir'
argument from `package-vc--unpack-1' calls.
(package-vc-log-incoming): Ensure VC backend is deduce-able when
called from outside of default deducing context.
* lisp/emacs-lisp/package.el (package--add-info-node): New
function to install info node for package. Extracted from
`package-activate-1'.
(package-activate-1): Call `package--add-info-node'.
(Bug#79188)
---
lisp/emacs-lisp/package-vc.el | 202 +++++++++++++++++++++-------------
lisp/emacs-lisp/package.el | 15 ++-
2 files changed, 136 insertions(+), 81 deletions(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index b9723ae0ea2..bfed3661943 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -31,8 +31,7 @@
;; aren't interested in activating a package, you can use
;; `package-vc-checkout' instead, which will prompt you for a target
;; directory. If you wish to reuse an existing checkout, the command
-;; `package-vc-install-from-checkout' will create a symbolic link and
-;; prepare the package.
+;; `package-vc-install-from-checkout' will prepare the package.
;;
;; If you make local changes that you wish to share with an upstream
;; maintainer, the command `package-vc-prepare-patch' can prepare
@@ -85,6 +84,12 @@ package-vc-register-as-project
(defvar package-vc-selected-packages) ; pacify byte-compiler
+(defconst package-vc--url-scheme
+ (if (memq system-type '(ms-dos windows-nt cygwin))
+ "file:///"
+ "file://")
+ "Scheme for `:url' property in package spec.")
+
;;;###autoload
(defun package-vc-install-selected-packages ()
"Ensure packages specified in `package-vc-selected-packages' are installed."
@@ -180,16 +185,39 @@ package-vc--checkout-dir
that case the package redirects to the actual VC checkout. If the
optional LISP-DIR argument is non-nil, then check if a related package
specification has a `:lisp-dir' field to indicate that Lisp files are
-located in a sub directory of a checkout and return that instead."
+located in a sub directory of the checkout, or the checkout has a sub
+directory named \"lisp\" or \"src\" that contains .el files and return
+that instead."
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
- (url (plist-get pkg-spec :url)))
+ (pkg-dir (pcase (plist-get pkg-spec :url)
+ ((rx (literal package-vc--url-scheme)
+ (let checkout-dir (+ any)))
+ checkout-dir)
+ (_ (package-desc-dir pkg-desc)))))
(expand-file-name
- (or (and (not lisp-dir) (plist-get pkg-spec :lisp-dir)) ".")
- (cond
- ((save-match-data
- (and url (string-match (rx "file://" (group (+ any))) url)
- (match-string 1 url))))
- (t (package-desc-dir pkg-desc))))))
+ (or (and lisp-dir
+ (or (plist-get pkg-spec :lisp-dir)
+ ;; When nothing is specified about a `lisp-dir', then
+ ;; should heuristically check if there is a
+ ;; sub-directory with lisp files. These are
+ ;; conventionally just called "lisp" or "src". If
+ ;; this directory exists and contains non-zero number
+ ;; of lisp files, we will use that instead of
+ ;; `pkg-dir'.
+ (catch 'done
+ (dolist (name '("lisp" "src"))
+ (when-let* ((dir (expand-file-name name pkg-dir))
+ ((file-directory-p dir))
+ ((directory-files
+ dir nil "\\`[^.].+\\.el\\'" t 1)))
+ ;; We won't use `dir', since dir is an absolute
+ ;; path and we don't want `lisp-dir' to depend
+ ;; on the current location of the package
+ ;; installation, ie. to break if moved around
+ ;; the file system or between installations.
+ (throw 'done name))))))
+ ".")
+ pkg-dir)))
(defun package-vc--read-archive-data (archive)
"Update `package-vc--archive-spec-alists' for ARCHIVE.
@@ -285,7 +313,9 @@ package-vc--main-file
(defun package-vc--generate-description-file (pkg-desc pkg-file)
"Generate a package description file for PKG-DESC and write it to PKG-FILE."
- (let ((name (package-desc-name pkg-desc)))
+ (let ((name (package-desc-name pkg-desc))
+ (main-file (let ((file (package-vc--main-file pkg-desc)))
+ (and (file-exists-p file) file))))
(when (equal (package-desc-summary pkg-desc) package--default-summary)
;; We unset the package description if it is just the default
;; summary, so that the following heuristic can take effect.
@@ -293,13 +323,12 @@ package-vc--generate-description-file
;; Infer the package description if missing.
(unless (package-desc-summary pkg-desc)
(setf (package-desc-summary pkg-desc)
- (let ((main-file (package-vc--main-file pkg-desc)))
- (or (package-desc-summary pkg-desc)
- (and-let* ((pkg (cadr (assq name package-archive-contents))))
- (package-desc-summary pkg))
- (and main-file (file-exists-p main-file)
- (lm-summary main-file))
- package--default-summary))))
+ (or (package-desc-summary pkg-desc)
+ (and-let* ((pkg (cadr (assq name package-archive-contents))))
+ (package-desc-summary pkg))
+ (and main-file
+ (lm-summary main-file))
+ package--default-summary)))
(let ((print-level nil)
(print-quoted t)
(print-length nil))
@@ -329,6 +358,16 @@ package-vc--generate-description-file
(let ((extras (copy-alist (package-desc-extras pkg-desc))))
(setf (alist-get :commit extras)
(package-vc-commit pkg-desc))
+ (when-let* (((null (alist-get :maintainer extras)))
+ (main-file)
+ (maintainers (lm-maintainers main-file)))
+ ;; Like in `pakcage-buffer-info', for backward
+ ;; compatibility, use a single cons-cell if there's
+ ;; only one maintainer.
+ (setf (alist-get :maintainer extras)
+ (if (cdr maintainers)
+ maintainers
+ (car maintainers))))
extras)
)))
"\n")
@@ -469,14 +508,24 @@ package-vc-install-dependencies
(mapc #'package-install-from-archive to-install)
missing))
-(defun package-vc--unpack-1 (pkg-desc pkg-dir)
- "Prepare PKG-DESC that is already checked-out in PKG-DIR.
-This includes downloading missing dependencies, generating
-autoloads, generating a package description file (used to
-identify a package as a VC package later on), building
-documentation and marking the package as installed."
- (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
+(defun package-vc--unpack-1 (pkg-desc)
+ "Prepare PKG-DESC that is already checked-out.
+When there's a relevant pkg-spec it is used for checkout directory.
+Otherwise `dir' slot of PKG-SPEC is used. This includes downloading
+missing dependencies, generating autoloads, generating a package
+description file (used to identify a package as a VC package later on),
+building documentation and marking the package as installed."
+ (let* (;; Main package directory, under `package-user-dir'. This is
+ ;; the same `checkout-dir' when package has been installed with
+ ;; `package-vc-install'.
+ (pkg-dir (package-desc-dir pkg-desc))
+ (pkg-spec (package-vc--desc->spec pkg-desc))
+ ;; Directory where the package repository has been checked out.
+ ;; This is the `dir' argument of
+ ;; `package-vc-install-from-checkout'.
(checkout-dir (package-vc--checkout-dir pkg-desc))
+ ;; Directory where package's Lisp code resides. It may be
+ ;; equal to `checkout-dir' or be a subdirectory of it.
(lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
missing)
@@ -519,13 +568,17 @@ package-vc--unpack-1
(auto-name (format "%s-autoloads.el" name)))
(package-generate-autoloads name lisp-dir)
;; There are two cases when we wish to "indirect" the loading of
- ;; autoload files: 1. a package specification has a `:lisp-dir'
- ;; entry listing indicting that the actual Lisp code is located in
- ;; a subdirectory of the checkout, 2. the package has been
- ;; installed using `package-vc-install-from-checkout' and we want
- ;; to load the other directory instead -- which is outside of the
- ;; checkout. We can therefore take file inequality as a sign that
- ;; we have to set up an indirection.
+ ;; autoload files:
+ ;;
+ ;; 1. a package specification has a `:lisp-dir' entry listing
+ ;; indicting that the actual Lisp code is located in a
+ ;; subdirectory of the checkout,
+ ;;
+ ;; 2. the package has been installed using
+ ;; `package-vc-install-from-checkout' and we want to load the
+ ;; other directory instead -- which is outside of the checkout.
+ ;; We can therefore take file inequality as a sign that we have to
+ ;; set up an indirection.
(unless (file-equal-p lisp-dir pkg-dir)
(write-region
(concat
@@ -569,20 +622,37 @@ package-vc--unpack-1
(setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
;; Update package-alist.
- (let ((new-desc (package-load-descriptor pkg-dir)))
+ (let* ((new-desc (package-load-descriptor pkg-dir))
+ (compile-desc (package-desc-create :name (package-desc-name new-desc)
+ :dir lisp-dir)))
;; Activation has to be done before compilation, so that if we're
;; upgrading and macros have changed we load the new definitions
;; before compiling.
(when (package-activate-1 new-desc :reload :deps)
+ ;; `package-activate-1' will reload all necessary package files
+ ;; as long as their stems are relative to of `pkg-dir'. If
+ ;; that's not the case (for example for packages with different
+ ;; `checkout-dir' or with source files in a sub directory of
+ ;; `pkg-dir'), we want to reload package files from the
+ ;; `lisp-dir' before compilation.
+ (unless (file-equal-p lisp-dir pkg-dir)
+ (package--reload-previously-loaded compile-desc))
+ ;; `package-activate-1' will add info node as long as dir file
+ ;; exists in `pkg-dir'. We need to manually add it when
+ ;; `checkout-dir' is in different location.
+ (unless (file-equal-p checkout-dir pkg-dir)
+ (package--add-info-node checkout-dir))
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
- (package--compile (package-desc-create :dir lisp-dir))
+ (package--compile compile-desc)
(when package-native-compile
- (package--native-compile-async new-desc))
+ (package--native-compile-async compile-desc))
;; After compilation, load again any files loaded by
- ;; `activate-1', so that we use the byte-compiled definitions.
- (package--reload-previously-loaded new-desc)))
+ ;; `package-activate-1', so that we use the byte-compiled
+ ;; definitions. This time we'll use `compile-desc' straight
+ ;; away.
+ (package--reload-previously-loaded compile-desc)))
;; Mark package as selected
(let ((name (package-desc-name pkg-desc)))
@@ -670,10 +740,9 @@ package-vc--unpack
(let ((copy (copy-package-desc pkg-desc)))
(setf (package-desc-kind copy) 'vc
pkg-desc copy)))
- (pcase-let* (((map :lisp-dir) pkg-spec)
- (name (package-desc-name pkg-desc))
- (dirname (package-desc-full-name pkg-desc))
- (pkg-dir (file-name-as-directory (expand-file-name dirname package-user-dir))))
+ (let* ((name (package-desc-name pkg-desc))
+ (dirname (package-desc-full-name pkg-desc))
+ (pkg-dir (file-name-as-directory (expand-file-name dirname package-user-dir))))
(when (string-empty-p name)
(user-error "Empty package name"))
(setf (package-desc-dir pkg-desc) pkg-dir)
@@ -694,28 +763,11 @@ package-vc--unpack
(delete-directory pkg-dir t)
(user-error "Installation aborted")))
- ;; When nothing is specified about a `lisp-dir', then should
- ;; heuristically check if there is a sub-directory with lisp
- ;; files. These are conventionally just called "lisp" or "src".
- ;; If this directory exists and contains non-zero number of lisp
- ;; files, we will use that instead of `pkg-dir'.
- (catch 'done
- (dolist (name '("lisp" "src"))
- (when-let* (((null lisp-dir))
- (dir (expand-file-name name pkg-dir))
- ((file-directory-p dir))
- ((directory-files dir nil "\\`[^.].+\\.el\\'" t 1)))
- ;; We won't use `dir', since dir is an absolute path and we
- ;; don't want `lisp-dir' to depend on the current location of
- ;; the package installation, ie. to break if moved around the
- ;; file system or between installations.
- (throw 'done (setq lisp-dir name)))))
-
;; Ensure we have a copy of the package specification
(when (null (package-vc--desc->spec pkg-desc name))
(package-vc--save-selected-packages name pkg-spec))
- (package-vc--unpack-1 pkg-desc pkg-dir)))
+ (package-vc--unpack-1 pkg-desc)))
(defun package-vc--read-package-name (prompt &optional allow-url installed)
"Query the user for a VC package and return a name with PROMPT.
@@ -783,7 +835,7 @@ package-vc-upgrade
;;
;; If there is a better way to do this, it should be done.
(cl-assert (package-vc-p pkg-desc))
- (letrec ((pkg-dir (package-vc--checkout-dir pkg-desc))
+ (letrec ((checkout-dir (package-vc--checkout-dir pkg-desc))
(vc-flags)
(vc-filter-command-function
(lambda (command file-or-list flags)
@@ -791,18 +843,19 @@ package-vc-upgrade
(list command file-or-list flags)))
(post-upgrade
(lambda (_command _file-or-list flags)
- (when (and (file-equal-p pkg-dir default-directory)
+ (when (and (file-equal-p checkout-dir default-directory)
(eq flags vc-flags))
(unwind-protect
(with-demoted-errors "Failed to activate: %S"
- (package-vc--unpack-1 pkg-desc pkg-dir))
+ (package-vc--unpack-1 pkg-desc))
(remove-hook 'vc-post-command-functions post-upgrade))))))
(add-hook 'vc-post-command-functions post-upgrade)
(with-demoted-errors "Failed to fetch: %S"
(require 'vc-dir)
(with-current-buffer (vc-dir-prepare-status-buffer
- (format " *package-vc-dir: %s*" pkg-dir)
- pkg-dir (vc-responsible-backend pkg-dir))
+ (format " *package-vc-dir: %s*" checkout-dir)
+ checkout-dir
+ (vc-responsible-backend checkout-dir))
(vc-pull)))))
(defun package-vc--archives-initialize ()
@@ -967,24 +1020,22 @@ package-vc-install-from-checkout
(package-vc--archives-initialize)
(let* ((dir (if interactive dir (expand-file-name dir))) ;avoid double expansion
(name (or name (file-name-base (directory-file-name dir))))
- (pkg-dir (file-name-concat package-user-dir name))
- (package-vc-selected-packages
- (cons (list name :lisp-dir dir)
- package-vc-selected-packages)))
+ (pkg-dir (file-name-concat package-user-dir name)))
(when (file-exists-p pkg-dir)
(if (yes-or-no-p (format "Overwrite previous checkout for package `%s'?" name))
(package--delete-directory pkg-dir)
(error "There already exists a checkout for %s" name)))
(make-directory pkg-dir t)
- ;; We store a custom package specification so that
- ;; `package-vc--checkout-dir' can later retrieve the actual checkout.
- (package-vc--save-selected-packages name (list :url (concat "file://" dir)))
+ ;; We store a custom package specification so that it is available
+ ;; for `package-vc--unpack-1' as well as `package-vc--checkout-dir'
+ ;; can later retrieve the actual checkout.
+ (package-vc--save-selected-packages
+ name (list :url (concat package-vc--url-scheme dir)))
(package-vc--unpack-1
(package-desc-create
:name (intern name)
:dir pkg-dir
- :kind 'vc)
- (file-name-as-directory pkg-dir))))
+ :kind 'vc))))
;;;###autoload
(defun package-vc-rebuild (pkg-desc)
@@ -996,7 +1047,7 @@ package-vc-rebuild
is the responsibility of `package-vc-upgrade'. Interactively,
prompt for the name of the package to rebuild."
(interactive (list (package-vc--read-package-desc "Rebuild package: " t)))
- (package-vc--unpack-1 pkg-desc (package-vc--checkout-dir pkg-desc)))
+ (package-vc--unpack-1 pkg-desc))
;;;###autoload
(defun package-vc-prepare-patch (pkg-desc subject revisions)
@@ -1024,7 +1075,8 @@ package-vc-log-incoming
"Call `vc-log-incoming' for the package PKG-DESC."
(interactive
(list (package-vc--read-package-desc "Incoming log for package: " t)))
- (let ((default-directory (package-vc--checkout-dir pkg-desc)))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc))
+ (vc-deduce-backend-nonvc-modes t))
(call-interactively #'vc-log-incoming)))
(provide 'package-vc)
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 63124706e28..418e807f227 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -903,6 +903,14 @@ package--reload-previously-loaded
(mapc (lambda (c) (load (car c) nil t))
(sort result (lambda (x y) (< (cdr x) (cdr y))))))))
+(defun package--add-info-node (pkg-dir)
+ "Add info node located in PKG-DIR."
+ (when (file-exists-p (expand-file-name "dir" pkg-dir))
+ ;; FIXME: not the friendliest, but simple.
+ (require 'info)
+ (info-initialize)
+ (add-to-list 'Info-directory-list pkg-dir)))
+
(defun package-activate-1 (pkg-desc &optional reload deps)
"Activate package given by PKG-DESC, even if it was already active.
If DEPS is non-nil, also activate its dependencies (unless they
@@ -934,12 +942,7 @@ package-activate-1
The following files have already been loaded: %S")))
(with-demoted-errors "Error loading autoloads: %s"
(load (package--autoloads-file-name pkg-desc) nil t)))
- ;; Add info node.
- (when (file-exists-p (expand-file-name "dir" pkg-dir))
- ;; FIXME: not the friendliest, but simple.
- (require 'info)
- (info-initialize)
- (add-to-list 'Info-directory-list pkg-dir))
+ (package--add-info-node pkg-dir)
(push name package-activated-list)
;; Don't return nil.
t)))
--
2.51.2
--=-=-=
Content-Type: text/x-patch; charset=utf-8
Content-Disposition: attachment;
filename=0002-Add-tests-for-package-vc.patch
Content-Transfer-Encoding: quoted-printable
Content-Description: package-vc tests
From 7a5e45a29477589ad029a39d363e321332b67df4 Mon Sep 17 00:00:00 2001
From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
Date: Tue, 2 Sep 2025 09:28:13 +0100
Subject: [PATCH 2/2] Add tests for package-vc
* test/lisp/package-vc-tests.el (package-vc-tests-dir):
Temporary directory to store `package' and test data during the
test.
(package-vc-tests-packages): List of packages to tests, together
with their checkout locations.
(package-vc-tessts-bundles): List of package bundles and their
most recent commits.
(package-vc-tests-checkin): Copy a an in file and create a new
file and create a new commit for a test package source.
(package-vc-tests-create-bundle): Create a package git
repository bundle with test package source.
(with-package-vc-tests-enviroment): Setup environment for test,
that includes configuring `package', `package-vc', and `vc'
variables, as well as defining test packages and creating their
bundles.
(package-vc-tests-package-desc): Retrieve a `package-desc' for
tested package.
(package-vc-tests-package-lisp-dir): Determine a lisp directory
for a package.
(package-vc-tests-package-main-file): Calculate expected
location of package's main file.
(package-vc-tests-load-history-position): Calculate a position
in load-history of a file. The position only accounts for
interesting files, that is only files that are in
`package-vc-tests-dir'.
(package-vc-tests-valid-commit-p): Check that commit is a string
and it is not "unknown".
(package-vc-tests-in-strict-order-p): Check that args are in
strict order (each arg is less than the following args).
(package-vc-tests-match-p): Check that string matches a regexp.
(package-vc-tests-buffer-p): Check that object is a buffer.
(package-vc-tests-elc-files): Check that there are elc files and
that there is no compiled autoloads file amongst them.
(package-vc-tests-assert-delete-elc): Assert that .elc files
have been gernerated for a package and delete them.
(package-vc-tests-assert-package-alist): Assert that
`pakcage-alist' contains a `package-desc' for package, and that
the `pakcage-desc' has correct slot `version' and slot `dir'.
(package-vc-tests-reset-heads): Reset heads of checkouts of
tested packages to a HEAD^.
(package-vc-tests-packages-heads): Return a list of checkouts of
tested packages current HEAD revisions.
(package-vc-tests-000-install): Test that packages can be
installed with `package-vc-install' and
`package-vc-install-from-checkout', including
`package-vc-checkout'.
(package-vc-tests-001-main-file): Test that
`package-vc--main-file' return main file in expected locations.
(package-vc-tests-002-commit): Test that `package-vc-commit' is
returning a revision.
(package-vc-tests-003-load-history-after-install): Test that
`load-history' has entries for autoloads of tested packages.
(package-vc-tests-package-vc-async-wait): Helper function to
wait for an asynchronous VC command to finish. This is needed
due to asynchronous nature of `vc-pull' and `vc-log-incoming'.
(package-vc-tests-004-upgrade-all): Test that
`package-vc-upgrade-all' indeed upgrades all packages.
(package-vc-tests-005-load-history-after-upgrade-all): Test that
`load-history' has entries for autoloads of tested packages.
(package-vc-tests-006-require): Test that packages can be
`require'd, and that `load-history' has entries for non-compiled
package main files.
(package-vc-tests-007-upgrade): Test that `package-vc-upgrade'
upgrades a package.
(package-vc-tests-008-load-history-after-upgrade): Test that
`load-history' has entries for autoloads, non-compiled main
files, and compiled main files after a package has been
upgraded.
(package-vc-tests-009-rebuild): Test that a downgraded package
can be rebuild with `package-vc-rebuild', and that appropriate
files are reloaded.
(package-vc-tests-010-prepare-patch): Test that
`package-vc-prepare-patch' creates a new message buffer for a
package.
(package-vc-tests-011-log-incoming): Test that
`package-vc-log-incoming' creates a new log buffer for a
package.
* test/lisp/package-vc-resources/test-package-v0.1.el.in:
Skeleton of version 0.1 of a test package.
* test/lisp/package-vc-resources/test-package-v0.2.el.in:
Skeleton of version 0.2 of a test package.
---
.../test-package-v0.1.el.in | 24 +
.../test-package-v0.2.el.in | 20 +
test/lisp/package-vc-tests.el | 703 ++++++++++++++++++
3 files changed, 747 insertions(+)
create mode 100644 test/lisp/package-vc-resources/test-package-v0.1.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-v0.2.el.in
create mode 100644 test/lisp/package-vc-tests.el
diff --git a/test/lisp/package-vc-resources/test-package-v0.1.el.in b/test/=
lisp/package-vc-resources/test-package-v0.1.el.in
new file mode 100644
index 00000000000..e6f2f209f2b
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-v0.1.el.in
@@ -0,0 +1,24 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.1
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+;;;###autoload
+(defun test-package-SUFFIX-func ()
+ "Test.")
+
+;;;###autoload
+(defun test-package-SUFFIX-old-func ()
+ "Test.")
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-v0.2.el.in b/test/=
lisp/package-vc-resources/test-package-v0.2.el.in
new file mode 100644
index 00000000000..f9d098ad3e2
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-v0.2.el.in
@@ -0,0 +1,20 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.2
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+;;;###autoload
+(defun test-package-SUFFIX-func ()
+ "Test.")
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
new file mode 100644
index 00000000000..56d004cda78
--- /dev/null
+++ b/test/lisp/package-vc-tests.el
@@ -0,0 +1,703 @@
+;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
+
+;; Copyright (C) 2025 Free Software Foundation, Inc.
+
+;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
+;; Keywords: package
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These tests focus on verifying post conditions for `package-vc'
+;; operations on packages. Since installing a package changes the state
+;; of running process these tests are ment to be executed in order, as
+;; denoted by digits in their name. Also in many cases the subsequent
+;; test often depends on the passing of the previous test.
+
+;; These tests load test packages with some test implementation, as well
+;; as `load-history' is being modified. This may contaminate the
+;; running Emacs instance. This, compounded with a need to run all
+;; tests in the order it is recommended to run this suite in a separate
+;; process, for example, in root of Emacs source directory:
+
+;; ./src/emacs -batch \
+;; -l ../test/lisp/package-vc-tests.el \
+;; -f ert-run-tests-batch-and-exit
+
+;;; Code:
+
+(require 'package-vc)
+(require 'package)
+(require 'vc-git)
+(require 'vc)
+(require 'cl-lib)
+(require 'ert-x)
+(require 'ert)
+
+(defvar package-vc-tests-dir nil)
+(defvar package-vc-tests-packages nil)
+(defvar package-vc-tests-bundles nil)
+
+(defun package-vc-tests-checkin (name suffix in commit-msg &optional lisp-=
dir)
+ "For package NAME copy IN file as main file.
+After copying update SUFFIX in the file and check it in with COMMIT-MSG.
+If LISP-DIR is non-nil place the file under LISP-DIR."
+ (let ((resource-dir (ert-resource-directory))
+ (main-file (format "%s.el" (if lisp-dir
+ (expand-file-name name lisp-dir)
+ name)))
+ (suffix (if (stringp suffix) suffix (format "%s" suffix))))
+ (copy-file (expand-file-name in resource-dir) main-file t)
+ (with-temp-buffer
+ (insert-file-contents main-file)
+ (goto-char (point-min))
+ (while (search-forward "SUFFIX" nil t)
+ (replace-match suffix))
+ (write-file main-file))
+ (vc-git-command nil 0 nil "add" ".")
+ (vc-git-command nil 0 nil "commit" "-m" commit-msg)))
+
+(defun package-vc-tests-create-bundle (suffix &optional lisp-dir)
+ "Create a test package bundle with SUFFIX.
+If LISP-DIR is non-nil place sources of the package in LISP-DIR."
+ (let* ((name (format "test-package-%s" suffix))
+ (src-dir (expand-file-name (format "src/%s" name)
+ package-vc-tests-dir)))
+ (make-directory (if lisp-dir
+ (expand-file-name lisp-dir src-dir)
+ src-dir)
+ :parents)
+ (let ((default-directory src-dir)
+ (bundle-file (expand-file-name (format "%s.bundle" name)
+ package-vc-tests-dir)))
+ (vc-git-command nil 0 nil "init" "-b" "master")
+ (package-vc-tests-checkin
+ name suffix "test-package-v0.1.el.in" "First commit" lisp-dir)
+ (package-vc-tests-checkin
+ name suffix "test-package-v0.2.el.in" "Second commit" lisp-dir)
+ (vc-git-command nil 0 nil
+ "bundle" "create" bundle-file "master")
+ (list (intern name)
+ bundle-file (vc-git-working-revision nil)))))
+
+(defmacro with-package-vc-tests-enviroment (&rest body)
+ "Eval BODY with test environment."
+ (declare (debug t))
+ ;; Test packages sources are stored in bundle files produced by
+ ;; git-bundle(1) and are stored in directory package-vc-resources.
+ ;; Before executing body make sure that:
+ ;; - `package' is initialised, and there are no `package-archives'
+ `(let* ((package-archives (unless package--initialized
+ (let (package-archives)
+ (package-initialize)
+ (package-vc--archives-initialize))
+ nil))
+ ;; - temporary location for packages and test files is ready
+ (package-vc-tests-dir
+ (or package-vc-tests-dir
+ (setq package-vc-tests-dir
+ (expand-file-name
+ (make-temp-file "package-vc-tests-"
+ t
+ (format-time-string "-%Y%m%d.%H%M%S"=
))))))
+ ;; - packages are installed into a test directory
+ (package-user-dir (expand-file-name "elpa"
+ package-vc-tests-dir))
+ ;; - create test package bundles if necessary and define test
+ ;; packages and their checkout locations
+ (package-vc-tests-bundles
+ (or package-vc-tests-bundles
+ (setq package-vc-tests-bundles
+ (mapcar (lambda (suffix)
+ (package-vc-tests-create-bundle
+ suffix (and (< 4 suffix) "lisp")))
+ '(1 2 3 4 5 6)))))
+ (package-vc-tests-packages
+ `(;; checkout and install with `package-vc-install' (on
+ ;; ELPA)
+ (test-package-1
+ . ,(expand-file-name "test-package-1"
+ package-user-dir))
+ ;; checkout and install with `package-vc-install' (not on
+ ;; ELPA)
+ (test-package-2
+ . ,(expand-file-name "test-package-2"
+ package-user-dir))
+ ;; checkout with `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-3
+ . ,(expand-file-name "test-package-3"
+ package-vc-tests-dir))
+ ;; checkout with git and install with
+ ;; `package-vc-install-from-checkout'
+ (test-package-4
+ . ,(expand-file-name "test-package-4"
+ package-vc-tests-dir))
+ ;; sources in "lisp" sub directory, checkout and install
+ ;; with `package-vc-install'
+ (test-package-5
+ . ,(expand-file-name "test-package-5"
+ package-user-dir))
+ ;; sources in "lisp" sub directory, checkout with git and
+ ;; install with `package-vc-install-from-checkout'
+ (test-package-6
+ . ,(expand-file-name "test-package-6"
+ package-vc-tests-dir))
+
+ ;; TODO: a package with source files in a non-standard
+ ;; :lisp-dir, a custom Makefile and non-standard :doc
+ ;; (both methods of installation)
+ ))
+ ;; - test packages are recognised by `package' and
+ ;; `package-vc' internals:
+ (package-archive-contents
+ (mapcar
+ (lambda (pkg)
+ (let ((bundle (alist-get pkg
+ package-vc-tests-bundles)))
+ (list pkg
+ (package-desc-create
+ :name pkg
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras
+ (list
+ '(:maintainer
+ ("Test Maintainer" . "test-maintainer@test-domai=
n.org"))
+ (cons :url (car bundle))
+ (cons :commit (cadr bundle))
+ (cons :revdesc (substring (cadr bundle) 0 12)))))))
+ '(test-package-1 test-package-3)))
+ (package-vc--archive-spec-alists
+ (list
+ (cons 'test-elpa
+ (mapcar
+ (lambda (pkg)
+ (list pkg
+ :url (car (alist-get pkg
+ package-vc-tests-bundles))
+ :branch "master"))
+ '(test-package-1 test-package-3)))))
+ (package-vc--archive-data-alist
+ (list
+ (list 'test-elpa :version 1 :default-vc 'Git)))
+ ;; - `vc-guess-backend-url' is recognising bundles as `Git'
+ ;; repositories:
+ (vc-clone-heuristic-alist
+ (cons
+ (cons (rx "test-package-" (one-or-more digit) ".bundle"
+ string-end)
+ 'Git)
+ vc-clone-heuristic-alist)))
+ ,@body))
+
+
+;; TODO: add test for deleting packages, with asserting
+;; `package-vc-selected-packages'
+
+;; TODO: clarify `package-vc-install-all' behaviour with regards to
+;; packages installed with `package-vc' but not stored in
+;; `package-vc-selected-packages' i.e., packages from ELPAs
+
+(defun package-vc-tests-package-desc (package &optional installed)
+ "Return descriptor of PACKAGE.
+When INSTALLED is non-nil the descriptor will come from `package-alist'.
+Otherwise the descriptor will be from `package-archive-contents'. This
+is to mimic `package-vc--read-package-desc'."
+ (cadr (assoc (if (stringp package) package (symbol-name package))
+ (if installed package-alist package-archive-contents)
+ #'string=3D)))
+
+(defun package-vc-tests-package-lisp-dir (pkg)
+ "Return a Lisp directory of PKG."
+ (when-let* ((checkout-dir (alist-get pkg package-vc-tests-packages)))
+ (cond
+ ((member pkg '(test-package-5 test-package-6))
+ (expand-file-name "lisp" checkout-dir))
+ (t checkout-dir))))
+
+(defun package-vc-tests-package-main-file (pkg)
+ "Return a main file of PKG."
+ (format "%s/%s.el" (package-vc-tests-package-lisp-dir pkg) pkg))
+
+
+;; When a package source is being recompiled - for example as result of
+;; `pakckage-vc-upgrade' or `package-vc-rebuild' - it is also reloaded
+;; [1] to ensure that the most recent version of compiled code is
+;; available to Emacs. There are a few tests that add markers in
+;; `load-history' before executing such functions. And then follow up
+;; tests use these markers to assert that expected package files are in
+;; correct places in the `load-history'.
+;;
+;; [1] Only when a file has been loaded previously.
+(defun package-vc-tests-load-history-position (pkg type)
+ "Return a PKG's position in `load-history'.
+If TYPE is `:autoloads' return a position of a PKG autoloads file.
+Otherwise, if TYPE is `:main' return a position of PKG main file (not
+compiled). Otherwise, if TYPE is `:main-compiled' return a position of
+PKG compiled main file. Otherwise, if TYPE is `:marker' return a
+position of a marker PKG."
+ (let ((pkg-file (pcase type
+ (:autoloads
+ (rx (literal
+ (format "%s/%s/%s-autoloads.el"
+ package-user-dir pkg pkg))
+ string-end))
+ (:main
+ (rx
+ (literal
+ (package-vc-tests-package-main-file pkg))
+ string-end))
+ (:main-compiled
+ (rx
+ (literal
+ (package-vc-tests-package-main-file pkg))
+ "c"
+ string-end))
+ (:marker
+ (rx "/" (literal (format "%s" pkg))))))
+ (interesting-entry
+ (rx string-start
+ (literal (file-truename package-vc-tests-dir)))))
+ (cl-position-if
+ (lambda (file)
+ (string-match pkg-file file))
+ (cl-remove-if-not
+ (lambda (file-name)
+ (string-match interesting-entry file-name))
+ (mapcar
+ #'file-truename
+ (cl-remove-if-not
+ #'stringp
+ (mapcar #'car load-history)))))))
+
+;; The following predicates and helper functions take an extra PKG
+;; argument. This is needed for ERT to print package name in case of
+;; failure.
+
+(defun package-vc-tests-valid-commit-p (_pkg commit)
+ "Return non-nil when COMMIT is a valid commit."
+ (and (stringp commit)
+ (not (string=3D commit "unknown"))))
+
+(defun package-vc-tests-in-strict-order-p (_pkg &rest args)
+ "Return non-nil when ARGS are in strict order."
+ (apply #'< args))
+
+(defun package-vc-tests-match-p (_pkg regexp string)
+ "Return non-nil when REGEXP matches STRING."
+ (string-match regexp string))
+
+(defun package-vc-tests-buffer-p (_pkg obj)
+ "Return non-nil when OBJ is a buffer."
+ (bufferp obj))
+
+(defun package-vc-tests-elc-files (pkg)
+ "Return elc files for PKG."
+ (when-let* ((dir (package-vc-tests-package-lisp-dir pkg))
+ (elc-files (directory-files
+ dir nil (rx ".elc" string-end))))
+ elc-files))
+
+(defun package-vc-tests-assert-delete-elc ()
+ "Assert that .elc files are in expected directories and delete them.
+When ALL is non nil, check all packages under test."
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let* ((dir (package-vc-tests-package-lisp-dir pkg))
+ (elc-files (should (package-vc-tests-elc-files pkg)))
+ (autoloads-rx (rx
+ (literal (format "%s-autoloads.elc" pkg))
+ string-end)))
+ (should-not (cl-find-if (lambda (elc)
+ (string-match autoloads-rx elc))
+ elc-files))
+ (dolist (elc-file elc-files)
+ (delete-file (expand-file-name elc-file dir))))))
+
+(defun package-vc-tests-assert-package-alist (version)
+ "Assert that entries in `package-alist' have correct VERSION and dir."
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
+ (should (equal (file-name-as-directory
+ (expand-file-name (format "%s" pkg)
+ package-user-dir))
+ (file-name-as-directory
+ (package-desc-dir pkg-desc))))
+ (should (equal (list pkg version)
+ (list pkg (package-desc-version pkg-desc)))))))
+
+(defun package-vc-tests-reset-heads ()
+ "Reset to HEAD^ checkouts `package-vc-tests-packages'."
+ (pcase-dolist (`(,_ . ,dir) package-vc-tests-packages)
+ (let ((default-directory dir))
+ (vc-git-command nil 0 nil "reset" "--hard" "HEAD^"))))
+
+(defun package-vc-tests-packages-heads ()
+ "Return HEAD revisions of `package-vc-tests-packages'."
+ (mapcar (lambda (pkg-checkout-dir)
+ (let ((default-directory (cdr pkg-checkout-dir)))
+ (cons (car pkg-checkout-dir)
+ (vc-git-working-revision nil))))
+ package-vc-tests-packages))
+
+(ert-deftest package-vc-tests-000-install ()
+ (with-package-vc-tests-enviroment
+ (push (list (format "%s/install-begin" package-vc-tests-dir))
+ load-history)
+ (package-vc-install 'test-package-1)
+ (should-not (alist-get "test-package-1"
+ package-vc-selected-packages
+ nil nil #'string=3D))
+
+ (let ((bundle (car (alist-get 'test-package-2
+ package-vc-tests-bundles))))
+ (package-vc-install `(test-package-2
+ :url ,bundle
+ :branch "master"))
+ (should (equal bundle
+ (plist-get (alist-get "test-package-2"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-3"
+ package-vc-tests-dir)))
+ (package-vc-checkout (package-vc-tests-package-desc
+ 'test-package-3)
+ checkout-dir)
+ (package-vc-install-from-checkout checkout-dir)
+ (should (equal (concat package-vc--url-scheme checkout-dir)
+ (plist-get (alist-get "test-package-3"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-4"
+ package-vc-tests-dir)))
+ (vc-git-clone
+ (car (alist-get 'test-package-4
+ package-vc-tests-bundles))
+ checkout-dir
+ "master")
+ (package-vc-install-from-checkout checkout-dir "test-package-4")
+ (should (equal (concat package-vc--url-scheme checkout-dir)
+ (plist-get (alist-get "test-package-4"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((bundle (car (alist-get 'test-package-5
+ package-vc-tests-bundles))))
+ (package-vc-install `(test-package-5
+ :url ,bundle
+ :branch "master"))
+ (should (equal bundle
+ (plist-get (alist-get "test-package-5"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (let ((checkout-dir (expand-file-name "test-package-6"
+ package-vc-tests-dir)))
+ (vc-git-clone
+ (car (alist-get 'test-package-6
+ package-vc-tests-bundles))
+ checkout-dir
+ "master")
+ (package-vc-install-from-checkout checkout-dir "test-package-6")
+ (should (equal (concat package-vc--url-scheme checkout-dir)
+ (plist-get (alist-get "test-package-6"
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+ (push (list (format "%s/install-end" package-vc-tests-dir))
+ load-history)
+
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc)))
+
+(ert-deftest package-vc-tests-001-main-file ()
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (should (equal (package-vc--main-file
+ (package-vc-tests-package-desc pkg t))
+ (package-vc-tests-package-main-file pkg))))))
+
+(ert-deftest package-vc-tests-002-commit ()
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (should (package-vc-tests-valid-commit-p
+ pkg
+ (package-vc-commit
+ (package-vc-tests-package-desc pkg t)))))))
+
+(ert-deftest package-vc-tests-003-load-history-after-install ()
+ (with-package-vc-tests-enviroment
+ (let ((install-begin
+ (should (package-vc-tests-load-history-position
+ 'install-begin :marker)))
+ (install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker))))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ install-end
+ autoloads-pos
+ install-begin)))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))))))
+
+(defmacro package-vc-tests-package-vc-async-wait (seconds count flags &res=
t body)
+ "Wait up to SECONDS for COUNT async vc commands with FLAGS called by BOD=
Y.
+Return nil on timeout or the value of last form in BODY."
+ (declare (indent 3))
+ (let ((count-sym (make-symbol "count"))
+ (post-vc-command-sym (make-symbol "post-vc-command")))
+ `(letrec ((,count-sym ,count)
+ (,post-vc-command-sym
+ (lambda (command _ command-flags)
+ ;; A crude filter for vc commands
+ (when (and (equal command "git")
+ (cl-every (lambda (flag)
+ (member flag command-flags))
+ ,flags))
+ (decf ,count-sym)))))
+ (add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
+ (unwind-protect
+ (with-timeout (,seconds nil)
+ (prog1
+ (progn ,@body)
+ (while (/=3D ,count-sym 0)
+ (accept-process-output nil 0.01))))
+ (remove-hook 'vc-post-command-functions ,post-vc-command-sym)))))
+
+(ert-deftest package-vc-tests-004-upgrade-all ()
+ (with-package-vc-tests-enviroment
+ (push (list (format "%s/upgrade-all-begin" package-vc-tests-dir))
+ load-history)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (package-vc-tests-reset-heads)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 (length package-vc-tests-packages) '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (push (list (format "%s/upgrade-all-end" package-vc-tests-dir))
+ load-history)
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc)))
+
+(ert-deftest package-vc-tests-005-load-history-after-upgrade-all ()
+ (with-package-vc-tests-enviroment
+ (let ((upgrade-all-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-all-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker))))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-all-end
+ autoloads-pos
+ upgrade-all-begin))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled)))))))
+
+(ert-deftest package-vc-tests-006-require ()
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should (require pkg))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg)))))
+ (let ((upgrade-all-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker))))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((main-pos (should (package-vc-tests-load-history-position
+ pkg :main))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ main-pos
+ upgrade-all-end)))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))))))
+
+(ert-deftest package-vc-tests-007-upgrade ()
+ (with-package-vc-tests-enviroment
+ (push (list (format "%s/upgrade-begin" package-vc-tests-dir))
+ load-history)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (package-vc-tests-reset-heads)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 (length package-vc-tests-packages) '("pull")
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (package-vc-upgrade
+ (package-vc-tests-package-desc pkg t))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function
+ (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg)))))
+ t))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (push (list (format "%s/upgrade-end" package-vc-tests-dir))
+ load-history)
+ (package-vc-tests-assert-package-alist '(0 2))
+ (package-vc-tests-assert-delete-elc)))
+
+(ert-deftest package-vc-tests-008-load-history-after-upgrade ()
+ (with-package-vc-tests-enviroment
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker))))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (let ((autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ autoloads-pos
+ upgrade-begin))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ main-pos
+ upgrade-begin))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ main-compiled-pos
+ upgrade-begin)))))))
+
+(ert-deftest package-vc-tests-009-rebuild ()
+ (with-package-vc-tests-enviroment
+ (package-vc-tests-reset-heads)
+ (let ((heads (package-vc-tests-packages-heads)))
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function
+ (intern (format "%s-func" pkg)))))
+ (should (fboundp (intern (format "%s-old-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function
+ (intern (format "%s-old-func" pkg))))))
+ (should (equal heads
+ (package-vc-tests-packages-heads))))
+ (package-vc-tests-assert-package-alist '(0 1))
+ (package-vc-tests-assert-delete-elc)))
+
+(ert-deftest package-vc-tests-010-prepare-patch ()
+ (let (vc-prepare-patches-separately)
+ ;; Ensure `vc-prepare-patch' respects subject from function
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (package-vc-prepare-patch (package-vc-tests-package-desc pkg t)
+ "test-subject"
+ (cdr (alist-get
+ pkg package-vc-tests-bundles)))
+ (let ((message-buffer
+ (get-buffer "*unsent mail to Test Maintainer*")))
+ (should (equal (format "%s: message-buffer" pkg)
+ (format "%s: %s"
+ pkg (if (bufferp message-buffer)
+ "message-buffer"
+ "no message-buffer"))))
+ (switch-to-buffer message-buffer)
+ (goto-char (point-min))
+ (should
+ (package-vc-tests-match-p
+ pkg
+ (rx
+ "To: Test Maintainer <test-maintainer@HIDDEN>")
+ (buffer-substring (point) (pos-eol))))
+ (forward-line)
+ (should
+ (package-vc-tests-match-p
+ pkg
+ (rx "Subject: test-subject")
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer message-buffer)))))))
+
+(ert-deftest package-vc-tests-011-log-incoming ()
+ (with-package-vc-tests-enviroment
+ (pcase-dolist (`(,pkg . ,_) package-vc-tests-packages)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 1 '("log" "--decorate")
+ (package-vc-log-incoming (package-vc-tests-package-desc pkg t))
+ t))
+ (let ((incoming-buffer (get-buffer "*vc-incoming*"))
+ (pattern (rx (literal
+ (substring
+ (cadr (alist-get pkg
+ package-vc-tests-bundles))
+ 0 7))
+ (one-or-more any)
+ "Second commit"
+ line-end)))
+ (should (package-vc-tests-buffer-p pkg incoming-buffer))
+ (switch-to-buffer incoming-buffer)
+ (goto-char (point-min))
+ (should
+ (package-vc-tests-match-p
+ pkg
+ pattern
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer incoming-buffer))))))
+
+(provide 'package-vc-tests)
+
+;;; package-vc-tests.el ends here
--=20
2.51.2
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Wed, 12 Nov 2025 18:24:02 +0000
Resent-Message-ID: <handler.79188.B79188.176297180311750 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176297180311750
(code B ref 79188); Wed, 12 Nov 2025 18:24:02 +0000
Received: (at 79188) by debbugs.gnu.org; 12 Nov 2025 18:23:23 +0000
Received: from localhost ([127.0.0.1]:50639 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vJFV4-00033S-GK
for submit <at> debbugs.gnu.org; Wed, 12 Nov 2025 13:23:23 -0500
Received: from mail-ed1-x52a.google.com ([2a00:1450:4864:20::52a]:49209)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <michelangelo.rodriguez@HIDDEN>)
id 1vJFV0-00033K-52
for 79188 <at> debbugs.gnu.org; Wed, 12 Nov 2025 13:23:20 -0500
Received: by mail-ed1-x52a.google.com with SMTP id
4fb4d7f45d1cf-64198771a9bso2010508a12.2
for <79188 <at> debbugs.gnu.org>; Wed, 12 Nov 2025 10:23:18 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1762971791; x=1763576591; darn=debbugs.gnu.org;
h=content-transfer-encoding:mime-version:user-agent:message-id:date
:references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date
:message-id:reply-to;
bh=+iUh79zR/2MfLzLtx6Cl0uYaxDQtwl/mqXFlv2Qpjrw=;
b=duTupUzuQWVGxtsvMZRqtqmKVCGZp/fE9/ZJqXV8w3kGdRCLOJBC2iHJu6ZYXuBNq/
rjg+IDIQaClrnOCuL/jWuGpJR8H6dH/dmSKAnLFkPtp0GBCBZr2kijj8qmFrEy63Ovss
a3k/9xgvDPvdOujrp0yDJ1MK6GocUO7QM553+2gLYuVpqau68asmXvT7WWjhZvAFvrGA
eZd22t5Y41rNsga47vLUzVKGCDHTF7G9WubjJLz5bxDMsEzy2rh0gx4xMWhkFJTqQYRf
K6TpyF8U5LblFD5YGrcfOLulUZARTkBOnaQn7tI3o0GaYeacwXYMIakX3vepPBz4Z8ZR
Hpuw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1762971791; x=1763576591;
h=content-transfer-encoding:mime-version:user-agent:message-id:date
:references:in-reply-to:subject:cc:to:from:x-gm-gg
:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
bh=+iUh79zR/2MfLzLtx6Cl0uYaxDQtwl/mqXFlv2Qpjrw=;
b=qbFWy43wZlDgfzR/Ym1cLE3Ay542TnvWSxHsCooopEcUGM0xHE8EVoWPhoNrTdgmBl
6Fh0bfkFfInL1lwZVFMt/Wu1M0zUGtpFPZJszfBPg4xyzUHT50rAkw4vXSr1LhNNuP/5
LgYv1R4GG1K2dYyreNCATEmGby/3ThDSSZGbxY1o6VJkeDdyaA3tdZVKqJLiiUyq9MQl
+54Jo0w0IvBED6uWouv5CQ2YPIRQrKmFKfIiTdF/bfPQBAeQsj3AaqFMxYYZE+8qYTeS
b8bbNeGdaQ9IdMf71Ps/eOfQcBp28MpGfAroJPvS0t4qPUcPqq+k2qTKuVsA17QhLlHY
ikjw==
X-Gm-Message-State: AOJu0Yxf/ff1bVkMf634VYO336nXaJtWWw29Y2NYwWdfw8uy/vQkdvs2
JGAuJTkCR1EiuPMnpyLaje3ylRkPK5B0jHOD9LxdOz0r019jn0xdeq1ik2fDRmJG
X-Gm-Gg: ASbGncv9CBu7+OisJcd8GMAPKBYTMvY/rfmE4/+bY9Pi1bNbHxM+2PwvEJmpBi0DN2Q
eJ3fs65Y+Zoih0jMwvO3aO9HDvW4qozWM8hM2Bus9hmGRmYf9s58aMRYk1wEUQhp01B3W1fVlbN
I/du8ejN8M8GXjBWekfBzEPJTvv5bBKba8t8h+d1oy7b5NsXTBxIbL7DS7LZ2iX0xQuKAW9ok1p
71TprdXAQyOpjlQaX8oB88dpLFOHaj4oVa7ZIFCW1mrhrT4E+8BpaPEaLFeW/Tkj1yHNM2PvSEj
b5limI5EDzzvTYuxMSOwmVSIO/fcS/QQ6DcTp3bUW+n3tbDBu0UTEuURog7xxv5tUcroTHpq1ne
Af4p97pWUivipxcb39GeA1BWvNFsB0we2W5JRBSaj7tFMs4qkB6BhDm3/dFqlawqaVz+BuEN5eU
MYpx43hLssn5uw6eKWEGnhuwgvUiu0lg==
X-Google-Smtp-Source: AGHT+IGGbNjmpePtfwtXfyqlgyisQBYy++/tzFGACKAYjHzsZMfwOp90LyoWtBHsHusDie7Ul07jTw==
X-Received: by 2002:a17:907:6092:b0:b6d:62e4:a63a with SMTP id
a640c23a62f3a-b7331aa9775mr451334566b.40.1762971791100;
Wed, 12 Nov 2025 10:23:11 -0800 (PST)
Received: from mac-mikey.local ([62.18.41.95])
by smtp.gmail.com with ESMTPSA id
a640c23a62f3a-b72bf9bcd59sm1634846266b.53.2025.11.12.10.23.09
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Wed, 12 Nov 2025 10:23:10 -0800 (PST)
From: Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
In-Reply-To: <m28qgbqsx0.fsf_-_@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<m24iqzmqh6.fsf@HIDDEN> <m28qgbqsx0.fsf_-_@HIDDEN>
Date: Wed, 12 Nov 2025 19:23:07 +0100
Message-ID: <m2tsyzjek4.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN> writes:
>
>> Hello,
>> These days I tried to follow all the various phases of the discussion,
>> but at a certain point, I lost track of the patches.
>
> Yeah - it's kinda blew up when I tried to add some systematic testing,
> and kept finding little kinks to iron out. I suggest to start with the
> latest patches and see what they change. That should give you an idea
> which bits of `package-vc' I found to require distinction between a
> package directory (usually named `pkg-dir') and a checkout directory
> (usually `checkout-dir' or - in your case - `vc-dir'). Perhaps you can
> use tests to see if the patch covers all aspects (probably removing
> unnecessary bits).
>
>> In any case, I propose a patch that takes into account the
>> observations made in bug#79716. At the end of the execution of
>> `package-vc-install-from-checkout` we will find the files
>> "package-autoloads.el" and "package-pkg.el" in the package directory.
>> In the vc directory, we will instead find "package.el",
>> "package-autoloads.el", and "package.elc". If this is correct then
>> the following patch should resolve the inconsistencies:
>
> I applied the patch below, and indeed - I could find the files were
> correctly compiled on installation from directory.
>
> However, this patch seems to break `package-vc-install'. For example,
> evaling the following in emacs -Q:
Ok, I think even package-vc-install now is fixed.
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 6642522d11e..ab489b17a2f 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -244,7 +244,9 @@ package-vc--main-file
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
(name (symbol-name (package-desc-name pkg-desc)))
(directory (expand-file-name
- (or (plist-get pkg-spec :lisp-dir) ".")
+ (or (plist-get pkg-spec :lisp-dir)
+ (alist-get :vc-dir (package-desc-extras pkg-desc))
+ ".")
(or (package-desc-dir pkg-desc)
(expand-file-name name package-user-dir))))
(file (expand-file-name
@@ -462,7 +464,8 @@ package-vc--unpack-1
identify a package as a VC package later on), building
documentation and marking the package as installed."
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
- (lisp-dir (plist-get pkg-spec :lisp-dir))
+ (lisp-dir (or (alist-get :vc-dir (package-desc-extras
+ pkg-desc)) pkg-dir))
(lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
missing)
=20
@@ -505,8 +508,8 @@ package-vc--unpack-1
;; Generate autoloads
(let* ((name (package-desc-name pkg-desc))
(auto-name (format "%s-autoloads.el" name)))
- (package-generate-autoloads name lisp-path)
- (when lisp-dir
+ (package-generate-autoloads name lisp-dir)=20
+ (unless (string-equal lisp-dir pkg-dir)
(write-region
(with-temp-buffer
(insert ";; Autoload indirection for package-vc\n\n")
@@ -547,9 +550,15 @@ package-vc--unpack-1
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all pa=
ckages
;; and then compile them.
- (package--compile new-desc)
- (when package-native-compile
- (package--native-compile-async new-desc))
+
+ ;; we induce `package--compile' to look in the vc directory
+ (let ((pkg-desc new-desc))
+ (setf (package-desc-dir pkg-desc) (or (alist-get :vc-dir
+ (package-desc-e=
xtras
+ pkg-desc)) lis=
p-dir))
+ (package--compile pkg-desc)
+ (when package-native-compile
+ (package--native-compile-async pkg-desc)))
;; After compilation, load again any files loaded by
;; `activate-1', so that we use the byte-compiled definitions.
(package--reload-previously-loaded new-desc)))
@@ -572,12 +581,12 @@ package-vc--unpack-1
(lm-header "version"))))
(vc-working-revision main-file)
(if missing
- (format
- " Failed to install the following dependencies: %s"
- (mapconcat
- (lambda (p)
- (format "%s (%s)" (car p) (cadr p)))
- missing ", "))
+ (format
+ " Failed to install the following dependencies: %s"
+ (mapconcat
+ (lambda (p)
+ (format "%s (%s)" (car p) (cadr p)))
+ missing ", "))
"")))
t))
=20
@@ -900,7 +909,7 @@ package-vc-checkout
(list (cadr (assoc name package-archive-contents #'string=3D))
(read-directory-name "Clone into new or empty directory: " nil =
nil
(lambda (dir) (or (not (file-exists-p dir))
- (directory-empty-p dir))))
+ (directory-empty-p dir))=
))
(and current-prefix-arg :last-release))))
(package-vc--archives-initialize)
(let ((pkg-spec (or (package-vc--desc->spec pkg-desc)
@@ -947,6 +956,9 @@ package-vc-install-from-checkout
(package-desc-create
:name (intern name)
:dir pkg-dir
+ ;; We use the :extras slot of vc-desc to store the directory where t=
he
+ ;; sources are actually located.
+ :extras (list (cons :vc-dir dir))
:kind 'vc)
(file-name-as-directory pkg-dir))))
>
> (require 'vc-git)
> (require 'package-vc)
> (let ((package-user-dir (expand-file-name "~/tmp/elpa" )))
> (package-vc-install "gcmh"))
>
> Yields, the following backtrace:
>
> Debugger entered--Lisp error: (wrong-type-argument stringp nil)
> file-name-as-directory(nil)
> package--parse-elpaignore(#s(package-desc :name gcmh :version (0 2
> 1) :summary "the Garbage Collector Magic Hack" :reqs ((emacs (24)))
> :kind vc :archive nil :dir nil :extras ((:commit
> . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9") (:authors ("Andrea
> Corallo" . "akrl@HIDDEN")) (:maintainer nil . "akrl@HIDDEN")
> (:keywords "internal") (:url . "https://gitlab.com/koral/gcmh"))
> :signed nil))
> package--compile(#s(package-desc :name gcmh :version (0 2 1)
> :summary "the Garbage Collector Magic Hack" :reqs ((emacs (24))) :kind
> vc :archive nil :dir nil :extras ((:commit
> . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9") (:authors ("Andrea
> Corallo" . "akrl@HIDDEN")) (:maintainer nil . "akrl@HIDDEN")
> (:keywords "internal") (:url . "https://gitlab.com/koral/gcmh"))
> :signed nil))
> package-vc--unpack-1(#s(package-desc :name gcmh :version (0 2 1)
> :summary "the Garbage Collector Magic Hack" :reqs ((emacs (24))) :kind
> vc :archive "gnu" :dir "/Users/pkryger/tmp/elpa/gcmh/" :extras ((:url
> . "https://gitlab.com/koral/gcmh") (:keywords "internal") (:maintainer
> nil . "akrl@HIDDEN") (:authors ("Andrea Corallo" . "akrl@HIDDEN"))
> (:commit . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9")) :signed nil)
> "/Users/pkryger/tmp/elpa/gcmh/")
> package-vc--unpack(#s(package-desc :name gcmh :version (0 2 1)
> :summary "the Garbage Collector Magic Hack" :reqs ((emacs (24))) :kind
> tar :archive "gnu" :dir nil :extras ((:url
> . "https://gitlab.com/koral/gcmh") (:keywords "internal") (:maintainer
> nil . "akrl@HIDDEN") (:authors ("Andrea Corallo" . "akrl@HIDDEN"))
> (:commit . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9")) :signed nil)
> (:url "https://gitlab.com/koral/gcmh") nil)
> package-vc-install("gcmh")
> (let ((package-user-dir (expand-file-name "~/tmp/elpa")))
> (package-vc-install "gcmh"))
> (progn (let ((package-user-dir (expand-file-name "~/tmp/elpa")))
> (package-vc-install "gcmh")))
> eval((progn (let ((package-user-dir (expand-file-name
> "~/tmp/elpa"))) (package-vc-install "gcmh"))) t)
> elisp--eval-last-sexp(nil)
> #f(compiled-function () #<bytecode 0x1866f2fbe5b2>)()
> handler-bind-1(#f(compiled-function () #<bytecode 0x1866f2fbe5b2>)
> (error) eval-expression--debug)
> eval-last-sexp(nil)
> funcall-interactively(eval-last-sexp nil)
> call-interactively(eval-last-sexp nil nil)
> command-execute(eval-last-sexp)
>
>
>
>> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.=
el
>> index 7433fce2d89..8c1d7147b22 100644
>> --- a/lisp/emacs-lisp/package-vc.el
>> +++ b/lisp/emacs-lisp/package-vc.el
>> @@ -244,7 +244,9 @@ package-vc--main-file
>> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>> (name (symbol-name (package-desc-name pkg-desc)))
>> (directory (expand-file-name
>> - (or (plist-get pkg-spec :lisp-dir) ".")
>> + (or (plist-get pkg-spec :lisp-dir)
>> + (alist-get :vc-dir (package-desc-extras pkg-de=
sc))
>> + ".")
>> (or (package-desc-dir pkg-desc)
>> (expand-file-name name package-user-dir))))
>> (file (expand-file-name
>> @@ -461,7 +463,7 @@ package-vc--unpack-1
>> identify a package as a VC package later on), building
>> documentation and marking the package as installed."
>> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>> - (lisp-dir (plist-get pkg-spec :lisp-dir))
>> + (lisp-dir (alist-get :vc-dir (package-desc-extras pkg-desc)))
>> (lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
>> missing)
>>=20=20
>> @@ -546,9 +548,14 @@ package-vc--unpack-1
>> ;; FIXME: Compilation should be done as a separate, optional, s=
tep.
>> ;; E.g. for multi-package installs, we should first install all=
packages
>> ;; and then compile them.
>> - (package--compile new-desc)
>> - (when package-native-compile
>> - (package--native-compile-async new-desc))
>> +
>> + ;; we induce `package--compile' to look in the vc directory
>> + (let ((pkg-desc new-desc))
>> + (setf (package-desc-dir pkg-desc) (alist-get :vc-dir
>> + (package-desc-ex=
tras pkg-desc)))
>> + (package--compile pkg-desc)
>> + (when package-native-compile
>> + (package--native-compile-async pkg-desc)))
>
> When you're on it, you may want to fix the indentation.
>
>> ;; After compilation, load again any files loaded by
>> ;; `activate-1', so that we use the byte-compiled definitions.
>> (package--reload-previously-loaded new-desc)))
>> @@ -946,6 +953,9 @@ package-vc-install-from-checkout
>> (package-desc-create
>> :name (intern name)
>> :dir pkg-dir
>> + ;; We use the :extras slot of vc-desc to store the directory wher=
e the
>> + ;; sources are actually located.
>> + :extras (list (cons :vc-dir dir))
>> :kind 'vc)
>> (file-name-as-directory pkg-dir))))
>>=20=20
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Fri, 14 Nov 2025 18:56:02 +0000
Resent-Message-ID: <handler.79188.B79188.176314655717105 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Cc: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>, 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176314655717105
(code B ref 79188); Fri, 14 Nov 2025 18:56:02 +0000
Received: (at 79188) by debbugs.gnu.org; 14 Nov 2025 18:55:57 +0000
Received: from localhost ([127.0.0.1]:60174 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vJyxf-0004Rp-QZ
for submit <at> debbugs.gnu.org; Fri, 14 Nov 2025 13:55:57 -0500
Received: from mout01.posteo.de ([185.67.36.65]:38043)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1vJyxc-0004Rh-GB
for 79188 <at> debbugs.gnu.org; Fri, 14 Nov 2025 13:55:54 -0500
Received: from submission (posteo.de [185.67.36.169])
by mout01.posteo.de (Postfix) with ESMTPS id 200CA240027
for <79188 <at> debbugs.gnu.org>; Fri, 14 Nov 2025 19:55:45 +0100 (CET)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1763146546; bh=Ej5R9MA7p2Bi9+RfOQvVaZL/dCQl6VgT9ljkygFKoj8=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:From;
b=CnhqR06HtP7CJYrE2RK4gdiU2/nP1VESBSJ9tptYHCkrslQqfpWEqjYrMS2EOiaSi
jAVayhGZUUq0ss6jiN9X3ftvgLFjrProJ4CNndKP7vA7AsfXS0AAv4sQVH6MPjSpcM
9Tp08OtLyDkMh0FxiWd+LypyEVHhtDnqgHJzpjCNnAOE0lK5meMH92N+dMoEW+ZNct
M97OfRmUvIiwN1rRRAA729mBMSm2Kuk9YL+FN53sSMdV6wu4F6sNr2wVpO5aOkfgpi
lBgdrxbNKbXFxXlYmx6NqBK5QV9IGDW5XzE9cBRbvfyQXpiVnp9vfyJk3nYPP5yxOW
Xg9UYUtMfQGJQ==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4d7RDK22T7z9rxN;
Fri, 14 Nov 2025 19:55:44 +0100 (CET)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2tsyzjek4.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<m24iqzmqh6.fsf@HIDDEN> <m28qgbqsx0.fsf_-_@HIDDEN>
<m2tsyzjek4.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Fri, 14 Nov 2025 18:55:45 +0000
Message-ID: <875xbcbg0f.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN> writes:
> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>
>> Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN> writes:
>>
>>> Hello,
>>> These days I tried to follow all the various phases of the discussion,
>>> but at a certain point, I lost track of the patches.
>>
>> Yeah - it's kinda blew up when I tried to add some systematic testing,
>> and kept finding little kinks to iron out. I suggest to start with the
>> latest patches and see what they change. That should give you an idea
>> which bits of `package-vc' I found to require distinction between a
>> package directory (usually named `pkg-dir') and a checkout directory
>> (usually `checkout-dir' or - in your case - `vc-dir'). Perhaps you can
>> use tests to see if the patch covers all aspects (probably removing
>> unnecessary bits).
>>
>>> In any case, I propose a patch that takes into account the
>>> observations made in bug#79716. At the end of the execution of
>>> `package-vc-install-from-checkout` we will find the files
>>> "package-autoloads.el" and "package-pkg.el" in the package directory.
>>> In the vc directory, we will instead find "package.el",
>>> "package-autoloads.el", and "package.elc". If this is correct then
>>> the following patch should resolve the inconsistencies:
>>
>> I applied the patch below, and indeed - I could find the files were
>> correctly compiled on installation from directory.
>>
>> However, this patch seems to break `package-vc-install'. For example,
>> evaling the following in emacs -Q:
I'll have to try it out myself and get into the weeds of the issue (that
Przemys=C5=82aw currently understands better than I do), but inherently the
approach of using the package descriptor to store this data doesn't
sound that bad to me.
> Ok, I think even package-vc-install now is fixed.
>
> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
> index 6642522d11e..ab489b17a2f 100644
> --- a/lisp/emacs-lisp/package-vc.el
> +++ b/lisp/emacs-lisp/package-vc.el
> @@ -244,7 +244,9 @@ package-vc--main-file
> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> (name (symbol-name (package-desc-name pkg-desc)))
> (directory (expand-file-name
> - (or (plist-get pkg-spec :lisp-dir) ".")
> + (or (plist-get pkg-spec :lisp-dir)
> + (alist-get :vc-dir (package-desc-extras pkg-des=
c))
> + ".")
I am attaching a patch we haven't pushed yet to this message, as I think
that it would make sense to merge your approach with what I proposed there.
> (or (package-desc-dir pkg-desc)
> (expand-file-name name package-user-dir))))
> (file (expand-file-name
> @@ -462,7 +464,8 @@ package-vc--unpack-1
> identify a package as a VC package later on), building
> documentation and marking the package as installed."
> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> - (lisp-dir (plist-get pkg-spec :lisp-dir))
> + (lisp-dir (or (alist-get :vc-dir (package-desc-extras
> + pkg-desc)) pkg-dir))
> (lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
> missing)
>=20=20
> @@ -505,8 +508,8 @@ package-vc--unpack-1
> ;; Generate autoloads
> (let* ((name (package-desc-name pkg-desc))
> (auto-name (format "%s-autoloads.el" name)))
> - (package-generate-autoloads name lisp-path)
> - (when lisp-dir
> + (package-generate-autoloads name lisp-dir)=20
> + (unless (string-equal lisp-dir pkg-dir)
String-equality is not robust in general, it would be better to use
file-equal-p in some capacity.
> (write-region
> (with-temp-buffer
> (insert ";; Autoload indirection for package-vc\n\n")
> @@ -547,9 +550,15 @@ package-vc--unpack-1
> ;; FIXME: Compilation should be done as a separate, optional, st=
ep.
> ;; E.g. for multi-package installs, we should first install all =
packages
> ;; and then compile them.
> - (package--compile new-desc)
> - (when package-native-compile
> - (package--native-compile-async new-desc))
> +
> + ;; we induce `package--compile' to look in the vc directory
> + (let ((pkg-desc new-desc))
> + (setf (package-desc-dir pkg-desc) (or (alist-get :vc-dir
> + (package-desc=
-extras
> + pkg-desc)) l=
isp-dir))
> + (package--compile pkg-desc)
> + (when package-native-compile
> + (package--native-compile-async pkg-desc)))
> ;; After compilation, load again any files loaded by
> ;; `activate-1', so that we use the byte-compiled definitions.
> (package--reload-previously-loaded new-desc)))
> @@ -572,12 +581,12 @@ package-vc--unpack-1
> (lm-header "version"))))
> (vc-working-revision main-file)
> (if missing
> - (format
> - " Failed to install the following dependencies: %s"
> - (mapconcat
> - (lambda (p)
> - (format "%s (%s)" (car p) (cadr p)))
> - missing ", "))
> + (format
> + " Failed to install the following dependencies: %s"
> + (mapconcat
> + (lambda (p)
> + (format "%s (%s)" (car p) (cadr p)))
> + missing ", "))
This is just whitespace change. I can remove it before applying, but it
is something to keep in mind for the future.
> "")))
> t))
>=20=20
> @@ -900,7 +909,7 @@ package-vc-checkout
> (list (cadr (assoc name package-archive-contents #'string=3D))
> (read-directory-name "Clone into new or empty directory: " ni=
l nil
> (lambda (dir) (or (not (file-exists-p di=
r))
> - (directory-empty-p dir))))
> + (directory-empty-p dir=
))))
This as well (even though it is misaligned right now...).
> (and current-prefix-arg :last-release))))
> (package-vc--archives-initialize)
> (let ((pkg-spec (or (package-vc--desc->spec pkg-desc)
> @@ -947,6 +956,9 @@ package-vc-install-from-checkout
> (package-desc-create
> :name (intern name)
> :dir pkg-dir
> + ;; We use the :extras slot of vc-desc to store the directory where=
the
> + ;; sources are actually located.
> + :extras (list (cons :vc-dir dir))
> :kind 'vc)
> (file-name-as-directory pkg-dir))))
[...]
--=-=-=
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename=0001-Fix-detection-of-VC-package-checkouts-bug-79188.patch
Content-Transfer-Encoding: quoted-printable
From: Philip Kaludercic <philipk@HIDDEN>
Date: Thu, 18 Sep 2025 19:43:46 +0200
Subject: [PATCH] Fix detection of VC package checkouts (bug#79188)
MIME-Version: 1.0
Content-Type: text/plain; charset=3DUTF-8
Content-Transfer-Encoding: 8bit
* lisp/emacs-lisp/package-vc.el (package-vc--checkout-dir): New
function to determine the real checkout of a VC package.
(package-vc-commit, package-vc--main-file)
(package-vc--build-documentation, package-vc-upgrade)
(package-vc-rebuild, package-vc-prepare-patch)
(package-vc-log-incoming): Use 'package-vc--checkout-dir'.
(package-vc--unpack-1): Use the right directories in the right
places.
(package-vc--save-selected-packages): Refactor new helper
function out of 'package-vc--unpack' to modify 'package-vc-selected-package=
s'.
(package-vc--unpack, package-vc-install-from-checkout): Use
'package-vc--save-selected-packages'.
Co-developed-by: Przemys=C5=82aw Kryger <pkryger@HIDDEN>
---
lisp/emacs-lisp/package-vc.el | 168 ++++++++++++++++++++++---------------
1 file changed, 99 insertions(+), 69 deletions(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 03767b99729..0da5ae4734d 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -175,6 +175,24 @@ package-vc--desc->spec
(mapcar #'cdr package-vc--archive-spec-alists))=
))
'() nil #'string=3D))
=20
+(defun package-vc--checkout-dir (pkg-desc &optional lisp-dir)
+ "Return the directory of the actual VC checkout for PKG-DESC.
+For most packages this is the same as `package-desc-dir', unless the
+package has been installed via `package-vc-install-from-checkout'. In
+that case the package redirects to the actual VC checkout. If the
+optional LISP-DIR argument is non-nil, then check if a related package
+specification has a `:lisp-dir' field to indicate that Lisp files are
+located in a sub directory of a checkout and return that instead."
+ (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
+ (url (plist-get pkg-spec :url)))
+ (expand-file-name
+ (or (and (not lisp-dir) (plist-get pkg-spec :lisp-dir)) ".")
+ (cond
+ ((save-match-data
+ (and url (string-match (rx "file://" (group (+ any))) url)
+ (match-string 1 url))))
+ (t (package-desc-dir pkg-desc))))))
+
(defun package-vc--read-archive-data (archive)
"Update `package-vc--archive-spec-alists' for ARCHIVE.
This function is meant to be used as a hook for `package-read-archive-hook=
'."
@@ -221,9 +239,7 @@ package-vc-commit
;; FIXME: vc should be extended to allow querying the commit of a
;; directory (as is possible when dealing with git repositories).
;; This should be a fallback option.
- (cl-loop with dir =3D (let ((pkg-spec (package-vc--desc->spec pkg-desc)))
- (or (plist-get pkg-spec :lisp-dir)
- (package-desc-dir pkg-desc)))
+ (cl-loop with dir =3D (package-vc--checkout-dir pkg-desc 'lisp-dir)
for file in (directory-files dir t "\\.el\\'" t)
when (vc-working-revision file) return it
finally return "unknown"))
@@ -245,10 +261,7 @@ package-vc--main-file
(cl-assert (package-vc-p pkg-desc))
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
(name (symbol-name (package-desc-name pkg-desc)))
- (directory (expand-file-name
- (or (plist-get pkg-spec :lisp-dir) ".")
- (or (package-desc-dir pkg-desc)
- (expand-file-name name package-user-dir))))
+ (directory (package-vc--checkout-dir pkg-desc 'lisp-dir))
(file (expand-file-name
(or (plist-get pkg-spec :main-file)
(concat name ".el"))
@@ -353,7 +366,8 @@ package-vc--make
"Process :make and :shell-command in PKG-SPEC.
PKG-DESC is the package descriptor for the package that is being
prepared."
- (let ((target (plist-get pkg-spec :make))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc))
+ (target (plist-get pkg-spec :make))
(cmd (plist-get pkg-spec :shell-command))
(buf (format " *package-vc make %s*" (package-desc-name pkg-desc))=
))
(when (or cmd target)
@@ -371,7 +385,7 @@ package-vc--build-documentation
FILE can be an Org file, indicated by its \".org\" extension,
otherwise it's assumed to be an Info file."
(let* ((pkg-name (package-desc-name pkg-desc))
- (default-directory (package-desc-dir pkg-desc))
+ (default-directory (package-vc--checkout-dir pkg-desc))
(docs-directory (file-name-directory (expand-file-name file)))
(output (expand-file-name (format "%s.info" pkg-name)))
(log-buffer (get-buffer-create (format " *package-vc doc: %s*" pk=
g-name)))
@@ -463,8 +477,8 @@ package-vc--unpack-1
identify a package as a VC package later on), building
documentation and marking the package as installed."
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
- (lisp-dir (plist-get pkg-spec :lisp-dir))
- (lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
+ (checkout-dir (package-vc--checkout-dir pkg-desc))
+ (lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
missing)
=20
;; In case the package was installed directly from source, the
@@ -476,13 +490,13 @@ package-vc--unpack-1
(lambda (ignore)
(wildcard-to-regexp
(if (string-match-p "\\`/" ignore)
- (concat pkg-dir ignore)
+ (concat checkout-dir ignore)
(concat "*/" ignore))))
(plist-get pkg-spec :ignored-files)
"\\|")
regexp-unmatchable))
(deps '()))
- (dolist (file (directory-files lisp-path t "\\.el\\'" t))
+ (dolist (file (directory-files lisp-dir t "\\.el\\'" t))
(unless (string-match-p ignored-files file)
(with-temp-buffer
(insert-file-contents file)
@@ -501,38 +515,54 @@ package-vc--unpack-1
missing)
missing)))
=20
- (let ((default-directory (file-name-as-directory pkg-dir))
- (pkg-file (expand-file-name (package--description-file pkg-dir) =
pkg-dir)))
- ;; Generate autoloads
- (let* ((name (package-desc-name pkg-desc))
- (auto-name (format "%s-autoloads.el" name)))
- (package-generate-autoloads name lisp-path)
- (when lisp-dir
- (write-region
- (with-temp-buffer
- (insert ";; Autoload indirection for package-vc\n\n")
- (prin1 `(load (expand-file-name
- ,(expand-file-name auto-name lisp-dir)
- (or (and load-file-name
- (file-name-directory load-file-name))
- (car load-path))))
- (current-buffer))
- (buffer-string))
- nil (expand-file-name auto-name pkg-dir))))
-
- ;; Generate package file
- (package-vc--generate-description-file pkg-desc pkg-file)
-
- ;; Process :make and :shell-command arguments before building docume=
ntation
- (when (or (eq package-vc-allow-build-commands t)
- (memq (package-desc-name pkg-desc)
- package-vc-allow-build-commands))
- (package-vc--make pkg-spec pkg-desc))
-
- ;; Detect a manual
- (when (executable-find "install-info")
- (dolist (doc-file (ensure-list (plist-get pkg-spec :doc)))
- (package-vc--build-documentation pkg-desc doc-file))))
+ ;; Generate autoloads
+ (let* ((name (package-desc-name pkg-desc))
+ (auto-name (format "%s-autoloads.el" name)))
+ (package-generate-autoloads name lisp-dir)
+ ;; There are two cases when we wish to "indirect" the loading of
+ ;; autoload files: 1. a package specification has a `:lisp-dir'
+ ;; entry listing indicting that the actual Lisp code is located in
+ ;; a subdirectory of the checkout, 2. the package has been
+ ;; installed using `package-vc-install-from-checkout' and we want
+ ;; to load the other directory instead -- which is outside of the
+ ;; checkout. We can therefore take file inequality as a sign that
+ ;; we have to set up an indirection.
+ (unless (file-equal-p lisp-dir pkg-dir)
+ (write-region
+ (concat
+ ";; Autoload indirection for package-vc\n\n"
+ (prin1-to-string
+ ;; The indirection is just a single load statement to the
+ ;; actual file (we don't want to use symbolic links due to
+ ;; portability reasons). Detecting which of the two cases
+ ;; mentioned above we are setting up can be done by checking
+ ;; if the directory with the lisp code is a subdirectory of
+ ;; the package directory.
+ `(load ,(if (file-in-directory-p lisp-dir pkg-dir)
+ `(expand-file-name
+ ,(file-relative-name
+ (expand-file-name auto-name lisp-dir)
+ pkg-dir)
+ (or (and load-file-name
+ (file-name-directory load-file-name))
+ (car load-path)))
+ (expand-file-name auto-name lisp-dir)))))
+ nil (expand-file-name auto-name pkg-dir))))
+
+ ;; Generate package file
+ (let ((pkg-file (expand-file-name (package--description-file pkg-dir) =
pkg-dir)))
+ (package-vc--generate-description-file pkg-desc pkg-file))
+
+ ;; Process :make and :shell-command arguments before building document=
ation
+ (when (or (eq package-vc-allow-build-commands t)
+ (memq (package-desc-name pkg-desc)
+ package-vc-allow-build-commands))
+ (package-vc--make pkg-spec pkg-desc))
+
+ ;; Detect a manual
+ (when (executable-find "install-info")
+ (dolist (doc-file (ensure-list (plist-get pkg-spec :doc)))
+ (package-vc--build-documentation pkg-desc doc-file)))
=20
;; Remove any previous instance of PKG-DESC from `package-alist'
(let ((pkgs (assq (package-desc-name pkg-desc) package-alist)))
@@ -548,13 +578,7 @@ package-vc--unpack-1
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all pa=
ckages
;; and then compile them.
- (package--compile
- (if lisp-dir
- ;; In case we are installing a package from a local
- ;; checkout, we want to compile the checkout, not the
- ;; redirection!
- (package-desc-create :dir lisp-dir)
- new-desc))
+ (package--compile (package-desc-create :dir lisp-dir))
=20
(when package-native-compile
(package--native-compile-async new-desc))
@@ -630,6 +654,14 @@ package-vc-non-code-file-names
user is fetching code from a repository that does not contain any
Emacs Lisp files.")
=20
+(defun package-vc--save-selected-packages (name pkg-spec)
+ "Save the package specification PKG-SPEC for a package NAME."
+ (customize-save-variable
+ 'package-vc-selected-packages
+ (cons (cons name pkg-spec)
+ (seq-remove (lambda (spec) (string=3D name (car spec)))
+ package-vc-selected-packages))))
+
(defun package-vc--unpack (pkg-desc pkg-spec &optional rev)
"Install the package described by PKG-DESC.
PKG-SPEC is a package specification, a property list describing
@@ -682,13 +714,8 @@ package-vc--unpack
(throw 'done (setq lisp-dir name)))))
=20
;; Ensure we have a copy of the package specification
- (unless (seq-some (lambda (alist) (equal (alist-get name (cdr alist)) =
pkg-spec))
- package-vc--archive-spec-alists)
- (customize-save-variable
- 'package-vc-selected-packages
- (cons (cons name pkg-spec)
- (seq-remove (lambda (spec) (string=3D name (car spec)))
- package-vc-selected-packages))))
+ (when (null (package-vc--desc->spec pkg-desc name))
+ (package-vc--save-selected-packages name pkg-spec))
=20
(package-vc--unpack-1 pkg-desc pkg-dir)))
=20
@@ -758,7 +785,7 @@ package-vc-upgrade
;;
;; If there is a better way to do this, it should be done.
(cl-assert (package-vc-p pkg-desc))
- (letrec ((pkg-dir (package-desc-dir pkg-desc))
+ (letrec ((pkg-dir (package-vc--checkout-dir pkg-desc))
(vc-flags)
(vc-filter-command-function
(lambda (command file-or-list flags)
@@ -951,6 +978,9 @@ package-vc-install-from-checkout
(package--delete-directory pkg-dir)
(error "There already exists a checkout for %s" name)))
(make-directory pkg-dir t)
+ ;; We store a custom package specification so that
+ ;; `package-vc--checkout-dir' can later retrieve the actual checkout.
+ (package-vc--save-selected-packages name (list :url (concat "file://" =
dir)))
(package-vc--unpack-1
(package-desc-create
:name (intern name)
@@ -968,7 +998,7 @@ package-vc-rebuild
is the responsibility of `package-vc-upgrade'. Interactively,
prompt for the name of the package to rebuild."
(interactive (list (package-vc--read-package-desc "Rebuild package: " t)=
))
- (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc)))
+ (package-vc--unpack-1 pkg-desc (package-vc--checkout-dir pkg-desc)))
=20
;;;###autoload
(defun package-vc-prepare-patch (pkg-desc subject revisions)
@@ -988,7 +1018,7 @@ package-vc-prepare-patch
(and (not vc-prepare-patches-separately)
(read-string "Subject: " "[PATCH] " nil nil t))
(vc-prepare-patch-prompt-revisions)))
- (let ((default-directory (package-desc-dir pkg-desc)))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc)))
(vc-prepare-patch (package-maintainers pkg-desc t)
subject revisions)))
=20
@@ -996,7 +1026,7 @@ package-vc-log-incoming
"Call `vc-log-incoming' for the package PKG-DESC."
(interactive
(list (package-vc--read-package-desc "Incoming log for package: " t)))
- (let ((default-directory (package-desc-dir pkg-desc)))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc)))
(call-interactively #'vc-log-incoming)))
=20
(provide 'package-vc)
--=20
2.47.3
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Mon, 17 Nov 2025 14:34:01 +0000
Resent-Message-ID: <handler.79188.B79188.176339003216626 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>, Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176339003216626
(code B ref 79188); Mon, 17 Nov 2025 14:34:01 +0000
Received: (at 79188) by debbugs.gnu.org; 17 Nov 2025 14:33:52 +0000
Received: from localhost ([127.0.0.1]:51498 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vL0Ii-0004K6-65
for submit <at> debbugs.gnu.org; Mon, 17 Nov 2025 09:33:52 -0500
Received: from mail-wm1-x32a.google.com ([2a00:1450:4864:20::32a]:57399)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1vL0Ib-0004Jh-5u
for 79188 <at> debbugs.gnu.org; Mon, 17 Nov 2025 09:33:50 -0500
Received: by mail-wm1-x32a.google.com with SMTP id
5b1f17b1804b1-4779ce2a624so15859785e9.2
for <79188 <at> debbugs.gnu.org>; Mon, 17 Nov 2025 06:33:45 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1763390018; x=1763994818; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=Gc/ba8wV9zY4fU9Puc+ZF5pMRjY4xtE/Iz+I9S1oXXs=;
b=dDTsIBRZWF0LfHI/wEibrkExBQWxdMXKsME4yIZ1+HPs/vMWmaSk1Q7aVIm2VbY+BA
HOD7ccyNCc1zHEw7wyyPbtIUK3r45OLmmEmLH+607UDh4BX/nYcFdk8bXULRDAv2qB1P
yrrZhRDAn4Qs4wjcutkxNZfyqLW8JNHjTOJshlFWg+9ZiPyde8Q4972AmNr/zexTR/xi
5XkhsMDOMwS7z7gVuPzHT7nHymukrM7c05zQf2zPvcAqVbsJjD/aFDVpSxvDv0fxavkb
igeDxaiy5SbbqJk33d1/O1UP3TgcTvcg7jEYpLgOnZ23dEKpgW4KxdT/sfacbNL33+VU
dFkw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1763390018; x=1763994818;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject
:date:message-id:reply-to;
bh=Gc/ba8wV9zY4fU9Puc+ZF5pMRjY4xtE/Iz+I9S1oXXs=;
b=s16c+zsWJFZPdGKHK7Alu0RjWEePWN/i9EGRDvGNZaMWJlMytDQdJzNycc1vwFXRSL
Zp4t/LFnUyKWeeS83sUK6W7MYfwEClA85ESxycmOEygU1xxkjJqW4zMCiUIxvanE5RqM
ewzKQTO1cS1IBJGu7lPeurE1Yk7xVjdwfw9i8P1Y7dMfc0P45JKnbBMZ5Zpm9sO9Tqih
cLe7yndLZ+gKemjQ5qbIBSMW9g6A9EAP2Dj7rxZ850VlMtSaPzx4Z7D3e5WZDnmqRQR5
Oiqjzxi7jihb1uiXZmdlJa/bPSoldCyXTiYCgS4yYkEqHkfqKutmcf9kLjvPOsCfFupG
NcAA==
X-Gm-Message-State: AOJu0YyTkA70RSdwrQkYHYjPw2uHJ7jLt/6e6NXt0BG6RGKojKzxAyN7
Kfsyo73p2gVicUpxa7nX3Bi7tuKwPp2866WJmrndkN6VP0Rk9ma92VtGdQ+UoVP+
X-Gm-Gg: ASbGncvmPODEWZgagdbRPE97Ivd0ECTRs21D0fE7nAtcThGi7XXPUewo+5GiM4m+i2y
yObWhaKoyjzB/wLpg9wkLj5ORH9eaVM8KEBIBlB/Op8vQvbLTLpu6NxshWYmlINkgYn/suOKMdM
xo9kKfGmf318llBsU5rsQKTKyUcsuJMPbJc4q+oAWSRxBHeLiFsdQRrelfdvGPbIoRFtpyE+5t9
/k1u3G/7FTLVVWdhkTkT+cb8BGbvjqa+pBP9qmyvA7BK6V3ZKl+LQ+B8NjA8EI1svhEGDqi/+xG
C0gzqkCpPC+0FyCRBrq/33mZAIWXx6zd8/VbLu8Vm37nub5RSeEboI+nbO3cAWhe6iaspluKA9B
Dt9kJp8Ky6vLKhVVwLyOARdQ24HzQPKgg0/YBvaQNo3tWyu6elLeN0DRTXSJRCtwIhl83XH/oCT
Ga6aVvrCEQWdoaXmpBvaSV+GXohaSTDZflMAMEipUvypM4fLqMBPNE/iTG98cs2Lum
X-Google-Smtp-Source: AGHT+IFvnVUbxK2JFFahNFgpm0C5yp8P65zs7QHdk90ob42HfQI4UoWQu6ihSrmYih3zUubcxWPl+Q==
X-Received: by 2002:a05:600c:c4a1:b0:477:3f35:66d5 with SMTP id
5b1f17b1804b1-4778fe95fedmr119430345e9.26.1763390017637;
Mon, 17 Nov 2025 06:33:37 -0800 (PST)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:8535:bca5:6aef:2cc4])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-477975022ecsm150148895e9.4.2025.11.17.06.33.36
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Mon, 17 Nov 2025 06:33:36 -0800 (PST)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <875xbcbg0f.fsf@HIDDEN> (Philip Kaludercic's message of "Fri,
14 Nov 2025 18:55:45 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<m24iqzmqh6.fsf@HIDDEN> <m28qgbqsx0.fsf_-_@HIDDEN>
<m2tsyzjek4.fsf@HIDDEN> <875xbcbg0f.fsf@HIDDEN>
Date: Mon, 17 Nov 2025 14:33:35 +0000
Message-ID: <m2bjl0vidc.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Philip Kaludercic <philipk@HIDDEN> writes:
> Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN> writes:
>
>> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>>
>>> Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN> writes:
>>>
>>>> Hello,
>>>> These days I tried to follow all the various phases of the discussion,
>>>> but at a certain point, I lost track of the patches.
>>>
>>> Yeah - it's kinda blew up when I tried to add some systematic testing,
>>> and kept finding little kinks to iron out. I suggest to start with the
>>> latest patches and see what they change. That should give you an idea
>>> which bits of `package-vc' I found to require distinction between a
>>> package directory (usually named `pkg-dir') and a checkout directory
>>> (usually `checkout-dir' or - in your case - `vc-dir'). Perhaps you can
>>> use tests to see if the patch covers all aspects (probably removing
>>> unnecessary bits).
>>>
>>>> In any case, I propose a patch that takes into account the
>>>> observations made in bug#79716. At the end of the execution of
>>>> `package-vc-install-from-checkout` we will find the files
>>>> "package-autoloads.el" and "package-pkg.el" in the package directory.
>>>> In the vc directory, we will instead find "package.el",
>>>> "package-autoloads.el", and "package.elc". If this is correct then
>>>> the following patch should resolve the inconsistencies:
>>>
>>> I applied the patch below, and indeed - I could find the files were
>>> correctly compiled on installation from directory.
>>>
>>> However, this patch seems to break `package-vc-install'. For example,
>>> evaling the following in emacs -Q:
>
> I'll have to try it out myself and get into the weeds of the issue (that
> Przemys=C5=82aw currently understands better than I do), but inherently t=
he
> approach of using the package descriptor to store this data doesn't
> sound that bad to me.
>
>> Ok, I think even package-vc-install now is fixed.
>>
>> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.=
el
>> index 6642522d11e..ab489b17a2f 100644
>> --- a/lisp/emacs-lisp/package-vc.el
>> +++ b/lisp/emacs-lisp/package-vc.el
>> @@ -244,7 +244,9 @@ package-vc--main-file
>> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>> (name (symbol-name (package-desc-name pkg-desc)))
>> (directory (expand-file-name
>> - (or (plist-get pkg-spec :lisp-dir) ".")
>> + (or (plist-get pkg-spec :lisp-dir)
>> + (alist-get :vc-dir (package-desc-extras pkg-de=
sc))
>> + ".")
>
> I am attaching a patch we haven't pushed yet to this message, as I think
> that it would make sense to merge your approach with what I proposed ther=
e.
>
>
>> (or (package-desc-dir pkg-desc)
>> (expand-file-name name package-user-dir))))
>> (file (expand-file-name
>> @@ -462,7 +464,8 @@ package-vc--unpack-1
>> identify a package as a VC package later on), building
>> documentation and marking the package as installed."
>> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>> - (lisp-dir (plist-get pkg-spec :lisp-dir))
>> + (lisp-dir (or (alist-get :vc-dir (package-desc-extras
>> + pkg-desc)) pkg-dir))
>> (lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
>> missing)
>>=20=20
>> @@ -505,8 +508,8 @@ package-vc--unpack-1
>> ;; Generate autoloads
>> (let* ((name (package-desc-name pkg-desc))
>> (auto-name (format "%s-autoloads.el" name)))
>> - (package-generate-autoloads name lisp-path)
>> - (when lisp-dir
>> + (package-generate-autoloads name lisp-dir)=20
>> + (unless (string-equal lisp-dir pkg-dir)
>
> String-equality is not robust in general, it would be better to use
> file-equal-p in some capacity.
>
>> (write-region
>> (with-temp-buffer
>> (insert ";; Autoload indirection for package-vc\n\n")
>> @@ -547,9 +550,15 @@ package-vc--unpack-1
>> ;; FIXME: Compilation should be done as a separate, optional, s=
tep.
>> ;; E.g. for multi-package installs, we should first install all=
packages
>> ;; and then compile them.
>> - (package--compile new-desc)
>> - (when package-native-compile
>> - (package--native-compile-async new-desc))
>> +
>> + ;; we induce `package--compile' to look in the vc directory
>> + (let ((pkg-desc new-desc))
>> + (setf (package-desc-dir pkg-desc) (or (alist-get :vc-dir
>> + (package-des=
c-extras
>> + pkg-desc)) =
lisp-dir))
>> + (package--compile pkg-desc)
>> + (when package-native-compile
>> + (package--native-compile-async pkg-desc)))
>> ;; After compilation, load again any files loaded by
>> ;; `activate-1', so that we use the byte-compiled definitions.
>> (package--reload-previously-loaded new-desc)))
>> @@ -572,12 +581,12 @@ package-vc--unpack-1
>> (lm-header "version"))))
>> (vc-working-revision main-file)
>> (if missing
>> - (format
>> - " Failed to install the following dependencies: %s"
>> - (mapconcat
>> - (lambda (p)
>> - (format "%s (%s)" (car p) (cadr p)))
>> - missing ", "))
>> + (format
>> + " Failed to install the following dependencies: %s"
>> + (mapconcat
>> + (lambda (p)
>> + (format "%s (%s)" (car p) (cadr p)))
>> + missing ", "))
>
> This is just whitespace change. I can remove it before applying, but it
> is something to keep in mind for the future.
>
>> "")))
>> t))
>>=20=20
>> @@ -900,7 +909,7 @@ package-vc-checkout
>> (list (cadr (assoc name package-archive-contents #'string=3D))
>> (read-directory-name "Clone into new or empty directory: " n=
il nil
>> (lambda (dir) (or (not (file-exists-p d=
ir))
>> - (directory-empty-p dir))))
>> + (directory-empty-p di=
r))))
>
> This as well (even though it is misaligned right now...).
>
>> (and current-prefix-arg :last-release))))
>> (package-vc--archives-initialize)
>> (let ((pkg-spec (or (package-vc--desc->spec pkg-desc)
>> @@ -947,6 +956,9 @@ package-vc-install-from-checkout
>> (package-desc-create
>> :name (intern name)
>> :dir pkg-dir
>> + ;; We use the :extras slot of vc-desc to store the directory wher=
e the
>> + ;; sources are actually located.
>> + :extras (list (cons :vc-dir dir))
>> :kind 'vc)
>> (file-name-as-directory pkg-dir))))
>
> [...]
So I applied this patch, and it seems to that :dir slot of a package
installed from checkout is incorrect., for example:
(require 'vc-git)
(require 'package-vc)
(setq package-user-dir (expand-file-name "~/tmp/elpa" ))
(shell-command "git clone https://gitlab.com/koral/gcmh.git ~/tmp/gcmh")
(package-vc-install-from-checkout "~/tmp/gcmh" "gcmh")
(package-desc-dir (cadr (assq 'gcmh package-alist)))
;; =3D> "/Users/pkryger/tmp/gcmh"
I'd expect it to be /Users/pkryger/tmp/elpa/gcmh (note the 'elpa' in
path). I guess corruption like that will cause more than one issue, but
the first I found is that calling:
(package-delete (cadr (assq 'gcmh package-alist)))
yields the following back trace (limiting relevant frames):
signal(error ("Package =E2=80=98gcmh=E2=80=99 is a system package, not de=
leting"))
error("Package `%s' is a system package, not deleting" "gcmh")
package-delete(#s(package-desc :name gcmh :version (0 2 1) :summary "the =
Garbage Collector Magic Hack" :reqs ((emacs (24))) :kind vc :archive nil :d=
ir "/Users/pkryger/tmp/gcmh" :extras ((:vc-dir . "/Users/pkryger/tmp/gcmh")=
(:commit . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9")) :signed nil))
(progn (package-delete (car (cdr (assq 'gcmh package-alist)))))
eval((progn (package-delete (car (cdr (assq 'gcmh package-alist))))) t)
I am attaching updated patches. I re-wrote tests to be executable in
regular Emacs session (although I haven't got to a point where I run
them under a development Emacs yet). With this it was so much easier to
add a few more tests, and I found that there's another issue with how a
package is rebuild. It manifests itself with a compilation using
preciously defined macro definitions, i.e., when macro has been changed
then the new version is not used.
@Philip: I merged your initial patch into mine, so it's easier to apply
on top of master. I hope I am not doing anything wrong here.
I also think that using :vc-dir in :extras slot is a viable candidate.
However, I haven't had a chance to apply it yet.
@Michelangelo: I again strongly recommend using tests from the patch.
While requiring a bit of fiddling, it should be quite easy to adjust
them to your implementation, e.g., remove assertions that relate to
`package-vc-selected-packages`.
--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment;
filename=0001-Fix-upgrading-rebuilding-and-logging-of-VC-packages.patch
Content-Description: code patch
From e509427dd760eb9ac69d68a9c9322f78b9c59bb7 Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@HIDDEN>
Date: Fri, 26 Sep 2025 14:00:54 +0100
Subject: [PATCH 1/2] Fix upgrading, rebuilding, and logging of VC packages
There are a few issues addressed in this patch:
1. Compilation (including native compilation) should happen in
directory that contains package's Lisp code.
2. After installing a package with
`package-vc-install-from-checkout' and subsequently upgrading it
with `package-vc-upgrade' the pkg-desc for the package becomes
corrupted. After the upgrade the pkg-desc's dir (a.k.a
`pkg-dir') points to checkout directory. This will cause the
subsequent `package-delete' to delete the checkout directory and
leaving incorrect forwarding autoloads file in
`package-user-directory'.
3. The detection of package's Lisp directory has been not
effective for packages installed with `package-vc-install' and
not existent for packages installed with
`package-install-from-checkout'.
4. Deduction of VC backend has been not working when called from
outside of deducing context.
5. Extract maintainers and store them in a package description
file when installing a package from a checkout.
* lisp/emacs-lisp/package-vc.el (package-vc--checkout-dir): New
function to determine the real checkout of a VC
package.
(package-vc--url-scheme): Define scheme for `:url' property.
(package-vc--generate-description-file): Extract maintainers
from main package file and store them in generated description
file.
(package-vc--save-selected-packages): Refactor new helper
function out of 'package-vc--unpack' to modify
'package-vc-selected-packages'.
(package-vc--checkout-dir): Use `pcase' to extract checkout
directory from `pkg-spec'. Detect standard lisp sub directory
if called with non-nil `lisp-dir'.
(package-vc-commit, package-vc--main-file)
(package-vc--build-documentation, package-vc-prepare-patch): Use
'package-vc--checkout-dir'.
(package-vc--unpack-1): Remove superfluous `pkg-dir' argument.
Remove elc files before compilation. Use a `package' with
`:dir' pointing to where package code is. When `checkout-dir'
is different than `pkg-dir' then call `package--add-info-node'
and after calling `package-activate-1' reload source files in
case when `lisp-dir' is a sub directory. Use the right
directories in the right places.
(package-vc-install-from-checkout): Remove superfluous
`package-vc-selected-packages' binding. Remove `pkg-dir'
argument from `package-vc--unpack-1' calls.
(package-vc--unpack): Remove `lisp-dir' variable and convert to
`let*'. Remove superfluous Lisp code sub directory detection -
logic moved to `package-vc--checkout-dir'. Remove `pkg-dir'
argument from `package-vc--unpack-1' call. Use
'package-vc--save-selected-packages'.
(package-vc-upgrade, package-vc-rebuild): Remove `pkg-dir'
argument from `package-vc--unpack-1' calls. Use
'package-vc--checkout-dir'.
(package-vc-log-incoming): Set `vc-deduce-backend-nonvc-modes'
to t. Use 'package-vc--checkout-dir'.
* lisp/emacs-lisp/package.el (package--add-info-node): New
function to install info node for package. Extracted from
`package-activate-1'.
(package-activate-1): Call `package--add-info-node'.
Co-developed-by: Philip Kaludercic <philipk@HIDDEN>
(Bug#79188)
---
lisp/emacs-lisp/package-vc.el | 329 ++++++++++++++++++++++------------
lisp/emacs-lisp/package.el | 15 +-
2 files changed, 225 insertions(+), 119 deletions(-)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 6642522d11e..a53ffff399b 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -31,8 +31,7 @@
;; aren't interested in activating a package, you can use
;; `package-vc-checkout' instead, which will prompt you for a target
;; directory. If you wish to reuse an existing checkout, the command
-;; `package-vc-install-from-checkout' will create a symbolic link and
-;; prepare the package.
+;; `package-vc-install-from-checkout' will prepare the package.
;;
;; If you make local changes that you wish to share with an upstream
;; maintainer, the command `package-vc-prepare-patch' can prepare
@@ -85,6 +84,12 @@ package-vc-register-as-project
(defvar package-vc-selected-packages) ; pacify byte-compiler
+(defconst package-vc--url-scheme
+ (if (memq system-type '(ms-dos windows-nt cygwin))
+ "file:///"
+ "file://")
+ "Scheme for `:url' property in package spec.")
+
;;;###autoload
(defun package-vc-install-selected-packages ()
"Ensure packages specified in `package-vc-selected-packages' are installed."
@@ -173,6 +178,47 @@ package-vc--desc->spec
(mapcar #'cdr package-vc--archive-spec-alists))))
'() nil #'string=))
+(defun package-vc--checkout-dir (pkg-desc &optional lisp-dir)
+ "Return the directory of the actual VC checkout for PKG-DESC.
+For most packages this is the same as `package-desc-dir', unless the
+package has been installed via `package-vc-install-from-checkout'. In
+that case the package redirects to the actual VC checkout. If the
+optional LISP-DIR argument is non-nil, then check if a related package
+specification has a `:lisp-dir' field to indicate that Lisp files are
+located in a sub directory of the checkout, or the checkout has a sub
+directory named \"lisp\" or \"src\" that contains .el files and return
+that instead."
+ (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
+ (pkg-dir (pcase (plist-get pkg-spec :url)
+ ((rx (literal package-vc--url-scheme)
+ (let checkout-dir (+ any)))
+ checkout-dir)
+ (_ (package-desc-dir pkg-desc)))))
+ (expand-file-name
+ (or (and lisp-dir
+ (or (plist-get pkg-spec :lisp-dir)
+ ;; When nothing is specified about a `lisp-dir', then
+ ;; should heuristically check if there is a
+ ;; sub-directory with lisp files. These are
+ ;; conventionally just called "lisp" or "src". If
+ ;; this directory exists and contains non-zero number
+ ;; of lisp files, we will use that instead of
+ ;; `pkg-dir'.
+ (catch 'done
+ (dolist (name '("lisp" "src"))
+ (when-let* ((dir (expand-file-name name pkg-dir))
+ ((file-directory-p dir))
+ ((directory-files
+ dir nil "\\`[^.].+\\.el\\'" t 1)))
+ ;; We won't use `dir', since dir is an absolute
+ ;; path and we don't want `lisp-dir' to depend
+ ;; on the current location of the package
+ ;; installation, ie. to break if moved around
+ ;; the file system or between installations.
+ (throw 'done name))))))
+ ".")
+ pkg-dir)))
+
(defun package-vc--read-archive-data (archive)
"Update `package-vc--archive-spec-alists' for ARCHIVE.
This function is meant to be used as a hook for `package-read-archive-hook'."
@@ -219,9 +265,7 @@ package-vc-commit
;; FIXME: vc should be extended to allow querying the commit of a
;; directory (as is possible when dealing with git repositories).
;; This should be a fallback option.
- (cl-loop with dir = (let ((pkg-spec (package-vc--desc->spec pkg-desc)))
- (or (plist-get pkg-spec :lisp-dir)
- (package-desc-dir pkg-desc)))
+ (cl-loop with dir = (package-vc--checkout-dir pkg-desc 'lisp-dir)
for file in (directory-files dir t "\\.el\\'" t)
when (vc-working-revision file) return it
finally return "unknown"))
@@ -243,10 +287,7 @@ package-vc--main-file
(cl-assert (package-vc-p pkg-desc))
(let* ((pkg-spec (package-vc--desc->spec pkg-desc))
(name (symbol-name (package-desc-name pkg-desc)))
- (directory (expand-file-name
- (or (plist-get pkg-spec :lisp-dir) ".")
- (or (package-desc-dir pkg-desc)
- (expand-file-name name package-user-dir))))
+ (directory (package-vc--checkout-dir pkg-desc 'lisp-dir))
(file (expand-file-name
(or (plist-get pkg-spec :main-file)
(concat name ".el"))
@@ -272,7 +313,9 @@ package-vc--main-file
(defun package-vc--generate-description-file (pkg-desc pkg-file)
"Generate a package description file for PKG-DESC and write it to PKG-FILE."
- (let ((name (package-desc-name pkg-desc)))
+ (let ((name (package-desc-name pkg-desc))
+ (main-file (let ((file (package-vc--main-file pkg-desc)))
+ (and (file-exists-p file) file))))
(when (equal (package-desc-summary pkg-desc) package--default-summary)
;; We unset the package description if it is just the default
;; summary, so that the following heuristic can take effect.
@@ -280,13 +323,12 @@ package-vc--generate-description-file
;; Infer the package description if missing.
(unless (package-desc-summary pkg-desc)
(setf (package-desc-summary pkg-desc)
- (let ((main-file (package-vc--main-file pkg-desc)))
- (or (package-desc-summary pkg-desc)
- (and-let* ((pkg (cadr (assq name package-archive-contents))))
- (package-desc-summary pkg))
- (and main-file (file-exists-p main-file)
- (lm-summary main-file))
- package--default-summary))))
+ (or (package-desc-summary pkg-desc)
+ (and-let* ((pkg (cadr (assq name package-archive-contents))))
+ (package-desc-summary pkg))
+ (and main-file
+ (lm-summary main-file))
+ package--default-summary)))
(let ((print-level nil)
(print-quoted t)
(print-length nil))
@@ -316,6 +358,16 @@ package-vc--generate-description-file
(let ((extras (copy-alist (package-desc-extras pkg-desc))))
(setf (alist-get :commit extras)
(package-vc-commit pkg-desc))
+ (when-let* (((null (alist-get :maintainer extras)))
+ (main-file)
+ (maintainers (lm-maintainers main-file)))
+ ;; Like in `pakcage-buffer-info', for backward
+ ;; compatibility, use a single cons-cell if there's
+ ;; only one maintainer.
+ (setf (alist-get :maintainer extras)
+ (if (cdr maintainers)
+ maintainers
+ (car maintainers))))
extras)
)))
"\n")
@@ -351,7 +403,8 @@ package-vc--make
"Process :make and :shell-command in PKG-SPEC.
PKG-DESC is the package descriptor for the package that is being
prepared."
- (let ((target (plist-get pkg-spec :make))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc))
+ (target (plist-get pkg-spec :make))
(cmd (plist-get pkg-spec :shell-command))
(buf (format " *package-vc make %s*" (package-desc-name pkg-desc))))
(when (or cmd target)
@@ -369,7 +422,7 @@ package-vc--build-documentation
FILE can be an Org file, indicated by its \".org\" extension,
otherwise it's assumed to be an Info file."
(let* ((pkg-name (package-desc-name pkg-desc))
- (default-directory (package-desc-dir pkg-desc))
+ (default-directory (package-vc--checkout-dir pkg-desc))
(docs-directory (file-name-directory (expand-file-name file)))
(output (expand-file-name (format "%s.info" (file-name-base file))))
(log-buffer (get-buffer-create (format " *package-vc doc: %s*" pkg-name)))
@@ -455,15 +508,25 @@ package-vc-install-dependencies
(mapc #'package-install-from-archive to-install)
missing))
-(defun package-vc--unpack-1 (pkg-desc pkg-dir)
- "Prepare PKG-DESC that is already checked-out in PKG-DIR.
-This includes downloading missing dependencies, generating
-autoloads, generating a package description file (used to
-identify a package as a VC package later on), building
-documentation and marking the package as installed."
- (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
- (lisp-dir (plist-get pkg-spec :lisp-dir))
- (lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
+(defun package-vc--unpack-1 (pkg-desc)
+ "Prepare PKG-DESC that is already checked-out.
+When there's a relevant pkg-spec it is used for checkout directory.
+Otherwise `dir' slot of PKG-SPEC is used. This includes downloading
+missing dependencies, generating autoloads, generating a package
+description file (used to identify a package as a VC package later on),
+building documentation and marking the package as installed."
+ (let* (;; Main package directory, under `package-user-dir'. This is
+ ;; the same `checkout-dir' when package has been installed with
+ ;; `package-vc-install'.
+ (pkg-dir (package-desc-dir pkg-desc))
+ (pkg-spec (package-vc--desc->spec pkg-desc))
+ ;; Directory where the package repository has been checked out.
+ ;; This is the `dir' argument of
+ ;; `package-vc-install-from-checkout'.
+ (checkout-dir (package-vc--checkout-dir pkg-desc))
+ ;; Directory where package's Lisp code resides. It may be
+ ;; equal to `checkout-dir' or be a subdirectory of it.
+ (lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
missing)
;; In case the package was installed directly from source, the
@@ -475,13 +538,13 @@ package-vc--unpack-1
(lambda (ignore)
(wildcard-to-regexp
(if (string-match-p "\\`/" ignore)
- (concat pkg-dir ignore)
+ (concat checkout-dir ignore)
(concat "*/" ignore))))
(plist-get pkg-spec :ignored-files)
"\\|")
regexp-unmatchable))
(deps '()))
- (dolist (file (directory-files lisp-path t "\\.el\\'" t))
+ (dolist (file (directory-files lisp-dir t "\\.el\\'" t))
(unless (string-match-p ignored-files file)
(with-temp-buffer
(insert-file-contents file)
@@ -500,59 +563,111 @@ package-vc--unpack-1
missing)
missing)))
- (let ((default-directory (file-name-as-directory pkg-dir))
- (pkg-file (expand-file-name (package--description-file pkg-dir) pkg-dir)))
- ;; Generate autoloads
- (let* ((name (package-desc-name pkg-desc))
- (auto-name (format "%s-autoloads.el" name)))
- (package-generate-autoloads name lisp-path)
- (when lisp-dir
- (write-region
- (with-temp-buffer
- (insert ";; Autoload indirection for package-vc\n\n")
- (prin1 `(load (expand-file-name
- ,(expand-file-name auto-name lisp-dir)
- (or (and load-file-name
- (file-name-directory load-file-name))
- (car load-path))))
- (current-buffer))
- (buffer-string))
- nil (expand-file-name auto-name pkg-dir))))
+ ;; Generate autoloads
+ (let* ((name (package-desc-name pkg-desc))
+ (auto-name (format "%s-autoloads.el" name)))
+ (package-generate-autoloads name lisp-dir)
+ ;; There are two cases when we wish to "indirect" the loading of
+ ;; autoload files:
+ ;;
+ ;; 1. a package specification has a `:lisp-dir' entry listing
+ ;; indicting that the actual Lisp code is located in a
+ ;; subdirectory of the checkout,
+ ;;
+ ;; 2. the package has been installed using
+ ;; `package-vc-install-from-checkout' and we want to load the
+ ;; other directory instead -- which is outside of the checkout.
+ ;; We can therefore take file inequality as a sign that we have to
+ ;; set up an indirection.
+ (unless (file-equal-p lisp-dir pkg-dir)
+ (write-region
+ (concat
+ ";; Autoload indirection for package-vc\n\n"
+ (prin1-to-string
+ ;; The indirection is just a single load statement to the
+ ;; actual file (we don't want to use symbolic links due to
+ ;; portability reasons). Detecting which of the two cases
+ ;; mentioned above we are setting up can be done by checking
+ ;; if the directory with the lisp code is a subdirectory of
+ ;; the package directory.
+ `(load ,(if (file-in-directory-p lisp-dir pkg-dir)
+ `(expand-file-name
+ ,(file-relative-name
+ (expand-file-name auto-name lisp-dir)
+ pkg-dir)
+ (or (and load-file-name
+ (file-name-directory load-file-name))
+ (car load-path)))
+ (expand-file-name auto-name lisp-dir)))))
+ nil (expand-file-name auto-name pkg-dir))))
- ;; Generate package file
- (package-vc--generate-description-file pkg-desc pkg-file)
+ ;; Generate package file
+ (let ((pkg-file (expand-file-name (package--description-file pkg-dir) pkg-dir)))
+ (package-vc--generate-description-file pkg-desc pkg-file))
- ;; Process :make and :shell-command arguments before building documentation
- (when (or (eq package-vc-allow-build-commands t)
- (memq (package-desc-name pkg-desc)
- package-vc-allow-build-commands))
- (package-vc--make pkg-spec pkg-desc))
+ ;; Process :make and :shell-command arguments before building documentation
+ (when (or (eq package-vc-allow-build-commands t)
+ (memq (package-desc-name pkg-desc)
+ package-vc-allow-build-commands))
+ (package-vc--make pkg-spec pkg-desc))
- ;; Detect a manual
- (when (executable-find "install-info")
- (dolist (doc-file (ensure-list (plist-get pkg-spec :doc)))
- (package-vc--build-documentation pkg-desc doc-file))))
+ ;; Detect a manual
+ (when (executable-find "install-info")
+ (dolist (doc-file (ensure-list (plist-get pkg-spec :doc)))
+ (package-vc--build-documentation pkg-desc doc-file)))
;; Remove any previous instance of PKG-DESC from `package-alist'
(let ((pkgs (assq (package-desc-name pkg-desc) package-alist)))
(when pkgs
(setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
+ ;; Remove all compiled files to allow for macros to be used from
+ ;; source files, regardless of order of source files compilation and
+ ;; load ordering. As a side effect there are no compiled files for
+ ;; source files that no longer exist.
+ (dolist (elc-file (directory-files-recursively
+ lisp-dir
+ (rx string-start
+ (not ".") (zero-or-more any) ".elc"
+ string-end)
+ nil
+ (lambda (dir)
+ (and (file-accessible-directory-p dir)
+ (not (string-prefix-p "." dir))))))
+ (delete-file elc-file))
+
;; Update package-alist.
- (let ((new-desc (package-load-descriptor pkg-dir)))
+ (let* ((new-desc (package-load-descriptor pkg-dir))
+ (compile-desc (package-desc-create :name (package-desc-name new-desc)
+ :dir lisp-dir)))
;; Activation has to be done before compilation, so that if we're
;; upgrading and macros have changed we load the new definitions
;; before compiling.
(when (package-activate-1 new-desc :reload :deps)
+ ;; `package-activate-1' will reload all necessary package files
+ ;; as long as their stems are relative to of `pkg-dir'. If
+ ;; that's not the case (for example for packages with different
+ ;; `checkout-dir' or with source files in a sub directory of
+ ;; `pkg-dir'), we want to reload package files from the
+ ;; `lisp-dir' before compilation.
+ (unless (file-equal-p lisp-dir pkg-dir)
+ (package--reload-previously-loaded compile-desc))
+ ;; `package-activate-1' will add info node as long as dir file
+ ;; exists in `pkg-dir'. We need to manually add it when
+ ;; `checkout-dir' is in different location.
+ (unless (file-equal-p checkout-dir pkg-dir)
+ (package--add-info-node checkout-dir))
;; FIXME: Compilation should be done as a separate, optional, step.
;; E.g. for multi-package installs, we should first install all packages
;; and then compile them.
- (package--compile new-desc)
+ (package--compile compile-desc)
(when package-native-compile
- (package--native-compile-async new-desc))
+ (package--native-compile-async compile-desc))
;; After compilation, load again any files loaded by
- ;; `activate-1', so that we use the byte-compiled definitions.
- (package--reload-previously-loaded new-desc)))
+ ;; `package-activate-1', so that we use the byte-compiled
+ ;; definitions. This time we'll use `compile-desc' straight
+ ;; away.
+ (package--reload-previously-loaded compile-desc)))
;; Mark package as selected
(let ((name (package-desc-name pkg-desc)))
@@ -572,12 +687,12 @@ package-vc--unpack-1
(lm-header "version"))))
(vc-working-revision main-file)
(if missing
- (format
- " Failed to install the following dependencies: %s"
- (mapconcat
- (lambda (p)
- (format "%s (%s)" (car p) (cadr p)))
- missing ", "))
+ (format
+ " Failed to install the following dependencies: %s"
+ (mapconcat
+ (lambda (p)
+ (format "%s (%s)" (car p) (cadr p)))
+ missing ", "))
"")))
t))
@@ -622,6 +737,14 @@ package-vc-non-code-file-names
user is fetching code from a repository that does not contain any
Emacs Lisp files.")
+(defun package-vc--save-selected-packages (name pkg-spec)
+ "Save the package specification PKG-SPEC for a package NAME."
+ (customize-save-variable
+ 'package-vc-selected-packages
+ (cons (cons name pkg-spec)
+ (seq-remove (lambda (spec) (string= name (car spec)))
+ package-vc-selected-packages))))
+
(defun package-vc--unpack (pkg-desc pkg-spec &optional rev)
"Install the package described by PKG-DESC.
PKG-SPEC is a package specification, a property list describing
@@ -632,10 +755,9 @@ package-vc--unpack
(let ((copy (copy-package-desc pkg-desc)))
(setf (package-desc-kind copy) 'vc
pkg-desc copy)))
- (pcase-let* (((map :lisp-dir) pkg-spec)
- (name (package-desc-name pkg-desc))
- (dirname (package-desc-full-name pkg-desc))
- (pkg-dir (file-name-as-directory (expand-file-name dirname package-user-dir))))
+ (let* ((name (package-desc-name pkg-desc))
+ (dirname (package-desc-full-name pkg-desc))
+ (pkg-dir (file-name-as-directory (expand-file-name dirname package-user-dir))))
(when (string-empty-p name)
(user-error "Empty package name"))
(setf (package-desc-dir pkg-desc) pkg-dir)
@@ -656,33 +778,11 @@ package-vc--unpack
(delete-directory pkg-dir t)
(user-error "Installation aborted")))
- ;; When nothing is specified about a `lisp-dir', then should
- ;; heuristically check if there is a sub-directory with lisp
- ;; files. These are conventionally just called "lisp" or "src".
- ;; If this directory exists and contains non-zero number of lisp
- ;; files, we will use that instead of `pkg-dir'.
- (catch 'done
- (dolist (name '("lisp" "src"))
- (when-let* (((null lisp-dir))
- (dir (expand-file-name name pkg-dir))
- ((file-directory-p dir))
- ((directory-files dir nil "\\`[^.].+\\.el\\'" t 1)))
- ;; We won't use `dir', since dir is an absolute path and we
- ;; don't want `lisp-dir' to depend on the current location of
- ;; the package installation, ie. to break if moved around the
- ;; file system or between installations.
- (throw 'done (setq lisp-dir name)))))
-
;; Ensure we have a copy of the package specification
- (unless (seq-some (lambda (alist) (equal (alist-get name (cdr alist)) pkg-spec))
- package-vc--archive-spec-alists)
- (customize-save-variable
- 'package-vc-selected-packages
- (cons (cons name pkg-spec)
- (seq-remove (lambda (spec) (string= name (car spec)))
- package-vc-selected-packages))))
+ (when (null (package-vc--desc->spec pkg-desc name))
+ (package-vc--save-selected-packages name pkg-spec))
- (package-vc--unpack-1 pkg-desc pkg-dir)))
+ (package-vc--unpack-1 pkg-desc)))
(defun package-vc--read-package-name (prompt &optional allow-url installed)
"Query the user for a VC package and return a name with PROMPT.
@@ -750,7 +850,7 @@ package-vc-upgrade
;;
;; If there is a better way to do this, it should be done.
(cl-assert (package-vc-p pkg-desc))
- (letrec ((pkg-dir (package-desc-dir pkg-desc))
+ (letrec ((checkout-dir (package-vc--checkout-dir pkg-desc))
(vc-flags)
(vc-filter-command-function
(lambda (command file-or-list flags)
@@ -758,18 +858,19 @@ package-vc-upgrade
(list command file-or-list flags)))
(post-upgrade
(lambda (_command _file-or-list flags)
- (when (and (file-equal-p pkg-dir default-directory)
+ (when (and (file-equal-p checkout-dir default-directory)
(eq flags vc-flags))
(unwind-protect
(with-demoted-errors "Failed to activate: %S"
- (package-vc--unpack-1 pkg-desc pkg-dir))
+ (package-vc--unpack-1 pkg-desc))
(remove-hook 'vc-post-command-functions post-upgrade))))))
(add-hook 'vc-post-command-functions post-upgrade)
(with-demoted-errors "Failed to fetch: %S"
(require 'vc-dir)
(with-current-buffer (vc-dir-prepare-status-buffer
- (format " *package-vc-dir: %s*" pkg-dir)
- pkg-dir (vc-responsible-backend pkg-dir))
+ (format " *package-vc-dir: %s*" checkout-dir)
+ checkout-dir
+ (vc-responsible-backend checkout-dir))
(vc-pull)))))
(defun package-vc--archives-initialize ()
@@ -934,21 +1035,22 @@ package-vc-install-from-checkout
(package-vc--archives-initialize)
(let* ((dir (if interactive dir (expand-file-name dir))) ;avoid double expansion
(name (or name (file-name-base (directory-file-name dir))))
- (pkg-dir (file-name-concat package-user-dir name))
- (package-vc-selected-packages
- (cons (list name :lisp-dir dir)
- package-vc-selected-packages)))
+ (pkg-dir (file-name-concat package-user-dir name)))
(when (file-exists-p pkg-dir)
(if (yes-or-no-p (format "Overwrite previous checkout for package `%s'?" name))
(package--delete-directory pkg-dir)
(error "There already exists a checkout for %s" name)))
(make-directory pkg-dir t)
+ ;; We store a custom package specification so that it is available
+ ;; for `package-vc--unpack-1' as well as `package-vc--checkout-dir'
+ ;; can later retrieve the actual checkout.
+ (package-vc--save-selected-packages
+ name (list :url (concat package-vc--url-scheme dir)))
(package-vc--unpack-1
(package-desc-create
:name (intern name)
:dir pkg-dir
- :kind 'vc)
- (file-name-as-directory pkg-dir))))
+ :kind 'vc))))
;;;###autoload
(defun package-vc-rebuild (pkg-desc)
@@ -960,7 +1062,7 @@ package-vc-rebuild
is the responsibility of `package-vc-upgrade'. Interactively,
prompt for the name of the package to rebuild."
(interactive (list (package-vc--read-package-desc "Rebuild package: " t)))
- (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc)))
+ (package-vc--unpack-1 pkg-desc))
;;;###autoload
(defun package-vc-prepare-patch (pkg-desc subject revisions)
@@ -980,7 +1082,7 @@ package-vc-prepare-patch
(and (not vc-prepare-patches-separately)
(read-string "Subject: " "[PATCH] " nil nil t))
(vc-prepare-patch-prompt-revisions)))
- (let ((default-directory (package-desc-dir pkg-desc)))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc)))
(vc-prepare-patch (package-maintainers pkg-desc t)
subject revisions)))
@@ -988,7 +1090,8 @@ package-vc-log-incoming
"Call `vc-log-incoming' for the package PKG-DESC."
(interactive
(list (package-vc--read-package-desc "Incoming log for package: " t)))
- (let ((default-directory (package-desc-dir pkg-desc)))
+ (let ((default-directory (package-vc--checkout-dir pkg-desc))
+ (vc-deduce-backend-nonvc-modes t))
(call-interactively #'vc-log-incoming)))
(provide 'package-vc)
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 63124706e28..418e807f227 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -903,6 +903,14 @@ package--reload-previously-loaded
(mapc (lambda (c) (load (car c) nil t))
(sort result (lambda (x y) (< (cdr x) (cdr y))))))))
+(defun package--add-info-node (pkg-dir)
+ "Add info node located in PKG-DIR."
+ (when (file-exists-p (expand-file-name "dir" pkg-dir))
+ ;; FIXME: not the friendliest, but simple.
+ (require 'info)
+ (info-initialize)
+ (add-to-list 'Info-directory-list pkg-dir)))
+
(defun package-activate-1 (pkg-desc &optional reload deps)
"Activate package given by PKG-DESC, even if it was already active.
If DEPS is non-nil, also activate its dependencies (unless they
@@ -934,12 +942,7 @@ package-activate-1
The following files have already been loaded: %S")))
(with-demoted-errors "Error loading autoloads: %s"
(load (package--autoloads-file-name pkg-desc) nil t)))
- ;; Add info node.
- (when (file-exists-p (expand-file-name "dir" pkg-dir))
- ;; FIXME: not the friendliest, but simple.
- (require 'info)
- (info-initialize)
- (add-to-list 'Info-directory-list pkg-dir))
+ (package--add-info-node pkg-dir)
(push name package-activated-list)
;; Don't return nil.
t)))
--
2.51.2
--=-=-=
Content-Type: text/x-patch; charset=utf-8
Content-Disposition: attachment;
filename=0002-Add-tests-for-package-vc.patch
Content-Transfer-Encoding: quoted-printable
Content-Description: tests
From da677da063cb48c7c70eab3974d99ba772914dc8 Mon Sep 17 00:00:00 2001
From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
Date: Tue, 2 Sep 2025 09:28:13 +0100
Subject: [PATCH 2/2] Add tests for package-vc
* test/lisp/package-vc-tests.el (package-vc-tests-under-test):
Define packages names to run tests on.
(package-vc-tests-preserve-temporary): When non nil then
preserve temporary test files.
(package-vc-tests-dir, package-vc-tests-packages)
(package-vc-tests-bundle): Silence byte compiler.
(package-vc-tests-add): Copy a an in file template,
update SUFFIX in it and add it to index.
(package-vc-tests-create-bundle): Create a package git
repository bundle with test package source.
(package-vc-tests-package-desc): Retrieve a `package-desc' for
tested package.
(package-vc-tests-package-lisp-dir): Determine a lisp directory
for a package.
(package-vc-tests-package-main-file): Calculate expected
location of package's main file.
(package-vc-tests-load-history-marker): Create a load history
marker.
(package-vc-tests-load-history-pattern): Create a regexp pattern
to search in `load-history'.
(package-vc-tests-load-history-position): Calculate a position
in `load-history'.
(package-vc-tests-explain-load-history-position): Return ERT
explanation for failures.
(package-vc-tests-valid-commit-p): Check that commit is a string
and it is not "unknown".
(package-vc-tests-in-strict-order-p): Check that args are in
strict order (each arg is less than the following args).
(package-vc-tests-match-p): Check that string matches a regexp.
(package-vc-tests-buffer-p): Check that object is a buffer.
(package-vc-tests-elc-files): Check that there are elc files and
that there is no compiled autoloads file amongst them.
(package-vc-tests-assert-delete-elc): Assert that .elc files
are present for a package.
(package-vc-tests-assert-package-alist): Assert that
`pakcage-alist' contains a `package-desc' for package, and that
the `pakcage-desc' has correct slot `version' and slot `dir'.
(package-vc-tests-reset-heads): Reset head of checkout of
tested packages to HEAD^.
(package-vc-tests-packages-heads): Return current checkout
revision.
(with-package-vc-tests-installed): Setup test environment,
install package, evaluate test body, and then tear down the test
environment.
(package-vc-tests-install-from-elpa)
(package-vc-tests-install-from-spec): Install a test package.
(pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
(package-vc-tests-checkout-with-git-install-from-checkout):
Checkout and install a test package.
(package-vc-tests-package-vc-async-wait): Wait for an
asynchronous VC command to finish.
(package-vc-tests-install-post-conditions): Tests that after
installing a test package the `load-history' entries, package's
main file, commit, elc files, and `package-alist' entry are
correct.
(package-vc-tests-require): Test that after calling `require'
the `load-history' entries are correct.
(package-vc-tests-upgrade, package-vc-tests-upgrade-all): Test
that after calling `package-vc-upgrade'/`package-vc-upgrade-all'
the `load-history' entries, package's elc files, commit, and
`package-alist' entry are correct.
(package-vc-tests-upgrade-after-require)
(package-vc-tests-upgrade-all-after-require): Test that after
calling `require' followed by
`package-vc-upgrade'/`package-vc-upgrade-all' the `load-history'
entries, commit, package's elc files, and `package-alist' entry
are correct.
(package-vc-tests-rebuild): Test that after calling
`package-vc-rebuild' on an old version of a package, the
package's old function, old macro, elc files, and
`package-alist' entry are correct.
(package-vc-tests-rebuild-after-require): Test that after
calling `require' followed by `package-vc-rebuild' on an old
version of a package, the package's old function, old macro, elc
files, and `package-alist' entry are correct.
(package-vc-tests-prepare-patch): Test that after calling
`package-vc-prepare-patch' the message buffer is correct.
(package-vc-tests-log-incoming): Test that after calling
`package-vc-log-incoming' the log buffer is correct.
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in:
* test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in:
Code template of version 0.1 of a test package.
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in:
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.2-lib.el.in:
Code template of code of version 0.2 of a test package.
* test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in:
* test/lisp/package-vc-resources/test-package-SUFFIX.texi.in:
Documentation template of a test package.
* test/lisp/package-vc-resources/Makefile:
Makefile template of a test package.
---
test/lisp/package-vc-resources/Makefile.in | 4 +
.../test-package-SUFFIX-inc.texi.in | 3 +
.../test-package-SUFFIX-lib-v0.1.el.in | 16 +
.../test-package-SUFFIX-lib-v0.2.el.in | 16 +
.../test-package-SUFFIX-v0.1.el.in | 28 +
.../test-package-SUFFIX-v0.2.el.in | 24 +
.../test-package-SUFFIX.texi.in | 11 +
test/lisp/package-vc-tests.el | 1045 +++++++++++++++++
8 files changed, 1147 insertions(+)
create mode 100644 test/lisp/package-vc-resources/Makefile.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-inc.=
texi.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-lib-=
v0.1.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-lib-=
v0.2.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-v0.1=
.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-v0.2=
.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX.texi=
.in
create mode 100644 test/lisp/package-vc-tests.el
diff --git a/test/lisp/package-vc-resources/Makefile.in b/test/lisp/package=
-vc-resources/Makefile.in
new file mode 100644
index 00000000000..8618ae8f2f4
--- /dev/null
+++ b/test/lisp/package-vc-resources/Makefile.in
@@ -0,0 +1,4 @@
+.PHONY: build-test-package-SUFFIX
+
+build-test-package-SUFFIX:
+ @touch test-package-SUFFIX.make-build
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in=
b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in
new file mode 100644
index 00000000000..9e4e38b74a4
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in
@@ -0,0 +1,3 @@
+@c -*- texinfo -*-
+@chapter Second chapter for test-package-SUFFIX
+ Second test text.
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el=
.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in
new file mode 100644
index 00000000000..c8bfce3e8ab
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in
@@ -0,0 +1,16 @@
+;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding: t=
-*-
+
+;;; Commentary:
+;;
+;; Test package SUFFIX library.
+
+;;; Code:
+
+(defmacro test-package-SUFFIX-mac (arg)
+ ;; checkdoc-params: (arg)
+ "Old test macro for `test-package-SUFFIX'."
+ `(format "Old macro %s" ,arg))
+
+(provide 'test-package-SUFFIX-lib)
+
+;;; test-package-SUFFIX-lib.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el=
.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in
new file mode 100644
index 00000000000..bfa4c35f014
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in
@@ -0,0 +1,16 @@
+;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding: t=
-*-
+
+;;; Commentary:
+;;
+;; Test package SUFFIX library.
+
+;;; Code:
+
+(defmacro test-package-SUFFIX-mac (arg)
+ ;; checkdoc-params: (arg)
+ "Test macro for `test-package-SUFFIX'."
+ `(format "New macro %s" ,arg))
+
+(provide 'test-package-SUFFIX-lib)
+
+;;; test-package-SUFFIX-lib.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in =
b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in
new file mode 100644
index 00000000000..ddecc88e1c5
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in
@@ -0,0 +1,28 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.1
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+(require 'test-package-SUFFIX-lib)
+
+;;;###autoload
+(defun test-package-SUFFIX-func (arg)
+ ;; checkdoc-params: (arg)
+ "Test function for `test-package-SUFFIX'."
+ (test-package-SUFFIX-mac arg))
+
+;;;###autoload
+(defun test-package-SUFFIX-old-func ()
+ "Old test function for `test-package-SUFFIX'.")
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in =
b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in
new file mode 100644
index 00000000000..902066d787d
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in
@@ -0,0 +1,24 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.2
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+(require 'test-package-SUFFIX-lib)
+
+;;;###autoload
+(defun test-package-SUFFIX-func (arg)
+ ;; checkdoc-params: (arg)
+ "Test function for `test-package-SUFFIX'."
+ (test-package-SUFFIX-mac arg))
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in b/t=
est/lisp/package-vc-resources/test-package-SUFFIX.texi.in
new file mode 100644
index 00000000000..0fc4fc3653d
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in
@@ -0,0 +1,11 @@
+\input texinfo @c -*- texinfo -*-
+@settitle Info for test-package-SUFFIX
+@direntry
+* Test-package-SUFFIX: (test-package-SUFFIX). test-package-SUFFIX.
+@end direntry
+
+@chapter First chapter for test-package-SUFFIX
+ First test text.
+
+@include test-package-SUFFIX-inc.texi
+@bye
diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
new file mode 100644
index 00000000000..9f00d0f508f
--- /dev/null
+++ b/test/lisp/package-vc-tests.el
@@ -0,0 +1,1045 @@
+;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
+
+;; Copyright (C) 2025 Free Software Foundation, Inc.
+
+;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
+;; Keywords: package
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These tests focus on verifying post conditions for `package-vc'
+;; operations on packages. These tests install and load test packages
+;; with a sample test implementation, resulting in modification of
+;; numerous global variables, for example `load-history', `load-path',
+;; `features', etc. When run with `ert' it may contaminate current
+;; Emacs session. For this reason, tests execute their bodies in
+;; `with-package-vc-tests-installed' (which see), that takes care of
+;; cleaning up the environment.
+
+;;; Code:
+
+(require 'package-vc)
+(require 'package)
+(require 'vc-git)
+(require 'vc)
+(require 'cl-lib)
+(require 'info)
+(require 'ert-x)
+(require 'ert)
+
+(defvar package-vc-tests-under-test '(test-package-1
+ test-package-2
+ test-package-3
+ test-package-4
+ test-package-5
+ test-package-6
+ test-package-7
+ test-package-8
+ test-package-9))
+
+(defvar package-vc-tests-preserve-temporary nil
+ "When non-nil preserve temporary files produced by tests.
+Each test produces a new temporary directory for each package under
+test. This leads to creation of [length of
+`package-vc-tests-under-test'] times [number of tests executed]
+temporary directories for each tests run. When this variable is nil
+then delete all temporary directories as soon as they are no longer
+needed. When this variable is a symbol, then preserve temporary
+directories for the package that matches the symbol. When this variable
+is a list of symbol, then preserve temporary directories for each
+package that matches symbol in the list. When this variable is t then
+preserve all temporary directories. Tests create temporary directories
+with `make-temp-file', which see.")
+
+(defvar package-vc-tests-dir)
+(defvar package-vc-tests-packages)
+(defvar package-vc-tests-bundle)
+
+;; TODO: add test for deleting packages, with asserting
+;; `package-vc-selected-packages'
+
+;; TODO: clarify `package-vc-install-all' behaviour with regards to
+;; packages installed with `package-vc' but not stored in
+;; `package-vc-selected-packages' i.e., packages from ELPAs
+
+(defun package-vc-tests-add (suffix in-file &optional lisp-dir)
+ "Create a new file from IN-FILE template updating SUFFIX in it.
+When LISP-DIR is non-nil place the NAME file under LISP-DIR."
+ (let* ((resource-dir (ert-resource-directory))
+ (suffix (if (stringp suffix) suffix (format "%s" suffix)))
+ (file (let ((file (replace-regexp-in-string
+ (rx ".in" string-end) ""
+ (replace-regexp-in-string
+ "SUFFIX" suffix
+ (replace-regexp-in-string
+ (rx "-v" digit (zero-or-more
+ "." (one-or-more digit)))
+ ""
+ in-file
+ nil nil 0)
+ nil nil 0)
+ nil nil 0)))
+ (if lisp-dir
+ (file-name-concat lisp-dir file)
+ file))))
+ (copy-file (expand-file-name in-file resource-dir) file t)
+ (with-temp-buffer
+ (insert-file-contents file)
+ (goto-char (point-min))
+ (while (search-forward "SUFFIX" nil t)
+ (replace-match suffix))
+ (write-file file))
+ (vc-git-command nil 0 nil "add" ".")))
+
+(defun package-vc-tests-create-bundle (suffix &optional lisp-dir)
+ "Create a test package bundle with SUFFIX.
+If LISP-DIR is non-nil place sources of the package in LISP-DIR."
+ (let* ((name (format "test-package-%s" suffix))
+ (repo-dir (expand-file-name (file-name-concat "repo" name)
+ package-vc-tests-dir)))
+ (make-directory (if lisp-dir
+ (expand-file-name lisp-dir repo-dir)
+ repo-dir)
+ :parents)
+ (let ((default-directory repo-dir)
+ (bundle-file (expand-file-name (format "%s.bundle" name)
+ package-vc-tests-dir)))
+ (vc-git-command nil 0 nil "init" "-b" "master")
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-lib-v0.1.el.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-v0.1.el.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX.texi.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-inc.texi.in" lisp-dir)
+ ;; Place Makefile in root of the repository
+ (package-vc-tests-add
+ suffix "Makefile.in" nil)
+ (vc-git-command nil 0 nil "commit" "-m" "First commit")
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-lib-v0.2.el.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-v0.2.el.in" lisp-dir)
+ (vc-git-command nil 0 nil "commit" "-m" "Second commit")
+ (vc-git-command nil 0 nil
+ "bundle" "create" bundle-file "master")
+ (list bundle-file (vc-git-working-revision nil)))))
+
+(defun package-vc-tests-package-desc (package &optional installed)
+ "Return descriptor of PACKAGE.
+When INSTALLED is non-nil the descriptor will come from `package-alist'.
+Otherwise the descriptor will be from `package-archive-contents'. This
+is to mimic `package-vc--read-package-desc'."
+ (cadr (assoc (if (stringp package) package (symbol-name package))
+ (if installed package-alist package-archive-contents)
+ #'string=3D)))
+
+(defun package-vc-tests-package-lisp-dir (pkg)
+ "Return a Lisp directory of PKG."
+ (and-let* ((checkout-dir (car
+ (alist-get pkg
+ package-vc-tests-packages))))
+ (or (and-let* ((lisp-dir (cadr
+ (alist-get pkg
+ package-vc-tests-packages))))
+ (expand-file-name lisp-dir checkout-dir))
+ checkout-dir)))
+
+(defun package-vc-tests-package-main-file (pkg)
+ "Return a main file of PKG."
+ (file-name-concat (package-vc-tests-package-lisp-dir pkg)
+ (format "%s.el" pkg)))
+
+;; When a package source is being recompiled - for example as result of
+;; `pakckage-vc-upgrade' or `package-vc-rebuild' - it is also reloaded
+;; [1] to ensure that the most recent version of compiled code is
+;; available to Emacs. There are a few tests that add markers in
+;; `load-history' before executing such functions. And then follow up
+;; tests use these markers to assert that expected package files are in
+;; correct places in the `load-history'.
+;;
+;; [1] Only when a file has been loaded previously.
+
+(defun package-vc-tests-load-history-marker (name)
+ "Return a `load-history' marker with NAME."
+ (expand-file-name (symbol-name name)
+ package-vc-tests-dir))
+
+(defun package-vc-tests-load-history-pattern (pkg type)
+ "Return a regexp pattern for PKG's file of TYPE."
+ (pcase type
+ (:autoloads
+ (rx (literal (file-name-concat
+ package-user-dir
+ (symbol-name pkg)
+ (format "%s-autoloads.el" pkg)))
+ string-end))
+ (:main
+ (rx
+ (literal
+ (package-vc-tests-package-main-file pkg))
+ string-end))
+ (:main-compiled
+ (rx
+ (literal
+ (package-vc-tests-package-main-file pkg))
+ "c"
+ string-end))
+ (:marker
+ (rx (literal (package-vc-tests-load-history-marker pkg))))))
+
+(defun package-vc-tests-load-history-position (pkg type)
+ "Return a PKG's file of TYPE position in `load-history'.
+If TYPE is `:autoloads' return a position of a PKG autoloads file.
+Otherwise, if TYPE is `:main' return a position of PKG main file (not
+compiled). Otherwise, if TYPE is `:main-compiled' return a position of
+PKG compiled main file. Otherwise, if TYPE is `:marker' return a
+position of a marker PKG."
+ (let ((pkg-file (package-vc-tests-load-history-pattern pkg type))
+ (interesting-entry
+ (rx string-start
+ (literal (file-truename package-vc-tests-dir)))))
+ (cl-position-if
+ (lambda (file)
+ (string-match pkg-file file))
+ (cl-remove-if-not
+ (lambda (file-name)
+ (string-match interesting-entry file-name))
+ (mapcar
+ #'file-truename
+ (cl-remove-if-not
+ #'stringp
+ (mapcar #'car-safe load-history)))))))
+
+(defun package-vc-tests-explain-load-history-position (pkg type)
+ "Explain `package-vc-tests-load-history' failed for PKG of TYPE."
+ (let ((pattern
+ (concat "..."
+ (substring
+ (package-vc-tests-load-history-pattern pkg type)
+ (length (rx (literal package-vc-tests-dir))))))
+ (reason
+ (if-let* ((pos (package-vc-tests-load-history-position
+ pkg type)))
+ `(found in load-history at pos ,pos)
+ '(not found in load-history)))
+ (entries
+ (mapcar
+ (lambda (file)
+ (concat "..."
+ (substring file (length package-vc-tests-dir))))
+ (cl-remove-if
+ (lambda (file)
+ (or (not (stringp file))
+ (not (string-prefix-p package-vc-tests-dir file))))
+ (mapcar #'car-safe load-history)))))
+ (append (list 'pattern pattern)
+ reason
+ (list entries))))
+
+(put #'package-vc-tests-load-history-position
+ 'ert-explainer
+ #'package-vc-tests-explain-load-history-position)
+
+;; The following predicates and helper functions take an extra PKG
+;; argument. This is needed for ERT to print package name in case of
+;; failure.
+
+(defun package-vc-tests-valid-commit-p (_pkg commit)
+ "Return non-nil when COMMIT is a valid commit."
+ (and (stringp commit)
+ (not (string=3D commit "unknown"))))
+
+(defun package-vc-tests-in-strict-order-p (_pkg &rest args)
+ "Return non-nil when ARGS are in strict order."
+ (apply #'< args))
+
+(defun package-vc-tests-match-p (_pkg regexp string)
+ "Return non-nil when REGEXP matches STRING."
+ (string-match regexp string))
+
+(defun package-vc-tests-buffer-p (_pkg obj)
+ "Return non-nil when OBJ is a buffer."
+ (bufferp obj))
+
+(defun package-vc-tests-elc-files (pkg)
+ "Return elc files for PKG."
+ (when-let* ((dir (package-vc-tests-package-lisp-dir pkg))
+ (elc-files (directory-files
+ dir nil (rx ".elc" string-end))))
+ elc-files))
+
+(defun package-vc-tests-assert-elc (pkg)
+ "Assert that PKG has correct .elc files in."
+ (let* ((dir (package-vc-tests-package-lisp-dir pkg))
+ (elc-files (should (package-vc-tests-elc-files pkg)))
+ (autoloads-rx (rx
+ (literal (format "%s-autoloads.elc" pkg))
+ string-end)))
+ (should-not (cl-find-if (lambda (elc)
+ (string-match autoloads-rx elc))
+ elc-files))
+ (dolist (elc-file elc-files)
+ (delete-file (expand-file-name elc-file dir)))))
+
+(defun package-vc-tests-assert-package-alist (pkg version)
+ "Assert that PKG entry in `package-alist' have correct VERSION and dir."
+ (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
+ (should (equal (file-name-as-directory
+ (expand-file-name (format "%s" pkg)
+ package-user-dir))
+ (file-name-as-directory
+ (package-desc-dir pkg-desc))))
+ (should (equal (list pkg version)
+ (list pkg (package-desc-version pkg-desc))))))
+
+(defun package-vc-tests-reset-head (pkg)
+ "Reset to HEAD^ checkout for PKG."
+ (let ((default-directory (car
+ (alist-get pkg package-vc-tests-packages))))
+ (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))
+
+(defun package-vc-tests-package-head (pkg)
+ "Return HEAD revisions of a PKG."
+ (let ((default-directory (car
+ (alist-get pkg package-vc-tests-packages))))
+ (vc-git-working-revision nil)))
+
+(defmacro with-package-vc-tests-installed (pkg &rest body)
+ "Eval BODY with PKG installed in a test environment."
+ (declare (indent 1) (debug t))
+ ;; git-bundle(1) produces test packages sources in bundle files, based
+ ;; on skeleton files in directory package-vc-resources. Before
+ ;; executing body make sure that:
+ ;;
+ ;; - `package' has been initialised, and there are no
+ ;; `package-archives' defined
+ `(let* ((package-archives (unless package--initialized
+ (let (package-archives)
+ (package-initialize)
+ (package-vc--archives-initialize))
+ nil))
+ ;; - create a temporary location for packages and test files
+ (package-vc-tests-dir
+ (expand-file-name
+ (make-temp-file "package-vc-tests-"
+ t
+ (format-time-string "-%Y%m%d.%H%M%S.%3N"))))
+ ;; - packages are installed into a test directory
+ (package-user-dir (expand-file-name "elpa"
+ package-vc-tests-dir))
+ ;; - define test packages, their checkout locations, lisp
+ ;; directories, and install functions
+ (package-vc-tests-packages
+ `(;; checkout and install with `package-vc-install' (on
+ ;; ELPA)
+ (test-package-1
+ ,(expand-file-name "test-package-1"
+ package-user-dir)
+ nil
+ package-vc-tests-install-from-elpa)
+ ;; checkout and install with `package-vc-install' (not on
+ ;; ELPA)
+ (test-package-2
+ ,(expand-file-name "test-package-2"
+ package-user-dir)
+ nil
+ package-vc-tests-install-from-spec)
+ ;; checkout with `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-3
+ ,(expand-file-name "test-package-3"
+ package-vc-tests-dir)
+ nil
+ pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
+ ;; checkout with git and install with
+ ;; `package-vc-install-from-checkout'
+ (test-package-4
+ ,(expand-file-name "test-package-4"
+ package-vc-tests-dir)
+ nil
+ package-vc-tests-checkout-with-git-install-from-checkout)
+ ;; sources in "lisp" sub directory, checkout and install
+ ;; with `package-vc-install' (not on ELPA)
+ (test-package-5
+ ,(expand-file-name "test-package-5"
+ package-user-dir)
+ "lisp"
+ package-vc-tests-install-from-spec)
+ ;; sources in "lisp" sub directory, checkout with git and
+ ;; install with `package-vc-install-from-checkout'
+ (test-package-6
+ ,(expand-file-name "test-package-6"
+ package-vc-tests-dir)
+ "lisp"
+ package-vc-tests-checkout-with-git-install-from-checkout)
+
+ ;; sources in "src" sub directory, checkout and install
+ ;; with `package-vc-install' (on ELPA)
+ (test-package-7
+ ,(expand-file-name "test-package-7"
+ package-user-dir)
+ "src"
+ package-vc-tests-install-from-elpa)
+ ;; sources in "src" sub directory, checkout with
+ ;; `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-8
+ ,(expand-file-name "test-package-8"
+ package-vc-tests-dir)
+ nil
+ pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
+ ;; sources in "custom-dir" sub directory, checkout and
+ ;; install with `package-vc-install' (on ELPA)
+ (test-package-9
+ ,(expand-file-name "test-package-9"
+ package-user-dir)
+ "custom-dir"
+ package-vc-tests-install-from-elpa)))
+ ;; - create a test package bundle
+ (package-vc-tests-bundle
+ (let* ((pkg-name (symbol-name ,pkg))
+ (suffix (and (string-match
+ (rx ?-
+ (group (one-or-more (not ?-)))
+ string-end)
+ pkg-name)
+ (match-string 1 pkg-name))))
+ (package-vc-tests-create-bundle
+ suffix (cadr (alist-get ,pkg package-vc-tests-packages)))))
+ ;; - find all packages that are present in a test ELPA
+ (package-vc-tests-elpa-packages
+ (mapcar
+ #'car
+ (cl-remove-if-not
+ (lambda (package)
+ (memq
+ (cadddr package)
+ '(package-vc-tests-install-from-elpa
+ pakcage-vc-tests-checkout-from-elpa-install-from-checkou=
t)))
+ package-vc-tests-packages)))
+ ;; - make test packages recognisable by `package' and
+ ;; `package-vc' internals:
+ (package-archive-contents
+ (mapcar
+ (lambda (pkg)
+ (list pkg
+ (package-desc-create
+ :name pkg
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras
+ (list
+ '(:maintainer
+ ("Test Maintainer"
+ . "test-maintainer@HIDDEN"))
+ (cons :url (car package-vc-tests-bundle))
+ (cons :commit (cadr package-vc-tests-bundle))
+ (cons :revdesc (substring
+ (cadr package-vc-tests-bundle)
+ 0 12))))))
+ package-vc-tests-elpa-packages))
+ (package-vc--archive-spec-alists
+ (list
+ (cons 'test-elpa
+ (mapcar
+ (lambda (pkg)
+ (let ((lisp-dir
+ (cadr (alist-get
+ ,pkg package-vc-tests-packages))))
+ (append
+ (list pkg
+ :url (car package-vc-tests-bundle)
+ :branch "master"
+ :doc (let ((doc-file
+ (format "%s.texi" ,pkg)))
+ (if lisp-dir
+ (file-name-concat lisp-dir
+ doc-file)
+ doc-file))
+ :make (format "build-%s" ,pkg)
+ :shell-command (format
+ "touch %s.cmd-build"
+ ,pkg))
+ (and lisp-dir
+ (not (member lisp-dir '("lisp" "src")))
+ (list :lisp-dir lisp-dir)))))
+ package-vc-tests-elpa-packages))))
+ (package-vc--archive-data-alist
+ (list
+ (list 'test-elpa :version 1 :default-vc 'Git)))
+ ;; - `vc-guess-backend-url' is recognising bundles as `Git'
+ ;; repositories:
+ (vc-clone-heuristic-alist
+ (cons
+ (cons (rx "test-package-" (one-or-more digit) ".bundle"
+ string-end)
+ 'Git)
+ vc-clone-heuristic-alist))
+ ;; - ensure that `package-alist' and
+ ;; `package-vc-selected-packages' are empty
+ package-alist
+ package-vc-selected-packages
+ ;; - don't save any customization
+ (user-init-file nil)
+ ;; - FIXME: something sets `default-directory' to last
+ ;; checkout directory after `package-vc-checkout', which
+ ;; causes problems when this macro deletes the temporary
+ ;; directory after body execution.
+ (default-directory package-vc-tests-dir))
+ (unwind-protect
+ (progn
+ (funcall (or (caddr (alist-get ,pkg
+ package-vc-tests-packages))
+ (lambda (pkg)
+ (ert-fail
+ (format
+ "Cannot find %s in package-vc-tests-packages"
+ pkg))))
+ ,pkg)
+ ,@body)
+ ;; Unbind package defined symbols, and remove package defined
+ ;; features and entries from `load-path',`load-history', and
+ ;; `Info-directory-list'.
+ (let ((pattern (rx string-start (literal package-vc-tests-dir))))
+ (dolist (entry load-history)
+ (when-let* ((file (car-safe entry))
+ ((stringp file))
+ ((string-match pattern file)))
+ (dolist (elt (cdr entry))
+ (pcase elt
+ (`(defun . ,fun)
+ (fmakunbound fun))
+ (`(provide . ,feat)
+ (setq features (cl-remove feat features)))
+ ((and (pred symbolp)
+ (pred boundp))
+ (makunbound elt))))))
+ (setq load-path (cl-remove-if
+ (lambda (path)
+ (and (stringp path)
+ (string-match pattern path)))
+ load-path)
+ load-history (cl-remove-if
+ (lambda (entry)
+ (and-let* ((path (car-safe entry))
+ ((stringp path)))
+ (string-match pattern path)))
+ load-history)
+ Info-directory-list (cl-remove-if
+ (lambda (dir)
+ (and (stringp dir)
+ (string-match pattern dir)))
+ Info-directory-list)))
+ (if (or (eq package-vc-tests-preserve-temporary t)
+ (eq package-vc-tests-preserve-temporary ,pkg)
+ (and (listp package-vc-tests-preserve-temporary)
+ (memq ,pkg package-vc-tests-preserve-temporary)))
+ (message "package-vc-tests: preserving temporary directory %s"
+ package-vc-tests-dir)
+ (delete-directory package-vc-tests-dir t)))))
+
+(defun package-vc-tests-install-from-elpa (pkg)
+ "Install PKG with `package-vc-install'."
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (package-vc-install pkg)
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should-not (alist-get (symbol-name pkg)
+ package-vc-selected-packages
+ nil nil #'string=3D)))
+
+(defun package-vc-tests-install-from-spec (pkg)
+ "Install PKG with `package-vc-install' (not on ELPA)."
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (package-vc-install `(,pkg
+ :url ,(car package-vc-tests-bundle)
+ :branch "master"))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (car package-vc-tests-bundle)
+ (plist-get (alist-get (symbol-name pkg)
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+(defun pakcage-vc-tests-checkout-from-elpa-install-from-checkout (pkg)
+ "Install PKG with `package-vc-install-from-checkout'.
+Make checkout with `package-vc-checkout'."
+ (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
+ (package-vc-checkout (package-vc-tests-package-desc
+ pkg)
+ checkout-dir)
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (package-vc-install-from-checkout checkout-dir)
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (concat package-vc--url-scheme checkout-dir)
+ (plist-get (alist-get (symbol-name pkg)
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url)))))
+
+(defun package-vc-tests-checkout-with-git-install-from-checkout (pkg)
+ "Install PKG with `package-vc-install-from-checkout'.
+Make checkout with git(1)."
+ (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
+ (vc-git-clone (car package-vc-tests-bundle)
+ checkout-dir
+ "master")
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (package-vc-install-from-checkout checkout-dir (symbol-name pkg))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (concat package-vc--url-scheme checkout-dir)
+ (plist-get (alist-get (symbol-name pkg)
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url)))))
+
+(defmacro package-vc-tests-package-vc-async-wait (seconds count flags &res=
t body)
+ "Wait up to SECONDS for COUNT async vc commands with FLAGS called by BOD=
Y.
+Return nil on timeout or the value of last form in BODY."
+ (declare (indent 3))
+ (let ((count-sym (make-symbol "count"))
+ (post-vc-command-sym (make-symbol "post-vc-command")))
+ `(letrec ((,count-sym ,count)
+ (,post-vc-command-sym
+ (lambda (command _ command-flags)
+ ;; A crude filter for vc commands
+ (when (and (equal command "git")
+ (cl-every (lambda (flag)
+ (member flag command-flags))
+ ,flags))
+ (decf ,count-sym)))))
+ (add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
+ (unwind-protect
+ (with-timeout (,seconds nil)
+ (prog1
+ (progn ,@body)
+ (while (/=3D ,count-sym 0)
+ (accept-process-output nil 0.01))))
+ (remove-hook 'vc-post-command-functions
+ ,post-vc-command-sym)))))
+
+(ert-deftest package-vc-tests-install-post-conditions ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (let ((install-begin
+ (should (package-vc-tests-load-history-position
+ 'install-begin :marker)))
+ (install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ install-end
+ autoloads-pos
+ install-begin))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled)))
+ (should (equal (package-vc--main-file
+ (package-vc-tests-package-desc pkg t))
+ (package-vc-tests-package-main-file pkg)))
+ (should (package-vc-tests-valid-commit-p
+ pkg
+ (package-vc-commit
+ (package-vc-tests-package-desc pkg t))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))))
+
+(ert-deftest package-vc-tests-require ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should (require pkg))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (let ((install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ main-compiled-pos
+ install-end))))))
+
+(ert-deftest package-vc-tests-upgrade ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade (package-vc-tests-package-desc pkg t))
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-end))
+ load-history)
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ autoloads-pos
+ upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))))
+
+(ert-deftest package-vc-tests-upgrade-after-require ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (should (require pkg))
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade (package-vc-tests-package-desc pkg t))
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-end))
+ load-history)
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ autoloads-pos
+ upgrade-begin))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ main-pos
+ upgrade-begin))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ main-compiled-pos
+ upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))))
+
+(ert-deftest package-vc-tests-upgrade-all ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-end))
+ load-history)
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ autoloads-pos
+ upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))))
+
+(ert-deftest package-vc-tests-upgrade-all-after-require ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (should (require pkg))
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-end))
+ load-history)
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ autoloads-pos
+ upgrade-begin))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ main-pos
+ upgrade-begin))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ main-compiled-pos
+ upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))))
+
+(ert-deftest package-vc-tests-rebuild ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (package-vc-tests-reset-head pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (let ((old-func (intern (format "%s-old-func" pkg))))
+ (should (fboundp old-func))
+ (should (autoloadp
+ (symbol-function old-func))))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "Old macro test"
+ (funcall func "test"))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 1)))))
+
+(ert-deftest package-vc-tests-rebuild-after-require ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (should (require pkg))
+ (package-vc-tests-reset-head pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (let ((old-func (intern (format "%s-old-func" pkg))))
+ (should (fboundp old-func))
+ (should-not (autoloadp
+ (symbol-function old-func))))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
+ (symbol-function func)))
+ (should (equal "Old macro test"
+ (funcall func "test"))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 1)))))
+
+(ert-deftest package-vc-tests-prepare-patch ()
+ ;; Ensure `vc-prepare-patch' respects subject from function argument
+ (let (vc-prepare-patches-separately)
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (package-vc-prepare-patch (package-vc-tests-package-desc pkg t)
+ "test-subject"
+ (cdr package-vc-tests-bundle))
+ (let ((message-buffer
+ (should (get-buffer "*unsent mail to Test Maintainer*"))))
+ (should (package-vc-tests-buffer-p pkg message-buffer))
+ (switch-to-buffer message-buffer)
+ (goto-char (point-min))
+ (should
+ (package-vc-tests-match-p
+ pkg
+ (rx
+ "To: Test Maintainer <test-maintainer@HIDDEN>")
+ (buffer-substring (point) (pos-eol))))
+ (forward-line)
+ (should
+ (package-vc-tests-match-p
+ pkg
+ (rx "Subject: test-subject")
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer message-buffer)))))))
+
+(ert-deftest package-vc-tests-log-incoming ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (package-vc-tests-reset-head pkg)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 1 '("log" "--decorate")
+ (package-vc-log-incoming (package-vc-tests-package-desc pkg t))
+ t))
+ (let ((incoming-buffer (get-buffer "*vc-incoming*"))
+ (pattern (rx (literal
+ (substring
+ (cadr package-vc-tests-bundle)
+ 0 7))
+ (one-or-more any)
+ "Second commit"
+ line-end)))
+ (should (package-vc-tests-buffer-p pkg incoming-buffer))
+ (switch-to-buffer incoming-buffer)
+ (goto-char (point-min))
+ (should
+ (package-vc-tests-match-p
+ pkg
+ pattern
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer incoming-buffer))))))
+
+(ert-deftest package-vc-tests-pkg-spec-doc-make-shell-command ()
+ (let ((package-vc-allow-build-commands t))
+ ;; Only `packge-vc-install' runs make and shell command
+ (dolist (pkg '(test-package-1 test-package-7 test-package-9))
+ (with-package-vc-tests-installed pkg
+ (let ((checkout-dir (car (alist-get
+ pkg package-vc-tests-packages))))
+ (should (file-exists-p
+ (expand-file-name
+ (format "%s.make-build" pkg)
+ checkout-dir)))
+ (should (file-exists-p
+ (expand-file-name
+ (format "%s.cmd-build" pkg)
+ checkout-dir))))
+ (should (cl-member-if (lambda (dir)
+ (and (stringp dir)
+ (string-prefix-p package-vc-tests-dir
+ dir)))
+ Info-directory-list))
+ (let ((info-file
+ (expand-file-name (format "%s.info" pkg)
+ (car (alist-get
+ pkg package-vc-tests-packages)))))
+ (should (file-exists-p info-file))
+ (ert-with-test-buffer
+ (:name (format "*package-vc-tests: %s.info*" pkg))
+ (insert-file-contents info-file)
+ (goto-char (point-min))
+ (should (re-search-forward
+ (format "First chapter for %s" pkg)))
+ (should (re-search-forward
+ (format "Second chapter for %s" pkg)))))))))
+
+(provide 'package-vc-tests)
+
+;;; package-vc-tests.el ends here
--=20
2.51.2
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Mon, 17 Nov 2025 21:17:02 +0000
Resent-Message-ID: <handler.79188.B79188.17634142132867 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org, Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17634142132867
(code B ref 79188); Mon, 17 Nov 2025 21:17:02 +0000
Received: (at 79188) by debbugs.gnu.org; 17 Nov 2025 21:16:53 +0000
Received: from localhost ([127.0.0.1]:54234 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vL6ae-0000k0-BY
for submit <at> debbugs.gnu.org; Mon, 17 Nov 2025 16:16:53 -0500
Received: from mout01.posteo.de ([185.67.36.65]:46043)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1vL6aX-0000jP-Nt
for 79188 <at> debbugs.gnu.org; Mon, 17 Nov 2025 16:16:47 -0500
Received: from submission (posteo.de [185.67.36.169])
by mout01.posteo.de (Postfix) with ESMTPS id 6EC36240027
for <79188 <at> debbugs.gnu.org>; Mon, 17 Nov 2025 22:16:34 +0100 (CET)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1763414194; bh=xLlyv/QGVkvXfvk6asIIOw8IFnVwFe33E5n7GiXQTF8=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:Content-Transfer-Encoding:From;
b=SBDJUAPoDDYo/L4yMeEQ+o+GeZxITzXyUQAAFWKU6Xv7VAXJIXlf+aefO3JsvvjV/
eIUrtZ+5fWMqY4BPs6yzNfIu99i6YgfGPwph4/dCoi0GgNjQsmnlQXLV/do+LGooQJ
4Aof5vzbwtqb5iqEo+sWlCVC3aoPRT8SBHnd67hBnGHQ9KVdZZhJyDFvnMZmArjpfo
KxSf+KpCm8T8lUWGVvnR742CltQZJ+6u7zEEONqdjp5k8KgYCuANJCQz3f8vHZh+t9
rAxr9eZy7SzBkR3WNJZ7qXU5w7+tW7fB972efgEsG6TWlfyFOi/cFHMy0ApE8OhClV
nXBr/F4i57IMg==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4d9LCP1p3Qz6tw4;
Mon, 17 Nov 2025 22:16:33 +0100 (CET)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2bjl0vidc.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<m24iqzmqh6.fsf@HIDDEN> <m28qgbqsx0.fsf_-_@HIDDEN>
<m2tsyzjek4.fsf@HIDDEN> <875xbcbg0f.fsf@HIDDEN>
<m2bjl0vidc.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Mon, 17 Nov 2025 21:16:33 +0000
Message-ID: <87y0o4nyvi.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
[...]
> So I applied this patch, and it seems to that :dir slot of a package
> installed from checkout is incorrect., for example:
>
> (require 'vc-git)
> (require 'package-vc)
> (setq package-user-dir (expand-file-name "~/tmp/elpa" ))
> (shell-command "git clone https://gitlab.com/koral/gcmh.git ~/tmp/gcmh")
> (package-vc-install-from-checkout "~/tmp/gcmh" "gcmh")
> (package-desc-dir (cadr (assq 'gcmh package-alist)))
> ;; =3D> "/Users/pkryger/tmp/gcmh"
>
> I'd expect it to be /Users/pkryger/tmp/elpa/gcmh (note the 'elpa' in
> path). I guess corruption like that will cause more than one issue, but
> the first I found is that calling:
>
> (package-delete (cadr (assq 'gcmh package-alist)))
>
> yields the following back trace (limiting relevant frames):
>
> signal(error ("Package =E2=80=98gcmh=E2=80=99 is a system package, not =
deleting"))
> error("Package `%s' is a system package, not deleting" "gcmh")
> package-delete(#s(package-desc :name gcmh :version (0 2 1) :summary
> "the Garbage Collector Magic Hack" :reqs ((emacs (24))) :kind vc
> :archive nil :dir "/Users/pkryger/tmp/gcmh" :extras ((:vc-dir
> . "/Users/pkryger/tmp/gcmh") (:commit
> . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9")) :signed nil))
> (progn (package-delete (car (cdr (assq 'gcmh package-alist)))))
> eval((progn (package-delete (car (cdr (assq 'gcmh package-alist))))) t)
Thanks for checking! It helps me out a lot ^^
> I am attaching updated patches. I re-wrote tests to be executable in
> regular Emacs session (although I haven't got to a point where I run
> them under a development Emacs yet). With this it was so much easier to
> add a few more tests, and I found that there's another issue with how a
> package is rebuild. It manifests itself with a compilation using
> preciously defined macro definitions, i.e., when macro has been changed
> then the new version is not used.
Hmm, we might have to use something like `unload-feature' here, but
inherently this is an issue that regular tarball packages should also
have. I would have thought that `package--reload-previously-loaded'
should take care of that...
> @Philip: I merged your initial patch into mine, so it's easier to apply
> on top of master. I hope I am not doing anything wrong here.
Of course not.
> I also think that using :vc-dir in :extras slot is a viable candidate.
> However, I haven't had a chance to apply it yet.
If you want to, I can take a shot at updating the patch to use :extras
as Michelangelo proposed. That way I'll also have a better
understanding of the patch, compared to just reading it.
> @Michelangelo: I again strongly recommend using tests from the patch.
> While requiring a bit of fiddling, it should be quite easy to adjust
> them to your implementation, e.g., remove assertions that relate to
> `package-vc-selected-packages`.
>
> From e509427dd760eb9ac69d68a9c9322f78b9c59bb7 Mon Sep 17 00:00:00 2001
> From: Philip Kaludercic <philipk@HIDDEN>
> Date: Fri, 26 Sep 2025 14:00:54 +0100
> Subject: [PATCH 1/2] Fix upgrading, rebuilding, and logging of VC packages
>
> There are a few issues addressed in this patch:
>
> 1. Compilation (including native compilation) should happen in
> directory that contains package's Lisp code.
>
> 2. After installing a package with
> `package-vc-install-from-checkout' and subsequently upgrading it
> with `package-vc-upgrade' the pkg-desc for the package becomes
> corrupted. After the upgrade the pkg-desc's dir (a.k.a
> `pkg-dir') points to checkout directory. This will cause the
> subsequent `package-delete' to delete the checkout directory and
> leaving incorrect forwarding autoloads file in
> `package-user-directory'.
>
> 3. The detection of package's Lisp directory has been not
> effective for packages installed with `package-vc-install' and
> not existent for packages installed with
> `package-install-from-checkout'.
>
> 4. Deduction of VC backend has been not working when called from
> outside of deducing context.
>
> 5. Extract maintainers and store them in a package description
> file when installing a package from a checkout.
>
> * lisp/emacs-lisp/package-vc.el (package-vc--checkout-dir): New
> function to determine the real checkout of a VC
> package.
>
> (package-vc--url-scheme): Define scheme for `:url' property.
>
> (package-vc--generate-description-file): Extract maintainers
> from main package file and store them in generated description
> file.
>
> (package-vc--save-selected-packages): Refactor new helper
> function out of 'package-vc--unpack' to modify
> 'package-vc-selected-packages'.
>
> (package-vc--checkout-dir): Use `pcase' to extract checkout
> directory from `pkg-spec'. Detect standard lisp sub directory
> if called with non-nil `lisp-dir'.
>
> (package-vc-commit, package-vc--main-file)
> (package-vc--build-documentation, package-vc-prepare-patch): Use
> 'package-vc--checkout-dir'.
>
> (package-vc--unpack-1): Remove superfluous `pkg-dir' argument.
> Remove elc files before compilation. Use a `package' with
> `:dir' pointing to where package code is. When `checkout-dir'
> is different than `pkg-dir' then call `package--add-info-node'
> and after calling `package-activate-1' reload source files in
> case when `lisp-dir' is a sub directory. Use the right
> directories in the right places.
>
> (package-vc-install-from-checkout): Remove superfluous
> `package-vc-selected-packages' binding. Remove `pkg-dir'
> argument from `package-vc--unpack-1' calls.
>
> (package-vc--unpack): Remove `lisp-dir' variable and convert to
> `let*'. Remove superfluous Lisp code sub directory detection -
> logic moved to `package-vc--checkout-dir'. Remove `pkg-dir'
> argument from `package-vc--unpack-1' call. Use
> 'package-vc--save-selected-packages'.
>
> (package-vc-upgrade, package-vc-rebuild): Remove `pkg-dir'
> argument from `package-vc--unpack-1' calls. Use
> 'package-vc--checkout-dir'.
>
> (package-vc-log-incoming): Set `vc-deduce-backend-nonvc-modes'
> to t. Use 'package-vc--checkout-dir'.
>
> * lisp/emacs-lisp/package.el (package--add-info-node): New
> function to install info node for package. Extracted from
> `package-activate-1'.
>
> (package-activate-1): Call `package--add-info-node'.
>
> Co-developed-by: Philip Kaludercic <philipk@HIDDEN>
>
> (Bug#79188)
> ---
> lisp/emacs-lisp/package-vc.el | 329 ++++++++++++++++++++++------------
> lisp/emacs-lisp/package.el | 15 +-
> 2 files changed, 225 insertions(+), 119 deletions(-)
>
> diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
> index 6642522d11e..a53ffff399b 100644
> --- a/lisp/emacs-lisp/package-vc.el
> +++ b/lisp/emacs-lisp/package-vc.el
> @@ -31,8 +31,7 @@
> ;; aren't interested in activating a package, you can use
> ;; `package-vc-checkout' instead, which will prompt you for a target
> ;; directory. If you wish to reuse an existing checkout, the command
> -;; `package-vc-install-from-checkout' will create a symbolic link and
> -;; prepare the package.
> +;; `package-vc-install-from-checkout' will prepare the package.
> ;;
> ;; If you make local changes that you wish to share with an upstream
> ;; maintainer, the command `package-vc-prepare-patch' can prepare
> @@ -85,6 +84,12 @@ package-vc-register-as-project
>
> (defvar package-vc-selected-packages) ; pacify byte-compiler
>
> +(defconst package-vc--url-scheme
> + (if (memq system-type '(ms-dos windows-nt cygwin))
> + "file:///"
> + "file://")
> + "Scheme for `:url' property in package spec.")
>
> ;;;###autoload
> (defun package-vc-install-selected-packages ()
> "Ensure packages specified in `package-vc-selected-packages' are insta=
lled."
> @@ -173,6 +178,47 @@ package-vc--desc->spec
> (mapcar #'cdr package-vc--archive-spec-alists=
))))
> '() nil #'string=3D))
>
> +(defun package-vc--checkout-dir (pkg-desc &optional lisp-dir)
> + "Return the directory of the actual VC checkout for PKG-DESC.
> +For most packages this is the same as `package-desc-dir', unless the
> +package has been installed via `package-vc-install-from-checkout'. In
> +that case the package redirects to the actual VC checkout. If the
> +optional LISP-DIR argument is non-nil, then check if a related package
> +specification has a `:lisp-dir' field to indicate that Lisp files are
> +located in a sub directory of the checkout, or the checkout has a sub
> +directory named \"lisp\" or \"src\" that contains .el files and return
> +that instead."
> + (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> + (pkg-dir (pcase (plist-get pkg-spec :url)
> + ((rx (literal package-vc--url-scheme)
> + (let checkout-dir (+ any)))
> + checkout-dir)
> + (_ (package-desc-dir pkg-desc)))))
> + (expand-file-name
> + (or (and lisp-dir
> + (or (plist-get pkg-spec :lisp-dir)
> + ;; When nothing is specified about a `lisp-dir', then
> + ;; should heuristically check if there is a
> + ;; sub-directory with lisp files. These are
> + ;; conventionally just called "lisp" or "src". If
> + ;; this directory exists and contains non-zero number
> + ;; of lisp files, we will use that instead of
> + ;; `pkg-dir'.
> + (catch 'done
> + (dolist (name '("lisp" "src"))
> + (when-let* ((dir (expand-file-name name pkg-dir))
> + ((file-directory-p dir))
> + ((directory-files
> + dir nil "\\`[^.].+\\.el\\'" t 1)))
> + ;; We won't use `dir', since dir is an absolute
> + ;; path and we don't want `lisp-dir' to depend
> + ;; on the current location of the package
> + ;; installation, ie. to break if moved around
> + ;; the file system or between installations.
> + (throw 'done name))))))
> + ".")
Why are we falling back to "."?
> + pkg-dir)))
> +
> (defun package-vc--read-archive-data (archive)
> "Update `package-vc--archive-spec-alists' for ARCHIVE.
> This function is meant to be used as a hook for `package-read-archive-ho=
ok'."
> @@ -219,9 +265,7 @@ package-vc-commit
> ;; FIXME: vc should be extended to allow querying the commit of a
> ;; directory (as is possible when dealing with git repositories).
> ;; This should be a fallback option.
> - (cl-loop with dir =3D (let ((pkg-spec (package-vc--desc->spec pkg-desc=
)))
> - (or (plist-get pkg-spec :lisp-dir)
> - (package-desc-dir pkg-desc)))
> + (cl-loop with dir =3D (package-vc--checkout-dir pkg-desc 'lisp-dir)
> for file in (directory-files dir t "\\.el\\'" t)
> when (vc-working-revision file) return it
> finally return "unknown"))
> @@ -243,10 +287,7 @@ package-vc--main-file
> (cl-assert (package-vc-p pkg-desc))
> (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> (name (symbol-name (package-desc-name pkg-desc)))
> - (directory (expand-file-name
> - (or (plist-get pkg-spec :lisp-dir) ".")
> - (or (package-desc-dir pkg-desc)
> - (expand-file-name name package-user-dir))))
> + (directory (package-vc--checkout-dir pkg-desc 'lisp-dir))
> (file (expand-file-name
> (or (plist-get pkg-spec :main-file)
> (concat name ".el"))
> @@ -272,7 +313,9 @@ package-vc--main-file
>
> (defun package-vc--generate-description-file (pkg-desc pkg-file)
> "Generate a package description file for PKG-DESC and write it to PKG-=
FILE."
> - (let ((name (package-desc-name pkg-desc)))
> + (let ((name (package-desc-name pkg-desc))
> + (main-file (let ((file (package-vc--main-file pkg-desc)))
> + (and (file-exists-p file) file))))
> (when (equal (package-desc-summary pkg-desc) package--default-summar=
y)
> ;; We unset the package description if it is just the default
> ;; summary, so that the following heuristic can take effect.
> @@ -280,13 +323,12 @@ package-vc--generate-description-file
> ;; Infer the package description if missing.
> (unless (package-desc-summary pkg-desc)
> (setf (package-desc-summary pkg-desc)
> - (let ((main-file (package-vc--main-file pkg-desc)))
> - (or (package-desc-summary pkg-desc)
> - (and-let* ((pkg (cadr (assq name package-archive-conte=
nts))))
> - (package-desc-summary pkg))
> - (and main-file (file-exists-p main-file)
> - (lm-summary main-file))
> - package--default-summary))))
> + (or (package-desc-summary pkg-desc)
> + (and-let* ((pkg (cadr (assq name package-archive-content=
s))))
> + (package-desc-summary pkg))
> + (and main-file
> + (lm-summary main-file))
> + package--default-summary)))
> (let ((print-level nil)
> (print-quoted t)
> (print-length nil))
> @@ -316,6 +358,16 @@ package-vc--generate-description-file
> (let ((extras (copy-alist (package-desc-extras pkg-desc))))
> (setf (alist-get :commit extras)
> (package-vc-commit pkg-desc))
> + (when-let* (((null (alist-get :maintainer extras)))
> + (main-file)
> + (maintainers (lm-maintainers main-file)))
> + ;; Like in `pakcage-buffer-info', for backward
> + ;; compatibility, use a single cons-cell if there's
> + ;; only one maintainer.
> + (setf (alist-get :maintainer extras)
> + (if (cdr maintainers)
> + maintainers
> + (car maintainers))))
> extras)
> )))
> "\n")
> @@ -351,7 +403,8 @@ package-vc--make
> "Process :make and :shell-command in PKG-SPEC.
> PKG-DESC is the package descriptor for the package that is being
> prepared."
> - (let ((target (plist-get pkg-spec :make))
> + (let ((default-directory (package-vc--checkout-dir pkg-desc))
> + (target (plist-get pkg-spec :make))
> (cmd (plist-get pkg-spec :shell-command))
> (buf (format " *package-vc make %s*" (package-desc-name pkg-desc=
))))
> (when (or cmd target)
> @@ -369,7 +422,7 @@ package-vc--build-documentation
> FILE can be an Org file, indicated by its \".org\" extension,
> otherwise it's assumed to be an Info file."
> (let* ((pkg-name (package-desc-name pkg-desc))
> - (default-directory (package-desc-dir pkg-desc))
> + (default-directory (package-vc--checkout-dir pkg-desc))
> (docs-directory (file-name-directory (expand-file-name file)))
> (output (expand-file-name (format "%s.info" (file-name-base fil=
e))))
> (log-buffer (get-buffer-create (format " *package-vc doc: %s*" =
pkg-name)))
> @@ -455,15 +508,25 @@ package-vc-install-dependencies
> (mapc #'package-install-from-archive to-install)
> missing))
>
> -(defun package-vc--unpack-1 (pkg-desc pkg-dir)
> - "Prepare PKG-DESC that is already checked-out in PKG-DIR.
> -This includes downloading missing dependencies, generating
> -autoloads, generating a package description file (used to
> -identify a package as a VC package later on), building
> -documentation and marking the package as installed."
> - (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
> - (lisp-dir (plist-get pkg-spec :lisp-dir))
> - (lisp-path (expand-file-name (or lisp-dir ".") pkg-dir))
> +(defun package-vc--unpack-1 (pkg-desc)
> + "Prepare PKG-DESC that is already checked-out.
> +When there's a relevant pkg-spec it is used for checkout directory.
> +Otherwise `dir' slot of PKG-SPEC is used. This includes downloading
> +missing dependencies, generating autoloads, generating a package
> +description file (used to identify a package as a VC package later on),
> +building documentation and marking the package as installed."
> + (let* (;; Main package directory, under `package-user-dir'. This is
> + ;; the same `checkout-dir' when package has been installed with
> + ;; `package-vc-install'.
> + (pkg-dir (package-desc-dir pkg-desc))
> + (pkg-spec (package-vc--desc->spec pkg-desc))
> + ;; Directory where the package repository has been checked out.
> + ;; This is the `dir' argument of
> + ;; `package-vc-install-from-checkout'.
> + (checkout-dir (package-vc--checkout-dir pkg-desc))
> + ;; Directory where package's Lisp code resides. It may be
> + ;; equal to `checkout-dir' or be a subdirectory of it.
> + (lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
> missing)
>
> ;; In case the package was installed directly from source, the
> @@ -475,13 +538,13 @@ package-vc--unpack-1
> (lambda (ignore)
> (wildcard-to-regexp
> (if (string-match-p "\\`/" ignore)
> - (concat pkg-dir ignore)
> + (concat checkout-dir ignore)
> (concat "*/" ignore))))
> (plist-get pkg-spec :ignored-files)
> "\\|")
> regexp-unmatchable))
> (deps '()))
> - (dolist (file (directory-files lisp-path t "\\.el\\'" t))
> + (dolist (file (directory-files lisp-dir t "\\.el\\'" t))
> (unless (string-match-p ignored-files file)
> (with-temp-buffer
> (insert-file-contents file)
> @@ -500,59 +563,111 @@ package-vc--unpack-1
> missing)
> missing)))
>
> - (let ((default-directory (file-name-as-directory pkg-dir))
> - (pkg-file (expand-file-name (package--description-file pkg-dir=
) pkg-dir)))
> - ;; Generate autoloads
> - (let* ((name (package-desc-name pkg-desc))
> - (auto-name (format "%s-autoloads.el" name)))
> - (package-generate-autoloads name lisp-path)
> - (when lisp-dir
> - (write-region
> - (with-temp-buffer
> - (insert ";; Autoload indirection for package-vc\n\n")
> - (prin1 `(load (expand-file-name
> - ,(expand-file-name auto-name lisp-dir)
> - (or (and load-file-name
> - (file-name-directory load-file-name=
))
> - (car load-path))))
> - (current-buffer))
> - (buffer-string))
> - nil (expand-file-name auto-name pkg-dir))))
> + ;; Generate autoloads
> + (let* ((name (package-desc-name pkg-desc))
> + (auto-name (format "%s-autoloads.el" name)))
> + (package-generate-autoloads name lisp-dir)
> + ;; There are two cases when we wish to "indirect" the loading of
> + ;; autoload files:
> + ;;
> + ;; 1. a package specification has a `:lisp-dir' entry listing
> + ;; indicting that the actual Lisp code is located in a
> + ;; subdirectory of the checkout,
> + ;;
> + ;; 2. the package has been installed using
> + ;; `package-vc-install-from-checkout' and we want to load the
> + ;; other directory instead -- which is outside of the checkout.
> + ;; We can therefore take file inequality as a sign that we have to
> + ;; set up an indirection.
> + (unless (file-equal-p lisp-dir pkg-dir)
> + (write-region
> + (concat
> + ";; Autoload indirection for package-vc\n\n"
> + (prin1-to-string
> + ;; The indirection is just a single load statement to the
> + ;; actual file (we don't want to use symbolic links due to
> + ;; portability reasons). Detecting which of the two cases
> + ;; mentioned above we are setting up can be done by checking
> + ;; if the directory with the lisp code is a subdirectory of
> + ;; the package directory.
> + `(load ,(if (file-in-directory-p lisp-dir pkg-dir)
> + `(expand-file-name
> + ,(file-relative-name
> + (expand-file-name auto-name lisp-dir)
> + pkg-dir)
> + (or (and load-file-name
> + (file-name-directory load-file-name))
> + (car load-path)))
> + (expand-file-name auto-name lisp-dir)))))
> + nil (expand-file-name auto-name pkg-dir))))
>
> - ;; Generate package file
> - (package-vc--generate-description-file pkg-desc pkg-file)
> + ;; Generate package file
> + (let ((pkg-file (expand-file-name (package--description-file pkg-dir=
) pkg-dir)))
> + (package-vc--generate-description-file pkg-desc pkg-file))
>
> - ;; Process :make and :shell-command arguments before building docu=
mentation
> - (when (or (eq package-vc-allow-build-commands t)
> - (memq (package-desc-name pkg-desc)
> - package-vc-allow-build-commands))
> - (package-vc--make pkg-spec pkg-desc))
> + ;; Process :make and :shell-command arguments before building docume=
ntation
> + (when (or (eq package-vc-allow-build-commands t)
> + (memq (package-desc-name pkg-desc)
> + package-vc-allow-build-commands))
> + (package-vc--make pkg-spec pkg-desc))
>
> - ;; Detect a manual
> - (when (executable-find "install-info")
> - (dolist (doc-file (ensure-list (plist-get pkg-spec :doc)))
> - (package-vc--build-documentation pkg-desc doc-file))))
> + ;; Detect a manual
> + (when (executable-find "install-info")
> + (dolist (doc-file (ensure-list (plist-get pkg-spec :doc)))
> + (package-vc--build-documentation pkg-desc doc-file)))
>
> ;; Remove any previous instance of PKG-DESC from `package-alist'
> (let ((pkgs (assq (package-desc-name pkg-desc) package-alist)))
> (when pkgs
> (setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
>
> + ;; Remove all compiled files to allow for macros to be used from
> + ;; source files, regardless of order of source files compilation and
> + ;; load ordering. As a side effect there are no compiled files for
> + ;; source files that no longer exist.
> + (dolist (elc-file (directory-files-recursively
> + lisp-dir
> + (rx string-start
> + (not ".") (zero-or-more any) ".elc"
> + string-end)
> + nil
> + (lambda (dir)
> + (and (file-accessible-directory-p dir)
> + (not (string-prefix-p "." dir))))))
> + (delete-file elc-file))
> +
> ;; Update package-alist.
> - (let ((new-desc (package-load-descriptor pkg-dir)))
> + (let* ((new-desc (package-load-descriptor pkg-dir))
> + (compile-desc (package-desc-create :name (package-desc-name n=
ew-desc)
> + :dir lisp-dir)))
> ;; Activation has to be done before compilation, so that if we're
> ;; upgrading and macros have changed we load the new definitions
> ;; before compiling.
> (when (package-activate-1 new-desc :reload :deps)
> + ;; `package-activate-1' will reload all necessary package files
> + ;; as long as their stems are relative to of `pkg-dir'. If
> + ;; that's not the case (for example for packages with different
> + ;; `checkout-dir' or with source files in a sub directory of
> + ;; `pkg-dir'), we want to reload package files from the
> + ;; `lisp-dir' before compilation.
> + (unless (file-equal-p lisp-dir pkg-dir)
> + (package--reload-previously-loaded compile-desc))
> + ;; `package-activate-1' will add info node as long as dir file
> + ;; exists in `pkg-dir'. We need to manually add it when
> + ;; `checkout-dir' is in different location.
> + (unless (file-equal-p checkout-dir pkg-dir)
> + (package--add-info-node checkout-dir))
> ;; FIXME: Compilation should be done as a separate, optional, st=
ep.
> ;; E.g. for multi-package installs, we should first install all =
packages
> ;; and then compile them.
> - (package--compile new-desc)
> + (package--compile compile-desc)
> (when package-native-compile
> - (package--native-compile-async new-desc))
> + (package--native-compile-async compile-desc))
> ;; After compilation, load again any files loaded by
> - ;; `activate-1', so that we use the byte-compiled definitions.
> - (package--reload-previously-loaded new-desc)))
> + ;; `package-activate-1', so that we use the byte-compiled
> + ;; definitions. This time we'll use `compile-desc' straight
> + ;; away.
> + (package--reload-previously-loaded compile-desc)))
>
> ;; Mark package as selected
> (let ((name (package-desc-name pkg-desc)))
> @@ -572,12 +687,12 @@ package-vc--unpack-1
> (lm-header "version"))))
> (vc-working-revision main-file)
> (if missing
> - (format
> - " Failed to install the following dependencies: %s"
> - (mapconcat
> - (lambda (p)
> - (format "%s (%s)" (car p) (cadr p)))
> - missing ", "))
> + (format
> + " Failed to install the following dependencies: %s"
> + (mapconcat
> + (lambda (p)
> + (format "%s (%s)" (car p) (cadr p)))
> + missing ", "))
> "")))
> t))
I think I mentioned this before, but this seems like an unrelated
change, right?
> @@ -622,6 +737,14 @@ package-vc-non-code-file-names
> user is fetching code from a repository that does not contain any
> Emacs Lisp files.")
>
> +(defun package-vc--save-selected-packages (name pkg-spec)
> + "Save the package specification PKG-SPEC for a package NAME."
> + (customize-save-variable
> + 'package-vc-selected-packages
> + (cons (cons name pkg-spec)
> + (seq-remove (lambda (spec) (string=3D name (car spec)))
> + package-vc-selected-packages))))
We will probably not need this if we go with the :extras solution.
> (defun package-vc--unpack (pkg-desc pkg-spec &optional rev)
> "Install the package described by PKG-DESC.
> PKG-SPEC is a package specification, a property list describing
> @@ -632,10 +755,9 @@ package-vc--unpack
> (let ((copy (copy-package-desc pkg-desc)))
> (setf (package-desc-kind copy) 'vc
> pkg-desc copy)))
> - (pcase-let* (((map :lisp-dir) pkg-spec)
> - (name (package-desc-name pkg-desc))
> - (dirname (package-desc-full-name pkg-desc))
> - (pkg-dir (file-name-as-directory (expand-file-name dirnam=
e package-user-dir))))
> + (let* ((name (package-desc-name pkg-desc))
> + (dirname (package-desc-full-name pkg-desc))
> + (pkg-dir (file-name-as-directory (expand-file-name dirname pack=
age-user-dir))))
> (when (string-empty-p name)
> (user-error "Empty package name"))
> (setf (package-desc-dir pkg-desc) pkg-dir)
> @@ -656,33 +778,11 @@ package-vc--unpack
> (delete-directory pkg-dir t)
> (user-error "Installation aborted")))
>
> - ;; When nothing is specified about a `lisp-dir', then should
> - ;; heuristically check if there is a sub-directory with lisp
> - ;; files. These are conventionally just called "lisp" or "src".
> - ;; If this directory exists and contains non-zero number of lisp
> - ;; files, we will use that instead of `pkg-dir'.
> - (catch 'done
> - (dolist (name '("lisp" "src"))
> - (when-let* (((null lisp-dir))
> - (dir (expand-file-name name pkg-dir))
> - ((file-directory-p dir))
> - ((directory-files dir nil "\\`[^.].+\\.el\\'" t 1)))
> - ;; We won't use `dir', since dir is an absolute path and we
> - ;; don't want `lisp-dir' to depend on the current location of
> - ;; the package installation, ie. to break if moved around the
> - ;; file system or between installations.
> - (throw 'done (setq lisp-dir name)))))
> -
> ;; Ensure we have a copy of the package specification
> - (unless (seq-some (lambda (alist) (equal (alist-get name (cdr alist)=
) pkg-spec))
> - package-vc--archive-spec-alists)
> - (customize-save-variable
> - 'package-vc-selected-packages
> - (cons (cons name pkg-spec)
> - (seq-remove (lambda (spec) (string=3D name (car spec)))
> - package-vc-selected-packages))))
> + (when (null (package-vc--desc->spec pkg-desc name))
> + (package-vc--save-selected-packages name pkg-spec))
>
> - (package-vc--unpack-1 pkg-desc pkg-dir)))
> + (package-vc--unpack-1 pkg-desc)))
>
> (defun package-vc--read-package-name (prompt &optional allow-url install=
ed)
> "Query the user for a VC package and return a name with PROMPT.
> @@ -750,7 +850,7 @@ package-vc-upgrade
> ;;
> ;; If there is a better way to do this, it should be done.
> (cl-assert (package-vc-p pkg-desc))
> - (letrec ((pkg-dir (package-desc-dir pkg-desc))
> + (letrec ((checkout-dir (package-vc--checkout-dir pkg-desc))
> (vc-flags)
> (vc-filter-command-function
> (lambda (command file-or-list flags)
> @@ -758,18 +858,19 @@ package-vc-upgrade
> (list command file-or-list flags)))
> (post-upgrade
> (lambda (_command _file-or-list flags)
> - (when (and (file-equal-p pkg-dir default-directory)
> + (when (and (file-equal-p checkout-dir default-directory)
> (eq flags vc-flags))
> (unwind-protect
> (with-demoted-errors "Failed to activate: %S"
> - (package-vc--unpack-1 pkg-desc pkg-dir))
> + (package-vc--unpack-1 pkg-desc))
> (remove-hook 'vc-post-command-functions post-upgrade))=
))))
> (add-hook 'vc-post-command-functions post-upgrade)
> (with-demoted-errors "Failed to fetch: %S"
> (require 'vc-dir)
> (with-current-buffer (vc-dir-prepare-status-buffer
> - (format " *package-vc-dir: %s*" pkg-dir)
> - pkg-dir (vc-responsible-backend pkg-dir))
> + (format " *package-vc-dir: %s*" checkout-dir)
> + checkout-dir
> + (vc-responsible-backend checkout-dir))
> (vc-pull)))))
>
> (defun package-vc--archives-initialize ()
> @@ -934,21 +1035,22 @@ package-vc-install-from-checkout
> (package-vc--archives-initialize)
> (let* ((dir (if interactive dir (expand-file-name dir))) ;avoid double=
expansion
> (name (or name (file-name-base (directory-file-name dir))))
> - (pkg-dir (file-name-concat package-user-dir name))
> - (package-vc-selected-packages
> - (cons (list name :lisp-dir dir)
> - package-vc-selected-packages)))
> + (pkg-dir (file-name-concat package-user-dir name)))
> (when (file-exists-p pkg-dir)
> (if (yes-or-no-p (format "Overwrite previous checkout for package =
`%s'?" name))
> (package--delete-directory pkg-dir)
> (error "There already exists a checkout for %s" name)))
> (make-directory pkg-dir t)
> + ;; We store a custom package specification so that it is available
> + ;; for `package-vc--unpack-1' as well as `package-vc--checkout-dir'
> + ;; can later retrieve the actual checkout.
> + (package-vc--save-selected-packages
> + name (list :url (concat package-vc--url-scheme dir)))
> (package-vc--unpack-1
> (package-desc-create
> :name (intern name)
> :dir pkg-dir
> - :kind 'vc)
> - (file-name-as-directory pkg-dir))))
> + :kind 'vc))))
The commit message doesn't appear to explain this change. I am not sure
if we have already been over it, but changing the return value of a
non-internal function like this is not something we shouldn't do for no
reason.
> ;;;###autoload
> (defun package-vc-rebuild (pkg-desc)
> @@ -960,7 +1062,7 @@ package-vc-rebuild
> is the responsibility of `package-vc-upgrade'. Interactively,
> prompt for the name of the package to rebuild."
> (interactive (list (package-vc--read-package-desc "Rebuild package: " =
t)))
> - (package-vc--unpack-1 pkg-desc (package-desc-dir pkg-desc)))
> + (package-vc--unpack-1 pkg-desc))
>
> ;;;###autoload
> (defun package-vc-prepare-patch (pkg-desc subject revisions)
> @@ -980,7 +1082,7 @@ package-vc-prepare-patch
> (and (not vc-prepare-patches-separately)
> (read-string "Subject: " "[PATCH] " nil nil t))
> (vc-prepare-patch-prompt-revisions)))
> - (let ((default-directory (package-desc-dir pkg-desc)))
> + (let ((default-directory (package-vc--checkout-dir pkg-desc)))
> (vc-prepare-patch (package-maintainers pkg-desc t)
> subject revisions)))
>
> @@ -988,7 +1090,8 @@ package-vc-log-incoming
> "Call `vc-log-incoming' for the package PKG-DESC."
> (interactive
> (list (package-vc--read-package-desc "Incoming log for package: " t)))
> - (let ((default-directory (package-desc-dir pkg-desc)))
> + (let ((default-directory (package-vc--checkout-dir pkg-desc))
> + (vc-deduce-backend-nonvc-modes t))
> (call-interactively #'vc-log-incoming)))
>
> (provide 'package-vc)
> diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
> index 63124706e28..418e807f227 100644
> --- a/lisp/emacs-lisp/package.el
> +++ b/lisp/emacs-lisp/package.el
> @@ -903,6 +903,14 @@ package--reload-previously-loaded
> (mapc (lambda (c) (load (car c) nil t))
> (sort result (lambda (x y) (< (cdr x) (cdr y))))))))
>
> +(defun package--add-info-node (pkg-dir)
> + "Add info node located in PKG-DIR."
> + (when (file-exists-p (expand-file-name "dir" pkg-dir))
> + ;; FIXME: not the friendliest, but simple.
> + (require 'info)
> + (info-initialize)
> + (add-to-list 'Info-directory-list pkg-dir)))
> +
> (defun package-activate-1 (pkg-desc &optional reload deps)
> "Activate package given by PKG-DESC, even if it was already active.
> If DEPS is non-nil, also activate its dependencies (unless they
> @@ -934,12 +942,7 @@ package-activate-1
> The following files have already been loaded: %S")))
> (with-demoted-errors "Error loading autoloads: %s"
> (load (package--autoloads-file-name pkg-desc) nil t)))
> - ;; Add info node.
> - (when (file-exists-p (expand-file-name "dir" pkg-dir))
> - ;; FIXME: not the friendliest, but simple.
> - (require 'info)
> - (info-initialize)
> - (add-to-list 'Info-directory-list pkg-dir))
> + (package--add-info-node pkg-dir)
> (push name package-activated-list)
> ;; Don't return nil.
> t)))
> --
> 2.51.2
>
>
> From da677da063cb48c7c70eab3974d99ba772914dc8 Mon Sep 17 00:00:00 2001
> From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
> Date: Tue, 2 Sep 2025 09:28:13 +0100
> Subject: [PATCH 2/2] Add tests for package-vc
>
> * test/lisp/package-vc-tests.el (package-vc-tests-under-test):
> Define packages names to run tests on.
>
> (package-vc-tests-preserve-temporary): When non nil then
> preserve temporary test files.
>
> (package-vc-tests-dir, package-vc-tests-packages)
> (package-vc-tests-bundle): Silence byte compiler.
>
> (package-vc-tests-add): Copy a an in file template,
> update SUFFIX in it and add it to index.
>
> (package-vc-tests-create-bundle): Create a package git
> repository bundle with test package source.
>
> (package-vc-tests-package-desc): Retrieve a `package-desc' for
> tested package.
>
> (package-vc-tests-package-lisp-dir): Determine a lisp directory
> for a package.
>
> (package-vc-tests-package-main-file): Calculate expected
> location of package's main file.
>
> (package-vc-tests-load-history-marker): Create a load history
> marker.
>
> (package-vc-tests-load-history-pattern): Create a regexp pattern
> to search in `load-history'.
>
> (package-vc-tests-load-history-position): Calculate a position
> in `load-history'.
>
> (package-vc-tests-explain-load-history-position): Return ERT
> explanation for failures.
>
> (package-vc-tests-valid-commit-p): Check that commit is a string
> and it is not "unknown".
>
> (package-vc-tests-in-strict-order-p): Check that args are in
> strict order (each arg is less than the following args).
>
> (package-vc-tests-match-p): Check that string matches a regexp.
>
> (package-vc-tests-buffer-p): Check that object is a buffer.
>
> (package-vc-tests-elc-files): Check that there are elc files and
> that there is no compiled autoloads file amongst them.
>
> (package-vc-tests-assert-delete-elc): Assert that .elc files
> are present for a package.
>
> (package-vc-tests-assert-package-alist): Assert that
> `pakcage-alist' contains a `package-desc' for package, and that
> the `pakcage-desc' has correct slot `version' and slot `dir'.
>
> (package-vc-tests-reset-heads): Reset head of checkout of
> tested packages to HEAD^.
>
> (package-vc-tests-packages-heads): Return current checkout
> revision.
>
> (with-package-vc-tests-installed): Setup test environment,
> install package, evaluate test body, and then tear down the test
> environment.
>
> (package-vc-tests-install-from-elpa)
> (package-vc-tests-install-from-spec): Install a test package.
>
> (pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
> (package-vc-tests-checkout-with-git-install-from-checkout):
> Checkout and install a test package.
>
> (package-vc-tests-package-vc-async-wait): Wait for an
> asynchronous VC command to finish.
>
> (package-vc-tests-install-post-conditions): Tests that after
> installing a test package the `load-history' entries, package's
> main file, commit, elc files, and `package-alist' entry are
> correct.
>
> (package-vc-tests-require): Test that after calling `require'
> the `load-history' entries are correct.
>
> (package-vc-tests-upgrade, package-vc-tests-upgrade-all): Test
> that after calling `package-vc-upgrade'/`package-vc-upgrade-all'
> the `load-history' entries, package's elc files, commit, and
> `package-alist' entry are correct.
>
> (package-vc-tests-upgrade-after-require)
> (package-vc-tests-upgrade-all-after-require): Test that after
> calling `require' followed by
> `package-vc-upgrade'/`package-vc-upgrade-all' the `load-history'
> entries, commit, package's elc files, and `package-alist' entry
> are correct.
>
> (package-vc-tests-rebuild): Test that after calling
> `package-vc-rebuild' on an old version of a package, the
> package's old function, old macro, elc files, and
> `package-alist' entry are correct.
>
> (package-vc-tests-rebuild-after-require): Test that after
> calling `require' followed by `package-vc-rebuild' on an old
> version of a package, the package's old function, old macro, elc
> files, and `package-alist' entry are correct.
>
> (package-vc-tests-prepare-patch): Test that after calling
> `package-vc-prepare-patch' the message buffer is correct.
>
> (package-vc-tests-log-incoming): Test that after calling
> `package-vc-log-incoming' the log buffer is correct.
>
> * test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in:
> * test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in:
> Code template of version 0.1 of a test package.
>
> * test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in:
> * test/lisp/package-vc-resources/test-package-SUFFIX-v0.2-lib.el.in:
> Code template of code of version 0.2 of a test package.
>
> * test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in:
> * test/lisp/package-vc-resources/test-package-SUFFIX.texi.in:
> Documentation template of a test package.
>
> * test/lisp/package-vc-resources/Makefile:
> Makefile template of a test package.
> ---
> test/lisp/package-vc-resources/Makefile.in | 4 +
> .../test-package-SUFFIX-inc.texi.in | 3 +
> .../test-package-SUFFIX-lib-v0.1.el.in | 16 +
> .../test-package-SUFFIX-lib-v0.2.el.in | 16 +
> .../test-package-SUFFIX-v0.1.el.in | 28 +
> .../test-package-SUFFIX-v0.2.el.in | 24 +
> .../test-package-SUFFIX.texi.in | 11 +
> test/lisp/package-vc-tests.el | 1045 +++++++++++++++++
> 8 files changed, 1147 insertions(+)
> create mode 100644 test/lisp/package-vc-resources/Makefile.in
> create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-in=
c.texi.in
> create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-li=
b-v0.1.el.in
> create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-li=
b-v0.2.el.in
> create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-v0=
.1.el.in
> create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-v0=
.2.el.in
> create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX.te=
xi.in
> create mode 100644 test/lisp/package-vc-tests.el
>
> diff --git a/test/lisp/package-vc-resources/Makefile.in b/test/lisp/packa=
ge-vc-resources/Makefile.in
> new file mode 100644
> index 00000000000..8618ae8f2f4
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/Makefile.in
> @@ -0,0 +1,4 @@
> +.PHONY: build-test-package-SUFFIX
> +
> +build-test-package-SUFFIX:
> + @touch test-package-SUFFIX.make-build
> diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.=
in b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in
> new file mode 100644
> index 00000000000..9e4e38b74a4
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in
> @@ -0,0 +1,3 @@
> +@c -*- texinfo -*-
> +@chapter Second chapter for test-package-SUFFIX
> + Second test text.
> diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.=
el.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in
> new file mode 100644
> index 00000000000..c8bfce3e8ab
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in
> @@ -0,0 +1,16 @@
> +;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding:=
t -*-
> +
> +;;; Commentary:
> +;;
> +;; Test package SUFFIX library.
> +
> +;;; Code:
> +
> +(defmacro test-package-SUFFIX-mac (arg)
> + ;; checkdoc-params: (arg)
> + "Old test macro for `test-package-SUFFIX'."
> + `(format "Old macro %s" ,arg))
> +
> +(provide 'test-package-SUFFIX-lib)
> +
> +;;; test-package-SUFFIX-lib.el ends here
> diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.=
el.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in
> new file mode 100644
> index 00000000000..bfa4c35f014
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in
> @@ -0,0 +1,16 @@
> +;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding:=
t -*-
> +
> +;;; Commentary:
> +;;
> +;; Test package SUFFIX library.
> +
> +;;; Code:
> +
> +(defmacro test-package-SUFFIX-mac (arg)
> + ;; checkdoc-params: (arg)
> + "Test macro for `test-package-SUFFIX'."
> + `(format "New macro %s" ,arg))
> +
> +(provide 'test-package-SUFFIX-lib)
> +
> +;;; test-package-SUFFIX-lib.el ends here
> diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.i=
n b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in
> new file mode 100644
> index 00000000000..ddecc88e1c5
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in
> @@ -0,0 +1,28 @@
> +;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
> +
> +;; Homepage: https://test-domain.org
> +;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
> +;; Package-Requires: ((emacs "30.1"))
> +;; Version: 0.1
> +
> +;;; Commentary:
> +;;
> +;; Test package SUFFIX.
> +
> +;;; Code:
> +
> +(require 'test-package-SUFFIX-lib)
> +
> +;;;###autoload
> +(defun test-package-SUFFIX-func (arg)
> + ;; checkdoc-params: (arg)
> + "Test function for `test-package-SUFFIX'."
> + (test-package-SUFFIX-mac arg))
> +
> +;;;###autoload
> +(defun test-package-SUFFIX-old-func ()
> + "Old test function for `test-package-SUFFIX'.")
> +
> +(provide 'test-package-SUFFIX)
> +
> +;;; test-package-SUFFIX.el ends here
> diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.i=
n b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in
> new file mode 100644
> index 00000000000..902066d787d
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in
> @@ -0,0 +1,24 @@
> +;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
> +
> +;; Homepage: https://test-domain.org
> +;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
> +;; Package-Requires: ((emacs "30.1"))
> +;; Version: 0.2
> +
> +;;; Commentary:
> +;;
> +;; Test package SUFFIX.
> +
> +;;; Code:
> +
> +(require 'test-package-SUFFIX-lib)
> +
> +;;;###autoload
> +(defun test-package-SUFFIX-func (arg)
> + ;; checkdoc-params: (arg)
> + "Test function for `test-package-SUFFIX'."
> + (test-package-SUFFIX-mac arg))
> +
> +(provide 'test-package-SUFFIX)
> +
> +;;; test-package-SUFFIX.el ends here
> diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in b=
/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in
> new file mode 100644
> index 00000000000..0fc4fc3653d
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in
> @@ -0,0 +1,11 @@
> +\input texinfo @c -*- texinfo -*-
> +@settitle Info for test-package-SUFFIX
> +@direntry
> +* Test-package-SUFFIX: (test-package-SUFFIX). test-package-SUFFIX.
> +@end direntry
> +
> +@chapter First chapter for test-package-SUFFIX
> + First test text.
> +
> +@include test-package-SUFFIX-inc.texi
> +@bye
> diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
> new file mode 100644
> index 00000000000..9f00d0f508f
> --- /dev/null
> +++ b/test/lisp/package-vc-tests.el
> @@ -0,0 +1,1045 @@
> +;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -=
*-
> +
> +;; Copyright (C) 2025 Free Software Foundation, Inc.
> +
> +;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
> +;; Keywords: package
> +
> +;; This file is part of GNU Emacs.
> +
> +;; GNU Emacs is free software: you can redistribute it and/or modify
> +;; it under the terms of the GNU General Public License as published by
> +;; the Free Software Foundation, either version 3 of the License, or
> +;; (at your option) any later version.
> +
> +;; GNU Emacs is distributed in the hope that it will be useful,
> +;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +;; GNU General Public License for more details.
> +
> +;; You should have received a copy of the GNU General Public License
> +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
> +
> +;;; Commentary:
> +
> +;; These tests focus on verifying post conditions for `package-vc'
> +;; operations on packages. These tests install and load test packages
> +;; with a sample test implementation, resulting in modification of
> +;; numerous global variables, for example `load-history', `load-path',
> +;; `features', etc. When run with `ert' it may contaminate current
> +;; Emacs session. For this reason, tests execute their bodies in
> +;; `with-package-vc-tests-installed' (which see), that takes care of
> +;; cleaning up the environment.
> +
> +;;; Code:
> +
> +(require 'package-vc)
> +(require 'package)
> +(require 'vc-git)
BTW. I don't think there is any reason you would have to use vc-git in
the tests compared to just invoking git commands manually, in case that
makes anything easier for you.
> +(require 'vc)
> +(require 'cl-lib)
> +(require 'info)
> +(require 'ert-x)
> +(require 'ert)
> +
> +(defvar package-vc-tests-under-test '(test-package-1
> + test-package-2
> + test-package-3
> + test-package-4
> + test-package-5
> + test-package-6
> + test-package-7
> + test-package-8
> + test-package-9))
> +
> +(defvar package-vc-tests-preserve-temporary nil
> + "When non-nil preserve temporary files produced by tests.
> +Each test produces a new temporary directory for each package under
> +test. This leads to creation of [length of
> +`package-vc-tests-under-test'] times [number of tests executed]
> +temporary directories for each tests run. When this variable is nil
> +then delete all temporary directories as soon as they are no longer
> +needed. When this variable is a symbol, then preserve temporary
> +directories for the package that matches the symbol. When this variable
> +is a list of symbol, then preserve temporary directories for each
> +package that matches symbol in the list. When this variable is t then
> +preserve all temporary directories. Tests create temporary directories
> +with `make-temp-file', which see.")
> +
> +(defvar package-vc-tests-dir)
> +(defvar package-vc-tests-packages)
> +(defvar package-vc-tests-bundle)
> +
> +;; TODO: add test for deleting packages, with asserting
> +;; `package-vc-selected-packages'
> +
> +;; TODO: clarify `package-vc-install-all' behaviour with regards to
> +;; packages installed with `package-vc' but not stored in
> +;; `package-vc-selected-packages' i.e., packages from ELPAs
> +
> +(defun package-vc-tests-add (suffix in-file &optional lisp-dir)
> + "Create a new file from IN-FILE template updating SUFFIX in it.
> +When LISP-DIR is non-nil place the NAME file under LISP-DIR."
> + (let* ((resource-dir (ert-resource-directory))
> + (suffix (if (stringp suffix) suffix (format "%s" suffix)))
> + (file (let ((file (replace-regexp-in-string
> + (rx ".in" string-end) ""
> + (replace-regexp-in-string
> + "SUFFIX" suffix
> + (replace-regexp-in-string
> + (rx "-v" digit (zero-or-more
> + "." (one-or-more digit)))
> + ""
> + in-file
> + nil nil 0)
> + nil nil 0)
> + nil nil 0)))
> + (if lisp-dir
> + (file-name-concat lisp-dir file)
> + file))))
> + (copy-file (expand-file-name in-file resource-dir) file t)
> + (with-temp-buffer
> + (insert-file-contents file)
> + (goto-char (point-min))
> + (while (search-forward "SUFFIX" nil t)
> + (replace-match suffix))
> + (write-file file))
> + (vc-git-command nil 0 nil "add" ".")))
> +
> +(defun package-vc-tests-create-bundle (suffix &optional lisp-dir)
> + "Create a test package bundle with SUFFIX.
> +If LISP-DIR is non-nil place sources of the package in LISP-DIR."
> + (let* ((name (format "test-package-%s" suffix))
> + (repo-dir (expand-file-name (file-name-concat "repo" name)
> + package-vc-tests-dir)))
> + (make-directory (if lisp-dir
> + (expand-file-name lisp-dir repo-dir)
> + repo-dir)
> + :parents)
> + (let ((default-directory repo-dir)
> + (bundle-file (expand-file-name (format "%s.bundle" name)
> + package-vc-tests-dir)))
> + (vc-git-command nil 0 nil "init" "-b" "master")
> + (package-vc-tests-add
> + suffix "test-package-SUFFIX-lib-v0.1.el.in" lisp-dir)
> + (package-vc-tests-add
> + suffix "test-package-SUFFIX-v0.1.el.in" lisp-dir)
> + (package-vc-tests-add
> + suffix "test-package-SUFFIX.texi.in" lisp-dir)
> + (package-vc-tests-add
> + suffix "test-package-SUFFIX-inc.texi.in" lisp-dir)
> + ;; Place Makefile in root of the repository
> + (package-vc-tests-add
> + suffix "Makefile.in" nil)
> + (vc-git-command nil 0 nil "commit" "-m" "First commit")
> + (package-vc-tests-add
> + suffix "test-package-SUFFIX-lib-v0.2.el.in" lisp-dir)
> + (package-vc-tests-add
> + suffix "test-package-SUFFIX-v0.2.el.in" lisp-dir)
> + (vc-git-command nil 0 nil "commit" "-m" "Second commit")
> + (vc-git-command nil 0 nil
> + "bundle" "create" bundle-file "master")
> + (list bundle-file (vc-git-working-revision nil)))))
> +
> +(defun package-vc-tests-package-desc (package &optional installed)
> + "Return descriptor of PACKAGE.
> +When INSTALLED is non-nil the descriptor will come from `package-alist'.
> +Otherwise the descriptor will be from `package-archive-contents'. This
> +is to mimic `package-vc--read-package-desc'."
> + (cadr (assoc (if (stringp package) package (symbol-name package))
> + (if installed package-alist package-archive-contents)
> + #'string=3D)))
> +
> +(defun package-vc-tests-package-lisp-dir (pkg)
> + "Return a Lisp directory of PKG."
> + (and-let* ((checkout-dir (car
> + (alist-get pkg
> + package-vc-tests-packages))))
> + (or (and-let* ((lisp-dir (cadr
> + (alist-get pkg
> + package-vc-tests-packages))))
> + (expand-file-name lisp-dir checkout-dir))
> + checkout-dir)))
> +
> +(defun package-vc-tests-package-main-file (pkg)
> + "Return a main file of PKG."
> + (file-name-concat (package-vc-tests-package-lisp-dir pkg)
> + (format "%s.el" pkg)))
> +
> +;; When a package source is being recompiled - for example as result of
> +;; `pakckage-vc-upgrade' or `package-vc-rebuild' - it is also reloaded
> +;; [1] to ensure that the most recent version of compiled code is
> +;; available to Emacs. There are a few tests that add markers in
> +;; `load-history' before executing such functions. And then follow up
> +;; tests use these markers to assert that expected package files are in
> +;; correct places in the `load-history'.
> +;;
> +;; [1] Only when a file has been loaded previously.
> +
> +(defun package-vc-tests-load-history-marker (name)
> + "Return a `load-history' marker with NAME."
> + (expand-file-name (symbol-name name)
> + package-vc-tests-dir))
> +
> +(defun package-vc-tests-load-history-pattern (pkg type)
> + "Return a regexp pattern for PKG's file of TYPE."
> + (pcase type
> + (:autoloads
> + (rx (literal (file-name-concat
> + package-user-dir
> + (symbol-name pkg)
> + (format "%s-autoloads.el" pkg)))
> + string-end))
> + (:main
> + (rx
> + (literal
> + (package-vc-tests-package-main-file pkg))
> + string-end))
> + (:main-compiled
> + (rx
> + (literal
> + (package-vc-tests-package-main-file pkg))
> + "c"
> + string-end))
> + (:marker
> + (rx (literal (package-vc-tests-load-history-marker pkg))))))
> +
> +(defun package-vc-tests-load-history-position (pkg type)
> + "Return a PKG's file of TYPE position in `load-history'.
> +If TYPE is `:autoloads' return a position of a PKG autoloads file.
> +Otherwise, if TYPE is `:main' return a position of PKG main file (not
> +compiled). Otherwise, if TYPE is `:main-compiled' return a position of
> +PKG compiled main file. Otherwise, if TYPE is `:marker' return a
> +position of a marker PKG."
> + (let ((pkg-file (package-vc-tests-load-history-pattern pkg type))
> + (interesting-entry
> + (rx string-start
> + (literal (file-truename package-vc-tests-dir)))))
> + (cl-position-if
> + (lambda (file)
> + (string-match pkg-file file))
> + (cl-remove-if-not
> + (lambda (file-name)
> + (string-match interesting-entry file-name))
> + (mapcar
> + #'file-truename
> + (cl-remove-if-not
> + #'stringp
> + (mapcar #'car-safe load-history)))))))
> +
> +(defun package-vc-tests-explain-load-history-position (pkg type)
> + "Explain `package-vc-tests-load-history' failed for PKG of TYPE."
> + (let ((pattern
> + (concat "..."
> + (substring
> + (package-vc-tests-load-history-pattern pkg type)
> + (length (rx (literal package-vc-tests-dir))))))
> + (reason
> + (if-let* ((pos (package-vc-tests-load-history-position
> + pkg type)))
> + `(found in load-history at pos ,pos)
> + '(not found in load-history)))
> + (entries
> + (mapcar
> + (lambda (file)
> + (concat "..."
> + (substring file (length package-vc-tests-dir))))
> + (cl-remove-if
> + (lambda (file)
> + (or (not (stringp file))
> + (not (string-prefix-p package-vc-tests-dir file))))
> + (mapcar #'car-safe load-history)))))
> + (append (list 'pattern pattern)
> + reason
> + (list entries))))
> +
> +(put #'package-vc-tests-load-history-position
> + 'ert-explainer
> + #'package-vc-tests-explain-load-history-position)
> +
> +;; The following predicates and helper functions take an extra PKG
> +;; argument. This is needed for ERT to print package name in case of
> +;; failure.
> +
> +(defun package-vc-tests-valid-commit-p (_pkg commit)
> + "Return non-nil when COMMIT is a valid commit."
> + (and (stringp commit)
> + (not (string=3D commit "unknown"))))
> +
> +(defun package-vc-tests-in-strict-order-p (_pkg &rest args)
> + "Return non-nil when ARGS are in strict order."
> + (apply #'< args))
> +
> +(defun package-vc-tests-match-p (_pkg regexp string)
> + "Return non-nil when REGEXP matches STRING."
> + (string-match regexp string))
> +
> +(defun package-vc-tests-buffer-p (_pkg obj)
> + "Return non-nil when OBJ is a buffer."
> + (bufferp obj))
> +
> +(defun package-vc-tests-elc-files (pkg)
> + "Return elc files for PKG."
> + (when-let* ((dir (package-vc-tests-package-lisp-dir pkg))
> + (elc-files (directory-files
> + dir nil (rx ".elc" string-end))))
> + elc-files))
> +
> +(defun package-vc-tests-assert-elc (pkg)
> + "Assert that PKG has correct .elc files in."
> + (let* ((dir (package-vc-tests-package-lisp-dir pkg))
> + (elc-files (should (package-vc-tests-elc-files pkg)))
> + (autoloads-rx (rx
> + (literal (format "%s-autoloads.elc" pkg))
> + string-end)))
> + (should-not (cl-find-if (lambda (elc)
> + (string-match autoloads-rx elc))
> + elc-files))
> + (dolist (elc-file elc-files)
> + (delete-file (expand-file-name elc-file dir)))))
> +
> +(defun package-vc-tests-assert-package-alist (pkg version)
> + "Assert that PKG entry in `package-alist' have correct VERSION and dir=
."
> + (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
> + (should (equal (file-name-as-directory
> + (expand-file-name (format "%s" pkg)
> + package-user-dir))
> + (file-name-as-directory
> + (package-desc-dir pkg-desc))))
> + (should (equal (list pkg version)
> + (list pkg (package-desc-version pkg-desc))))))
> +
> +(defun package-vc-tests-reset-head (pkg)
> + "Reset to HEAD^ checkout for PKG."
> + (let ((default-directory (car
> + (alist-get pkg package-vc-tests-packages))))
> + (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))
> +
> +(defun package-vc-tests-package-head (pkg)
> + "Return HEAD revisions of a PKG."
> + (let ((default-directory (car
> + (alist-get pkg package-vc-tests-packages))))
> + (vc-git-working-revision nil)))
> +
> +(defmacro with-package-vc-tests-installed (pkg &rest body)
> + "Eval BODY with PKG installed in a test environment."
> + (declare (indent 1) (debug t))
> + ;; git-bundle(1) produces test packages sources in bundle files, based
> + ;; on skeleton files in directory package-vc-resources. Before
> + ;; executing body make sure that:
> + ;;
> + ;; - `package' has been initialised, and there are no
> + ;; `package-archives' defined
> + `(let* ((package-archives (unless package--initialized
> + (let (package-archives)
> + (package-initialize)
> + (package-vc--archives-initialize))
> + nil))
This form always return nil, right? I'd pull it up behind the let* and
then just bind `package-archives' to nil.
> + ;; - create a temporary location for packages and test files
> + (package-vc-tests-dir
> + (expand-file-name
> + (make-temp-file "package-vc-tests-"
> + t
> + (format-time-string "-%Y%m%d.%H%M%S.%3N"))))
> + ;; - packages are installed into a test directory
> + (package-user-dir (expand-file-name "elpa"
> + package-vc-tests-dir))
> + ;; - define test packages, their checkout locations, lisp
> + ;; directories, and install functions
> + (package-vc-tests-packages
> + `(;; checkout and install with `package-vc-install' (on
> + ;; ELPA)
> + (test-package-1
> + ,(expand-file-name "test-package-1"
> + package-user-dir)
> + nil
> + package-vc-tests-install-from-elpa)
> + ;; checkout and install with `package-vc-install' (not on
> + ;; ELPA)
> + (test-package-2
> + ,(expand-file-name "test-package-2"
> + package-user-dir)
> + nil
> + package-vc-tests-install-from-spec)
> + ;; checkout with `package-vc-checktout' and install with
> + ;; `package-vc-install-from-checkout' (on ELPA)
> + (test-package-3
> + ,(expand-file-name "test-package-3"
> + package-vc-tests-dir)
> + nil
> + pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
> + ;; checkout with git and install with
> + ;; `package-vc-install-from-checkout'
> + (test-package-4
> + ,(expand-file-name "test-package-4"
> + package-vc-tests-dir)
> + nil
> + package-vc-tests-checkout-with-git-install-from-checkout)
> + ;; sources in "lisp" sub directory, checkout and install
> + ;; with `package-vc-install' (not on ELPA)
> + (test-package-5
> + ,(expand-file-name "test-package-5"
> + package-user-dir)
> + "lisp"
> + package-vc-tests-install-from-spec)
> + ;; sources in "lisp" sub directory, checkout with git and
> + ;; install with `package-vc-install-from-checkout'
> + (test-package-6
> + ,(expand-file-name "test-package-6"
> + package-vc-tests-dir)
> + "lisp"
> + package-vc-tests-checkout-with-git-install-from-checkout)
> +
> + ;; sources in "src" sub directory, checkout and install
> + ;; with `package-vc-install' (on ELPA)
> + (test-package-7
> + ,(expand-file-name "test-package-7"
> + package-user-dir)
> + "src"
> + package-vc-tests-install-from-elpa)
> + ;; sources in "src" sub directory, checkout with
> + ;; `package-vc-checktout' and install with
> + ;; `package-vc-install-from-checkout' (on ELPA)
> + (test-package-8
> + ,(expand-file-name "test-package-8"
> + package-vc-tests-dir)
> + nil
> + pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
> + ;; sources in "custom-dir" sub directory, checkout and
> + ;; install with `package-vc-install' (on ELPA)
> + (test-package-9
> + ,(expand-file-name "test-package-9"
> + package-user-dir)
> + "custom-dir"
> + package-vc-tests-install-from-elpa)))
> + ;; - create a test package bundle
> + (package-vc-tests-bundle
> + (let* ((pkg-name (symbol-name ,pkg))
> + (suffix (and (string-match
> + (rx ?-
> + (group (one-or-more (not ?-)))
> + string-end)
> + pkg-name)
> + (match-string 1 pkg-name))))
> + (package-vc-tests-create-bundle
> + suffix (cadr (alist-get ,pkg package-vc-tests-packages)))))
> + ;; - find all packages that are present in a test ELPA
> + (package-vc-tests-elpa-packages
> + (mapcar
> + #'car
> + (cl-remove-if-not
> + (lambda (package)
> + (memq
> + (cadddr package)
> + '(package-vc-tests-install-from-elpa
> + pakcage-vc-tests-checkout-from-elpa-install-from-check=
out)))
> + package-vc-tests-packages)))
> + ;; - make test packages recognisable by `package' and
> + ;; `package-vc' internals:
> + (package-archive-contents
> + (mapcar
> + (lambda (pkg)
> + (list pkg
> + (package-desc-create
> + :name pkg
> + :version '(0 2)
> + :reqs '((emacs (30.1)))
> + :kind 'tar
> + :archive "test-elpa"
> + :extras
> + (list
> + '(:maintainer
> + ("Test Maintainer"
> + . "test-maintainer@HIDDEN"))
> + (cons :url (car package-vc-tests-bundle))
> + (cons :commit (cadr package-vc-tests-bundle))
> + (cons :revdesc (substring
> + (cadr package-vc-tests-bundle)
> + 0 12))))))
> + package-vc-tests-elpa-packages))
> + (package-vc--archive-spec-alists
> + (list
> + (cons 'test-elpa
> + (mapcar
> + (lambda (pkg)
> + (let ((lisp-dir
> + (cadr (alist-get
> + ,pkg package-vc-tests-packages))))
> + (append
> + (list pkg
> + :url (car package-vc-tests-bundle)
> + :branch "master"
> + :doc (let ((doc-file
> + (format "%s.texi" ,pkg)))
> + (if lisp-dir
> + (file-name-concat lisp-dir
> + doc-file)
> + doc-file))
> + :make (format "build-%s" ,pkg)
> + :shell-command (format
> + "touch %s.cmd-build"
> + ,pkg))
> + (and lisp-dir
> + (not (member lisp-dir '("lisp" "src")))
> + (list :lisp-dir lisp-dir)))))
> + package-vc-tests-elpa-packages))))
> + (package-vc--archive-data-alist
> + (list
> + (list 'test-elpa :version 1 :default-vc 'Git)))
> + ;; - `vc-guess-backend-url' is recognising bundles as `Git'
> + ;; repositories:
> + (vc-clone-heuristic-alist
> + (cons
> + (cons (rx "test-package-" (one-or-more digit) ".bundle"
> + string-end)
> + 'Git)
> + vc-clone-heuristic-alist))
> + ;; - ensure that `package-alist' and
> + ;; `package-vc-selected-packages' are empty
> + package-alist
> + package-vc-selected-packages
> + ;; - don't save any customization
> + (user-init-file nil)
> + ;; - FIXME: something sets `default-directory' to last
> + ;; checkout directory after `package-vc-checkout', which
> + ;; causes problems when this macro deletes the temporary
> + ;; directory after body execution.
> + (default-directory package-vc-tests-dir))
> + (unwind-protect
> + (progn
> + (funcall (or (caddr (alist-get ,pkg
> + package-vc-tests-packages))
> + (lambda (pkg)
> + (ert-fail
> + (format
> + "Cannot find %s in package-vc-tests-packages"
> + pkg))))
> + ,pkg)
> + ,@body)
> + ;; Unbind package defined symbols, and remove package defined
> + ;; features and entries from `load-path',`load-history', and
> + ;; `Info-directory-list'.
> + (let ((pattern (rx string-start (literal package-vc-tests-dir))))
> + (dolist (entry load-history)
> + (when-let* ((file (car-safe entry))
> + ((stringp file))
> + ((string-match pattern file)))
> + (dolist (elt (cdr entry))
> + (pcase elt
> + (`(defun . ,fun)
> + (fmakunbound fun))
> + (`(provide . ,feat)
> + (setq features (cl-remove feat features)))
> + ((and (pred symbolp)
> + (pred boundp))
> + (makunbound elt))))))
> + (setq load-path (cl-remove-if
> + (lambda (path)
> + (and (stringp path)
> + (string-match pattern path)))
> + load-path)
> + load-history (cl-remove-if
> + (lambda (entry)
> + (and-let* ((path (car-safe entry))
> + ((stringp path)))
> + (string-match pattern path)))
> + load-history)
> + Info-directory-list (cl-remove-if
> + (lambda (dir)
> + (and (stringp dir)
> + (string-match pattern dir)))
> + Info-directory-list)))
> + (if (or (eq package-vc-tests-preserve-temporary t)
> + (eq package-vc-tests-preserve-temporary ,pkg)
> + (and (listp package-vc-tests-preserve-temporary)
> + (memq ,pkg package-vc-tests-preserve-temporary)))
> + (message "package-vc-tests: preserving temporary directory %s"
> + package-vc-tests-dir)
> + (delete-directory package-vc-tests-dir t)))))
> +
> +(defun package-vc-tests-install-from-elpa (pkg)
> + "Install PKG with `package-vc-install'."
> + (push (list (package-vc-tests-load-history-marker 'install-begin))
> + load-history)
> + (package-vc-install pkg)
> + (push (list (package-vc-tests-load-history-marker 'install-end))
> + load-history)
> + (should-not (alist-get (symbol-name pkg)
> + package-vc-selected-packages
> + nil nil #'string=3D)))
> +
> +(defun package-vc-tests-install-from-spec (pkg)
> + "Install PKG with `package-vc-install' (not on ELPA)."
> + (push (list (package-vc-tests-load-history-marker 'install-begin))
> + load-history)
> + (package-vc-install `(,pkg
> + :url ,(car package-vc-tests-bundle)
> + :branch "master"))
> + (push (list (package-vc-tests-load-history-marker 'install-end))
> + load-history)
> + (should (equal (car package-vc-tests-bundle)
> + (plist-get (alist-get (symbol-name pkg)
> + package-vc-selected-packages
> + nil nil #'string=3D)
> + :url))))
> +
> +(defun pakcage-vc-tests-checkout-from-elpa-install-from-checkout (pkg)
> + "Install PKG with `package-vc-install-from-checkout'.
> +Make checkout with `package-vc-checkout'."
> + (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
> + (package-vc-checkout (package-vc-tests-package-desc
> + pkg)
> + checkout-dir)
> + (push (list (package-vc-tests-load-history-marker 'install-begin))
> + load-history)
> + (package-vc-install-from-checkout checkout-dir)
> + (push (list (package-vc-tests-load-history-marker 'install-end))
> + load-history)
> + (should (equal (concat package-vc--url-scheme checkout-dir)
> + (plist-get (alist-get (symbol-name pkg)
> + package-vc-selected-packages
> + nil nil #'string=3D)
> + :url)))))
> +
> +(defun package-vc-tests-checkout-with-git-install-from-checkout (pkg)
> + "Install PKG with `package-vc-install-from-checkout'.
> +Make checkout with git(1)."
> + (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
> + (vc-git-clone (car package-vc-tests-bundle)
> + checkout-dir
> + "master")
> + (push (list (package-vc-tests-load-history-marker 'install-begin))
> + load-history)
> + (package-vc-install-from-checkout checkout-dir (symbol-name pkg))
> + (push (list (package-vc-tests-load-history-marker 'install-end))
> + load-history)
> + (should (equal (concat package-vc--url-scheme checkout-dir)
> + (plist-get (alist-get (symbol-name pkg)
> + package-vc-selected-packages
> + nil nil #'string=3D)
> + :url)))))
> +
> +(defmacro package-vc-tests-package-vc-async-wait (seconds count flags &r=
est body)
> + "Wait up to SECONDS for COUNT async vc commands with FLAGS called by B=
ODY.
> +Return nil on timeout or the value of last form in BODY."
> + (declare (indent 3))
> + (let ((count-sym (make-symbol "count"))
> + (post-vc-command-sym (make-symbol "post-vc-command")))
> + `(letrec ((,count-sym ,count)
> + (,post-vc-command-sym
> + (lambda (command _ command-flags)
> + ;; A crude filter for vc commands
> + (when (and (equal command "git")
> + (cl-every (lambda (flag)
> + (member flag command-flags))
> + ,flags))
> + (decf ,count-sym)))))
> + (add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
> + (unwind-protect
> + (with-timeout (,seconds nil)
> + (prog1
> + (progn ,@body)
> + (while (/=3D ,count-sym 0)
> + (accept-process-output nil 0.01))))
> + (remove-hook 'vc-post-command-functions
> + ,post-vc-command-sym)))))
> +
> +(ert-deftest package-vc-tests-install-post-conditions ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (let ((install-begin
> + (should (package-vc-tests-load-history-position
> + 'install-begin :marker)))
> + (install-end
> + (should (package-vc-tests-load-history-position
> + 'install-end :marker)))
> + (autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads))))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + install-end
> + autoloads-pos
> + install-begin))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main-compiled)))
> + (should (equal (package-vc--main-file
> + (package-vc-tests-package-desc pkg t))
> + (package-vc-tests-package-main-file pkg)))
> + (should (package-vc-tests-valid-commit-p
> + pkg
> + (package-vc-commit
> + (package-vc-tests-package-desc pkg t))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 2)))))
> +
> +(ert-deftest package-vc-tests-require ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (should (fboundp (intern (format "%s-func" pkg))))
> + (should (autoloadp
> + (symbol-function (intern (format "%s-func" pkg)))))
> + (should (require pkg))
> + (should (fboundp (intern (format "%s-func" pkg))))
> + (should-not (autoloadp
> + (symbol-function (intern (format "%s-func" pkg)))))
> + (should-not (fboundp (intern (format "%s-old-func" pkg))))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main))
> + (let ((install-end
> + (should (package-vc-tests-load-history-position
> + 'install-end :marker)))
> + (main-compiled-pos
> + (should (package-vc-tests-load-history-position
> + pkg :main-compiled))))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + main-compiled-pos
> + install-end))))))
> +
> +(ert-deftest package-vc-tests-upgrade ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (let ((head (package-vc-tests-package-head pkg)))
> + (package-vc-tests-reset-head pkg)
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-begin))
> + load-history)
> + (should
> + (package-vc-tests-package-vc-async-wait 5 1 '("pull")
> + (package-vc-upgrade (package-vc-tests-package-desc pkg t))
> + t))
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-end))
> + load-history)
> + (should-not (package-vc-tests-load-history-position
> + pkg :main))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main-compiled))
> + (let ((upgrade-begin
> + (should (package-vc-tests-load-history-position
> + 'upgrade-begin :marker)))
> + (upgrade-end
> + (should (package-vc-tests-load-history-position
> + 'upgrade-end :marker)))
> + (autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads))))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + autoloads-pos
> + upgrade-begin)))
> + (let ((func (intern (format "%s-func" pkg))))
> + (should (fboundp func))
> + (should (autoloadp
> + (symbol-function func)))
> + (should (equal "New macro test"
> + (funcall func "test"))))
> + (should-not (fboundp (intern (format "%s-old-func" pkg))))
> + (should (equal head
> + (package-vc-tests-package-head pkg))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 2)))))
> +
> +(ert-deftest package-vc-tests-upgrade-after-require ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (should (require pkg))
> + (let ((head (package-vc-tests-package-head pkg)))
> + (package-vc-tests-reset-head pkg)
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-begin))
> + load-history)
> + (should
> + (package-vc-tests-package-vc-async-wait 5 1 '("pull")
> + (package-vc-upgrade (package-vc-tests-package-desc pkg t))
> + t))
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-end))
> + load-history)
> + (let ((upgrade-begin
> + (should (package-vc-tests-load-history-position
> + 'upgrade-begin :marker)))
> + (upgrade-end
> + (should (package-vc-tests-load-history-position
> + 'upgrade-end :marker)))
> + (autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads)))
> + (main-pos
> + (should (package-vc-tests-load-history-position
> + pkg :main)))
> + (main-compiled-pos
> + (should (package-vc-tests-load-history-position
> + pkg :main-compiled))))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + autoloads-pos
> + upgrade-begin))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + main-pos
> + upgrade-begin))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + main-compiled-pos
> + upgrade-begin)))
> + (let ((func (intern (format "%s-func" pkg))))
> + (should (fboundp func))
> + (should-not (autoloadp
> + (symbol-function func)))
> + (should (equal "New macro test"
> + (funcall func "test"))))
> + (should-not (fboundp (intern (format "%s-old-func" pkg))))
> + (should (equal head
> + (package-vc-tests-package-head pkg))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 2)))))
> +
> +(ert-deftest package-vc-tests-upgrade-all ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (let ((head (package-vc-tests-package-head pkg)))
> + (package-vc-tests-reset-head pkg)
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-all-begin))
> + load-history)
> + (should
> + (package-vc-tests-package-vc-async-wait 5 1 '("pull")
> + (package-vc-upgrade-all)
> + t))
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-all-end))
> + load-history)
> + (should-not (package-vc-tests-load-history-position
> + pkg :main))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main-compiled))
> + (let ((upgrade-begin
> + (should (package-vc-tests-load-history-position
> + 'upgrade-all-begin :marker)))
> + (upgrade-end
> + (should (package-vc-tests-load-history-position
> + 'upgrade-all-end :marker)))
> + (autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads))))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + autoloads-pos
> + upgrade-begin)))
> + (let ((func (intern (format "%s-func" pkg))))
> + (should (fboundp func))
> + (should (autoloadp
> + (symbol-function func)))
> + (should (equal "New macro test"
> + (funcall func "test"))))
> + (should-not (fboundp (intern (format "%s-old-func" pkg))))
> + (should (equal head
> + (package-vc-tests-package-head pkg))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 2)))))
> +
> +(ert-deftest package-vc-tests-upgrade-all-after-require ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (should (require pkg))
> + (let ((head (package-vc-tests-package-head pkg)))
> + (package-vc-tests-reset-head pkg)
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-all-begin))
> + load-history)
> + (should
> + (package-vc-tests-package-vc-async-wait 5 1 '("pull")
> + (package-vc-upgrade-all)
> + t))
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-all-end))
> + load-history)
> + (let ((upgrade-begin
> + (should (package-vc-tests-load-history-position
> + 'upgrade-all-begin :marker)))
> + (upgrade-end
> + (should (package-vc-tests-load-history-position
> + 'upgrade-all-end :marker)))
> + (autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads)))
> + (main-pos
> + (should (package-vc-tests-load-history-position
> + pkg :main)))
> + (main-compiled-pos
> + (should (package-vc-tests-load-history-position
> + pkg :main-compiled))))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + autoloads-pos
> + upgrade-begin))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + main-pos
> + upgrade-begin))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + main-compiled-pos
> + upgrade-begin)))
> + (let ((func (intern (format "%s-func" pkg))))
> + (should (fboundp func))
> + (should-not (autoloadp
> + (symbol-function func)))
> + (should (equal "New macro test"
> + (funcall func "test"))))
> + (should-not (fboundp (intern (format "%s-old-func" pkg))))
> + (should (equal head
> + (package-vc-tests-package-head pkg))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 2)))))
> +
> +(ert-deftest package-vc-tests-rebuild ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (package-vc-tests-reset-head pkg)
> + (let ((head (package-vc-tests-package-head pkg)))
> + (package-vc-rebuild
> + (package-vc-tests-package-desc pkg t))
> + (let ((old-func (intern (format "%s-old-func" pkg))))
> + (should (fboundp old-func))
> + (should (autoloadp
> + (symbol-function old-func))))
> + (let ((func (intern (format "%s-func" pkg))))
> + (should (fboundp func))
> + (should (autoloadp
> + (symbol-function func)))
> + (should (equal "Old macro test"
> + (funcall func "test"))))
> + (should (equal head
> + (package-vc-tests-package-head pkg))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 1)))))
> +
> +(ert-deftest package-vc-tests-rebuild-after-require ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (should (require pkg))
> + (package-vc-tests-reset-head pkg)
> + (let ((head (package-vc-tests-package-head pkg)))
> + (package-vc-rebuild
> + (package-vc-tests-package-desc pkg t))
> + (let ((old-func (intern (format "%s-old-func" pkg))))
> + (should (fboundp old-func))
> + (should-not (autoloadp
> + (symbol-function old-func))))
> + (let ((func (intern (format "%s-func" pkg))))
> + (should (fboundp func))
> + (should-not (autoloadp
> + (symbol-function func)))
> + (should (equal "Old macro test"
> + (funcall func "test"))))
> + (should (equal head
> + (package-vc-tests-package-head pkg))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 1)))))
> +
> +(ert-deftest package-vc-tests-prepare-patch ()
> + ;; Ensure `vc-prepare-patch' respects subject from function argument
> + (let (vc-prepare-patches-separately)
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (package-vc-prepare-patch (package-vc-tests-package-desc pkg t)
> + "test-subject"
> + (cdr package-vc-tests-bundle))
> + (let ((message-buffer
> + (should (get-buffer "*unsent mail to Test Maintainer*"))))
> + (should (package-vc-tests-buffer-p pkg message-buffer))
> + (switch-to-buffer message-buffer)
> + (goto-char (point-min))
> + (should
> + (package-vc-tests-match-p
> + pkg
> + (rx
> + "To: Test Maintainer <test-maintainer@HIDDEN>")
> + (buffer-substring (point) (pos-eol))))
> + (forward-line)
> + (should
> + (package-vc-tests-match-p
> + pkg
> + (rx "Subject: test-subject")
> + (buffer-substring (point) (pos-eol))))
> + (let (kill-buffer-query-functions)
> + (kill-buffer message-buffer)))))))
> +
> +(ert-deftest package-vc-tests-log-incoming ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (package-vc-tests-reset-head pkg)
> + (should
> + (package-vc-tests-package-vc-async-wait
> + 5 1 '("log" "--decorate")
> + (package-vc-log-incoming (package-vc-tests-package-desc pkg t))
> + t))
> + (let ((incoming-buffer (get-buffer "*vc-incoming*"))
> + (pattern (rx (literal
> + (substring
> + (cadr package-vc-tests-bundle)
> + 0 7))
> + (one-or-more any)
> + "Second commit"
> + line-end)))
> + (should (package-vc-tests-buffer-p pkg incoming-buffer))
> + (switch-to-buffer incoming-buffer)
> + (goto-char (point-min))
> + (should
> + (package-vc-tests-match-p
> + pkg
> + pattern
> + (buffer-substring (point) (pos-eol))))
> + (let (kill-buffer-query-functions)
> + (kill-buffer incoming-buffer))))))
> +
> +(ert-deftest package-vc-tests-pkg-spec-doc-make-shell-command ()
> + (let ((package-vc-allow-build-commands t))
> + ;; Only `packge-vc-install' runs make and shell command
> + (dolist (pkg '(test-package-1 test-package-7 test-package-9))
> + (with-package-vc-tests-installed pkg
> + (let ((checkout-dir (car (alist-get
> + pkg package-vc-tests-packages))))
> + (should (file-exists-p
> + (expand-file-name
> + (format "%s.make-build" pkg)
> + checkout-dir)))
> + (should (file-exists-p
> + (expand-file-name
> + (format "%s.cmd-build" pkg)
> + checkout-dir))))
> + (should (cl-member-if (lambda (dir)
> + (and (stringp dir)
> + (string-prefix-p package-vc-tests-d=
ir
> + dir)))
> + Info-directory-list))
> + (let ((info-file
> + (expand-file-name (format "%s.info" pkg)
> + (car (alist-get
> + pkg package-vc-tests-packages)))))
> + (should (file-exists-p info-file))
> + (ert-with-test-buffer
> + (:name (format "*package-vc-tests: %s.info*" pkg))
> + (insert-file-contents info-file)
> + (goto-char (point-min))
> + (should (re-search-forward
> + (format "First chapter for %s" pkg)))
> + (should (re-search-forward
> + (format "Second chapter for %s" pkg)))))))))
> +
> +(provide 'package-vc-tests)
> +
> +;;; package-vc-tests.el ends here
The tests already look a lot better, I'll have to review them in greater
detail in the near future, but thank you /very/ much for integrating my
feedback from the previous commits!
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Tue, 18 Nov 2025 10:45:02 +0000
Resent-Message-ID: <handler.79188.B79188.176346265212192 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org, Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176346265212192
(code B ref 79188); Tue, 18 Nov 2025 10:45:02 +0000
Received: (at 79188) by debbugs.gnu.org; 18 Nov 2025 10:44:12 +0000
Received: from localhost ([127.0.0.1]:56482 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vLJBv-0003AW-M2
for submit <at> debbugs.gnu.org; Tue, 18 Nov 2025 05:44:12 -0500
Received: from mail-wm1-x32b.google.com ([2a00:1450:4864:20::32b]:59742)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1vLJBq-00039p-CB
for 79188 <at> debbugs.gnu.org; Tue, 18 Nov 2025 05:44:06 -0500
Received: by mail-wm1-x32b.google.com with SMTP id
5b1f17b1804b1-47118259fd8so39658125e9.3
for <79188 <at> debbugs.gnu.org>; Tue, 18 Nov 2025 02:44:02 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1763462635; x=1764067435; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=2Tdx1QcR7AlDCs5OtP/9koVb9/53Fr7uYDsvoqVP0gE=;
b=iuVDgsElb11MVc2TPCOlTqiZ+RuMhoR79cVHx0EkDFdJQy3EIvo0UO+F0enV2N56rv
dYM1FOmJoVo3cR14+lWKIYy4a3JR7cZ9/YfsxTxkxKqat0gY7P2jNkLQq62urJNaLjCv
MYkEEPT4PnKBrRMJR7aIjAFZI0KaBuRdVBoe7SjIAmG1Bn3Em8S5SVKNHk3weG0DnJyX
HBKEIGsQkaMQwdLb+ZFLkB4xvljYeLH7pCmcb7gDDzLvY9i88HMh/7dwrbSNWcQk+Hru
UDam1ltu0Q0g1uBSIkX7Iy6XjDjThdPaSQNPJWGVSmLE3dHElk/DFm8PFWxD0NVU3RBo
vOtA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1763462635; x=1764067435;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject
:date:message-id:reply-to;
bh=2Tdx1QcR7AlDCs5OtP/9koVb9/53Fr7uYDsvoqVP0gE=;
b=a3frR6h8Gj+yVLWQbOWt7MXYWnGBqq2W78nkoUMFxvMWFEqmJQR+QxUHpkQwKqPLJw
J8DtiZVqIN4sYi/OKAhUzkqlcKh1SamIdcRjSRPCSmIZMiTH7tRY3C4T6Y/KRx8UElsT
PWOqZwYdYIYpW78PSDSrCy9C1o7iZ1vl52+MAGULltH1hGMrpTIDSQF7uTErhVTOTLNW
GVYkK57KRxi/AMTWxiOFC2WjNufBZojRNQrUu5qdFqF9xSTn49MBx0IR573aQKtPPqtf
6wUQ5l545DYH1+lEC8kiKp8ya+3nBvmAf3iHsrOF5c+zn8bzubxXd92x8rcjT1iAGH3M
Xcng==
X-Forwarded-Encrypted: i=1;
AJvYcCVak2LJIXjxJovOwVQbWrmJgttT+k4Vz8w/04g4om699GDfBRotQ4GgW45BQTZ0U8rDZgeQzA==@debbugs.gnu.org
X-Gm-Message-State: AOJu0Yy5LA1Si9zWDlSfg8drsqCr7wMreZsj0pPPXnoaLT8IHBE6Pz3/
GophlOY60tpzjeb54W0IGw+ItL3qKXpok0OASHAHF5DJDmWy+R/r27q9T3PeNRwc
X-Gm-Gg: ASbGnctlsur0lyKl3eyOxnRmgichcUWIWvYHIn2zgU4VWN0JNk3XHbdh3CM+PbcDzmx
7yuILbBy4fjQ++Fz7WEv6N+d0W2bw8vJEGRRj7NQuMWwYemXqrzW/tioS2MEgIcGk5KEkTeiBEF
VuTVQYRM+WgkHHChLSL1ZUyvcFa4hNXpPM7J7kOz/JTf3hihPA8he5z63vyXGmOE8SLS0lTBChA
Iz57HNFAowLWAK59gP1JZw3DielBQHST/kT8x3CFwDORQnlegR7ZqH1K3jq9xAA82MLUJWQ8jSO
LKjQWRKQO457xLgEy4mipqs3LTyxV5qkuHWBJGiQ11NWvsKXwTw1KrrBPFZdIz9wEzXDt55j7wU
tqGJTSjcWZv64ECrGN8WanOrdIO6EDWbq4Faf1BQbOoApzkq5QrqzbvNKS8iJkXE0FDathdGU30
e5fWYyIpxd8deMRm3Vsc7EindfKHHa7vM5l0zWghIEk+esgaKPIbWgXv+b
X-Google-Smtp-Source: AGHT+IFnRDkI538CfHXNBDW47JTqWVZqlqghbKqy8TegNGJwqcDB4rUQyQ6YqdWV0H3oJ37iCAeS5A==
X-Received: by 2002:a05:600c:1f87:b0:475:de68:3c30 with SMTP id
5b1f17b1804b1-4778fe68a14mr170883925e9.16.1763462635125;
Tue, 18 Nov 2025 02:43:55 -0800 (PST)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:65e6:2c92:bf3d:3b3e])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-4779b509a5esm179335805e9.2.2025.11.18.02.43.53
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Tue, 18 Nov 2025 02:43:53 -0800 (PST)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <87y0o4nyvi.fsf@HIDDEN> (Philip Kaludercic's message of "Mon,
17 Nov 2025 21:16:33 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<m24iqzmqh6.fsf@HIDDEN> <m28qgbqsx0.fsf_-_@HIDDEN>
<m2tsyzjek4.fsf@HIDDEN> <875xbcbg0f.fsf@HIDDEN>
<m2bjl0vidc.fsf@HIDDEN> <87y0o4nyvi.fsf@HIDDEN>
Date: Tue, 18 Nov 2025 10:43:53 +0000
Message-ID: <m2346bvcwm.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Philip Kaludercic <philipk@HIDDEN> writes:
> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>
>
> [...]
>
>> So I applied this patch, and it seems to that :dir slot of a package
>> installed from checkout is incorrect., for example:
>>
>> (require 'vc-git)
>> (require 'package-vc)
>> (setq package-user-dir (expand-file-name "~/tmp/elpa" ))
>> (shell-command "git clone https://gitlab.com/koral/gcmh.git ~/tmp/gcmh=
")
>> (package-vc-install-from-checkout "~/tmp/gcmh" "gcmh")
>> (package-desc-dir (cadr (assq 'gcmh package-alist)))
>> ;; =3D> "/Users/pkryger/tmp/gcmh"
>>
>> I'd expect it to be /Users/pkryger/tmp/elpa/gcmh (note the 'elpa' in
>> path). I guess corruption like that will cause more than one issue, but
>> the first I found is that calling:
>>
>> (package-delete (cadr (assq 'gcmh package-alist)))
>>
>> yields the following back trace (limiting relevant frames):
>>
>> signal(error ("Package =E2=80=98gcmh=E2=80=99 is a system package, not=
deleting"))
>> error("Package `%s' is a system package, not deleting" "gcmh")
>> package-delete(#s(package-desc :name gcmh :version (0 2 1) :summary
>> "the Garbage Collector Magic Hack" :reqs ((emacs (24))) :kind vc
>> :archive nil :dir "/Users/pkryger/tmp/gcmh" :extras ((:vc-dir
>> . "/Users/pkryger/tmp/gcmh") (:commit
>> . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9")) :signed nil))
>> (progn (package-delete (car (cdr (assq 'gcmh package-alist)))))
>> eval((progn (package-delete (car (cdr (assq 'gcmh package-alist))))) t)
>
> Thanks for checking! It helps me out a lot ^^
No problem. FWIW I have only applied patch that adds tests, commented
out `package-vc-selected-packages' assertions and deleted
`package-vc--url-scheme' bits, then run the tests and randomly picked
one of the failures. OFC, there are more failures, but I leave sifting
through them as an exercise to the reader =F0=9F=98=89.
>> I am attaching updated patches. I re-wrote tests to be executable in
>> regular Emacs session (although I haven't got to a point where I run
>> them under a development Emacs yet). With this it was so much easier to
>> add a few more tests, and I found that there's another issue with how a
>> package is rebuild. It manifests itself with a compilation using
>> preciously defined macro definitions, i.e., when macro has been changed
>> then the new version is not used.
>
> Hmm, we might have to use something like `unload-feature' here,
I checked `unload-feature' and it seems to focus on real features
unloading, e.g., removing hooks, timers, etc. In a process of unloading
it does some things as I like, but it takes a different approach to
functions. My main goal was to have a clean slate after a test has
finished, such that test check whether autoloads are correctly
established and resolved. `unload-feature' leaves function symbols
bounded, but I suspect that would make writing well encapsulated tests
hard. For that reason I'd rather to leave the manual cleanup. I wonder
if, prior to unbinding symbols, calling `loadhist-unload-element' is a
good idea? WDYT?
> but
> inherently this is an issue that regular tarball packages should also
> have. I would have thought that `package--reload-previously-loaded'
> should take care of that...
In a degree it does. The function loads `.el' files in a case when a
corresponding `.elc' has been previously loaded and there's no `.elc'
file present. This is obviously not a case for rebuilding a VC package.
N.B., above explanation assumes default value of `load-suffixes'.
>> @Philip: I merged your initial patch into mine, so it's easier to apply
>> on top of master. I hope I am not doing anything wrong here.
>
> Of course not.
=F0=9F=98=8E
>> I also think that using :vc-dir in :extras slot is a viable candidate.
>> However, I haven't had a chance to apply it yet.
>
> If you want to, I can take a shot at updating the patch to use :extras
> as Michelangelo proposed. That way I'll also have a better
> understanding of the patch, compared to just reading it.
That would be nice. I have been thinking about it, but I spent too much
time on other items recently. If you have any questions about choices
in tests, please ask.
[...]
>> From e509427dd760eb9ac69d68a9c9322f78b9c59bb7 Mon Sep 17 00:00:00 2001
>> From: Philip Kaludercic <philipk@HIDDEN>
>> Date: Fri, 26 Sep 2025 14:00:54 +0100
>> Subject: [PATCH 1/2] Fix upgrading, rebuilding, and logging of VC packag=
es
[...]
>>
>> +(defun package-vc--checkout-dir (pkg-desc &optional lisp-dir)
>> + "Return the directory of the actual VC checkout for PKG-DESC.
>> +For most packages this is the same as `package-desc-dir', unless the
>> +package has been installed via `package-vc-install-from-checkout'. In
>> +that case the package redirects to the actual VC checkout. If the
>> +optional LISP-DIR argument is non-nil, then check if a related package
>> +specification has a `:lisp-dir' field to indicate that Lisp files are
>> +located in a sub directory of the checkout, or the checkout has a sub
>> +directory named \"lisp\" or \"src\" that contains .el files and return
>> +that instead."
>> + (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>> + (pkg-dir (pcase (plist-get pkg-spec :url)
>> + ((rx (literal package-vc--url-scheme)
>> + (let checkout-dir (+ any)))
>> + checkout-dir)
>> + (_ (package-desc-dir pkg-desc)))))
>> + (expand-file-name
>> + (or (and lisp-dir
>> + (or (plist-get pkg-spec :lisp-dir)
>> + ;; When nothing is specified about a `lisp-dir', then
>> + ;; should heuristically check if there is a
>> + ;; sub-directory with lisp files. These are
>> + ;; conventionally just called "lisp" or "src". If
>> + ;; this directory exists and contains non-zero number
>> + ;; of lisp files, we will use that instead of
>> + ;; `pkg-dir'.
>> + (catch 'done
>> + (dolist (name '("lisp" "src"))
>> + (when-let* ((dir (expand-file-name name pkg-dir))
>> + ((file-directory-p dir))
>> + ((directory-files
>> + dir nil "\\`[^.].+\\.el\\'" t 1)))
>> + ;; We won't use `dir', since dir is an absolute
>> + ;; path and we don't want `lisp-dir' to depend
>> + ;; on the current location of the package
>> + ;; installation, ie. to break if moved around
>> + ;; the file system or between installations.
>> + (throw 'done name))))))
>> + ".")
>
> Why are we falling back to "."?
The argument `lisp-dir' is an optional one, and it is not a path, rather
a boolean like. When the first argument for `expand-file-name' is nil,
it signals, doesn't it?
[...]
>> @@ -572,12 +687,12 @@ package-vc--unpack-1
>> (lm-header "version"))))
>> (vc-working-revision main-file)
>> (if missing
>> - (format
>> - " Failed to install the following dependencies: %s"
>> - (mapconcat
>> - (lambda (p)
>> - (format "%s (%s)" (car p) (cadr p)))
>> - missing ", "))
>> + (format
>> + " Failed to install the following dependencies: %s"
>> + (mapconcat
>> + (lambda (p)
>> + (format "%s (%s)" (car p) (cadr p)))
>> + missing ", "))
>> "")))
>> t))
>
> I think I mentioned this before, but this seems like an unrelated
> change, right?
I do remember some comments about formatting, but I think this one came
from the initial patch. Since the change makes indentation as default
Emacs wants to and I was not adding any other changes in the file, I
haven't reverted this one for now.
[...]
>> @@ -622,6 +737,14 @@ package-vc-non-code-file-names
>> user is fetching code from a repository that does not contain any
>> Emacs Lisp files.")
>>
>> +(defun package-vc--save-selected-packages (name pkg-spec)
>> + "Save the package specification PKG-SPEC for a package NAME."
>> + (customize-save-variable
>> + 'package-vc-selected-packages
>> + (cons (cons name pkg-spec)
>> + (seq-remove (lambda (spec) (string=3D name (car spec)))
>> + package-vc-selected-packages))))
>
> We will probably not need this if we go with the :extras solution.
I suspect that's correct.
[...]
>> @@ -934,21 +1035,22 @@ package-vc-install-from-checkout
>> (package-vc--archives-initialize)
>> (let* ((dir (if interactive dir (expand-file-name dir))) ;avoid doubl=
e expansion
>> (name (or name (file-name-base (directory-file-name dir))))
>> - (pkg-dir (file-name-concat package-user-dir name))
>> - (package-vc-selected-packages
>> - (cons (list name :lisp-dir dir)
>> - package-vc-selected-packages)))
>> + (pkg-dir (file-name-concat package-user-dir name)))
>> (when (file-exists-p pkg-dir)
>> (if (yes-or-no-p (format "Overwrite previous checkout for package=
`%s'?" name))
>> (package--delete-directory pkg-dir)
>> (error "There already exists a checkout for %s" name)))
>> (make-directory pkg-dir t)
>> + ;; We store a custom package specification so that it is available
>> + ;; for `package-vc--unpack-1' as well as `package-vc--checkout-dir'
>> + ;; can later retrieve the actual checkout.
>> + (package-vc--save-selected-packages
>> + name (list :url (concat package-vc--url-scheme dir)))
>> (package-vc--unpack-1
>> (package-desc-create
>> :name (intern name)
>> :dir pkg-dir
>> - :kind 'vc)
>> - (file-name-as-directory pkg-dir))))
>> + :kind 'vc))))
>
> The commit message doesn't appear to explain this change.
I don't think I understood this comment. This patch removes `pkg-dir'
argument for `package-vc--unpack-1'. In this case I removed the value
of `(file-name-as-directory pkg-dir)' from the call site, and it's
documented in the patch:
(package-vc-install-from-checkout): [...] Remove `pkg-dir'
argument from `package-vc--unpack-1' calls.
> I am not sure
> if we have already been over it, but changing the return value of a
> non-internal function like this is not something we shouldn't do for no
> reason.
This part I don't understand either. The patch doesn't change the value
that `package-vc-install-from-checkout' returns. It has been, and it
still is the value that `package-vc--unpack-1' returns. Similarly the
patch doesn't change value returned from `package-vc--unpack-1', which
remains t.
But I appreciate highlighting the importance of keeping interface
stable. I will add appropriate assertions to tests.
[...]
>> diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.=
el
>> new file mode 100644
>> index 00000000000..9f00d0f508f
>> --- /dev/null
>> +++ b/test/lisp/package-vc-tests.el
[...]
>> +(require 'package-vc)
>> +(require 'package)
>> +(require 'vc-git)
>
> BTW. I don't think there is any reason you would have to use vc-git in
> the tests compared to just invoking git commands manually, in case that
> makes anything easier for you.
Actually, using `vc-git' makes is what makes it easier. I had some
funny encounters with my Windows CI builds on GitHub [1], which I
haven't pin point yet, I but for now working theory is that there are
multiple git binaries in the environment. Using `vc-git' makes it more
likely that CI, tests, and the code under test uses the same one.
[...]
> The tests already look a lot better, I'll have to review them in greater
> detail in the near future, but thank you /very/ much for integrating my
> feedback from the previous commits!
I am glad you like them. Although their execution is much longer, this
approach allows for greater flexibility with what and how to test. My
advice is to apply them and keep running them as you're making changes.
Perhaps also adding extra tests, for the areas that are not tested yet.
Attaching patch for tests only. Just added extra assertions for
`package-vc-install', `package-vc-checkout', and
`package-vc-install-from-checkout' return values.
--=-=-=
Content-Type: text/x-patch; charset=utf-8
Content-Disposition: attachment;
filename=0001-Add-tests-for-package-vc.patch
Content-Transfer-Encoding: quoted-printable
Content-Description: package-vc-tests
From bb773f13189ce0c392b94283a655fa8b878c9a00 Mon Sep 17 00:00:00 2001
From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
Date: Tue, 2 Sep 2025 09:28:13 +0100
Subject: [PATCH] Add tests for package-vc
* test/lisp/package-vc-tests.el (package-vc-tests-under-test):
Define packages names to run tests on.
(package-vc-tests-preserve-temporary): When non nil then
preserve temporary test files.
(package-vc-tests-dir, package-vc-tests-packages)
(package-vc-tests-bundle): Silence byte compiler.
(package-vc-tests-add): Copy a an in file template,
update SUFFIX in it and add it to index.
(package-vc-tests-create-bundle): Create a package git
repository bundle with test package source.
(package-vc-tests-package-desc): Retrieve a `package-desc' for
tested package.
(package-vc-tests-package-lisp-dir): Determine a lisp directory
for a package.
(package-vc-tests-package-main-file): Calculate expected
location of package's main file.
(package-vc-tests-load-history-marker): Create a load history
marker.
(package-vc-tests-load-history-pattern): Create a regexp pattern
to search in `load-history'.
(package-vc-tests-load-history-position): Calculate a position
in `load-history'.
(package-vc-tests-explain-load-history-position): Return ERT
explanation for failures.
(package-vc-tests-valid-commit-p): Check that commit is a string
and it is not "unknown".
(package-vc-tests-in-strict-order-p): Check that args are in
strict order (each arg is less than the following args).
(package-vc-tests-match-p): Check that string matches a regexp.
(package-vc-tests-buffer-p): Check that object is a buffer.
(package-vc-tests-elc-files): Check that there are elc files and
that there is no compiled autoloads file amongst them.
(package-vc-tests-assert-delete-elc): Assert that .elc files
are present for a package.
(package-vc-tests-assert-package-alist): Assert that
`pakcage-alist' contains a `package-desc' for package, and that
the `pakcage-desc' has correct slot `version' and slot `dir'.
(package-vc-tests-reset-heads): Reset head of checkout of
tested packages to HEAD^.
(package-vc-tests-packages-heads): Return current checkout
revision.
(with-package-vc-tests-installed): Setup test environment,
install package, evaluate test body, and then tear down the test
environment.
(package-vc-tests-install-from-elpa)
(package-vc-tests-install-from-spec): Install a test package.
(pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
(package-vc-tests-checkout-with-git-install-from-checkout):
Checkout and install a test package.
(package-vc-tests-package-vc-async-wait): Wait for an
asynchronous VC command to finish.
(package-vc-tests-install-post-conditions): Tests that after
installing a test package the `load-history' entries, package's
main file, commit, elc files, and `package-alist' entry are
correct.
(package-vc-tests-require): Test that after calling `require'
the `load-history' entries are correct.
(package-vc-tests-upgrade, package-vc-tests-upgrade-all): Test
that after calling `package-vc-upgrade'/`package-vc-upgrade-all'
the `load-history' entries, package's elc files, commit, and
`package-alist' entry are correct.
(package-vc-tests-upgrade-after-require)
(package-vc-tests-upgrade-all-after-require): Test that after
calling `require' followed by
`package-vc-upgrade'/`package-vc-upgrade-all' the `load-history'
entries, commit, package's elc files, and `package-alist' entry
are correct.
(package-vc-tests-rebuild): Test that after calling
`package-vc-rebuild' on an old version of a package, the
package's old function, old macro, elc files, and
`package-alist' entry are correct.
(package-vc-tests-rebuild-after-require): Test that after
calling `require' followed by `package-vc-rebuild' on an old
version of a package, the package's old function, old macro, elc
files, and `package-alist' entry are correct.
(package-vc-tests-prepare-patch): Test that after calling
`package-vc-prepare-patch' the message buffer is correct.
(package-vc-tests-log-incoming): Test that after calling
`package-vc-log-incoming' the log buffer is correct.
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in:
* test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in:
Code template of version 0.1 of a test package.
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in:
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.2-lib.el.in:
Code template of code of version 0.2 of a test package.
* test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in:
* test/lisp/package-vc-resources/test-package-SUFFIX.texi.in:
Documentation template of a test package.
* test/lisp/package-vc-resources/Makefile:
Makefile template of a test package.
---
test/lisp/package-vc-resources/Makefile.in | 4 +
.../test-package-SUFFIX-inc.texi.in | 3 +
.../test-package-SUFFIX-lib-v0.1.el.in | 16 +
.../test-package-SUFFIX-lib-v0.2.el.in | 16 +
.../test-package-SUFFIX-v0.1.el.in | 28 +
.../test-package-SUFFIX-v0.2.el.in | 24 +
.../test-package-SUFFIX.texi.in | 11 +
test/lisp/package-vc-tests.el | 1052 +++++++++++++++++
8 files changed, 1154 insertions(+)
create mode 100644 test/lisp/package-vc-resources/Makefile.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-inc.=
texi.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-lib-=
v0.1.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-lib-=
v0.2.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-v0.1=
.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-v0.2=
.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX.texi=
.in
create mode 100644 test/lisp/package-vc-tests.el
diff --git a/test/lisp/package-vc-resources/Makefile.in b/test/lisp/package=
-vc-resources/Makefile.in
new file mode 100644
index 00000000000..8618ae8f2f4
--- /dev/null
+++ b/test/lisp/package-vc-resources/Makefile.in
@@ -0,0 +1,4 @@
+.PHONY: build-test-package-SUFFIX
+
+build-test-package-SUFFIX:
+ @touch test-package-SUFFIX.make-build
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in=
b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in
new file mode 100644
index 00000000000..9e4e38b74a4
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in
@@ -0,0 +1,3 @@
+@c -*- texinfo -*-
+@chapter Second chapter for test-package-SUFFIX
+ Second test text.
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el=
.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in
new file mode 100644
index 00000000000..c8bfce3e8ab
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in
@@ -0,0 +1,16 @@
+;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding: t=
-*-
+
+;;; Commentary:
+;;
+;; Test package SUFFIX library.
+
+;;; Code:
+
+(defmacro test-package-SUFFIX-mac (arg)
+ ;; checkdoc-params: (arg)
+ "Old test macro for `test-package-SUFFIX'."
+ `(format "Old macro %s" ,arg))
+
+(provide 'test-package-SUFFIX-lib)
+
+;;; test-package-SUFFIX-lib.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el=
.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in
new file mode 100644
index 00000000000..bfa4c35f014
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in
@@ -0,0 +1,16 @@
+;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding: t=
-*-
+
+;;; Commentary:
+;;
+;; Test package SUFFIX library.
+
+;;; Code:
+
+(defmacro test-package-SUFFIX-mac (arg)
+ ;; checkdoc-params: (arg)
+ "Test macro for `test-package-SUFFIX'."
+ `(format "New macro %s" ,arg))
+
+(provide 'test-package-SUFFIX-lib)
+
+;;; test-package-SUFFIX-lib.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in =
b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in
new file mode 100644
index 00000000000..ddecc88e1c5
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in
@@ -0,0 +1,28 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.1
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+(require 'test-package-SUFFIX-lib)
+
+;;;###autoload
+(defun test-package-SUFFIX-func (arg)
+ ;; checkdoc-params: (arg)
+ "Test function for `test-package-SUFFIX'."
+ (test-package-SUFFIX-mac arg))
+
+;;;###autoload
+(defun test-package-SUFFIX-old-func ()
+ "Old test function for `test-package-SUFFIX'.")
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in =
b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in
new file mode 100644
index 00000000000..902066d787d
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in
@@ -0,0 +1,24 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.2
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+(require 'test-package-SUFFIX-lib)
+
+;;;###autoload
+(defun test-package-SUFFIX-func (arg)
+ ;; checkdoc-params: (arg)
+ "Test function for `test-package-SUFFIX'."
+ (test-package-SUFFIX-mac arg))
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in b/t=
est/lisp/package-vc-resources/test-package-SUFFIX.texi.in
new file mode 100644
index 00000000000..0fc4fc3653d
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in
@@ -0,0 +1,11 @@
+\input texinfo @c -*- texinfo -*-
+@settitle Info for test-package-SUFFIX
+@direntry
+* Test-package-SUFFIX: (test-package-SUFFIX). test-package-SUFFIX.
+@end direntry
+
+@chapter First chapter for test-package-SUFFIX
+ First test text.
+
+@include test-package-SUFFIX-inc.texi
+@bye
diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
new file mode 100644
index 00000000000..477df96416b
--- /dev/null
+++ b/test/lisp/package-vc-tests.el
@@ -0,0 +1,1052 @@
+;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
+
+;; Copyright (C) 2025 Free Software Foundation, Inc.
+
+;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
+;; Keywords: package
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These tests focus on verifying post conditions for `package-vc'
+;; operations on packages. These tests install and load test packages
+;; with a sample test implementation, resulting in modification of
+;; numerous global variables, for example `load-history', `load-path',
+;; `features', etc. When run with `ert' it may contaminate current
+;; Emacs session. For this reason, tests execute their bodies in
+;; `with-package-vc-tests-installed' (which see), that takes care of
+;; cleaning up the environment.
+
+;;; Code:
+
+(require 'package-vc)
+(require 'package)
+(require 'vc-git)
+(require 'vc)
+(require 'cl-lib)
+(require 'info)
+(require 'ert-x)
+(require 'ert)
+
+(defvar package-vc-tests-under-test '(test-package-1
+ test-package-2
+ test-package-3
+ test-package-4
+ test-package-5
+ test-package-6
+ test-package-7
+ test-package-8
+ test-package-9))
+
+(defvar package-vc-tests-preserve-temporary nil
+ "When non-nil preserve temporary files produced by tests.
+Each test produces a new temporary directory for each package under
+test. This leads to creation of [length of
+`package-vc-tests-under-test'] times [number of tests executed]
+temporary directories for each tests run. When this variable is nil
+then delete all temporary directories as soon as they are no longer
+needed. When this variable is a symbol, then preserve temporary
+directories for the package that matches the symbol. When this variable
+is a list of symbol, then preserve temporary directories for each
+package that matches symbol in the list. When this variable is t then
+preserve all temporary directories. Tests create temporary directories
+with `make-temp-file', which see.")
+
+(defvar package-vc-tests-dir)
+(defvar package-vc-tests-packages)
+(defvar package-vc-tests-bundle)
+
+;; TODO: add test for deleting packages, with asserting
+;; `package-vc-selected-packages'
+
+;; TODO: clarify `package-vc-install-all' behaviour with regards to
+;; packages installed with `package-vc' but not stored in
+;; `package-vc-selected-packages' i.e., packages from ELPAs
+
+(defun package-vc-tests-add (suffix in-file &optional lisp-dir)
+ "Create a new file from IN-FILE template updating SUFFIX in it.
+When LISP-DIR is non-nil place the NAME file under LISP-DIR."
+ (let* ((resource-dir (ert-resource-directory))
+ (suffix (if (stringp suffix) suffix (format "%s" suffix)))
+ (file (let ((file (replace-regexp-in-string
+ (rx ".in" string-end) ""
+ (replace-regexp-in-string
+ "SUFFIX" suffix
+ (replace-regexp-in-string
+ (rx "-v" digit (zero-or-more
+ "." (one-or-more digit)))
+ ""
+ in-file
+ nil nil 0)
+ nil nil 0)
+ nil nil 0)))
+ (if lisp-dir
+ (file-name-concat lisp-dir file)
+ file))))
+ (copy-file (expand-file-name in-file resource-dir) file t)
+ (with-temp-buffer
+ (insert-file-contents file)
+ (goto-char (point-min))
+ (while (search-forward "SUFFIX" nil t)
+ (replace-match suffix))
+ (write-file file))
+ (vc-git-command nil 0 nil "add" ".")))
+
+(defun package-vc-tests-create-bundle (suffix &optional lisp-dir)
+ "Create a test package bundle with SUFFIX.
+If LISP-DIR is non-nil place sources of the package in LISP-DIR."
+ (let* ((name (format "test-package-%s" suffix))
+ (repo-dir (expand-file-name (file-name-concat "repo" name)
+ package-vc-tests-dir)))
+ (make-directory (if lisp-dir
+ (expand-file-name lisp-dir repo-dir)
+ repo-dir)
+ :parents)
+ (let ((default-directory repo-dir)
+ (bundle-file (expand-file-name (format "%s.bundle" name)
+ package-vc-tests-dir)))
+ (vc-git-command nil 0 nil "init" "-b" "master")
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-lib-v0.1.el.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-v0.1.el.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX.texi.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-inc.texi.in" lisp-dir)
+ ;; Place Makefile in root of the repository
+ (package-vc-tests-add
+ suffix "Makefile.in" nil)
+ (vc-git-command nil 0 nil "commit" "-m" "First commit")
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-lib-v0.2.el.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-v0.2.el.in" lisp-dir)
+ (vc-git-command nil 0 nil "commit" "-m" "Second commit")
+ (vc-git-command nil 0 nil
+ "bundle" "create" bundle-file "master")
+ (list bundle-file (vc-git-working-revision nil)))))
+
+(defun package-vc-tests-package-desc (package &optional installed)
+ "Return descriptor of PACKAGE.
+When INSTALLED is non-nil the descriptor will come from `package-alist'.
+Otherwise the descriptor will be from `package-archive-contents'. This
+is to mimic `package-vc--read-package-desc'."
+ (cadr (assoc (if (stringp package) package (symbol-name package))
+ (if installed package-alist package-archive-contents)
+ #'string=3D)))
+
+(defun package-vc-tests-package-lisp-dir (pkg)
+ "Return a Lisp directory of PKG."
+ (and-let* ((checkout-dir (car
+ (alist-get pkg
+ package-vc-tests-packages))))
+ (or (and-let* ((lisp-dir (cadr
+ (alist-get pkg
+ package-vc-tests-packages))))
+ (expand-file-name lisp-dir checkout-dir))
+ checkout-dir)))
+
+(defun package-vc-tests-package-main-file (pkg)
+ "Return a main file of PKG."
+ (file-name-concat (package-vc-tests-package-lisp-dir pkg)
+ (format "%s.el" pkg)))
+
+;; When a package source is being recompiled - for example as result of
+;; `pakckage-vc-upgrade' or `package-vc-rebuild' - it is also reloaded
+;; [1] to ensure that the most recent version of compiled code is
+;; available to Emacs. There are a few tests that add markers in
+;; `load-history' before executing such functions. And then follow up
+;; tests use these markers to assert that expected package files are in
+;; correct places in the `load-history'.
+;;
+;; [1] Only when a file has been loaded previously.
+
+(defun package-vc-tests-load-history-marker (name)
+ "Return a `load-history' marker with NAME."
+ (expand-file-name (symbol-name name)
+ package-vc-tests-dir))
+
+(defun package-vc-tests-load-history-pattern (pkg type)
+ "Return a regexp pattern for PKG's file of TYPE."
+ (pcase type
+ (:autoloads
+ (rx (literal (file-name-concat
+ package-user-dir
+ (symbol-name pkg)
+ (format "%s-autoloads.el" pkg)))
+ string-end))
+ (:main
+ (rx
+ (literal
+ (package-vc-tests-package-main-file pkg))
+ string-end))
+ (:main-compiled
+ (rx
+ (literal
+ (package-vc-tests-package-main-file pkg))
+ "c"
+ string-end))
+ (:marker
+ (rx (literal (package-vc-tests-load-history-marker pkg))))))
+
+(defun package-vc-tests-load-history-position (pkg type)
+ "Return a PKG's file of TYPE position in `load-history'.
+If TYPE is `:autoloads' return a position of a PKG autoloads file.
+Otherwise, if TYPE is `:main' return a position of PKG main file (not
+compiled). Otherwise, if TYPE is `:main-compiled' return a position of
+PKG compiled main file. Otherwise, if TYPE is `:marker' return a
+position of a marker PKG."
+ (let ((pkg-file (package-vc-tests-load-history-pattern pkg type))
+ (interesting-entry
+ (rx string-start
+ (literal (file-truename package-vc-tests-dir)))))
+ (cl-position-if
+ (lambda (file)
+ (string-match pkg-file file))
+ (cl-remove-if-not
+ (lambda (file-name)
+ (string-match interesting-entry file-name))
+ (mapcar
+ #'file-truename
+ (cl-remove-if-not
+ #'stringp
+ (mapcar #'car-safe load-history)))))))
+
+(defun package-vc-tests-explain-load-history-position (pkg type)
+ "Explain `package-vc-tests-load-history' failed for PKG of TYPE."
+ (let ((pattern
+ (concat "..."
+ (substring
+ (package-vc-tests-load-history-pattern pkg type)
+ (length (rx (literal package-vc-tests-dir))))))
+ (reason
+ (if-let* ((pos (package-vc-tests-load-history-position
+ pkg type)))
+ `(found in load-history at pos ,pos)
+ '(not found in load-history)))
+ (entries
+ (mapcar
+ (lambda (file)
+ (concat "..."
+ (substring file (length package-vc-tests-dir))))
+ (cl-remove-if
+ (lambda (file)
+ (or (not (stringp file))
+ (not (string-prefix-p package-vc-tests-dir file))))
+ (mapcar #'car-safe load-history)))))
+ (append (list 'pattern pattern)
+ reason
+ (list entries))))
+
+(put #'package-vc-tests-load-history-position
+ 'ert-explainer
+ #'package-vc-tests-explain-load-history-position)
+
+;; The following predicates and helper functions take an extra PKG
+;; argument. This is needed for ERT to print package name in case of
+;; failure.
+
+(defun package-vc-tests-valid-commit-p (_pkg commit)
+ "Return non-nil when COMMIT is a valid commit."
+ (and (stringp commit)
+ (not (string=3D commit "unknown"))))
+
+(defun package-vc-tests-in-strict-order-p (_pkg &rest args)
+ "Return non-nil when ARGS are in strict order."
+ (apply #'< args))
+
+(defun package-vc-tests-match-p (_pkg regexp string)
+ "Return non-nil when REGEXP matches STRING."
+ (string-match regexp string))
+
+(defun package-vc-tests-buffer-p (_pkg obj)
+ "Return non-nil when OBJ is a buffer."
+ (bufferp obj))
+
+(defun package-vc-tests-elc-files (pkg)
+ "Return elc files for PKG."
+ (when-let* ((dir (package-vc-tests-package-lisp-dir pkg))
+ (elc-files (directory-files
+ dir nil (rx ".elc" string-end))))
+ elc-files))
+
+(defun package-vc-tests-assert-elc (pkg)
+ "Assert that PKG has correct .elc files in."
+ (let* ((dir (package-vc-tests-package-lisp-dir pkg))
+ (elc-files (should (package-vc-tests-elc-files pkg)))
+ (autoloads-rx (rx
+ (literal (format "%s-autoloads.elc" pkg))
+ string-end)))
+ (should-not (cl-find-if (lambda (elc)
+ (string-match autoloads-rx elc))
+ elc-files))
+ (dolist (elc-file elc-files)
+ (delete-file (expand-file-name elc-file dir)))))
+
+(defun package-vc-tests-assert-package-alist (pkg version)
+ "Assert that PKG entry in `package-alist' have correct VERSION and dir."
+ (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
+ (should (equal (file-name-as-directory
+ (expand-file-name (format "%s" pkg)
+ package-user-dir))
+ (file-name-as-directory
+ (package-desc-dir pkg-desc))))
+ (should (equal (list pkg version)
+ (list pkg (package-desc-version pkg-desc))))))
+
+(defun package-vc-tests-reset-head (pkg)
+ "Reset to HEAD^ checkout for PKG."
+ (let ((default-directory (car
+ (alist-get pkg package-vc-tests-packages))))
+ (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))
+
+(defun package-vc-tests-package-head (pkg)
+ "Return HEAD revisions of a PKG."
+ (let ((default-directory (car
+ (alist-get pkg package-vc-tests-packages))))
+ (vc-git-working-revision nil)))
+
+(defmacro with-package-vc-tests-installed (pkg &rest body)
+ "Eval BODY with PKG installed in a test environment."
+ (declare (indent 1) (debug t))
+ ;; git-bundle(1) produces test packages sources in bundle files, based
+ ;; on skeleton files in directory package-vc-resources. Before
+ ;; executing body make sure that:
+ ;;
+ ;; - `package' has been initialised, and there are no
+ ;; `package-archives' defined
+ `(let* ((package-archives (unless package--initialized
+ (let (package-archives)
+ (package-initialize)
+ (package-vc--archives-initialize))
+ nil))
+ ;; - create a temporary location for packages and test files
+ (package-vc-tests-dir
+ (expand-file-name
+ (make-temp-file "package-vc-tests-"
+ t
+ (format-time-string "-%Y%m%d.%H%M%S.%3N"))))
+ ;; - packages are installed into a test directory
+ (package-user-dir (expand-file-name "elpa"
+ package-vc-tests-dir))
+ ;; - define test packages, their checkout locations, lisp
+ ;; directories, and install functions
+ (package-vc-tests-packages
+ `(;; checkout and install with `package-vc-install' (on
+ ;; ELPA)
+ (test-package-1
+ ,(expand-file-name "test-package-1"
+ package-user-dir)
+ nil
+ package-vc-tests-install-from-elpa)
+ ;; checkout and install with `package-vc-install' (not on
+ ;; ELPA)
+ (test-package-2
+ ,(expand-file-name "test-package-2"
+ package-user-dir)
+ nil
+ package-vc-tests-install-from-spec)
+ ;; checkout with `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-3
+ ,(expand-file-name "test-package-3"
+ package-vc-tests-dir)
+ nil
+ pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
+ ;; checkout with git and install with
+ ;; `package-vc-install-from-checkout'
+ (test-package-4
+ ,(expand-file-name "test-package-4"
+ package-vc-tests-dir)
+ nil
+ package-vc-tests-checkout-with-git-install-from-checkout)
+ ;; sources in "lisp" sub directory, checkout and install
+ ;; with `package-vc-install' (not on ELPA)
+ (test-package-5
+ ,(expand-file-name "test-package-5"
+ package-user-dir)
+ "lisp"
+ package-vc-tests-install-from-spec)
+ ;; sources in "lisp" sub directory, checkout with git and
+ ;; install with `package-vc-install-from-checkout'
+ (test-package-6
+ ,(expand-file-name "test-package-6"
+ package-vc-tests-dir)
+ "lisp"
+ package-vc-tests-checkout-with-git-install-from-checkout)
+
+ ;; sources in "src" sub directory, checkout and install
+ ;; with `package-vc-install' (on ELPA)
+ (test-package-7
+ ,(expand-file-name "test-package-7"
+ package-user-dir)
+ "src"
+ package-vc-tests-install-from-elpa)
+ ;; sources in "src" sub directory, checkout with
+ ;; `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-8
+ ,(expand-file-name "test-package-8"
+ package-vc-tests-dir)
+ nil
+ pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
+ ;; sources in "custom-dir" sub directory, checkout and
+ ;; install with `package-vc-install' (on ELPA)
+ (test-package-9
+ ,(expand-file-name "test-package-9"
+ package-user-dir)
+ "custom-dir"
+ package-vc-tests-install-from-elpa)))
+ ;; - create a test package bundle
+ (package-vc-tests-bundle
+ (let* ((pkg-name (symbol-name ,pkg))
+ (suffix (and (string-match
+ (rx ?-
+ (group (one-or-more (not ?-)))
+ string-end)
+ pkg-name)
+ (match-string 1 pkg-name))))
+ (package-vc-tests-create-bundle
+ suffix (cadr (alist-get ,pkg package-vc-tests-packages)))))
+ ;; - find all packages that are present in a test ELPA
+ (package-vc-tests-elpa-packages
+ (mapcar
+ #'car
+ (cl-remove-if-not
+ (lambda (package)
+ (memq
+ (cadddr package)
+ '(package-vc-tests-install-from-elpa
+ pakcage-vc-tests-checkout-from-elpa-install-from-checkou=
t)))
+ package-vc-tests-packages)))
+ ;; - make test packages recognisable by `package' and
+ ;; `package-vc' internals:
+ (package-archive-contents
+ (mapcar
+ (lambda (pkg)
+ (list pkg
+ (package-desc-create
+ :name pkg
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras
+ (list
+ '(:maintainer
+ ("Test Maintainer"
+ . "test-maintainer@HIDDEN"))
+ (cons :url (car package-vc-tests-bundle))
+ (cons :commit (cadr package-vc-tests-bundle))
+ (cons :revdesc (substring
+ (cadr package-vc-tests-bundle)
+ 0 12))))))
+ package-vc-tests-elpa-packages))
+ (package-vc--archive-spec-alists
+ (list
+ (cons 'test-elpa
+ (mapcar
+ (lambda (pkg)
+ (let ((lisp-dir
+ (cadr (alist-get
+ ,pkg package-vc-tests-packages))))
+ (append
+ (list pkg
+ :url (car package-vc-tests-bundle)
+ :branch "master"
+ :doc (let ((doc-file
+ (format "%s.texi" ,pkg)))
+ (if lisp-dir
+ (file-name-concat lisp-dir
+ doc-file)
+ doc-file))
+ :make (format "build-%s" ,pkg)
+ :shell-command (format
+ "touch %s.cmd-build"
+ ,pkg))
+ (and lisp-dir
+ (not (member lisp-dir '("lisp" "src")))
+ (list :lisp-dir lisp-dir)))))
+ package-vc-tests-elpa-packages))))
+ (package-vc--archive-data-alist
+ (list
+ (list 'test-elpa :version 1 :default-vc 'Git)))
+ ;; - `vc-guess-backend-url' is recognising bundles as `Git'
+ ;; repositories:
+ (vc-clone-heuristic-alist
+ (cons
+ (cons (rx "test-package-" (one-or-more digit) ".bundle"
+ string-end)
+ 'Git)
+ vc-clone-heuristic-alist))
+ ;; - ensure that `package-alist' and
+ ;; `package-vc-selected-packages' are empty
+ package-alist
+ package-vc-selected-packages
+ ;; - don't save any customization
+ (user-init-file nil)
+ ;; - FIXME: something sets `default-directory' to last
+ ;; checkout directory after `package-vc-checkout', which
+ ;; causes problems when this macro deletes the temporary
+ ;; directory after body execution.
+ (default-directory package-vc-tests-dir))
+ (unwind-protect
+ (progn
+ (funcall (or (caddr (alist-get ,pkg
+ package-vc-tests-packages))
+ (lambda (pkg)
+ (ert-fail
+ (format
+ "Cannot find %s in package-vc-tests-packages"
+ pkg))))
+ ,pkg)
+ ,@body)
+ ;; Unbind package defined symbols, and remove package defined
+ ;; features and entries from `load-path',`load-history', and
+ ;; `Info-directory-list'.
+ (let ((pattern (rx string-start (literal package-vc-tests-dir))))
+ (dolist (entry load-history)
+ (when-let* ((file (car-safe entry))
+ ((stringp file))
+ ((string-match pattern file)))
+ (dolist (elt (cdr entry))
+ (pcase elt
+ (`(defun . ,fun)
+ (fmakunbound fun))
+ (`(provide . ,feat)
+ (setq features (cl-remove feat features)))
+ ((and (pred symbolp)
+ (pred boundp))
+ (makunbound elt))))))
+ (setq load-path (cl-remove-if
+ (lambda (path)
+ (and (stringp path)
+ (string-match pattern path)))
+ load-path)
+ load-history (cl-remove-if
+ (lambda (entry)
+ (and-let* ((path (car-safe entry))
+ ((stringp path)))
+ (string-match pattern path)))
+ load-history)
+ Info-directory-list (cl-remove-if
+ (lambda (dir)
+ (and (stringp dir)
+ (string-match pattern dir)))
+ Info-directory-list)))
+ (if (or (eq package-vc-tests-preserve-temporary t)
+ (eq package-vc-tests-preserve-temporary ,pkg)
+ (and (listp package-vc-tests-preserve-temporary)
+ (memq ,pkg package-vc-tests-preserve-temporary)))
+ (message "package-vc-tests: preserving temporary directory %s"
+ package-vc-tests-dir)
+ (delete-directory package-vc-tests-dir t)))))
+
+(defun package-vc-tests-install-from-elpa (pkg)
+ "Install PKG with `package-vc-install'."
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t (package-vc-install pkg)))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should-not (alist-get (symbol-name pkg)
+ package-vc-selected-packages
+ nil nil #'string=3D)))
+
+(defun package-vc-tests-install-from-spec (pkg)
+ "Install PKG with `package-vc-install' (not on ELPA)."
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t
+ (package-vc-install `(,pkg
+ :url ,(car package-vc-tests-bundle)
+ :branch "master"))))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (car package-vc-tests-bundle)
+ (plist-get (alist-get (symbol-name pkg)
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+(defun pakcage-vc-tests-checkout-from-elpa-install-from-checkout (pkg)
+ "Install PKG with `package-vc-install-from-checkout'.
+Make checkout with `package-vc-checkout'."
+ (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
+ (let ((buffer (package-vc-checkout (package-vc-tests-package-desc
+ pkg)
+ checkout-dir)))
+ (should (package-vc-tests-buffer-p pkg buffer))
+ (should (string-prefix-p (symbol-name pkg)
+ (buffer-name buffer))))
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t
+ (package-vc-install-from-checkout checkout-dir)))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (concat package-vc--url-scheme checkout-dir)
+ (plist-get (alist-get (symbol-name pkg)
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url)))))
+
+(defun package-vc-tests-checkout-with-git-install-from-checkout (pkg)
+ "Install PKG with `package-vc-install-from-checkout'.
+Make checkout with git(1)."
+ (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
+ (vc-git-clone (car package-vc-tests-bundle)
+ checkout-dir
+ "master")
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t
+ (package-vc-install-from-checkout checkout-dir
+ (symbol-name pkg))))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (concat package-vc--url-scheme checkout-dir)
+ (plist-get (alist-get (symbol-name pkg)
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url)))))
+
+(defmacro package-vc-tests-package-vc-async-wait (seconds count flags &res=
t body)
+ "Wait up to SECONDS for COUNT async vc commands with FLAGS called by BOD=
Y.
+Return nil on timeout or the value of last form in BODY."
+ (declare (indent 3))
+ (let ((count-sym (make-symbol "count"))
+ (post-vc-command-sym (make-symbol "post-vc-command")))
+ `(letrec ((,count-sym ,count)
+ (,post-vc-command-sym
+ (lambda (command _ command-flags)
+ ;; A crude filter for vc commands
+ (when (and (equal command "git")
+ (cl-every (lambda (flag)
+ (member flag command-flags))
+ ,flags))
+ (decf ,count-sym)))))
+ (add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
+ (unwind-protect
+ (with-timeout (,seconds nil)
+ (prog1
+ (progn ,@body)
+ (while (/=3D ,count-sym 0)
+ (accept-process-output nil 0.01))))
+ (remove-hook 'vc-post-command-functions
+ ,post-vc-command-sym)))))
+
+(ert-deftest package-vc-tests-install-post-conditions ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (let ((install-begin
+ (should (package-vc-tests-load-history-position
+ 'install-begin :marker)))
+ (install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ install-end
+ autoloads-pos
+ install-begin))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled)))
+ (should (equal (package-vc--main-file
+ (package-vc-tests-package-desc pkg t))
+ (package-vc-tests-package-main-file pkg)))
+ (should (package-vc-tests-valid-commit-p
+ pkg
+ (package-vc-commit
+ (package-vc-tests-package-desc pkg t))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))))
+
+(ert-deftest package-vc-tests-require ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should (require pkg))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (let ((install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ main-compiled-pos
+ install-end))))))
+
+(ert-deftest package-vc-tests-upgrade ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade (package-vc-tests-package-desc pkg t))
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-end))
+ load-history)
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ autoloads-pos
+ upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))))
+
+(ert-deftest package-vc-tests-upgrade-after-require ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (should (require pkg))
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade (package-vc-tests-package-desc pkg t))
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-end))
+ load-history)
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ autoloads-pos
+ upgrade-begin))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ main-pos
+ upgrade-begin))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ main-compiled-pos
+ upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))))
+
+(ert-deftest package-vc-tests-upgrade-all ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-end))
+ load-history)
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ autoloads-pos
+ upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))))
+
+(ert-deftest package-vc-tests-upgrade-all-after-require ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (should (require pkg))
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-end))
+ load-history)
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ autoloads-pos
+ upgrade-begin))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ main-pos
+ upgrade-begin))
+ (should (package-vc-tests-in-strict-order-p
+ pkg
+ upgrade-end
+ main-compiled-pos
+ upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))))
+
+(ert-deftest package-vc-tests-rebuild ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (package-vc-tests-reset-head pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (let ((old-func (intern (format "%s-old-func" pkg))))
+ (should (fboundp old-func))
+ (should (autoloadp
+ (symbol-function old-func))))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "Old macro test"
+ (funcall func "test"))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 1)))))
+
+(ert-deftest package-vc-tests-rebuild-after-require ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (should (require pkg))
+ (package-vc-tests-reset-head pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (let ((old-func (intern (format "%s-old-func" pkg))))
+ (should (fboundp old-func))
+ (should-not (autoloadp
+ (symbol-function old-func))))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
+ (symbol-function func)))
+ (should (equal "Old macro test"
+ (funcall func "test"))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 1)))))
+
+(ert-deftest package-vc-tests-prepare-patch ()
+ ;; Ensure `vc-prepare-patch' respects subject from function argument
+ (let (vc-prepare-patches-separately)
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (package-vc-prepare-patch (package-vc-tests-package-desc pkg t)
+ "test-subject"
+ (cdr package-vc-tests-bundle))
+ (let ((message-buffer
+ (should (get-buffer "*unsent mail to Test Maintainer*"))))
+ (should (package-vc-tests-buffer-p pkg message-buffer))
+ (switch-to-buffer message-buffer)
+ (goto-char (point-min))
+ (should
+ (package-vc-tests-match-p
+ pkg
+ (rx
+ "To: Test Maintainer <test-maintainer@HIDDEN>")
+ (buffer-substring (point) (pos-eol))))
+ (forward-line)
+ (should
+ (package-vc-tests-match-p
+ pkg
+ (rx "Subject: test-subject")
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer message-buffer)))))))
+
+(ert-deftest package-vc-tests-log-incoming ()
+ (dolist (pkg package-vc-tests-under-test)
+ (with-package-vc-tests-installed pkg
+ (package-vc-tests-reset-head pkg)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 1 '("log" "--decorate")
+ (package-vc-log-incoming (package-vc-tests-package-desc pkg t))
+ t))
+ (let ((incoming-buffer (get-buffer "*vc-incoming*"))
+ (pattern (rx (literal
+ (substring
+ (cadr package-vc-tests-bundle)
+ 0 7))
+ (one-or-more any)
+ "Second commit"
+ line-end)))
+ (should (package-vc-tests-buffer-p pkg incoming-buffer))
+ (switch-to-buffer incoming-buffer)
+ (goto-char (point-min))
+ (should
+ (package-vc-tests-match-p
+ pkg
+ pattern
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer incoming-buffer))))))
+
+(ert-deftest package-vc-tests-pkg-spec-doc-make-shell-command ()
+ (let ((package-vc-allow-build-commands t))
+ ;; Only `packgae-vc-install' runs make and shell command
+ (dolist (pkg '(test-package-1 test-package-7 test-package-9))
+ (with-package-vc-tests-installed pkg
+ (let ((checkout-dir (car (alist-get
+ pkg package-vc-tests-packages))))
+ (should (file-exists-p
+ (expand-file-name
+ (format "%s.make-build" pkg)
+ checkout-dir)))
+ (should (file-exists-p
+ (expand-file-name
+ (format "%s.cmd-build" pkg)
+ checkout-dir))))
+ (should (cl-member-if (lambda (dir)
+ (and (stringp dir)
+ (string-prefix-p package-vc-tests-dir
+ dir)))
+ Info-directory-list))
+ (let ((info-file
+ (expand-file-name (format "%s.info" pkg)
+ (car (alist-get
+ pkg package-vc-tests-packages)))))
+ (should (file-exists-p info-file))
+ (ert-with-test-buffer
+ (:name (format "*package-vc-tests: %s.info*" pkg))
+ (insert-file-contents info-file)
+ (goto-char (point-min))
+ (should (re-search-forward
+ (format "First chapter for %s" pkg)))
+ (should (re-search-forward
+ (format "Second chapter for %s" pkg)))))))))
+
+(provide 'package-vc-tests)
+
+;;; package-vc-tests.el ends here
--=20
2.51.2
--=-=-=
Content-Type: text/plain
[1] https://github.com/pkryger/setup-emacs-dev (FWIW: I am planning to
add Linux and macOS builds such that one can just test their development
branch with simple YAML file).
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Tue, 25 Nov 2025 20:23:03 +0000
Resent-Message-ID: <handler.79188.B79188.17641021674572 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org, Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17641021674572
(code B ref 79188); Tue, 25 Nov 2025 20:23:03 +0000
Received: (at 79188) by debbugs.gnu.org; 25 Nov 2025 20:22:47 +0000
Received: from localhost ([127.0.0.1]:41920 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vNzYR-00017N-PP
for submit <at> debbugs.gnu.org; Tue, 25 Nov 2025 15:22:46 -0500
Received: from mout02.posteo.de ([185.67.36.66]:52025)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1vNCyG-0000FX-OX
for 79188 <at> debbugs.gnu.org; Sun, 23 Nov 2025 11:29:57 -0500
Received: from submission (posteo.de [185.67.36.169])
by mout02.posteo.de (Postfix) with ESMTPS id D9B8B240101
for <79188 <at> debbugs.gnu.org>; Sun, 23 Nov 2025 17:29:45 +0100 (CET)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1763915385; bh=HBYvoJTpowYQsj7aEv9Is8v0B6y2JXzi+cgIEfsKdho=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:Content-Transfer-Encoding:From;
b=T5NjnpOXFZulJ1PpfjhiLPZbdltg33khmGlTnxzeiQHzGdAZJeerAC3Z9/u75LIpV
OMu4dXTVG6sACJnBuc21qnPEHNapibvaR49uWQMZfEP7cyRKY8iRjAeC2zdF+bCv6I
9xu8qxrBEzL6O95eIWdmkHiHxaEulfhs1U9RVzEk8d67aKYe3s0EhD0AXXgnT5Sa4g
00SQmr09PrXnCS3c5iQtQTccBv/2cLgm/RZEzJJsWezKDuIO+n4lOOWctQyEQ1doL+
dNOzkx03iAHVTB8YhYFssb3SrFf0fnW+NhgkQ4kN2V/VMjJzDMX84hcYW46GwGX2bY
A+jnB0skSSf1g==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4dDvYh5gdhz6tw2;
Sun, 23 Nov 2025 17:29:44 +0100 (CET)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2bjl0vidc.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<m24iqzmqh6.fsf@HIDDEN> <m28qgbqsx0.fsf_-_@HIDDEN>
<m2tsyzjek4.fsf@HIDDEN> <875xbcbg0f.fsf@HIDDEN>
<m2bjl0vidc.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Sun, 23 Nov 2025 16:29:45 +0000
Message-ID: <874iqkiufc.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> * test/lisp/package-vc-tests.el (package-vc-tests-under-test):
> Define packages names to run tests on.
>
> (package-vc-tests-preserve-temporary): When non nil then
> preserve temporary test files.
>
> (package-vc-tests-dir, package-vc-tests-packages)
> (package-vc-tests-bundle): Silence byte compiler.
>
> (package-vc-tests-add): Copy a an in file template,
> update SUFFIX in it and add it to index.
>
> (package-vc-tests-create-bundle): Create a package git
> repository bundle with test package source.
>
> (package-vc-tests-package-desc): Retrieve a `package-desc' for
> tested package.
>
> (package-vc-tests-package-lisp-dir): Determine a lisp directory
> for a package.
>
> (package-vc-tests-package-main-file): Calculate expected
> location of package's main file.
>
> (package-vc-tests-load-history-marker): Create a load history
> marker.
>
> (package-vc-tests-load-history-pattern): Create a regexp pattern
> to search in `load-history'.
>
> (package-vc-tests-load-history-position): Calculate a position
> in `load-history'.
>
> (package-vc-tests-explain-load-history-position): Return ERT
> explanation for failures.
>
> (package-vc-tests-valid-commit-p): Check that commit is a string
> and it is not "unknown".
>
> (package-vc-tests-in-strict-order-p): Check that args are in
> strict order (each arg is less than the following args).
>
> (package-vc-tests-match-p): Check that string matches a regexp.
>
> (package-vc-tests-buffer-p): Check that object is a buffer.
>
> (package-vc-tests-elc-files): Check that there are elc files and
> that there is no compiled autoloads file amongst them.
>
> (package-vc-tests-assert-delete-elc): Assert that .elc files
> are present for a package.
>
> (package-vc-tests-assert-package-alist): Assert that
> `pakcage-alist' contains a `package-desc' for package, and that
> the `pakcage-desc' has correct slot `version' and slot `dir'.
>
> (package-vc-tests-reset-heads): Reset head of checkout of
> tested packages to HEAD^.
>
> (package-vc-tests-packages-heads): Return current checkout
> revision.
>
> (with-package-vc-tests-installed): Setup test environment,
> install package, evaluate test body, and then tear down the test
> environment.
>
> (package-vc-tests-install-from-elpa)
> (package-vc-tests-install-from-spec): Install a test package.
>
> (pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
> (package-vc-tests-checkout-with-git-install-from-checkout):
> Checkout and install a test package.
>
> (package-vc-tests-package-vc-async-wait): Wait for an
> asynchronous VC command to finish.
>
> (package-vc-tests-install-post-conditions): Tests that after
> installing a test package the `load-history' entries, package's
> main file, commit, elc files, and `package-alist' entry are
> correct.
>
> (package-vc-tests-require): Test that after calling `require'
> the `load-history' entries are correct.
>
> (package-vc-tests-upgrade, package-vc-tests-upgrade-all): Test
> that after calling `package-vc-upgrade'/`package-vc-upgrade-all'
> the `load-history' entries, package's elc files, commit, and
> `package-alist' entry are correct.
>
> (package-vc-tests-upgrade-after-require)
> (package-vc-tests-upgrade-all-after-require): Test that after
> calling `require' followed by
> `package-vc-upgrade'/`package-vc-upgrade-all' the `load-history'
> entries, commit, package's elc files, and `package-alist' entry
> are correct.
>
> (package-vc-tests-rebuild): Test that after calling
> `package-vc-rebuild' on an old version of a package, the
> package's old function, old macro, elc files, and
> `package-alist' entry are correct.
>
> (package-vc-tests-rebuild-after-require): Test that after
> calling `require' followed by `package-vc-rebuild' on an old
> version of a package, the package's old function, old macro, elc
> files, and `package-alist' entry are correct.
>
> (package-vc-tests-prepare-patch): Test that after calling
> `package-vc-prepare-patch' the message buffer is correct.
>
> (package-vc-tests-log-incoming): Test that after calling
> `package-vc-log-incoming' the log buffer is correct.
>
> * test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in:
> * test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in:
> Code template of version 0.1 of a test package.
>
> * test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in:
> * test/lisp/package-vc-resources/test-package-SUFFIX-v0.2-lib.el.in:
> Code template of code of version 0.2 of a test package.
>
> * test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in:
> * test/lisp/package-vc-resources/test-package-SUFFIX.texi.in:
> Documentation template of a test package.
>
> * test/lisp/package-vc-resources/Makefile:
> Makefile template of a test package.
> ---
> test/lisp/package-vc-resources/Makefile.in | 4 +
> .../test-package-SUFFIX-inc.texi.in | 3 +
> .../test-package-SUFFIX-lib-v0.1.el.in | 16 +
> .../test-package-SUFFIX-lib-v0.2.el.in | 16 +
> .../test-package-SUFFIX-v0.1.el.in | 28 +
> .../test-package-SUFFIX-v0.2.el.in | 24 +
> .../test-package-SUFFIX.texi.in | 11 +
> test/lisp/package-vc-tests.el | 1045 +++++++++++++++++
> 8 files changed, 1147 insertions(+)
> create mode 100644 test/lisp/package-vc-resources/Makefile.in
> create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-in=
c.texi.in
> create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-li=
b-v0.1.el.in
> create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-li=
b-v0.2.el.in
> create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-v0=
.1.el.in
> create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-v0=
.2.el.in
> create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX.te=
xi.in
> create mode 100644 test/lisp/package-vc-tests.el
>
> diff --git a/test/lisp/package-vc-resources/Makefile.in b/test/lisp/packa=
ge-vc-resources/Makefile.in
> new file mode 100644
> index 00000000000..8618ae8f2f4
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/Makefile.in
> @@ -0,0 +1,4 @@
> +.PHONY: build-test-package-SUFFIX
> +
> +build-test-package-SUFFIX:
> + @touch test-package-SUFFIX.make-build
> diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.=
in b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in
> new file mode 100644
> index 00000000000..9e4e38b74a4
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in
> @@ -0,0 +1,3 @@
> +@c -*- texinfo -*-
> +@chapter Second chapter for test-package-SUFFIX
> + Second test text.
> diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.=
el.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in
> new file mode 100644
> index 00000000000..c8bfce3e8ab
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in
> @@ -0,0 +1,16 @@
> +;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding:=
t -*-
> +
> +;;; Commentary:
> +;;
> +;; Test package SUFFIX library.
> +
> +;;; Code:
> +
> +(defmacro test-package-SUFFIX-mac (arg)
> + ;; checkdoc-params: (arg)
> + "Old test macro for `test-package-SUFFIX'."
> + `(format "Old macro %s" ,arg))
> +
> +(provide 'test-package-SUFFIX-lib)
> +
> +;;; test-package-SUFFIX-lib.el ends here
> diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.=
el.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in
> new file mode 100644
> index 00000000000..bfa4c35f014
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in
> @@ -0,0 +1,16 @@
> +;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding:=
t -*-
> +
> +;;; Commentary:
> +;;
> +;; Test package SUFFIX library.
> +
> +;;; Code:
> +
> +(defmacro test-package-SUFFIX-mac (arg)
> + ;; checkdoc-params: (arg)
> + "Test macro for `test-package-SUFFIX'."
> + `(format "New macro %s" ,arg))
> +
> +(provide 'test-package-SUFFIX-lib)
> +
> +;;; test-package-SUFFIX-lib.el ends here
> diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.i=
n b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in
> new file mode 100644
> index 00000000000..ddecc88e1c5
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in
> @@ -0,0 +1,28 @@
> +;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
> +
> +;; Homepage: https://test-domain.org
> +;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
> +;; Package-Requires: ((emacs "30.1"))
> +;; Version: 0.1
> +
> +;;; Commentary:
> +;;
> +;; Test package SUFFIX.
> +
> +;;; Code:
> +
> +(require 'test-package-SUFFIX-lib)
> +
> +;;;###autoload
> +(defun test-package-SUFFIX-func (arg)
> + ;; checkdoc-params: (arg)
> + "Test function for `test-package-SUFFIX'."
> + (test-package-SUFFIX-mac arg))
> +
> +;;;###autoload
> +(defun test-package-SUFFIX-old-func ()
> + "Old test function for `test-package-SUFFIX'.")
> +
> +(provide 'test-package-SUFFIX)
> +
> +;;; test-package-SUFFIX.el ends here
> diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.i=
n b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in
> new file mode 100644
> index 00000000000..902066d787d
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in
> @@ -0,0 +1,24 @@
> +;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
> +
> +;; Homepage: https://test-domain.org
> +;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
> +;; Package-Requires: ((emacs "30.1"))
> +;; Version: 0.2
> +
> +;;; Commentary:
> +;;
> +;; Test package SUFFIX.
> +
> +;;; Code:
> +
> +(require 'test-package-SUFFIX-lib)
> +
> +;;;###autoload
> +(defun test-package-SUFFIX-func (arg)
> + ;; checkdoc-params: (arg)
> + "Test function for `test-package-SUFFIX'."
> + (test-package-SUFFIX-mac arg))
> +
> +(provide 'test-package-SUFFIX)
> +
> +;;; test-package-SUFFIX.el ends here
> diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in b=
/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in
> new file mode 100644
> index 00000000000..0fc4fc3653d
> --- /dev/null
> +++ b/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in
> @@ -0,0 +1,11 @@
> +\input texinfo @c -*- texinfo -*-
> +@settitle Info for test-package-SUFFIX
> +@direntry
> +* Test-package-SUFFIX: (test-package-SUFFIX). test-package-SUFFIX.
> +@end direntry
> +
> +@chapter First chapter for test-package-SUFFIX
> + First test text.
> +
> +@include test-package-SUFFIX-inc.texi
> +@bye
> diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
> new file mode 100644
> index 00000000000..9f00d0f508f
> --- /dev/null
> +++ b/test/lisp/package-vc-tests.el
> @@ -0,0 +1,1045 @@
> +;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -=
*-
> +
> +;; Copyright (C) 2025 Free Software Foundation, Inc.
> +
> +;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
> +;; Keywords: package
> +
> +;; This file is part of GNU Emacs.
> +
> +;; GNU Emacs is free software: you can redistribute it and/or modify
> +;; it under the terms of the GNU General Public License as published by
> +;; the Free Software Foundation, either version 3 of the License, or
> +;; (at your option) any later version.
> +
> +;; GNU Emacs is distributed in the hope that it will be useful,
> +;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +;; GNU General Public License for more details.
> +
> +;; You should have received a copy of the GNU General Public License
> +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
> +
> +;;; Commentary:
> +
> +;; These tests focus on verifying post conditions for `package-vc'
> +;; operations on packages. These tests install and load test packages
> +;; with a sample test implementation, resulting in modification of
> +;; numerous global variables, for example `load-history', `load-path',
> +;; `features', etc. When run with `ert' it may contaminate current
> +;; Emacs session. For this reason, tests execute their bodies in
> +;; `with-package-vc-tests-installed' (which see), that takes care of
> +;; cleaning up the environment.
> +
> +;;; Code:
> +
> +(require 'package-vc)
> +(require 'package)
> +(require 'vc-git)
> +(require 'vc)
> +(require 'cl-lib)
> +(require 'info)
> +(require 'ert-x)
> +(require 'ert)
> +
> +(defvar package-vc-tests-under-test '(test-package-1
> + test-package-2
> + test-package-3
> + test-package-4
> + test-package-5
> + test-package-6
> + test-package-7
> + test-package-8
> + test-package-9))
> +
> +(defvar package-vc-tests-preserve-temporary nil
> + "When non-nil preserve temporary files produced by tests.
> +Each test produces a new temporary directory for each package under
> +test. This leads to creation of [length of
> +`package-vc-tests-under-test'] times [number of tests executed]
> +temporary directories for each tests run. When this variable is nil
> +then delete all temporary directories as soon as they are no longer
> +needed. When this variable is a symbol, then preserve temporary
> +directories for the package that matches the symbol. When this variable
> +is a list of symbol, then preserve temporary directories for each
> +package that matches symbol in the list. When this variable is t then
> +preserve all temporary directories. Tests create temporary directories
> +with `make-temp-file', which see.")
> +
> +(defvar package-vc-tests-dir)
> +(defvar package-vc-tests-packages)
> +(defvar package-vc-tests-bundle)
> +
> +;; TODO: add test for deleting packages, with asserting
> +;; `package-vc-selected-packages'
> +
> +;; TODO: clarify `package-vc-install-all' behaviour with regards to
> +;; packages installed with `package-vc' but not stored in
> +;; `package-vc-selected-packages' i.e., packages from ELPAs
> +
> +(defun package-vc-tests-add (suffix in-file &optional lisp-dir)
> + "Create a new file from IN-FILE template updating SUFFIX in it.
> +When LISP-DIR is non-nil place the NAME file under LISP-DIR."
> + (let* ((resource-dir (ert-resource-directory))
> + (suffix (if (stringp suffix) suffix (format "%s" suffix)))
> + (file (let ((file (replace-regexp-in-string
> + (rx ".in" string-end) ""
> + (replace-regexp-in-string
> + "SUFFIX" suffix
> + (replace-regexp-in-string
> + (rx "-v" digit (zero-or-more
> + "." (one-or-more digit)))
> + ""
> + in-file
> + nil nil 0)
> + nil nil 0)
> + nil nil 0)))
> + (if lisp-dir
> + (file-name-concat lisp-dir file)
> + file))))
> + (copy-file (expand-file-name in-file resource-dir) file t)
> + (with-temp-buffer
> + (insert-file-contents file)
> + (goto-char (point-min))
> + (while (search-forward "SUFFIX" nil t)
> + (replace-match suffix))
> + (write-file file))
> + (vc-git-command nil 0 nil "add" ".")))
> +
> +(defun package-vc-tests-create-bundle (suffix &optional lisp-dir)
> + "Create a test package bundle with SUFFIX.
> +If LISP-DIR is non-nil place sources of the package in LISP-DIR."
> + (let* ((name (format "test-package-%s" suffix))
> + (repo-dir (expand-file-name (file-name-concat "repo" name)
> + package-vc-tests-dir)))
> + (make-directory (if lisp-dir
> + (expand-file-name lisp-dir repo-dir)
> + repo-dir)
> + :parents)
> + (let ((default-directory repo-dir)
> + (bundle-file (expand-file-name (format "%s.bundle" name)
> + package-vc-tests-dir)))
> + (vc-git-command nil 0 nil "init" "-b" "master")
> + (package-vc-tests-add
> + suffix "test-package-SUFFIX-lib-v0.1.el.in" lisp-dir)
> + (package-vc-tests-add
> + suffix "test-package-SUFFIX-v0.1.el.in" lisp-dir)
> + (package-vc-tests-add
> + suffix "test-package-SUFFIX.texi.in" lisp-dir)
> + (package-vc-tests-add
> + suffix "test-package-SUFFIX-inc.texi.in" lisp-dir)
> + ;; Place Makefile in root of the repository
> + (package-vc-tests-add
> + suffix "Makefile.in" nil)
> + (vc-git-command nil 0 nil "commit" "-m" "First commit")
> + (package-vc-tests-add
> + suffix "test-package-SUFFIX-lib-v0.2.el.in" lisp-dir)
> + (package-vc-tests-add
> + suffix "test-package-SUFFIX-v0.2.el.in" lisp-dir)
> + (vc-git-command nil 0 nil "commit" "-m" "Second commit")
> + (vc-git-command nil 0 nil
> + "bundle" "create" bundle-file "master")
> + (list bundle-file (vc-git-working-revision nil)))))
> +
> +(defun package-vc-tests-package-desc (package &optional installed)
> + "Return descriptor of PACKAGE.
> +When INSTALLED is non-nil the descriptor will come from `package-alist'.
> +Otherwise the descriptor will be from `package-archive-contents'. This
> +is to mimic `package-vc--read-package-desc'."
> + (cadr (assoc (if (stringp package) package (symbol-name package))
> + (if installed package-alist package-archive-contents)
> + #'string=3D)))
> +
> +(defun package-vc-tests-package-lisp-dir (pkg)
> + "Return a Lisp directory of PKG."
> + (and-let* ((checkout-dir (car
> + (alist-get pkg
> + package-vc-tests-packages))))
> + (or (and-let* ((lisp-dir (cadr
> + (alist-get pkg
> + package-vc-tests-packages))))
> + (expand-file-name lisp-dir checkout-dir))
> + checkout-dir)))
> +
> +(defun package-vc-tests-package-main-file (pkg)
> + "Return a main file of PKG."
> + (file-name-concat (package-vc-tests-package-lisp-dir pkg)
> + (format "%s.el" pkg)))
> +
> +;; When a package source is being recompiled - for example as result of
> +;; `pakckage-vc-upgrade' or `package-vc-rebuild' - it is also reloaded
> +;; [1] to ensure that the most recent version of compiled code is
> +;; available to Emacs. There are a few tests that add markers in
> +;; `load-history' before executing such functions. And then follow up
> +;; tests use these markers to assert that expected package files are in
> +;; correct places in the `load-history'.
> +;;
> +;; [1] Only when a file has been loaded previously.
> +
> +(defun package-vc-tests-load-history-marker (name)
> + "Return a `load-history' marker with NAME."
> + (expand-file-name (symbol-name name)
> + package-vc-tests-dir))
> +
> +(defun package-vc-tests-load-history-pattern (pkg type)
> + "Return a regexp pattern for PKG's file of TYPE."
> + (pcase type
> + (:autoloads
> + (rx (literal (file-name-concat
> + package-user-dir
> + (symbol-name pkg)
> + (format "%s-autoloads.el" pkg)))
> + string-end))
> + (:main
> + (rx
> + (literal
> + (package-vc-tests-package-main-file pkg))
> + string-end))
> + (:main-compiled
> + (rx
> + (literal
> + (package-vc-tests-package-main-file pkg))
> + "c"
> + string-end))
> + (:marker
> + (rx (literal (package-vc-tests-load-history-marker pkg))))))
> +
> +(defun package-vc-tests-load-history-position (pkg type)
> + "Return a PKG's file of TYPE position in `load-history'.
> +If TYPE is `:autoloads' return a position of a PKG autoloads file.
> +Otherwise, if TYPE is `:main' return a position of PKG main file (not
> +compiled). Otherwise, if TYPE is `:main-compiled' return a position of
> +PKG compiled main file. Otherwise, if TYPE is `:marker' return a
> +position of a marker PKG."
> + (let ((pkg-file (package-vc-tests-load-history-pattern pkg type))
> + (interesting-entry
> + (rx string-start
> + (literal (file-truename package-vc-tests-dir)))))
> + (cl-position-if
> + (lambda (file)
> + (string-match pkg-file file))
> + (cl-remove-if-not
> + (lambda (file-name)
> + (string-match interesting-entry file-name))
> + (mapcar
> + #'file-truename
> + (cl-remove-if-not
> + #'stringp
> + (mapcar #'car-safe load-history)))))))
> +
> +(defun package-vc-tests-explain-load-history-position (pkg type)
> + "Explain `package-vc-tests-load-history' failed for PKG of TYPE."
> + (let ((pattern
> + (concat "..."
> + (substring
> + (package-vc-tests-load-history-pattern pkg type)
> + (length (rx (literal package-vc-tests-dir))))))
> + (reason
> + (if-let* ((pos (package-vc-tests-load-history-position
> + pkg type)))
> + `(found in load-history at pos ,pos)
> + '(not found in load-history)))
> + (entries
> + (mapcar
> + (lambda (file)
> + (concat "..."
> + (substring file (length package-vc-tests-dir))))
> + (cl-remove-if
> + (lambda (file)
> + (or (not (stringp file))
> + (not (string-prefix-p package-vc-tests-dir file))))
> + (mapcar #'car-safe load-history)))))
> + (append (list 'pattern pattern)
> + reason
> + (list entries))))
> +
> +(put #'package-vc-tests-load-history-position
> + 'ert-explainer
> + #'package-vc-tests-explain-load-history-position)
> +
> +;; The following predicates and helper functions take an extra PKG
> +;; argument. This is needed for ERT to print package name in case of
> +;; failure.
> +
> +(defun package-vc-tests-valid-commit-p (_pkg commit)
> + "Return non-nil when COMMIT is a valid commit."
> + (and (stringp commit)
> + (not (string=3D commit "unknown"))))
We can simplify this by not checking for stringp and using equal
instead. But I'll take care of that and similar smaller points. We
should focus on the main point of the patch for now to get this moving.
I'll leave a few more comments like this below, parenthesised to make
clear that they are not that important.
> +
> +(defun package-vc-tests-in-strict-order-p (_pkg &rest args)
> + "Return non-nil when ARGS are in strict order."
(I'll also mention that these predicates are here to display the package
name in the ERT log.)
> + (apply #'< args))
> +
> +(defun package-vc-tests-match-p (_pkg regexp string)
> + "Return non-nil when REGEXP matches STRING."
> + (string-match regexp string))
> +
> +(defun package-vc-tests-buffer-p (_pkg obj)
> + "Return non-nil when OBJ is a buffer."
> + (bufferp obj))
> +
> +(defun package-vc-tests-elc-files (pkg)
> + "Return elc files for PKG."
> + (when-let* ((dir (package-vc-tests-package-lisp-dir pkg))
> + (elc-files (directory-files
> + dir nil (rx ".elc" string-end))))
> + elc-files))
> +
> +(defun package-vc-tests-assert-elc (pkg)
> + "Assert that PKG has correct .elc files in."
> + (let* ((dir (package-vc-tests-package-lisp-dir pkg))
> + (elc-files (should (package-vc-tests-elc-files pkg)))
> + (autoloads-rx (rx
> + (literal (format "%s-autoloads.elc" pkg))
> + string-end)))
> + (should-not (cl-find-if (lambda (elc)
> + (string-match autoloads-rx elc))
> + elc-files))
> + (dolist (elc-file elc-files)
> + (delete-file (expand-file-name elc-file dir)))))
> +
> +(defun package-vc-tests-assert-package-alist (pkg version)
> + "Assert that PKG entry in `package-alist' have correct VERSION and dir=
."
> + (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
> + (should (equal (file-name-as-directory
> + (expand-file-name (format "%s" pkg)
> + package-user-dir))
> + (file-name-as-directory
> + (package-desc-dir pkg-desc))))
> + (should (equal (list pkg version)
> + (list pkg (package-desc-version pkg-desc))))))
> +
> +(defun package-vc-tests-reset-head (pkg)
> + "Reset to HEAD^ checkout for PKG."
> + (let ((default-directory (car
> + (alist-get pkg package-vc-tests-packages))))
> + (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))
> +
> +(defun package-vc-tests-package-head (pkg)
> + "Return HEAD revisions of a PKG."
> + (let ((default-directory (car
> + (alist-get pkg package-vc-tests-packages))))
> + (vc-git-working-revision nil)))
> +
> +(defmacro with-package-vc-tests-installed (pkg &rest body)
> + "Eval BODY with PKG installed in a test environment."
> + (declare (indent 1) (debug t))
> + ;; git-bundle(1) produces test packages sources in bundle files, based
> + ;; on skeleton files in directory package-vc-resources. Before
> + ;; executing body make sure that:
> + ;;
> + ;; - `package' has been initialised, and there are no
> + ;; `package-archives' defined
> + `(let* ((package-archives (unless package--initialized
> + (let (package-archives)
> + (package-initialize)
> + (package-vc--archives-initialize))
> + nil))
> + ;; - create a temporary location for packages and test files
> + (package-vc-tests-dir
> + (expand-file-name
> + (make-temp-file "package-vc-tests-"
> + t
> + (format-time-string "-%Y%m%d.%H%M%S.%3N"))))
> + ;; - packages are installed into a test directory
> + (package-user-dir (expand-file-name "elpa"
> + package-vc-tests-dir))
> + ;; - define test packages, their checkout locations, lisp
> + ;; directories, and install functions
> + (package-vc-tests-packages
> + `(;; checkout and install with `package-vc-install' (on
> + ;; ELPA)
> + (test-package-1
> + ,(expand-file-name "test-package-1"
> + package-user-dir)
> + nil
> + package-vc-tests-install-from-elpa)
> + ;; checkout and install with `package-vc-install' (not on
> + ;; ELPA)
> + (test-package-2
> + ,(expand-file-name "test-package-2"
> + package-user-dir)
> + nil
> + package-vc-tests-install-from-spec)
> + ;; checkout with `package-vc-checktout' and install with
> + ;; `package-vc-install-from-checkout' (on ELPA)
> + (test-package-3
> + ,(expand-file-name "test-package-3"
> + package-vc-tests-dir)
> + nil
> + pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
> + ;; checkout with git and install with
> + ;; `package-vc-install-from-checkout'
> + (test-package-4
> + ,(expand-file-name "test-package-4"
> + package-vc-tests-dir)
> + nil
> + package-vc-tests-checkout-with-git-install-from-checkout)
> + ;; sources in "lisp" sub directory, checkout and install
> + ;; with `package-vc-install' (not on ELPA)
> + (test-package-5
> + ,(expand-file-name "test-package-5"
> + package-user-dir)
> + "lisp"
> + package-vc-tests-install-from-spec)
> + ;; sources in "lisp" sub directory, checkout with git and
> + ;; install with `package-vc-install-from-checkout'
> + (test-package-6
> + ,(expand-file-name "test-package-6"
> + package-vc-tests-dir)
> + "lisp"
> + package-vc-tests-checkout-with-git-install-from-checkout)
> +
> + ;; sources in "src" sub directory, checkout and install
> + ;; with `package-vc-install' (on ELPA)
> + (test-package-7
> + ,(expand-file-name "test-package-7"
> + package-user-dir)
> + "src"
> + package-vc-tests-install-from-elpa)
> + ;; sources in "src" sub directory, checkout with
> + ;; `package-vc-checktout' and install with
> + ;; `package-vc-install-from-checkout' (on ELPA)
> + (test-package-8
> + ,(expand-file-name "test-package-8"
> + package-vc-tests-dir)
> + nil
> + pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
> + ;; sources in "custom-dir" sub directory, checkout and
> + ;; install with `package-vc-install' (on ELPA)
> + (test-package-9
> + ,(expand-file-name "test-package-9"
> + package-user-dir)
> + "custom-dir"
> + package-vc-tests-install-from-elpa)))
> + ;; - create a test package bundle
> + (package-vc-tests-bundle
> + (let* ((pkg-name (symbol-name ,pkg))
> + (suffix (and (string-match
> + (rx ?-
> + (group (one-or-more (not ?-)))
> + string-end)
> + pkg-name)
> + (match-string 1 pkg-name))))
> + (package-vc-tests-create-bundle
> + suffix (cadr (alist-get ,pkg package-vc-tests-packages)))))
> + ;; - find all packages that are present in a test ELPA
> + (package-vc-tests-elpa-packages
> + (mapcar
> + #'car
> + (cl-remove-if-not
> + (lambda (package)
> + (memq
> + (cadddr package)
> + '(package-vc-tests-install-from-elpa
> + pakcage-vc-tests-checkout-from-elpa-install-from-check=
out)))
> + package-vc-tests-packages)))
> + ;; - make test packages recognisable by `package' and
> + ;; `package-vc' internals:
> + (package-archive-contents
> + (mapcar
> + (lambda (pkg)
> + (list pkg
> + (package-desc-create
> + :name pkg
> + :version '(0 2)
> + :reqs '((emacs (30.1)))
> + :kind 'tar
> + :archive "test-elpa"
> + :extras
> + (list
> + '(:maintainer
> + ("Test Maintainer"
> + . "test-maintainer@HIDDEN"))
> + (cons :url (car package-vc-tests-bundle))
> + (cons :commit (cadr package-vc-tests-bundle))
> + (cons :revdesc (substring
> + (cadr package-vc-tests-bundle)
> + 0 12))))))
> + package-vc-tests-elpa-packages))
> + (package-vc--archive-spec-alists
> + (list
> + (cons 'test-elpa
> + (mapcar
> + (lambda (pkg)
> + (let ((lisp-dir
> + (cadr (alist-get
> + ,pkg package-vc-tests-packages))))
> + (append
> + (list pkg
> + :url (car package-vc-tests-bundle)
> + :branch "master"
> + :doc (let ((doc-file
> + (format "%s.texi" ,pkg)))
> + (if lisp-dir
> + (file-name-concat lisp-dir
> + doc-file)
> + doc-file))
> + :make (format "build-%s" ,pkg)
> + :shell-command (format
> + "touch %s.cmd-build"
> + ,pkg))
> + (and lisp-dir
> + (not (member lisp-dir '("lisp" "src")))
> + (list :lisp-dir lisp-dir)))))
> + package-vc-tests-elpa-packages))))
> + (package-vc--archive-data-alist
> + (list
> + (list 'test-elpa :version 1 :default-vc 'Git)))
> + ;; - `vc-guess-backend-url' is recognising bundles as `Git'
> + ;; repositories:
> + (vc-clone-heuristic-alist
> + (cons
> + (cons (rx "test-package-" (one-or-more digit) ".bundle"
> + string-end)
> + 'Git)
> + vc-clone-heuristic-alist))
> + ;; - ensure that `package-alist' and
> + ;; `package-vc-selected-packages' are empty
> + package-alist
> + package-vc-selected-packages
> + ;; - don't save any customization
> + (user-init-file nil)
> + ;; - FIXME: something sets `default-directory' to last
> + ;; checkout directory after `package-vc-checkout', which
> + ;; causes problems when this macro deletes the temporary
> + ;; directory after body execution.
> + (default-directory package-vc-tests-dir))
> + (unwind-protect
> + (progn
> + (funcall (or (caddr (alist-get ,pkg
> + package-vc-tests-packages))
> + (lambda (pkg)
> + (ert-fail
> + (format
> + "Cannot find %s in package-vc-tests-packages"
> + pkg))))
> + ,pkg)
> + ,@body)
> + ;; Unbind package defined symbols, and remove package defined
> + ;; features and entries from `load-path',`load-history', and
> + ;; `Info-directory-list'.
> + (let ((pattern (rx string-start (literal package-vc-tests-dir))))
> + (dolist (entry load-history)
> + (when-let* ((file (car-safe entry))
> + ((stringp file))
> + ((string-match pattern file)))
> + (dolist (elt (cdr entry))
> + (pcase elt
> + (`(defun . ,fun)
> + (fmakunbound fun))
> + (`(provide . ,feat)
> + (setq features (cl-remove feat features)))
> + ((and (pred symbolp)
> + (pred boundp))
> + (makunbound elt))))))
> + (setq load-path (cl-remove-if
> + (lambda (path)
> + (and (stringp path)
> + (string-match pattern path)))
> + load-path)
> + load-history (cl-remove-if
> + (lambda (entry)
> + (and-let* ((path (car-safe entry))
> + ((stringp path)))
> + (string-match pattern path)))
> + load-history)
> + Info-directory-list (cl-remove-if
> + (lambda (dir)
> + (and (stringp dir)
> + (string-match pattern dir)))
> + Info-directory-list)))
> + (if (or (eq package-vc-tests-preserve-temporary t)
> + (eq package-vc-tests-preserve-temporary ,pkg)
(Sequential occurrences like (or (eq FOO ...) (eq FOO ...)) are
conventionally replaced by (memq FOO '(...)).)
> + (and (listp package-vc-tests-preserve-temporary)
> + (memq ,pkg package-vc-tests-preserve-temporary)))
> + (message "package-vc-tests: preserving temporary directory %s"
> + package-vc-tests-dir)
> + (delete-directory package-vc-tests-dir t)))))
> +
> +(defun package-vc-tests-install-from-elpa (pkg)
> + "Install PKG with `package-vc-install'."
> + (push (list (package-vc-tests-load-history-marker 'install-begin))
> + load-history)
> + (package-vc-install pkg)
> + (push (list (package-vc-tests-load-history-marker 'install-end))
> + load-history)
> + (should-not (alist-get (symbol-name pkg)
> + package-vc-selected-packages
> + nil nil #'string=3D)))
> +
> +(defun package-vc-tests-install-from-spec (pkg)
> + "Install PKG with `package-vc-install' (not on ELPA)."
> + (push (list (package-vc-tests-load-history-marker 'install-begin))
> + load-history)
> + (package-vc-install `(,pkg
> + :url ,(car package-vc-tests-bundle)
> + :branch "master"))
Why the explicit mention of the branch name here?
> + (push (list (package-vc-tests-load-history-marker 'install-end))
> + load-history)
> + (should (equal (car package-vc-tests-bundle)
> + (plist-get (alist-get (symbol-name pkg)
> + package-vc-selected-packages
> + nil nil #'string=3D)
> + :url))))
> +
> +(defun pakcage-vc-tests-checkout-from-elpa-install-from-checkout (pkg)
> + "Install PKG with `package-vc-install-from-checkout'.
> +Make checkout with `package-vc-checkout'."
> + (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
> + (package-vc-checkout (package-vc-tests-package-desc
> + pkg)
> + checkout-dir)
> + (push (list (package-vc-tests-load-history-marker 'install-begin))
> + load-history)
> + (package-vc-install-from-checkout checkout-dir)
> + (push (list (package-vc-tests-load-history-marker 'install-end))
> + load-history)
> + (should (equal (concat package-vc--url-scheme checkout-dir)
> + (plist-get (alist-get (symbol-name pkg)
> + package-vc-selected-packages
> + nil nil #'string=3D)
> + :url)))))
> +
> +(defun package-vc-tests-checkout-with-git-install-from-checkout (pkg)
> + "Install PKG with `package-vc-install-from-checkout'.
> +Make checkout with git(1)."
> + (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
> + (vc-git-clone (car package-vc-tests-bundle)
> + checkout-dir
> + "master")
> + (push (list (package-vc-tests-load-history-marker 'install-begin))
> + load-history)
> + (package-vc-install-from-checkout checkout-dir (symbol-name pkg))
> + (push (list (package-vc-tests-load-history-marker 'install-end))
> + load-history)
> + (should (equal (concat package-vc--url-scheme checkout-dir)
> + (plist-get (alist-get (symbol-name pkg)
> + package-vc-selected-packages
> + nil nil #'string=3D)
> + :url)))))
(This pattern appears to occur often enough, that we should extract it
out to a helper function.)
> +(defmacro package-vc-tests-package-vc-async-wait (seconds count flags &r=
est body)
> + "Wait up to SECONDS for COUNT async vc commands with FLAGS called by B=
ODY.
> +Return nil on timeout or the value of last form in BODY."
> + (declare (indent 3))
> + (let ((count-sym (make-symbol "count"))
> + (post-vc-command-sym (make-symbol "post-vc-command")))
> + `(letrec ((,count-sym ,count)
> + (,post-vc-command-sym
> + (lambda (command _ command-flags)
> + ;; A crude filter for vc commands
> + (when (and (equal command "git")
> + (cl-every (lambda (flag)
> + (member flag command-flags))
> + ,flags))
> + (decf ,count-sym)))))
> + (add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
> + (unwind-protect
> + (with-timeout (,seconds nil)
> + (prog1
> + (progn ,@body)
> + (while (/=3D ,count-sym 0)
> + (accept-process-output nil 0.01))))
And it wouldn't be bad to have a comment here on the topic of our
discussion w.r.t. timeouts in tests.
> + (remove-hook 'vc-post-command-functions
> + ,post-vc-command-sym)))))
> +
> +(ert-deftest package-vc-tests-install-post-conditions ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (let ((install-begin
> + (should (package-vc-tests-load-history-position
> + 'install-begin :marker)))
> + (install-end
> + (should (package-vc-tests-load-history-position
> + 'install-end :marker)))
> + (autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads))))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + install-end
> + autoloads-pos
> + install-begin))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main-compiled)))
> + (should (equal (package-vc--main-file
> + (package-vc-tests-package-desc pkg t))
> + (package-vc-tests-package-main-file pkg)))
> + (should (package-vc-tests-valid-commit-p
> + pkg
> + (package-vc-commit
> + (package-vc-tests-package-desc pkg t))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 2)))))
> +
> +(ert-deftest package-vc-tests-require ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (should (fboundp (intern (format "%s-func" pkg))))
> + (should (autoloadp
> + (symbol-function (intern (format "%s-func" pkg)))))
> + (should (require pkg))
> + (should (fboundp (intern (format "%s-func" pkg))))
> + (should-not (autoloadp
> + (symbol-function (intern (format "%s-func" pkg)))))
> + (should-not (fboundp (intern (format "%s-old-func" pkg))))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main))
> + (let ((install-end
> + (should (package-vc-tests-load-history-position
> + 'install-end :marker)))
> + (main-compiled-pos
> + (should (package-vc-tests-load-history-position
> + pkg :main-compiled))))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + main-compiled-pos
> + install-end))))))
> +
> +(ert-deftest package-vc-tests-upgrade ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (let ((head (package-vc-tests-package-head pkg)))
> + (package-vc-tests-reset-head pkg)
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-begin))
> + load-history)
> + (should
> + (package-vc-tests-package-vc-async-wait 5 1 '("pull")
> + (package-vc-upgrade (package-vc-tests-package-desc pkg t))
> + t))
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-end))
> + load-history)
> + (should-not (package-vc-tests-load-history-position
> + pkg :main))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main-compiled))
> + (let ((upgrade-begin
> + (should (package-vc-tests-load-history-position
> + 'upgrade-begin :marker)))
> + (upgrade-end
> + (should (package-vc-tests-load-history-position
> + 'upgrade-end :marker)))
> + (autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads))))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + autoloads-pos
> + upgrade-begin)))
> + (let ((func (intern (format "%s-func" pkg))))
> + (should (fboundp func))
> + (should (autoloadp
> + (symbol-function func)))
> + (should (equal "New macro test"
> + (funcall func "test"))))
> + (should-not (fboundp (intern (format "%s-old-func" pkg))))
> + (should (equal head
> + (package-vc-tests-package-head pkg))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 2)))))
> +
> +(ert-deftest package-vc-tests-upgrade-after-require ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (should (require pkg))
> + (let ((head (package-vc-tests-package-head pkg)))
> + (package-vc-tests-reset-head pkg)
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-begin))
> + load-history)
> + (should
> + (package-vc-tests-package-vc-async-wait 5 1 '("pull")
> + (package-vc-upgrade (package-vc-tests-package-desc pkg t))
> + t))
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-end))
> + load-history)
> + (let ((upgrade-begin
> + (should (package-vc-tests-load-history-position
> + 'upgrade-begin :marker)))
> + (upgrade-end
> + (should (package-vc-tests-load-history-position
> + 'upgrade-end :marker)))
> + (autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads)))
> + (main-pos
> + (should (package-vc-tests-load-history-position
> + pkg :main)))
> + (main-compiled-pos
> + (should (package-vc-tests-load-history-position
> + pkg :main-compiled))))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + autoloads-pos
> + upgrade-begin))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + main-pos
> + upgrade-begin))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + main-compiled-pos
> + upgrade-begin)))
> + (let ((func (intern (format "%s-func" pkg))))
> + (should (fboundp func))
> + (should-not (autoloadp
> + (symbol-function func)))
> + (should (equal "New macro test"
> + (funcall func "test"))))
> + (should-not (fboundp (intern (format "%s-old-func" pkg))))
> + (should (equal head
> + (package-vc-tests-package-head pkg))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 2)))))
> +
> +(ert-deftest package-vc-tests-upgrade-all ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (let ((head (package-vc-tests-package-head pkg)))
> + (package-vc-tests-reset-head pkg)
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-all-begin))
> + load-history)
> + (should
> + (package-vc-tests-package-vc-async-wait 5 1 '("pull")
> + (package-vc-upgrade-all)
> + t))
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-all-end))
> + load-history)
> + (should-not (package-vc-tests-load-history-position
> + pkg :main))
> + (should-not (package-vc-tests-load-history-position
> + pkg :main-compiled))
> + (let ((upgrade-begin
> + (should (package-vc-tests-load-history-position
> + 'upgrade-all-begin :marker)))
> + (upgrade-end
> + (should (package-vc-tests-load-history-position
> + 'upgrade-all-end :marker)))
> + (autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads))))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + autoloads-pos
> + upgrade-begin)))
> + (let ((func (intern (format "%s-func" pkg))))
> + (should (fboundp func))
> + (should (autoloadp
> + (symbol-function func)))
Does this work even if you run the tests multiple times?
> + (should (equal "New macro test"
> + (funcall func "test"))))
> + (should-not (fboundp (intern (format "%s-old-func" pkg))))
> + (should (equal head
> + (package-vc-tests-package-head pkg))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 2)))))
> +
> +(ert-deftest package-vc-tests-upgrade-all-after-require ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (should (require pkg))
> + (let ((head (package-vc-tests-package-head pkg)))
> + (package-vc-tests-reset-head pkg)
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-all-begin))
> + load-history)
> + (should
> + (package-vc-tests-package-vc-async-wait 5 1 '("pull")
> + (package-vc-upgrade-all)
> + t))
> + (push (list (package-vc-tests-load-history-marker
> + 'upgrade-all-end))
> + load-history)
> + (let ((upgrade-begin
> + (should (package-vc-tests-load-history-position
> + 'upgrade-all-begin :marker)))
> + (upgrade-end
> + (should (package-vc-tests-load-history-position
> + 'upgrade-all-end :marker)))
> + (autoloads-pos
> + (should (package-vc-tests-load-history-position
> + pkg :autoloads)))
> + (main-pos
> + (should (package-vc-tests-load-history-position
> + pkg :main)))
> + (main-compiled-pos
> + (should (package-vc-tests-load-history-position
> + pkg :main-compiled))))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + autoloads-pos
> + upgrade-begin))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + main-pos
> + upgrade-begin))
> + (should (package-vc-tests-in-strict-order-p
> + pkg
> + upgrade-end
> + main-compiled-pos
> + upgrade-begin)))
> + (let ((func (intern (format "%s-func" pkg))))
> + (should (fboundp func))
> + (should-not (autoloadp
> + (symbol-function func)))
> + (should (equal "New macro test"
> + (funcall func "test"))))
> + (should-not (fboundp (intern (format "%s-old-func" pkg))))
> + (should (equal head
> + (package-vc-tests-package-head pkg))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 2)))))
> +
> +(ert-deftest package-vc-tests-rebuild ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (package-vc-tests-reset-head pkg)
> + (let ((head (package-vc-tests-package-head pkg)))
> + (package-vc-rebuild
> + (package-vc-tests-package-desc pkg t))
> + (let ((old-func (intern (format "%s-old-func" pkg))))
> + (should (fboundp old-func))
> + (should (autoloadp
> + (symbol-function old-func))))
(Misindented!)
> + (let ((func (intern (format "%s-func" pkg))))
> + (should (fboundp func))
> + (should (autoloadp
> + (symbol-function func)))
> + (should (equal "Old macro test"
> + (funcall func "test"))))
> + (should (equal head
> + (package-vc-tests-package-head pkg))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 1)))))
> +
> +(ert-deftest package-vc-tests-rebuild-after-require ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (should (require pkg))
> + (package-vc-tests-reset-head pkg)
> + (let ((head (package-vc-tests-package-head pkg)))
> + (package-vc-rebuild
> + (package-vc-tests-package-desc pkg t))
> + (let ((old-func (intern (format "%s-old-func" pkg))))
> + (should (fboundp old-func))
> + (should-not (autoloadp
> + (symbol-function old-func))))
> + (let ((func (intern (format "%s-func" pkg))))
> + (should (fboundp func))
> + (should-not (autoloadp
> + (symbol-function func)))
> + (should (equal "Old macro test"
> + (funcall func "test"))))
> + (should (equal head
> + (package-vc-tests-package-head pkg))))
> + (package-vc-tests-assert-elc pkg)
> + (package-vc-tests-assert-package-alist pkg '(0 1)))))
> +
> +(ert-deftest package-vc-tests-prepare-patch ()
> + ;; Ensure `vc-prepare-patch' respects subject from function argument
> + (let (vc-prepare-patches-separately)
> + (dolist (pkg package-vc-tests-under-test)
Just while reading this, I had an idea for an alternative to the
`package-vc-tests-match-p'-situation. Instead of having the loop inside
the test, we can define our own functions and symbols (that include the
package name) and install them using `ert-set-test' -- stop me if we
have talked about this before -- and then the tests are more granular
and independent of another.=20
> + (with-package-vc-tests-installed pkg
> + (package-vc-prepare-patch (package-vc-tests-package-desc pkg t)
> + "test-subject"
> + (cdr package-vc-tests-bundle))
> + (let ((message-buffer
> + (should (get-buffer "*unsent mail to Test Maintainer*"))))
> + (should (package-vc-tests-buffer-p pkg message-buffer))
> + (switch-to-buffer message-buffer)
> + (goto-char (point-min))
> + (should
> + (package-vc-tests-match-p
> + pkg
> + (rx
> + "To: Test Maintainer <test-maintainer@HIDDEN>")
> + (buffer-substring (point) (pos-eol))))
> + (forward-line)
> + (should
> + (package-vc-tests-match-p
> + pkg
> + (rx "Subject: test-subject")
> + (buffer-substring (point) (pos-eol))))
> + (let (kill-buffer-query-functions)
> + (kill-buffer message-buffer)))))))
> +
> +(ert-deftest package-vc-tests-log-incoming ()
> + (dolist (pkg package-vc-tests-under-test)
> + (with-package-vc-tests-installed pkg
> + (package-vc-tests-reset-head pkg)
> + (should
> + (package-vc-tests-package-vc-async-wait
> + 5 1 '("log" "--decorate")
> + (package-vc-log-incoming (package-vc-tests-package-desc pkg t))
> + t))
> + (let ((incoming-buffer (get-buffer "*vc-incoming*"))
> + (pattern (rx (literal
> + (substring
> + (cadr package-vc-tests-bundle)
> + 0 7))
> + (one-or-more any)
> + "Second commit"
> + line-end)))
> + (should (package-vc-tests-buffer-p pkg incoming-buffer))
> + (switch-to-buffer incoming-buffer)
> + (goto-char (point-min))
> + (should
> + (package-vc-tests-match-p
> + pkg
> + pattern
> + (buffer-substring (point) (pos-eol))))
> + (let (kill-buffer-query-functions)
> + (kill-buffer incoming-buffer))))))
> +
> +(ert-deftest package-vc-tests-pkg-spec-doc-make-shell-command ()
> + (let ((package-vc-allow-build-commands t))
> + ;; Only `packge-vc-install' runs make and shell command
> + (dolist (pkg '(test-package-1 test-package-7 test-package-9))
> + (with-package-vc-tests-installed pkg
> + (let ((checkout-dir (car (alist-get
> + pkg package-vc-tests-packages))))
> + (should (file-exists-p
> + (expand-file-name
> + (format "%s.make-build" pkg)
> + checkout-dir)))
> + (should (file-exists-p
> + (expand-file-name
> + (format "%s.cmd-build" pkg)
> + checkout-dir))))
> + (should (cl-member-if (lambda (dir)
> + (and (stringp dir)
> + (string-prefix-p package-vc-tests-d=
ir
> + dir)))
> + Info-directory-list))
> + (let ((info-file
> + (expand-file-name (format "%s.info" pkg)
> + (car (alist-get
> + pkg package-vc-tests-packages)))))
> + (should (file-exists-p info-file))
> + (ert-with-test-buffer
> + (:name (format "*package-vc-tests: %s.info*" pkg))
> + (insert-file-contents info-file)
> + (goto-char (point-min))
> + (should (re-search-forward
> + (format "First chapter for %s" pkg)))
> + (should (re-search-forward
> + (format "Second chapter for %s" pkg)))))))))
> +
> +(provide 'package-vc-tests)
> +
> +;;; package-vc-tests.el ends here
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> Philip Kaludercic <philipk@HIDDEN> writes:
>
>> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>>
>>
>> [...]
>>
>>> So I applied this patch, and it seems to that :dir slot of a package
>>> installed from checkout is incorrect., for example:
>>>
>>> (require 'vc-git)
>>> (require 'package-vc)
>>> (setq package-user-dir (expand-file-name "~/tmp/elpa" ))
>>> (shell-command "git clone https://gitlab.com/koral/gcmh.git ~/tmp/gcm=
h")
>>> (package-vc-install-from-checkout "~/tmp/gcmh" "gcmh")
>>> (package-desc-dir (cadr (assq 'gcmh package-alist)))
>>> ;; =3D> "/Users/pkryger/tmp/gcmh"
>>>
>>> I'd expect it to be /Users/pkryger/tmp/elpa/gcmh (note the 'elpa' in
>>> path). I guess corruption like that will cause more than one issue, but
>>> the first I found is that calling:
>>>
>>> (package-delete (cadr (assq 'gcmh package-alist)))
>>>
>>> yields the following back trace (limiting relevant frames):
>>>
>>> signal(error ("Package =E2=80=98gcmh=E2=80=99 is a system package, no=
t deleting"))
>>> error("Package `%s' is a system package, not deleting" "gcmh")
>>> package-delete(#s(package-desc :name gcmh :version (0 2 1) :summary
>>> "the Garbage Collector Magic Hack" :reqs ((emacs (24))) :kind vc
>>> :archive nil :dir "/Users/pkryger/tmp/gcmh" :extras ((:vc-dir
>>> . "/Users/pkryger/tmp/gcmh") (:commit
>>> . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9")) :signed nil))
>>> (progn (package-delete (car (cdr (assq 'gcmh package-alist)))))
>>> eval((progn (package-delete (car (cdr (assq 'gcmh package-alist))))) =
t)
>>
>> Thanks for checking! It helps me out a lot ^^
>
> No problem. FWIW I have only applied patch that adds tests, commented
> out `package-vc-selected-packages' assertions and deleted
> `package-vc--url-scheme' bits, then run the tests and randomly picked
> one of the failures. OFC, there are more failures, but I leave sifting
> through them as an exercise to the reader =F0=9F=98=89.
OK, I can go through this on my own again.
>>> I am attaching updated patches. I re-wrote tests to be executable in
>>> regular Emacs session (although I haven't got to a point where I run
>>> them under a development Emacs yet). With this it was so much easier to
>>> add a few more tests, and I found that there's another issue with how a
>>> package is rebuild. It manifests itself with a compilation using
>>> preciously defined macro definitions, i.e., when macro has been changed
>>> then the new version is not used.
>>
>> Hmm, we might have to use something like `unload-feature' here,
>
> I checked `unload-feature' and it seems to focus on real features
> unloading, e.g., removing hooks, timers, etc. In a process of unloading
> it does some things as I like, but it takes a different approach to
> functions. My main goal was to have a clean slate after a test has
> finished, such that test check whether autoloads are correctly
> established and resolved. `unload-feature' leaves function symbols
> bounded, but I suspect that would make writing well encapsulated tests
> hard. For that reason I'd rather to leave the manual cleanup. I wonder
> if, prior to unbinding symbols, calling `loadhist-unload-element' is a
> good idea? WDYT?
I have no experience with that function. We can ask Stefan to comment
on this.
>> but
>> inherently this is an issue that regular tarball packages should also
>> have. I would have thought that `package--reload-previously-loaded'
>> should take care of that...
>
> In a degree it does. The function loads `.el' files in a case when a
> corresponding `.elc' has been previously loaded and there's no `.elc'
> file present. This is obviously not a case for rebuilding a VC package.
>
> N.B., above explanation assumes default value of `load-suffixes'.
>
>>> @Philip: I merged your initial patch into mine, so it's easier to apply
>>> on top of master. I hope I am not doing anything wrong here.
>>
>> Of course not.
>
> =F0=9F=98=8E
>
>>> I also think that using :vc-dir in :extras slot is a viable candidate.
>>> However, I haven't had a chance to apply it yet.
>>
>> If you want to, I can take a shot at updating the patch to use :extras
>> as Michelangelo proposed. That way I'll also have a better
>> understanding of the patch, compared to just reading it.
>
> That would be nice. I have been thinking about it, but I spent too much
> time on other items recently. If you have any questions about choices
> in tests, please ask.
1+
> [...]
>
>>> From e509427dd760eb9ac69d68a9c9322f78b9c59bb7 Mon Sep 17 00:00:00 2001
>>> From: Philip Kaludercic <philipk@HIDDEN>
>>> Date: Fri, 26 Sep 2025 14:00:54 +0100
>>> Subject: [PATCH 1/2] Fix upgrading, rebuilding, and logging of VC packa=
ges
>
> [...]
>
>>>
>>> +(defun package-vc--checkout-dir (pkg-desc &optional lisp-dir)
>>> + "Return the directory of the actual VC checkout for PKG-DESC.
>>> +For most packages this is the same as `package-desc-dir', unless the
>>> +package has been installed via `package-vc-install-from-checkout'. In
>>> +that case the package redirects to the actual VC checkout. If the
>>> +optional LISP-DIR argument is non-nil, then check if a related package
>>> +specification has a `:lisp-dir' field to indicate that Lisp files are
>>> +located in a sub directory of the checkout, or the checkout has a sub
>>> +directory named \"lisp\" or \"src\" that contains .el files and return
>>> +that instead."
>>> + (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
>>> + (pkg-dir (pcase (plist-get pkg-spec :url)
>>> + ((rx (literal package-vc--url-scheme)
>>> + (let checkout-dir (+ any)))
>>> + checkout-dir)
>>> + (_ (package-desc-dir pkg-desc)))))
>>> + (expand-file-name
>>> + (or (and lisp-dir
>>> + (or (plist-get pkg-spec :lisp-dir)
>>> + ;; When nothing is specified about a `lisp-dir', then
>>> + ;; should heuristically check if there is a
>>> + ;; sub-directory with lisp files. These are
>>> + ;; conventionally just called "lisp" or "src". If
>>> + ;; this directory exists and contains non-zero number
>>> + ;; of lisp files, we will use that instead of
>>> + ;; `pkg-dir'.
>>> + (catch 'done
>>> + (dolist (name '("lisp" "src"))
>>> + (when-let* ((dir (expand-file-name name pkg-dir))
>>> + ((file-directory-p dir))
>>> + ((directory-files
>>> + dir nil "\\`[^.].+\\.el\\'" t 1)))
>>> + ;; We won't use `dir', since dir is an absolute
>>> + ;; path and we don't want `lisp-dir' to depend
>>> + ;; on the current location of the package
>>> + ;; installation, ie. to break if moved around
>>> + ;; the file system or between installations.
>>> + (throw 'done name))))))
>>> + ".")
>>
>> Why are we falling back to "."?
>
> The argument `lisp-dir' is an optional one, and it is not a path, rather
> a boolean like. When the first argument for `expand-file-name' is nil,
> it signals, doesn't it?
Right, I misread the code and missed the `expand-file-name'.
> [...]
>
>>> @@ -572,12 +687,12 @@ package-vc--unpack-1
>>> (lm-header "version"))))
>>> (vc-working-revision main-file)
>>> (if missing
>>> - (format
>>> - " Failed to install the following dependencies: %=
s"
>>> - (mapconcat
>>> - (lambda (p)
>>> - (format "%s (%s)" (car p) (cadr p)))
>>> - missing ", "))
>>> + (format
>>> + " Failed to install the following dependencies: %s"
>>> + (mapconcat
>>> + (lambda (p)
>>> + (format "%s (%s)" (car p) (cadr p)))
>>> + missing ", "))
>>> "")))
>>> t))
>>
>> I think I mentioned this before, but this seems like an unrelated
>> change, right?
>
> I do remember some comments about formatting, but I think this one came
> from the initial patch. Since the change makes indentation as default
> Emacs wants to and I was not adding any other changes in the file, I
> haven't reverted this one for now.
Ok!
> [...]
>
>>> @@ -622,6 +737,14 @@ package-vc-non-code-file-names
>>> user is fetching code from a repository that does not contain any
>>> Emacs Lisp files.")
>>>
>>> +(defun package-vc--save-selected-packages (name pkg-spec)
>>> + "Save the package specification PKG-SPEC for a package NAME."
>>> + (customize-save-variable
>>> + 'package-vc-selected-packages
>>> + (cons (cons name pkg-spec)
>>> + (seq-remove (lambda (spec) (string=3D name (car spec)))
>>> + package-vc-selected-packages))))
>>
>> We will probably not need this if we go with the :extras solution.
>
> I suspect that's correct.
>
> [...]
>
>>> @@ -934,21 +1035,22 @@ package-vc-install-from-checkout
>>> (package-vc--archives-initialize)
>>> (let* ((dir (if interactive dir (expand-file-name dir))) ;avoid doub=
le expansion
>>> (name (or name (file-name-base (directory-file-name dir))))
>>> - (pkg-dir (file-name-concat package-user-dir name))
>>> - (package-vc-selected-packages
>>> - (cons (list name :lisp-dir dir)
>>> - package-vc-selected-packages)))
>>> + (pkg-dir (file-name-concat package-user-dir name)))
>>> (when (file-exists-p pkg-dir)
>>> (if (yes-or-no-p (format "Overwrite previous checkout for packag=
e `%s'?" name))
>>> (package--delete-directory pkg-dir)
>>> (error "There already exists a checkout for %s" name)))
>>> (make-directory pkg-dir t)
>>> + ;; We store a custom package specification so that it is available
>>> + ;; for `package-vc--unpack-1' as well as `package-vc--checkout-dir'
>>> + ;; can later retrieve the actual checkout.
>>> + (package-vc--save-selected-packages
>>> + name (list :url (concat package-vc--url-scheme dir)))
>>> (package-vc--unpack-1
>>> (package-desc-create
>>> :name (intern name)
>>> :dir pkg-dir
>>> - :kind 'vc)
>>> - (file-name-as-directory pkg-dir))))
>>> + :kind 'vc))))
>>
>> The commit message doesn't appear to explain this change.
>
> I don't think I understood this comment. This patch removes `pkg-dir'
> argument for `package-vc--unpack-1'. In this case I removed the value
> of `(file-name-as-directory pkg-dir)' from the call site, and it's
> documented in the patch:
>
> (package-vc-install-from-checkout): [...] Remove `pkg-dir'
> argument from `package-vc--unpack-1' calls.
A misreading again, I thought that the return value of
`file-name-as-directory' was the return value of the function (reading
patches in mail quotes is difficult ^^).
>
>> I am not sure
>> if we have already been over it, but changing the return value of a
>> non-internal function like this is not something we shouldn't do for no
>> reason.
>
> This part I don't understand either. The patch doesn't change the value
> that `package-vc-install-from-checkout' returns. It has been, and it
> still is the value that `package-vc--unpack-1' returns. Similarly the
> patch doesn't change value returned from `package-vc--unpack-1', which
> remains t.
>
> But I appreciate highlighting the importance of keeping interface
> stable. I will add appropriate assertions to tests.
I hope my above comment has clarified this point.
> [...]
>
>>> diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests=
.el
>>> new file mode 100644
>>> index 00000000000..9f00d0f508f
>>> --- /dev/null
>>> +++ b/test/lisp/package-vc-tests.el
>
> [...]
>
>>> +(require 'package-vc)
>>> +(require 'package)
>>> +(require 'vc-git)
>>
>> BTW. I don't think there is any reason you would have to use vc-git in
>> the tests compared to just invoking git commands manually, in case that
>> makes anything easier for you.
>
> Actually, using `vc-git' makes is what makes it easier. I had some
> funny encounters with my Windows CI builds on GitHub [1], which I
> haven't pin point yet, I but for now working theory is that there are
> multiple git binaries in the environment. Using `vc-git' makes it more
> likely that CI, tests, and the code under test uses the same one.
OK, then forget my previous point.
> [...]
>
>> The tests already look a lot better, I'll have to review them in greater
>> detail in the near future, but thank you /very/ much for integrating my
>> feedback from the previous commits!
>
> I am glad you like them. Although their execution is much longer, this
> approach allows for greater flexibility with what and how to test. My
> advice is to apply them and keep running them as you're making changes.
> Perhaps also adding extra tests, for the areas that are not tested yet.
>
> Attaching patch for tests only. Just added extra assertions for
> `package-vc-install', `package-vc-checkout', and
> `package-vc-install-from-checkout' return values.
Thanks!
>
> [1] https://github.com/pkryger/setup-emacs-dev (FWIW: I am planning to
> add Linux and macOS builds such that one can just test their development
> branch with simple YAML file).
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Tue, 25 Nov 2025 20:23:09 +0000
Resent-Message-ID: <handler.79188.B79188.17641021824763 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org, Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17641021824763
(code B ref 79188); Tue, 25 Nov 2025 20:23:09 +0000
Received: (at 79188) by debbugs.gnu.org; 25 Nov 2025 20:23:02 +0000
Received: from localhost ([127.0.0.1]:41940 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vNzYv-0001EH-OG
for submit <at> debbugs.gnu.org; Tue, 25 Nov 2025 15:23:01 -0500
Received: from mout01.posteo.de ([185.67.36.65]:58913)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1vNFdm-0008Jx-4q
for 79188 <at> debbugs.gnu.org; Sun, 23 Nov 2025 14:20:57 -0500
Received: from submission (posteo.de [185.67.36.169])
by mout01.posteo.de (Postfix) with ESMTPS id 847EB240027
for <79188 <at> debbugs.gnu.org>; Sun, 23 Nov 2025 20:20:47 +0100 (CET)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1763925647; bh=UEbwzWfwwcLkj4hey2xDdXrjx3D+2ATgNB0eafHuH+8=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:From;
b=VARweq/O991y38a41Moh7512wXghnBQ4jr0Rn+/cCB4/a1gjkCHT71/6z70XpzGEE
jznyB63ZcSyHCVmwJoMGj4CXqFm6OEfX2KZ8nyHBQZrYhYqQs3H2qkWHLMhBz/4n3k
Cs4QJe7gSOYINOinheunF7J0y/aafpI6P1Php5FAw4f3WYodHqmU7jeKCShok5Yk6L
94Uh/H2r8EUyPvtukqbLmXMkHJj2dFrkt129LfbmykIAtZUcEvGj0NQH3oQjpM1x5W
+yv7r4Jr9141X5rohL8mfDGPnWyt2t/4qy5UyKOn/ttY33O3xPCrDUnRRyNlYXs6rL
7RZTYU9jQyuJg==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4dDzM23J6Lz9rxG;
Sun, 23 Nov 2025 20:20:46 +0100 (CET)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <874iqkiufc.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<m24iqzmqh6.fsf@HIDDEN> <m28qgbqsx0.fsf_-_@HIDDEN>
<m2tsyzjek4.fsf@HIDDEN> <875xbcbg0f.fsf@HIDDEN>
<m2bjl0vidc.fsf@HIDDEN> <874iqkiufc.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Sun, 23 Nov 2025 19:20:46 +0000
Message-ID: <87zf8ch7xu.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
--=-=-=
Content-Type: text/plain
I have applied the patch containing the tests locally and made a few
changes that I haven't tested extensively yet: Can you take a look if
you find anything to object to:
--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline
diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
index 477df96416b..37eadfd4b53 100644
--- a/test/lisp/package-vc-tests.el
+++ b/test/lisp/package-vc-tests.el
@@ -42,15 +42,19 @@
(require 'ert-x)
(require 'ert)
-(defvar package-vc-tests-under-test '(test-package-1
- test-package-2
- test-package-3
- test-package-4
- test-package-5
- test-package-6
- test-package-7
- test-package-8
- test-package-9))
+(eval-and-compile
+ ;; We evaluate the definition at compile-time as well, so that
+ ;; `package-vc-test-deftest' can use the value.
+ (defvar package-vc-tests-under-test
+ '(test-package-1
+ test-package-2
+ test-package-3
+ test-package-4
+ test-package-5
+ test-package-6
+ test-package-7
+ test-package-8
+ test-package-9)))
(defvar package-vc-tests-preserve-temporary nil
"When non-nil preserve temporary files produced by tests.
@@ -83,27 +87,19 @@ package-vc-tests-add
(let* ((resource-dir (ert-resource-directory))
(suffix (if (stringp suffix) suffix (format "%s" suffix)))
(file (let ((file (replace-regexp-in-string
- (rx ".in" string-end) ""
- (replace-regexp-in-string
- "SUFFIX" suffix
- (replace-regexp-in-string
- (rx "-v" digit (zero-or-more
- "." (one-or-more digit)))
- ""
- in-file
- nil nil 0)
- nil nil 0)
- nil nil 0)))
- (if lisp-dir
- (file-name-concat lisp-dir file)
- file))))
- (copy-file (expand-file-name in-file resource-dir) file t)
- (with-temp-buffer
- (insert-file-contents file)
- (goto-char (point-min))
- (while (search-forward "SUFFIX" nil t)
- (replace-match suffix))
- (write-file file))
+ (rx (or "SUFFIX"
+ (: "-v" digit (* "." (1+ digit)))
+ (: ".in" string-end)) )
+ (lambda (mat)
+ (if (string= mat "SUFFIX") suffix ""))
+ in-file)))
+ (file-name-concat lisp-dir file))))
+ (unless (zerop (call-process
+ "m4" (expand-file-name in-file resource-dir)
+ `(:file ,file) nil
+ (format "--define=SUFFIX=%s" suffix)
+ "--prefix-builtins"))
+ (error "Failed to invoke M4 on %s" in-file))
(vc-git-command nil 0 nil "add" ".")))
(defun package-vc-tests-create-bundle (suffix &optional lisp-dir)
@@ -111,14 +107,11 @@ package-vc-tests-create-bundle
If LISP-DIR is non-nil place sources of the package in LISP-DIR."
(let* ((name (format "test-package-%s" suffix))
(repo-dir (expand-file-name (file-name-concat "repo" name)
- package-vc-tests-dir)))
- (make-directory (if lisp-dir
- (expand-file-name lisp-dir repo-dir)
- repo-dir)
- :parents)
+ package-vc-tests-dir)))
+ (make-directory (expand-file-name (or lisp-dir ".") repo-dir) t)
(let ((default-directory repo-dir)
- (bundle-file (expand-file-name (format "%s.bundle" name)
- package-vc-tests-dir)))
+ (bundle-file (expand-file-name (format "%s.bundle" name)
+ package-vc-tests-dir)))
(vc-git-command nil 0 nil "init" "-b" "master")
(package-vc-tests-add
suffix "test-package-SUFFIX-lib-v0.1.el.in" lisp-dir)
@@ -146,20 +139,15 @@ package-vc-tests-package-desc
When INSTALLED is non-nil the descriptor will come from `package-alist'.
Otherwise the descriptor will be from `package-archive-contents'. This
is to mimic `package-vc--read-package-desc'."
- (cadr (assoc (if (stringp package) package (symbol-name package))
- (if installed package-alist package-archive-contents)
+ (cadr (assoc package (if installed package-alist package-archive-contents)
#'string=)))
(defun package-vc-tests-package-lisp-dir (pkg)
"Return a Lisp directory of PKG."
- (and-let* ((checkout-dir (car
- (alist-get pkg
- package-vc-tests-packages))))
- (or (and-let* ((lisp-dir (cadr
- (alist-get pkg
- package-vc-tests-packages))))
- (expand-file-name lisp-dir checkout-dir))
- checkout-dir)))
+ (and-let* ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
+ (if-let* ((lisp-dir (cadr (alist-get pkg package-vc-tests-packages))))
+ (expand-file-name lisp-dir checkout-dir)
+ checkout-dir)))
(defun package-vc-tests-package-main-file (pkg)
"Return a main file of PKG."
@@ -178,8 +166,7 @@ package-vc-tests-package-main-file
(defun package-vc-tests-load-history-marker (name)
"Return a `load-history' marker with NAME."
- (expand-file-name (symbol-name name)
- package-vc-tests-dir))
+ (expand-file-name (symbol-name name) package-vc-tests-dir))
(defun package-vc-tests-load-history-pattern (pkg type)
"Return a regexp pattern for PKG's file of TYPE."
@@ -189,20 +176,13 @@ package-vc-tests-load-history-pattern
package-user-dir
(symbol-name pkg)
(format "%s-autoloads.el" pkg)))
- string-end))
+ eos))
(:main
- (rx
- (literal
- (package-vc-tests-package-main-file pkg))
- string-end))
+ (rx (literal (package-vc-tests-package-main-file pkg)) eos))
(:main-compiled
- (rx
- (literal
- (package-vc-tests-package-main-file pkg))
- "c"
- string-end))
+ (rx (literal (package-vc-tests-package-main-file pkg)) "c" eos))
(:marker
- (rx (literal (package-vc-tests-load-history-marker pkg))))))
+ (regexp-quote (package-vc-tests-load-history-marker pkg)))))
(defun package-vc-tests-load-history-position (pkg type)
"Return a PKG's file of TYPE position in `load-history'.
@@ -216,16 +196,15 @@ package-vc-tests-load-history-position
(rx string-start
(literal (file-truename package-vc-tests-dir)))))
(cl-position-if
- (lambda (file)
- (string-match pkg-file file))
- (cl-remove-if-not
- (lambda (file-name)
- (string-match interesting-entry file-name))
- (mapcar
- #'file-truename
- (cl-remove-if-not
- #'stringp
- (mapcar #'car-safe load-history)))))))
+ (lambda (file) (string-match pkg-file file))
+ (mapcan
+ (lambda (ent)
+ (and (consp ent)
+ (stringp (car ent))
+ (let ((file-name (file-truename (car ent))))
+ (and (string-match interesting-entry file-name)
+ (list file-name)))))
+ load-history))))
(defun package-vc-tests-explain-load-history-position (pkg type)
"Explain `package-vc-tests-load-history' failed for PKG of TYPE."
@@ -240,18 +219,14 @@ package-vc-tests-explain-load-history-position
`(found in load-history at pos ,pos)
'(not found in load-history)))
(entries
- (mapcar
- (lambda (file)
- (concat "..."
- (substring file (length package-vc-tests-dir))))
- (cl-remove-if
- (lambda (file)
- (or (not (stringp file))
- (not (string-prefix-p package-vc-tests-dir file))))
- (mapcar #'car-safe load-history)))))
- (append (list 'pattern pattern)
- reason
- (list entries))))
+ (cl-loop
+ with len = (length package-vc-tests-dir)
+ for hist in load-history
+ when (and (consp hist)
+ (stringp (car hist))
+ (string-prefix-p package-vc-tests-dir (car hist)))
+ collect (concat "..." (substring (car hist) len)))))
+ (append (list 'pattern pattern) reason (list entries))))
(put #'package-vc-tests-load-history-position
'ert-explainer
@@ -261,37 +236,17 @@ package-vc-tests-explain-load-history-position
;; argument. This is needed for ERT to print package name in case of
;; failure.
-(defun package-vc-tests-valid-commit-p (_pkg commit)
- "Return non-nil when COMMIT is a valid commit."
- (and (stringp commit)
- (not (string= commit "unknown"))))
-
-(defun package-vc-tests-in-strict-order-p (_pkg &rest args)
- "Return non-nil when ARGS are in strict order."
- (apply #'< args))
-
-(defun package-vc-tests-match-p (_pkg regexp string)
- "Return non-nil when REGEXP matches STRING."
- (string-match regexp string))
-
-(defun package-vc-tests-buffer-p (_pkg obj)
- "Return non-nil when OBJ is a buffer."
- (bufferp obj))
-
(defun package-vc-tests-elc-files (pkg)
"Return elc files for PKG."
- (when-let* ((dir (package-vc-tests-package-lisp-dir pkg))
- (elc-files (directory-files
- dir nil (rx ".elc" string-end))))
- elc-files))
+ (when-let* ((dir (package-vc-tests-package-lisp-dir pkg)))
+ (directory-files dir nil (rx ".elc" string-end))))
(defun package-vc-tests-assert-elc (pkg)
"Assert that PKG has correct .elc files in."
(let* ((dir (package-vc-tests-package-lisp-dir pkg))
(elc-files (should (package-vc-tests-elc-files pkg)))
- (autoloads-rx (rx
- (literal (format "%s-autoloads.elc" pkg))
- string-end)))
+ (autoloads-rx (rx (literal (format "%s-autoloads.elc" pkg))
+ string-end)))
(should-not (cl-find-if (lambda (elc)
(string-match autoloads-rx elc))
elc-files))
@@ -311,14 +266,12 @@ package-vc-tests-assert-package-alist
(defun package-vc-tests-reset-head (pkg)
"Reset to HEAD^ checkout for PKG."
- (let ((default-directory (car
- (alist-get pkg package-vc-tests-packages))))
+ (let ((default-directory (cadr (assoc pkg package-vc-tests-packages))))
(vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))
(defun package-vc-tests-package-head (pkg)
"Return HEAD revisions of a PKG."
- (let ((default-directory (car
- (alist-get pkg package-vc-tests-packages))))
+ (let ((default-directory (cadr (assoc pkg package-vc-tests-packages))))
(vc-git-working-revision nil)))
(defmacro with-package-vc-tests-installed (pkg &rest body)
@@ -350,90 +303,77 @@ with-package-vc-tests-installed
`(;; checkout and install with `package-vc-install' (on
;; ELPA)
(test-package-1
- ,(expand-file-name "test-package-1"
- package-user-dir)
+ ,(expand-file-name "test-package-1" package-user-dir)
nil
package-vc-tests-install-from-elpa)
;; checkout and install with `package-vc-install' (not on
;; ELPA)
(test-package-2
- ,(expand-file-name "test-package-2"
- package-user-dir)
+ ,(expand-file-name "test-package-2" package-user-dir)
nil
package-vc-tests-install-from-spec)
;; checkout with `package-vc-checktout' and install with
;; `package-vc-install-from-checkout' (on ELPA)
(test-package-3
- ,(expand-file-name "test-package-3"
- package-vc-tests-dir)
+ ,(expand-file-name "test-package-3" package-vc-tests-dir)
nil
pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
;; checkout with git and install with
;; `package-vc-install-from-checkout'
(test-package-4
- ,(expand-file-name "test-package-4"
- package-vc-tests-dir)
+ ,(expand-file-name "test-package-4" package-vc-tests-dir)
nil
package-vc-tests-checkout-with-git-install-from-checkout)
;; sources in "lisp" sub directory, checkout and install
;; with `package-vc-install' (not on ELPA)
(test-package-5
- ,(expand-file-name "test-package-5"
- package-user-dir)
+ ,(expand-file-name "test-package-5" package-user-dir)
"lisp"
package-vc-tests-install-from-spec)
;; sources in "lisp" sub directory, checkout with git and
;; install with `package-vc-install-from-checkout'
(test-package-6
- ,(expand-file-name "test-package-6"
- package-vc-tests-dir)
+ ,(expand-file-name "test-package-6" package-vc-tests-dir)
"lisp"
package-vc-tests-checkout-with-git-install-from-checkout)
;; sources in "src" sub directory, checkout and install
;; with `package-vc-install' (on ELPA)
(test-package-7
- ,(expand-file-name "test-package-7"
- package-user-dir)
+ ,(expand-file-name "test-package-7" package-user-dir)
"src"
package-vc-tests-install-from-elpa)
;; sources in "src" sub directory, checkout with
;; `package-vc-checktout' and install with
;; `package-vc-install-from-checkout' (on ELPA)
(test-package-8
- ,(expand-file-name "test-package-8"
- package-vc-tests-dir)
+ ,(expand-file-name "test-package-8" package-vc-tests-dir)
nil
pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
;; sources in "custom-dir" sub directory, checkout and
;; install with `package-vc-install' (on ELPA)
(test-package-9
- ,(expand-file-name "test-package-9"
- package-user-dir)
+ ,(expand-file-name "test-package-9" package-user-dir)
"custom-dir"
package-vc-tests-install-from-elpa)))
;; - create a test package bundle
(package-vc-tests-bundle
(let* ((pkg-name (symbol-name ,pkg))
(suffix (and (string-match
- (rx ?-
- (group (one-or-more (not ?-)))
- string-end)
+ (rx ?- (group (1+ (not ?-))) eos)
pkg-name)
(match-string 1 pkg-name))))
(package-vc-tests-create-bundle
suffix (cadr (alist-get ,pkg package-vc-tests-packages)))))
;; - find all packages that are present in a test ELPA
(package-vc-tests-elpa-packages
- (mapcar
- #'car
- (cl-remove-if-not
- (lambda (package)
- (memq
- (cadddr package)
- '(package-vc-tests-install-from-elpa
- pakcage-vc-tests-checkout-from-elpa-install-from-checkout)))
- package-vc-tests-packages)))
+ (cl-loop
+ for (name _ _ fn) in package-vc-tests-packages
+ when (memq
+ fn
+ '(package-vc-tests-install-from-elpa
+ pakcage-vc-tests-checkout-from-elpa-install-from-checkout))
+ collect name))
;; - make test packages recognisable by `package' and
;; `package-vc' internals:
(package-archive-contents
@@ -465,35 +405,32 @@ with-package-vc-tests-installed
(let ((lisp-dir
(cadr (alist-get
,pkg package-vc-tests-packages))))
- (append
- (list pkg
- :url (car package-vc-tests-bundle)
- :branch "master"
- :doc (let ((doc-file
- (format "%s.texi" ,pkg)))
- (if lisp-dir
- (file-name-concat lisp-dir
- doc-file)
- doc-file))
- :make (format "build-%s" ,pkg)
- :shell-command (format
- "touch %s.cmd-build"
- ,pkg))
- (and lisp-dir
- (not (member lisp-dir '("lisp" "src")))
- (list :lisp-dir lisp-dir)))))
+ (append
+ (list pkg
+ :url (car package-vc-tests-bundle)
+ :branch "master"
+ :doc (let ((doc-file
+ (format "%s.texi" ,pkg)))
+ (if lisp-dir
+ (file-name-concat lisp-dir
+ doc-file)
+ doc-file))
+ :make (format "build-%s" ,pkg)
+ :shell-command (format
+ "touch %s.cmd-build"
+ ,pkg))
+ (and lisp-dir
+ (not (member lisp-dir '("lisp" "src")))
+ (list :lisp-dir lisp-dir)))))
package-vc-tests-elpa-packages))))
(package-vc--archive-data-alist
- (list
- (list 'test-elpa :version 1 :default-vc 'Git)))
+ '((test-elpa :version 1 :default-vc Git)))
;; - `vc-guess-backend-url' is recognising bundles as `Git'
;; repositories:
(vc-clone-heuristic-alist
- (cons
- (cons (rx "test-package-" (one-or-more digit) ".bundle"
- string-end)
- 'Git)
- vc-clone-heuristic-alist))
+ `((,(rx "test-package-" (1+ digit) ".bundle" eos)
+ Git)
+ ,@vc-clone-heuristic-alist))
;; - ensure that `package-alist' and
;; `package-vc-selected-packages' are empty
package-alist
@@ -507,8 +444,7 @@ with-package-vc-tests-installed
(default-directory package-vc-tests-dir))
(unwind-protect
(progn
- (funcall (or (caddr (alist-get ,pkg
- package-vc-tests-packages))
+ (funcall (or (caddr (alist-get ,pkg package-vc-tests-packages))
(lambda (pkg)
(ert-fail
(format
@@ -541,7 +477,7 @@ with-package-vc-tests-installed
load-history (cl-remove-if
(lambda (entry)
(and-let* ((path (car-safe entry))
- ((stringp path)))
+ (_ (stringp path)))
(string-match pattern path)))
load-history)
Info-directory-list (cl-remove-if
@@ -564,18 +500,14 @@ package-vc-tests-install-from-elpa
(should (eq t (package-vc-install pkg)))
(push (list (package-vc-tests-load-history-marker 'install-end))
load-history)
- (should-not (alist-get (symbol-name pkg)
- package-vc-selected-packages
+ (should-not (alist-get pkg package-vc-selected-packages
nil nil #'string=)))
(defun package-vc-tests-install-from-spec (pkg)
"Install PKG with `package-vc-install' (not on ELPA)."
(push (list (package-vc-tests-load-history-marker 'install-begin))
load-history)
- (should (eq t
- (package-vc-install `(,pkg
- :url ,(car package-vc-tests-bundle)
- :branch "master"))))
+ (should (eq t (package-vc-install `(,pkg :url ,(car package-vc-tests-bundle)))))
(push (list (package-vc-tests-load-history-marker 'install-end))
load-history)
(should (equal (car package-vc-tests-bundle)
@@ -587,24 +519,23 @@ package-vc-tests-install-from-spec
(defun pakcage-vc-tests-checkout-from-elpa-install-from-checkout (pkg)
"Install PKG with `package-vc-install-from-checkout'.
Make checkout with `package-vc-checkout'."
- (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
- (let ((buffer (package-vc-checkout (package-vc-tests-package-desc
- pkg)
- checkout-dir)))
- (should (package-vc-tests-buffer-p pkg buffer))
- (should (string-prefix-p (symbol-name pkg)
- (buffer-name buffer))))
- (push (list (package-vc-tests-load-history-marker 'install-begin))
- load-history)
- (should (eq t
- (package-vc-install-from-checkout checkout-dir)))
- (push (list (package-vc-tests-load-history-marker 'install-end))
- load-history)
- (should (equal (concat package-vc--url-scheme checkout-dir)
- (plist-get (alist-get (symbol-name pkg)
- package-vc-selected-packages
- nil nil #'string=)
- :url)))))
+ (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
+ (let ((buffer (package-vc-checkout (package-vc-tests-package-desc
+ pkg)
+ checkout-dir)))
+ (should (bufferp pkg buffer))
+ (should (string-prefix-p (symbol-name pkg) (buffer-name buffer))))
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t
+ (package-vc-install-from-checkout checkout-dir)))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (concat package-vc--url-scheme checkout-dir)
+ (plist-get (alist-get (symbol-name pkg)
+ package-vc-selected-packages
+ nil nil #'string=)
+ :url)))))
(defun package-vc-tests-checkout-with-git-install-from-checkout (pkg)
"Install PKG with `package-vc-install-from-checkout'.
@@ -632,420 +563,381 @@ package-vc-tests-package-vc-async-wait
(declare (indent 3))
(let ((count-sym (make-symbol "count"))
(post-vc-command-sym (make-symbol "post-vc-command")))
- `(letrec ((,count-sym ,count)
- (,post-vc-command-sym
- (lambda (command _ command-flags)
- ;; A crude filter for vc commands
- (when (and (equal command "git")
- (cl-every (lambda (flag)
- (member flag command-flags))
- ,flags))
- (decf ,count-sym)))))
+ `(let* ((,count-sym ,count)
+ (,post-vc-command-sym
+ (lambda (command _ command-flags)
+ ;; A crude filter for vc commands
+ (when (and (equal command vc-git-program)
+ (cl-every (lambda (flag)
+ (member flag command-flags))
+ ,flags))
+ (decf ,count-sym)))))
(add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
(unwind-protect
(with-timeout (,seconds nil)
- (prog1
- (progn ,@body)
+ (prog1 (progn ,@body)
(while (/= ,count-sym 0)
(accept-process-output nil 0.01))))
- (remove-hook 'vc-post-command-functions
- ,post-vc-command-sym)))))
-
-(ert-deftest package-vc-tests-install-post-conditions ()
- (dolist (pkg package-vc-tests-under-test)
- (with-package-vc-tests-installed pkg
- (let ((install-begin
- (should (package-vc-tests-load-history-position
- 'install-begin :marker)))
- (install-end
- (should (package-vc-tests-load-history-position
- 'install-end :marker)))
- (autoloads-pos
- (should (package-vc-tests-load-history-position
- pkg :autoloads))))
- (should (package-vc-tests-in-strict-order-p
- pkg
- install-end
- autoloads-pos
- install-begin))
- (should-not (package-vc-tests-load-history-position
- pkg :main))
- (should-not (package-vc-tests-load-history-position
- pkg :main-compiled)))
- (should (equal (package-vc--main-file
- (package-vc-tests-package-desc pkg t))
- (package-vc-tests-package-main-file pkg)))
- (should (package-vc-tests-valid-commit-p
- pkg
- (package-vc-commit
- (package-vc-tests-package-desc pkg t))))
- (package-vc-tests-assert-elc pkg)
- (package-vc-tests-assert-package-alist pkg '(0 2)))))
-
-(ert-deftest package-vc-tests-require ()
- (dolist (pkg package-vc-tests-under-test)
- (with-package-vc-tests-installed pkg
- (should (fboundp (intern (format "%s-func" pkg))))
- (should (autoloadp
- (symbol-function (intern (format "%s-func" pkg)))))
- (should (require pkg))
- (should (fboundp (intern (format "%s-func" pkg))))
- (should-not (autoloadp
- (symbol-function (intern (format "%s-func" pkg)))))
- (should-not (fboundp (intern (format "%s-old-func" pkg))))
- (should-not (package-vc-tests-load-history-position
- pkg :main))
- (let ((install-end
- (should (package-vc-tests-load-history-position
- 'install-end :marker)))
- (main-compiled-pos
- (should (package-vc-tests-load-history-position
- pkg :main-compiled))))
- (should (package-vc-tests-in-strict-order-p
- pkg
- main-compiled-pos
- install-end))))))
-
-(ert-deftest package-vc-tests-upgrade ()
- (dolist (pkg package-vc-tests-under-test)
- (with-package-vc-tests-installed pkg
- (let ((head (package-vc-tests-package-head pkg)))
- (package-vc-tests-reset-head pkg)
- (push (list (package-vc-tests-load-history-marker
- 'upgrade-begin))
- load-history)
- (should
- (package-vc-tests-package-vc-async-wait 5 1 '("pull")
- (package-vc-upgrade (package-vc-tests-package-desc pkg t))
- t))
- (push (list (package-vc-tests-load-history-marker
- 'upgrade-end))
- load-history)
- (should-not (package-vc-tests-load-history-position
- pkg :main))
- (should-not (package-vc-tests-load-history-position
- pkg :main-compiled))
- (let ((upgrade-begin
- (should (package-vc-tests-load-history-position
- 'upgrade-begin :marker)))
- (upgrade-end
- (should (package-vc-tests-load-history-position
- 'upgrade-end :marker)))
- (autoloads-pos
- (should (package-vc-tests-load-history-position
- pkg :autoloads))))
- (should (package-vc-tests-in-strict-order-p
- pkg
- upgrade-end
- autoloads-pos
- upgrade-begin)))
- (let ((func (intern (format "%s-func" pkg))))
- (should (fboundp func))
- (should (autoloadp
+ (remove-hook 'vc-post-command-functions ,post-vc-command-sym)))))
+
+(defmacro package-vc-test-deftest (name args &rest body)
+ (declare (debug (&define [&name "test@" symbolp]
+ sexp
+ def-body))
+ (indent 2))
+ (unless (length= args 1)
+ (error "`package-vc' tests have to take a single argument"))
+ (let ((file (or (macroexp-file-name) buffer-file-name))
+ (tests '()))
+ (dolist (pkg package-vc-tests-under-test)
+ (let ((name (intern (format "package-vc-tests-%s/%s" name pkg))))
+ (push
+ `(ert-set-test
+ ',name
+ (make-ert-test
+ :name ',name
+ :tags '(package-vc)
+ :file-name ,file
+ :body
+ (lambda ()
+ (let ((,(car args) ',pkg))
+ (with-package-vc-tests-installed ,(car args)
+ ,@body))
+ nil)))
+ tests)))
+ `(progn ,@tests)))
+
+(package-vc-test-deftest install-post-conditions (pkg)
+ (let ((install-begin
+ (should (package-vc-tests-load-history-position
+ 'install-begin :marker)))
+ (install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (< install-end autoloads-pos install-begin))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled)))
+ (should (equal (package-vc--main-file
+ (package-vc-tests-package-desc pkg t))
+ (package-vc-tests-package-main-file pkg)))
+ (should (equal (package-vc-tests-package-desc pkg t) "unknown"))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest require (pkg)
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should (require pkg))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (let ((install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (< main-compiled-pos install-end))))
+
+(package-vc-test-deftest upgrade (pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade (package-vc-tests-package-desc pkg t))
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-end))
+ load-history)
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (< upgrade-end autoloads-pos upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest upgrade-after-require (pkg)
+ (should (require pkg))
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade (package-vc-tests-package-desc pkg t))
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-end))
+ load-history)
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (< upgrade-end autoloads-pos upgrade-begin))
+ (should (< upgrade-end main-pos upgrade-begin))
+ (should (< upgrade-end main-compiled-pos upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
(symbol-function func)))
- (should (equal "New macro test"
- (funcall func "test"))))
- (should-not (fboundp (intern (format "%s-old-func" pkg))))
- (should (equal head
- (package-vc-tests-package-head pkg))))
- (package-vc-tests-assert-elc pkg)
- (package-vc-tests-assert-package-alist pkg '(0 2)))))
-
-(ert-deftest package-vc-tests-upgrade-after-require ()
- (dolist (pkg package-vc-tests-under-test)
- (with-package-vc-tests-installed pkg
- (should (require pkg))
- (let ((head (package-vc-tests-package-head pkg)))
- (package-vc-tests-reset-head pkg)
- (push (list (package-vc-tests-load-history-marker
- 'upgrade-begin))
- load-history)
- (should
- (package-vc-tests-package-vc-async-wait 5 1 '("pull")
- (package-vc-upgrade (package-vc-tests-package-desc pkg t))
- t))
- (push (list (package-vc-tests-load-history-marker
- 'upgrade-end))
- load-history)
- (let ((upgrade-begin
- (should (package-vc-tests-load-history-position
- 'upgrade-begin :marker)))
- (upgrade-end
- (should (package-vc-tests-load-history-position
- 'upgrade-end :marker)))
- (autoloads-pos
- (should (package-vc-tests-load-history-position
- pkg :autoloads)))
- (main-pos
- (should (package-vc-tests-load-history-position
- pkg :main)))
- (main-compiled-pos
- (should (package-vc-tests-load-history-position
- pkg :main-compiled))))
- (should (package-vc-tests-in-strict-order-p
- pkg
- upgrade-end
- autoloads-pos
- upgrade-begin))
- (should (package-vc-tests-in-strict-order-p
- pkg
- upgrade-end
- main-pos
- upgrade-begin))
- (should (package-vc-tests-in-strict-order-p
- pkg
- upgrade-end
- main-compiled-pos
- upgrade-begin)))
- (let ((func (intern (format "%s-func" pkg))))
- (should (fboundp func))
- (should-not (autoloadp
- (symbol-function func)))
- (should (equal "New macro test"
- (funcall func "test"))))
- (should-not (fboundp (intern (format "%s-old-func" pkg))))
- (should (equal head
- (package-vc-tests-package-head pkg))))
- (package-vc-tests-assert-elc pkg)
- (package-vc-tests-assert-package-alist pkg '(0 2)))))
-
-(ert-deftest package-vc-tests-upgrade-all ()
- (dolist (pkg package-vc-tests-under-test)
- (with-package-vc-tests-installed pkg
- (let ((head (package-vc-tests-package-head pkg)))
- (package-vc-tests-reset-head pkg)
- (push (list (package-vc-tests-load-history-marker
- 'upgrade-all-begin))
- load-history)
- (should
- (package-vc-tests-package-vc-async-wait 5 1 '("pull")
- (package-vc-upgrade-all)
- t))
- (push (list (package-vc-tests-load-history-marker
- 'upgrade-all-end))
- load-history)
- (should-not (package-vc-tests-load-history-position
- pkg :main))
- (should-not (package-vc-tests-load-history-position
- pkg :main-compiled))
- (let ((upgrade-begin
- (should (package-vc-tests-load-history-position
- 'upgrade-all-begin :marker)))
- (upgrade-end
- (should (package-vc-tests-load-history-position
- 'upgrade-all-end :marker)))
- (autoloads-pos
- (should (package-vc-tests-load-history-position
- pkg :autoloads))))
- (should (package-vc-tests-in-strict-order-p
- pkg
- upgrade-end
- autoloads-pos
- upgrade-begin)))
- (let ((func (intern (format "%s-func" pkg))))
- (should (fboundp func))
- (should (autoloadp
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest upgrade-all (pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-end))
+ load-history)
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (< upgrade-end autoloads-pos upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest upgrade-all-after-require (pkg)
+ (should (require pkg))
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-end))
+ load-history)
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (< upgrade-end autoloads-pos upgrade-begin))
+ (should (< upgrade-end main-pos upgrade-begin))
+ (should (< upgrade-end main-compiled-pos upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
(symbol-function func)))
- (should (equal "New macro test"
- (funcall func "test"))))
- (should-not (fboundp (intern (format "%s-old-func" pkg))))
- (should (equal head
- (package-vc-tests-package-head pkg))))
- (package-vc-tests-assert-elc pkg)
- (package-vc-tests-assert-package-alist pkg '(0 2)))))
-
-(ert-deftest package-vc-tests-upgrade-all-after-require ()
- (dolist (pkg package-vc-tests-under-test)
- (with-package-vc-tests-installed pkg
- (should (require pkg))
- (let ((head (package-vc-tests-package-head pkg)))
- (package-vc-tests-reset-head pkg)
- (push (list (package-vc-tests-load-history-marker
- 'upgrade-all-begin))
- load-history)
- (should
- (package-vc-tests-package-vc-async-wait 5 1 '("pull")
- (package-vc-upgrade-all)
- t))
- (push (list (package-vc-tests-load-history-marker
- 'upgrade-all-end))
- load-history)
- (let ((upgrade-begin
- (should (package-vc-tests-load-history-position
- 'upgrade-all-begin :marker)))
- (upgrade-end
- (should (package-vc-tests-load-history-position
- 'upgrade-all-end :marker)))
- (autoloads-pos
- (should (package-vc-tests-load-history-position
- pkg :autoloads)))
- (main-pos
- (should (package-vc-tests-load-history-position
- pkg :main)))
- (main-compiled-pos
- (should (package-vc-tests-load-history-position
- pkg :main-compiled))))
- (should (package-vc-tests-in-strict-order-p
- pkg
- upgrade-end
- autoloads-pos
- upgrade-begin))
- (should (package-vc-tests-in-strict-order-p
- pkg
- upgrade-end
- main-pos
- upgrade-begin))
- (should (package-vc-tests-in-strict-order-p
- pkg
- upgrade-end
- main-compiled-pos
- upgrade-begin)))
- (let ((func (intern (format "%s-func" pkg))))
- (should (fboundp func))
- (should-not (autoloadp
- (symbol-function func)))
- (should (equal "New macro test"
- (funcall func "test"))))
- (should-not (fboundp (intern (format "%s-old-func" pkg))))
- (should (equal head
- (package-vc-tests-package-head pkg))))
- (package-vc-tests-assert-elc pkg)
- (package-vc-tests-assert-package-alist pkg '(0 2)))))
-
-(ert-deftest package-vc-tests-rebuild ()
- (dolist (pkg package-vc-tests-under-test)
- (with-package-vc-tests-installed pkg
- (package-vc-tests-reset-head pkg)
- (let ((head (package-vc-tests-package-head pkg)))
- (package-vc-rebuild
- (package-vc-tests-package-desc pkg t))
- (let ((old-func (intern (format "%s-old-func" pkg))))
- (should (fboundp old-func))
- (should (autoloadp
- (symbol-function old-func))))
- (let ((func (intern (format "%s-func" pkg))))
- (should (fboundp func))
- (should (autoloadp
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest rebuild (pkg)
+ (package-vc-tests-reset-head pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (let ((old-func (intern (format "%s-old-func" pkg))))
+ (should (fboundp old-func))
+ (should (autoloadp
+ (symbol-function old-func))))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "Old macro test"
+ (funcall func "test"))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 1)))
+
+(package-vc-test-deftest rebuild-after-require (pkg)
+ (should (require pkg))
+ (package-vc-tests-reset-head pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (let ((old-func (intern (format "%s-old-func" pkg))))
+ (should (fboundp old-func))
+ (should-not (autoloadp
+ (symbol-function old-func))))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
(symbol-function func)))
- (should (equal "Old macro test"
- (funcall func "test"))))
- (should (equal head
- (package-vc-tests-package-head pkg))))
- (package-vc-tests-assert-elc pkg)
- (package-vc-tests-assert-package-alist pkg '(0 1)))))
-
-(ert-deftest package-vc-tests-rebuild-after-require ()
- (dolist (pkg package-vc-tests-under-test)
- (with-package-vc-tests-installed pkg
- (should (require pkg))
- (package-vc-tests-reset-head pkg)
- (let ((head (package-vc-tests-package-head pkg)))
- (package-vc-rebuild
- (package-vc-tests-package-desc pkg t))
- (let ((old-func (intern (format "%s-old-func" pkg))))
- (should (fboundp old-func))
- (should-not (autoloadp
- (symbol-function old-func))))
- (let ((func (intern (format "%s-func" pkg))))
- (should (fboundp func))
- (should-not (autoloadp
- (symbol-function func)))
- (should (equal "Old macro test"
- (funcall func "test"))))
- (should (equal head
- (package-vc-tests-package-head pkg))))
- (package-vc-tests-assert-elc pkg)
- (package-vc-tests-assert-package-alist pkg '(0 1)))))
-
-(ert-deftest package-vc-tests-prepare-patch ()
+ (should (equal "Old macro test"
+ (funcall func "test"))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 1)))
+
+(package-vc-test-deftest prepare-patch (pkg)
;; Ensure `vc-prepare-patch' respects subject from function argument
- (let (vc-prepare-patches-separately)
- (dolist (pkg package-vc-tests-under-test)
- (with-package-vc-tests-installed pkg
- (package-vc-prepare-patch (package-vc-tests-package-desc pkg t)
- "test-subject"
- (cdr package-vc-tests-bundle))
- (let ((message-buffer
- (should (get-buffer "*unsent mail to Test Maintainer*"))))
- (should (package-vc-tests-buffer-p pkg message-buffer))
- (switch-to-buffer message-buffer)
- (goto-char (point-min))
- (should
- (package-vc-tests-match-p
- pkg
- (rx
- "To: Test Maintainer <test-maintainer@HIDDEN>")
- (buffer-substring (point) (pos-eol))))
- (forward-line)
- (should
- (package-vc-tests-match-p
- pkg
- (rx "Subject: test-subject")
- (buffer-substring (point) (pos-eol))))
- (let (kill-buffer-query-functions)
- (kill-buffer message-buffer)))))))
-
-(ert-deftest package-vc-tests-log-incoming ()
- (dolist (pkg package-vc-tests-under-test)
- (with-package-vc-tests-installed pkg
- (package-vc-tests-reset-head pkg)
- (should
- (package-vc-tests-package-vc-async-wait
- 5 1 '("log" "--decorate")
- (package-vc-log-incoming (package-vc-tests-package-desc pkg t))
- t))
- (let ((incoming-buffer (get-buffer "*vc-incoming*"))
- (pattern (rx (literal
- (substring
- (cadr package-vc-tests-bundle)
- 0 7))
- (one-or-more any)
- "Second commit"
- line-end)))
- (should (package-vc-tests-buffer-p pkg incoming-buffer))
- (switch-to-buffer incoming-buffer)
- (goto-char (point-min))
- (should
- (package-vc-tests-match-p
- pkg
- pattern
- (buffer-substring (point) (pos-eol))))
- (let (kill-buffer-query-functions)
- (kill-buffer incoming-buffer))))))
-
-(ert-deftest package-vc-tests-pkg-spec-doc-make-shell-command ()
+ (let ((vc-prepare-patches-separately nil))
+ (package-vc-prepare-patch (package-vc-tests-package-desc pkg t)
+ "test-subject"
+ (cdr package-vc-tests-bundle))
+ (let ((message-buffer
+ (should (get-buffer "*unsent mail to Test Maintainer*"))))
+ (should (bufferp pkg message-buffer))
+ (switch-to-buffer message-buffer)
+ (goto-char (point-min))
+ (should
+ (string-match
+ pkg
+ (rx
+ "To: Test Maintainer <test-maintainer@HIDDEN>")
+ (buffer-substring (point) (pos-eol))))
+ (forward-line)
+ (should
+ (string-match
+ pkg
+ (rx "Subject: test-subject")
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer message-buffer)))))
+
+(package-vc-test-deftest log-incoming (pkg)
+ (package-vc-tests-reset-head pkg)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 1 '("log" "--decorate")
+ (package-vc-log-incoming (package-vc-tests-package-desc pkg t))
+ t))
+ (let ((incoming-buffer (get-buffer "*vc-incoming*"))
+ (pattern (rx (literal
+ (substring
+ (cadr package-vc-tests-bundle)
+ 0 7))
+ (one-or-more any)
+ "Second commit"
+ line-end)))
+ (should (bufferp pkg incoming-buffer))
+ (switch-to-buffer incoming-buffer)
+ (goto-char (point-min))
+ (should
+ (string-match
+ pkg
+ pattern
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer incoming-buffer))))
+
+(package-vc-test-deftest pkg-spec-doc-make-shell-command (pkg)
(let ((package-vc-allow-build-commands t))
- ;; Only `packgae-vc-install' runs make and shell command
- (dolist (pkg '(test-package-1 test-package-7 test-package-9))
- (with-package-vc-tests-installed pkg
- (let ((checkout-dir (car (alist-get
- pkg package-vc-tests-packages))))
- (should (file-exists-p
- (expand-file-name
- (format "%s.make-build" pkg)
- checkout-dir)))
- (should (file-exists-p
- (expand-file-name
- (format "%s.cmd-build" pkg)
- checkout-dir))))
- (should (cl-member-if (lambda (dir)
- (and (stringp dir)
- (string-prefix-p package-vc-tests-dir
- dir)))
- Info-directory-list))
- (let ((info-file
- (expand-file-name (format "%s.info" pkg)
- (car (alist-get
- pkg package-vc-tests-packages)))))
- (should (file-exists-p info-file))
- (ert-with-test-buffer
- (:name (format "*package-vc-tests: %s.info*" pkg))
- (insert-file-contents info-file)
- (goto-char (point-min))
- (should (re-search-forward
- (format "First chapter for %s" pkg)))
- (should (re-search-forward
- (format "Second chapter for %s" pkg)))))))))
+ ;; Only `package-vc-install' runs make and shell command
+ (let ((checkout-dir (car (alist-get
+ pkg package-vc-tests-packages))))
+ (should (file-exists-p
+ (expand-file-name
+ (format "%s.make-build" pkg)
+ checkout-dir)))
+ (should (file-exists-p
+ (expand-file-name
+ (format "%s.cmd-build" pkg)
+ checkout-dir))))
+ (should (cl-member-if (lambda (dir)
+ (and (stringp dir)
+ (string-prefix-p package-vc-tests-dir
+ dir)))
+ Info-directory-list))
+ (let ((info-file
+ (expand-file-name (format "%s.info" pkg)
+ (car (alist-get
+ pkg package-vc-tests-packages)))))
+ (should (file-exists-p info-file))
+ (ert-with-test-buffer
+ (:name (format "*package-vc-tests: %s.info*" pkg))
+ (insert-file-contents info-file)
+ (goto-char (point-min))
+ (should (re-search-forward
+ (format "First chapter for %s" pkg)))
+ (should (re-search-forward
+ (format "Second chapter for %s" pkg)))))))
(provide 'package-vc-tests)
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Tue, 25 Nov 2025 20:28:21 +0000
Resent-Message-ID: <handler.79188.B79188.17641024577089 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org, Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17641024577089
(code B ref 79188); Tue, 25 Nov 2025 20:28:21 +0000
Received: (at 79188) by debbugs.gnu.org; 25 Nov 2025 20:27:37 +0000
Received: from localhost ([127.0.0.1]:42094 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vNzdN-0001q6-I6
for submit <at> debbugs.gnu.org; Tue, 25 Nov 2025 15:27:36 -0500
Received: from mail-wm1-x32a.google.com ([2a00:1450:4864:20::32a]:58748)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1vNaNJ-0003VS-1z
for 79188 <at> debbugs.gnu.org; Mon, 24 Nov 2025 12:29:21 -0500
Received: by mail-wm1-x32a.google.com with SMTP id
5b1f17b1804b1-477b1cc8fb4so26344245e9.1
for <79188 <at> debbugs.gnu.org>; Mon, 24 Nov 2025 09:29:17 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1764005350; x=1764610150; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=gJyZT/dEZlH1Yo8DzCpnJwrnhKE/nxT5O065l/IgaLk=;
b=hRvYFQadgIbI/ugxLl8KBlNpapytzzmBT4Rm6p6ILKy6JHnkec95a4ps2mhlRggVf2
g/f0YRkN9cLXB/qmS8o/pNxV9nZgm3wYkWOaS6rN10wuJE8XuyAuFNHPeaJ4+e5M1pwp
nlqvMU84KEDv0AThMr8NF1UxST6bwrRZSnrYAxv7IcDabfUwdff3+3LGwF2ELqMk/Z/U
3qmzvprgIPPNP+Vp0d4an4m8V4IOj+lsL4WA1wOebBtQkN483nl6XtgngzRLVtbvXTeJ
52+dF3vZxMxY8HAUHIobFdRqe1Cq2eHBtsanzsdm5hpkA5ypJSMxs5wGSGScdTmsGHoF
8TzA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1764005350; x=1764610150;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject
:date:message-id:reply-to;
bh=gJyZT/dEZlH1Yo8DzCpnJwrnhKE/nxT5O065l/IgaLk=;
b=JEqcPRt0HU99KJelQp+XWLtxI5lSp2GKrcpfOXYgOK8RvO1Dy7RfJdC5YJoUPtLGTm
rXA+QF1KlYZxLflqFSG1KyU5SFvqsi15yUOFk5pZ9aPXzKzfBlLAH/4ml+i0xXesd71X
vi5SbPtagGWPtgtwCJ33T3jLiCl0wHfSGdmXXf2+nDvjf+UxUV4O+leqw1Qof75kcWNE
NGELPR28MsMEdB/5386LsgaUHKo4IEJxvjPQ+upwD++KlEI3cx3IGKIEnUR6ZBMSILZA
3FLBkT/6ZYFqvmdlEU5OxaSX5+cGms6bWwC9tURrXMvlI+yOmvbh58GQIUVlkHLE1zLo
K8Pw==
X-Forwarded-Encrypted: i=1;
AJvYcCUy0wSJFtvFP2P3zR6fSM0lnea72pc9h+pX5jZewLqiapDcDHKmUDn0VCfgDJzLCZ4+z9tbow==@debbugs.gnu.org
X-Gm-Message-State: AOJu0Yx0PpUdgrEn4Ud7aQshVx2fgfgnqMBDIfwHHUx7sZHBEm3QrZCa
8zYR63YZ5rrXL+zeD5PMwrPCG16+CC5O/ERkWQmG/G9OuDl7gZC1fUvMWm23jw==
X-Gm-Gg: ASbGncubO5qR0ehyLRCzl1kXwcIAi8oupDk/UnjPk/t2eBNKmwcYPD6v7M4LYOW0bbU
Fbfg5XTHoUC/3eTIiGaX7PBi1y1SY6oiWEOAb6RuC/YfnbDK6xk25l/0ArodtKJWxWalQaLyhbI
DPHqL1WwxJWgN33AftRct3I+jNogt3uTj6EiovtqqObZCkahQvB8iN/5Ke+qv2Bk/kKp+WuGtii
njwc3NzWd7YelJTV8rRYHRxdfYonOP/xvtFVICgspq+CXoW8Z0ale0FirV/9Op9xXasU0DGNiDQ
AEvm2FADmThZcgfZYfDgAWykNOS6aEjXRnjT/amiSJwnEXPb8e7/EHFjFv70pnMDHUkAtt9Pp82
JffHN8Eojmds1De1mmDW8Zg8baXvWBUhi+vNfYrrYReMbcavZhTkdQP1sp0yhhlHoKmM8mkpq40
ceUB/QgNRRUQr/HJE3bHuKjvwUSyLMJ/MgVDn2SCQ+XrpoAanZ2hWPPQBM
X-Google-Smtp-Source: AGHT+IFzfplKTb4YGvdanx3i6WTNgNfDjDWT8RoTXfu9Pym1O+oqGKjycopCjUwKu4Bt1kgJoYPryw==
X-Received: by 2002:a05:600c:1c92:b0:477:73e9:dc17 with SMTP id
5b1f17b1804b1-477c0202473mr154625305e9.35.1764005350096;
Mon, 24 Nov 2025 09:29:10 -0800 (PST)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:ed5a:9fef:4874:2856])
by smtp.gmail.com with ESMTPSA id
5b1f17b1804b1-477a97213b8sm152299005e9.1.2025.11.24.09.29.08
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Mon, 24 Nov 2025 09:29:08 -0800 (PST)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <874iqkiufc.fsf@HIDDEN> (Philip Kaludercic's message of "Sun,
23 Nov 2025 16:29:45 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<m24iqzmqh6.fsf@HIDDEN> <m28qgbqsx0.fsf_-_@HIDDEN>
<m2tsyzjek4.fsf@HIDDEN> <875xbcbg0f.fsf@HIDDEN>
<m2bjl0vidc.fsf@HIDDEN> <874iqkiufc.fsf@HIDDEN>
Date: Mon, 24 Nov 2025 17:29:08 +0000
Message-ID: <m2ecpnpcez.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain
Philip Kaludercic <philipk@HIDDEN> writes:
> I have applied the patch containing the tests locally and made a few
> changes that I haven't tested extensively yet: Can you take a look if
> you find anything to object to:
>
> diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
> index 477df96416b..37eadfd4b53 100644
> --- a/test/lisp/package-vc-tests.el
> +++ b/test/lisp/package-vc-tests.el
[...]
I have applied your patch on top of mine. I had a similar idea in mind,
but I don't think I have mentioned it earlier, nor have I ever got around
to actually implement that. Thank you for doing it!
While trying to run it I found things that needed fixing. Some of them
were typical refactoring goofs. But I also extended macro a bit to
support `skip-when`/`skip-unless' and extra bindings for installing a
package. I have also added a fix for Windows execution - long story
short: I have not found a better solution than using `file-truename' for
`load-history' entries. On macOS adds extra /private, while Windows
expands the ~1.
Please find updated patch below.
--=-=-=
Content-Type: text/x-patch; charset=utf-8
Content-Disposition: attachment;
filename=0001-Add-tests-for-package-vc.patch
Content-Transfer-Encoding: quoted-printable
Content-Description: tests
From 740fd0b791db7c0840e31ca54a4ab81ef509f902 Mon Sep 17 00:00:00 2001
From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
Date: Tue, 2 Sep 2025 09:28:13 +0100
Subject: [PATCH] Add tests for package-vc
* test/lisp/package-vc-tests.el (package-vc-tests-under-test):
Define packages names to run tests on.
(package-vc-tests-preserve-temporary): When non nil then
preserve temporary test files.
(package-vc-tests-dir, package-vc-tests-packages)
(package-vc-tests-bundle): Silence byte compiler.
(package-vc-tests-add): Copy a an in file template,
update SUFFIX in it and add it to index.
(package-vc-tests-create-bundle): Create a package git
repository bundle with test package source.
(package-vc-tests-package-desc): Retrieve a `package-desc' for
tested package.
(package-vc-tests-package-lisp-dir): Determine a lisp directory
for a package.
(package-vc-tests-package-main-file): Calculate expected
location of package's main file.
(package-vc-tests-load-history-marker): Create a load history
marker.
(package-vc-tests-load-history-pattern): Create a regexp pattern
to search in `load-history'.
(package-vc-tests-load-history-position): Calculate a position
in `load-history'.
(package-vc-tests-load-history-interesting-entries): Return
`load-history' entries related to the current
`package-vc-tests-dir'.
(package-vc-tests-explain-load-history-position): Return ERT
explanation for failures.
(package-vc-tests-elc-files): Check that there are elc files and
that there is no compiled autoloads file amongst them.
(package-vc-tests-assert-delete-elc): Assert that .elc files
are present for a package.
(package-vc-tests-assert-package-alist): Assert that
`pakcage-alist' contains a `package-desc' for package, and that
the `pakcage-desc' has correct slot `version' and slot `dir'.
(package-vc-tests-reset-head^): Reset head of checkout of
tested packages to HEAD^.
(package-vc-tests-packages-head): Return current checkout
revision.
(package-vc-tests-make-spec): Return a test spec for a package.
(with-package-vc-tests-installed): Setup test environment,
install package, evaluate test body, and then tear down the test
environment.
(package-vc-tests-install-from-elpa)
(package-vc-tests-install-from-spec): Install a test package.
(pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
(package-vc-tests-checkout-with-git-install-from-checkout):
Checkout and install a test package.
(package-vc-tests-package-vc-async-wait): Wait for an
asynchronous VC command to finish.
(package-vc-tests-deftest): Define series tests for each package
in `package-vc-tests-under-test'.
(install-post-conditions): Tests that after installing a test
package the `load-history' entries, package's main file, commit,
elc files, and `package-alist' entry are correct.
(require): Test that after calling `require' the `load-history'
entries are correct.
(upgrade, upgrade-all): Test that after calling
`package-vc-upgrade'/`package-vc-upgrade-all' the `load-history'
entries, package's elc files, commit, and `package-alist' entry
are correct.
(upgrade-after-require, upgrade-all-after-require): Test that
after calling `require' followed by
`package-vc-upgrade'/`package-vc-upgrade-all' the `load-history'
entries, commit, package's elc files, and `package-alist' entry
are correct.
(rebuild): Test that after calling `package-vc-rebuild' on an
old version of a package, the package's old function, old macro,
elc files, and `package-alist' entry are correct.
(rebuild-after-require): Test that after calling `require'
followed by `package-vc-rebuild' on an old version of a package,
the package's old function, old macro, elc files, and
`package-alist' entry are correct.
(prepare-patch): Test that after calling
`package-vc-prepare-patch' the message buffer is correct.
(log-incoming): Test that after calling
`package-vc-log-incoming' the log buffer is correct.
(pkg-spec-doc-make-shell-command): Test that :doc, :make, and
:shell-command slots in a pkg spec are handled.
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in:
* test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in:
Code template of version 0.1 of a test package.
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in:
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.2-lib.el.in:
Code template of code of version 0.2 of a test package.
* test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in:
* test/lisp/package-vc-resources/test-package-SUFFIX.texi.in:
Documentation template of a test package.
* test/lisp/package-vc-resources/Makefile:
Makefile template of a test package.
Co-developed-by: Philip Kaludercic <philipk@HIDDEN>
---
test/lisp/package-vc-resources/Makefile.in | 4 +
.../test-package-SUFFIX-inc.texi.in | 3 +
.../test-package-SUFFIX-lib-v0.1.el.in | 16 +
.../test-package-SUFFIX-lib-v0.2.el.in | 16 +
.../test-package-SUFFIX-v0.1.el.in | 28 +
.../test-package-SUFFIX-v0.2.el.in | 24 +
.../test-package-SUFFIX.texi.in | 11 +
test/lisp/package-vc-tests.el | 959 ++++++++++++++++++
8 files changed, 1061 insertions(+)
create mode 100644 test/lisp/package-vc-resources/Makefile.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-inc.=
texi.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-lib-=
v0.1.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-lib-=
v0.2.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-v0.1=
.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-v0.2=
.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX.texi=
.in
create mode 100644 test/lisp/package-vc-tests.el
diff --git a/test/lisp/package-vc-resources/Makefile.in b/test/lisp/package=
-vc-resources/Makefile.in
new file mode 100644
index 00000000000..8618ae8f2f4
--- /dev/null
+++ b/test/lisp/package-vc-resources/Makefile.in
@@ -0,0 +1,4 @@
+.PHONY: build-test-package-SUFFIX
+
+build-test-package-SUFFIX:
+ @touch test-package-SUFFIX.make-build
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in=
b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in
new file mode 100644
index 00000000000..9e4e38b74a4
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in
@@ -0,0 +1,3 @@
+@c -*- texinfo -*-
+@chapter Second chapter for test-package-SUFFIX
+ Second test text.
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el=
.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in
new file mode 100644
index 00000000000..c8bfce3e8ab
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in
@@ -0,0 +1,16 @@
+;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding: t=
-*-
+
+;;; Commentary:
+;;
+;; Test package SUFFIX library.
+
+;;; Code:
+
+(defmacro test-package-SUFFIX-mac (arg)
+ ;; checkdoc-params: (arg)
+ "Old test macro for `test-package-SUFFIX'."
+ `(format "Old macro %s" ,arg))
+
+(provide 'test-package-SUFFIX-lib)
+
+;;; test-package-SUFFIX-lib.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el=
.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in
new file mode 100644
index 00000000000..bfa4c35f014
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in
@@ -0,0 +1,16 @@
+;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding: t=
-*-
+
+;;; Commentary:
+;;
+;; Test package SUFFIX library.
+
+;;; Code:
+
+(defmacro test-package-SUFFIX-mac (arg)
+ ;; checkdoc-params: (arg)
+ "Test macro for `test-package-SUFFIX'."
+ `(format "New macro %s" ,arg))
+
+(provide 'test-package-SUFFIX-lib)
+
+;;; test-package-SUFFIX-lib.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in =
b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in
new file mode 100644
index 00000000000..ddecc88e1c5
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in
@@ -0,0 +1,28 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.1
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+(require 'test-package-SUFFIX-lib)
+
+;;;###autoload
+(defun test-package-SUFFIX-func (arg)
+ ;; checkdoc-params: (arg)
+ "Test function for `test-package-SUFFIX'."
+ (test-package-SUFFIX-mac arg))
+
+;;;###autoload
+(defun test-package-SUFFIX-old-func ()
+ "Old test function for `test-package-SUFFIX'.")
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in =
b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in
new file mode 100644
index 00000000000..902066d787d
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in
@@ -0,0 +1,24 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.2
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+(require 'test-package-SUFFIX-lib)
+
+;;;###autoload
+(defun test-package-SUFFIX-func (arg)
+ ;; checkdoc-params: (arg)
+ "Test function for `test-package-SUFFIX'."
+ (test-package-SUFFIX-mac arg))
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in b/t=
est/lisp/package-vc-resources/test-package-SUFFIX.texi.in
new file mode 100644
index 00000000000..0fc4fc3653d
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in
@@ -0,0 +1,11 @@
+\input texinfo @c -*- texinfo -*-
+@settitle Info for test-package-SUFFIX
+@direntry
+* Test-package-SUFFIX: (test-package-SUFFIX). test-package-SUFFIX.
+@end direntry
+
+@chapter First chapter for test-package-SUFFIX
+ First test text.
+
+@include test-package-SUFFIX-inc.texi
+@bye
diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
new file mode 100644
index 00000000000..ad8960ee33f
--- /dev/null
+++ b/test/lisp/package-vc-tests.el
@@ -0,0 +1,959 @@
+;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
+
+;; Copyright (C) 2025 Free Software Foundation, Inc.
+
+;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
+;; Keywords: package
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These tests focus on verifying post conditions for `package-vc'
+;; operations on packages. These tests install and load test packages
+;; with a sample test implementation, resulting in modification of
+;; numerous global variables, for example `load-history', `load-path',
+;; `features', etc. When run with `ert' it may contaminate current
+;; Emacs session. For this reason, tests execute their bodies in
+;; `with-package-vc-tests-installed' (which see), that takes care of
+;; cleaning up the environment.
+
+;;; Code:
+
+(require 'package-vc)
+(require 'package)
+(require 'vc-git)
+(require 'vc)
+(require 'cl-lib)
+(require 'info)
+(require 'ert-x)
+(require 'ert)
+
+(eval-and-compile
+ ;; We evaluate the definition at compile-time as well, so that
+ ;; `package-vc-test-deftest' can use the value.
+ (defvar package-vc-tests-under-test
+ '(test-package-1
+ test-package-2
+ test-package-3
+ test-package-4
+ test-package-5
+ test-package-6
+ test-package-7
+ test-package-8
+ test-package-9)))
+
+(defvar package-vc-tests-preserve-temporary nil
+ "When non-nil preserve temporary files produced by tests.
+Each test produces a new temporary directory for each package under
+test. This leads to creation of [length of
+`package-vc-tests-under-test'] times [number of tests executed]
+temporary directories for each tests run. When this variable is nil
+then delete all temporary directories as soon as they are no longer
+needed. When this variable is a symbol, then preserve temporary
+directories for the package that matches the symbol. When this variable
+is a list of symbol, then preserve temporary directories for each
+package that matches symbol in the list. When this variable is t then
+preserve all temporary directories. Tests create temporary directories
+with `make-temp-file', which see.")
+
+(defvar package-vc-tests-dir)
+(defvar package-vc-tests-packages)
+(defvar package-vc-tests-bundle)
+
+;; TODO: add test for deleting packages, with asserting
+;; `package-vc-selected-packages'
+
+;; TODO: clarify `package-vc-install-all' behaviour with regards to
+;; packages installed with `package-vc' but not stored in
+;; `package-vc-selected-packages' i.e., packages from ELPAs
+
+(defun package-vc-tests-add (suffix in-file &optional lisp-dir)
+ "Create a new file from IN-FILE template updating SUFFIX in it.
+When LISP-DIR is non-nil place the NAME file under LISP-DIR."
+ (let* ((resource-dir (ert-resource-directory))
+ (suffix (if (stringp suffix) suffix (format "%s" suffix)))
+ (file (let ((file (replace-regexp-in-string
+ (rx (or "SUFFIX"
+ (: "-v" digit (* "." (1+ digit)))
+ (: ".in" string-end)) )
+ (lambda (mat)
+ (if (string=3D mat "SUFFIX") suffix ""))
+ in-file)))
+ (file-name-concat lisp-dir file))))
+ (unless (zerop (call-process
+ "sed" (expand-file-name in-file resource-dir)
+ `(:file ,file) nil
+ (format "s/SUFFIX/%s/g" suffix)))
+ (error "Failed to invoke M4 on %s" in-file))
+ (vc-git-command nil 0 nil "add" ".")))
+
+(defun package-vc-tests-create-bundle (suffix &optional lisp-dir)
+ "Create a test package bundle with SUFFIX.
+If LISP-DIR is non-nil place sources of the package in LISP-DIR."
+ (let* ((name (format "test-package-%s" suffix))
+ (repo-dir (expand-file-name (file-name-concat "repo" name)
+ package-vc-tests-dir)))
+ (make-directory (expand-file-name (or lisp-dir ".") repo-dir) t)
+ (let ((default-directory repo-dir)
+ (bundle-file (expand-file-name (format "%s.bundle" name)
+ package-vc-tests-dir)))
+ (vc-git-command nil 0 nil "init" "-b" "master")
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-lib-v0.1.el.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-v0.1.el.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX.texi.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-inc.texi.in" lisp-dir)
+ ;; Place Makefile in root of the repository
+ (package-vc-tests-add
+ suffix "Makefile.in" nil)
+ (vc-git-command nil 0 nil "commit" "-m" "First commit")
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-lib-v0.2.el.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-v0.2.el.in" lisp-dir)
+ (vc-git-command nil 0 nil "commit" "-m" "Second commit")
+ (vc-git-command nil 0 nil
+ "bundle" "create" bundle-file "master")
+ (list bundle-file (vc-git-working-revision nil)))))
+
+(defun package-vc-tests-package-desc (package &optional installed)
+ "Return descriptor of PACKAGE.
+When INSTALLED is non-nil the descriptor will come from `package-alist'.
+Otherwise the descriptor will be from `package-archive-contents'. This
+is to mimic `package-vc--read-package-desc'."
+ (cadr (assoc package (if installed package-alist package-archive-content=
s)
+ #'string=3D)))
+
+(defun package-vc-tests-package-lisp-dir (pkg)
+ "Return a Lisp directory of PKG."
+ (and-let* ((checkout-dir (car (alist-get pkg package-vc-tests-packages))=
))
+ (if-let* ((lisp-dir (cadr (alist-get pkg package-vc-tests-packages))))
+ (expand-file-name lisp-dir checkout-dir)
+ checkout-dir)))
+
+(defun package-vc-tests-package-main-file (pkg)
+ "Return a main file of PKG."
+ (file-name-concat (package-vc-tests-package-lisp-dir pkg)
+ (format "%s.el" pkg)))
+
+;; When a package source is being recompiled - for example as result of
+;; `pakckage-vc-upgrade' or `package-vc-rebuild' - it is also reloaded
+;; [1] to ensure that the most recent version of compiled code is
+;; available to Emacs. There are a few tests that add markers in
+;; `load-history' before executing such functions. And then follow up
+;; tests use these markers to assert that expected package files are in
+;; correct places in the `load-history'.
+;;
+;; [1] Only when a file has been loaded previously.
+
+(defun package-vc-tests-load-history-marker (name)
+ "Return a `load-history' marker with NAME."
+ (file-truename
+ (expand-file-name (symbol-name name) package-vc-tests-dir)))
+
+(defun package-vc-tests-load-history-pattern (pkg type)
+ "Return a regexp pattern for PKG's file of TYPE."
+ (pcase type
+ (:autoloads
+ (rx (literal (file-truename
+ (file-name-concat
+ package-user-dir
+ (symbol-name pkg)
+ (format "%s-autoloads.el" pkg))))
+ eos))
+ (:main
+ (rx (literal (file-truename
+ (package-vc-tests-package-main-file pkg)))
+ eos))
+ (:main-compiled
+ (rx (literal (file-truename
+ (package-vc-tests-package-main-file pkg)))
+ "c" eos))
+ (:marker
+ (regexp-quote (file-truename
+ (package-vc-tests-load-history-marker pkg))))))
+
+(defun package-vc-tests-load-history-interesting-entries ()
+ "Return interesting entries in `load-history'.
+An entry in `load-history' is interesting when it starts with
+`package-vc-tests-dir'."
+ (let ((interesting-entry
+ (rx bos (literal (file-truename package-vc-tests-dir)))))
+ (mapcan
+ (lambda (ent)
+ (and (consp ent)
+ (stringp (car ent))
+ (let ((file-name (file-truename (car ent))))
+ (and (string-match interesting-entry file-name)
+ (list file-name)))))
+ load-history)))
+
+(defun package-vc-tests-load-history-position (pkg type)
+ "Return a PKG's file of TYPE position in `load-history'.
+If TYPE is `:autoloads' return a position of a PKG autoloads file.
+Otherwise, if TYPE is `:main' return a position of PKG main file (not
+compiled). Otherwise, if TYPE is `:main-compiled' return a position of
+PKG compiled main file. Otherwise, if TYPE is `:marker' return a
+position of a marker PKG."
+ (let ((pkg-file (package-vc-tests-load-history-pattern pkg type)))
+ (cl-position-if
+ (lambda (file) (string-match pkg-file file))
+ (package-vc-tests-load-history-interesting-entries))))
+
+(defun package-vc-tests-explain-load-history-position (pkg type)
+ "Explain `package-vc-tests-load-history' failed for PKG of TYPE."
+ (let ((pattern
+ (concat "..."
+ (substring
+ (package-vc-tests-load-history-pattern pkg type)
+ (length (regexp-quote
+ (file-truename package-vc-tests-dir))))))
+ (reason
+ (if-let* ((pos (package-vc-tests-load-history-position
+ pkg type)))
+ `(found in load-history at pos ,pos)
+ '(not found in load-history)))
+ (entries
+ (cl-loop
+ with len =3D (length (file-truename package-vc-tests-dir))
+ for hist in (package-vc-tests-load-history-interesting-entries)
+ collect (concat "..." (substring hist len)))))
+ (append (list 'pattern pattern) reason (list entries))))
+
+(put #'package-vc-tests-load-history-position
+ 'ert-explainer
+ #'package-vc-tests-explain-load-history-position)
+
+(defun package-vc-tests-elc-files (pkg)
+ "Return elc files for PKG."
+ (when-let* ((dir (package-vc-tests-package-lisp-dir pkg)))
+ (directory-files dir nil (rx ".elc" string-end))))
+
+(defun package-vc-tests-assert-elc (pkg)
+ "Assert that PKG has correct .elc files in."
+ (let* ((dir (package-vc-tests-package-lisp-dir pkg))
+ (elc-files (should (package-vc-tests-elc-files pkg)))
+ (autoloads-rx (rx (literal (format "%s-autoloads.elc" pkg))
+ string-end)))
+ (should-not (cl-find-if (lambda (elc)
+ (string-match autoloads-rx elc))
+ elc-files))
+ (dolist (elc-file elc-files)
+ (delete-file (expand-file-name elc-file dir)))))
+
+(defun package-vc-tests-assert-package-alist (pkg version)
+ "Assert that PKG entry in `package-alist' have correct VERSION and dir."
+ (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
+ (should (equal (file-name-as-directory
+ (expand-file-name (format "%s" pkg)
+ package-user-dir))
+ (file-name-as-directory
+ (package-desc-dir pkg-desc))))
+ (should (equal (list pkg version)
+ (list pkg (package-desc-version pkg-desc))))))
+
+(defun package-vc-tests-reset-head^ (pkg)
+ "Reset to HEAD^ checkout for PKG."
+ (let ((default-directory (cadr (assoc pkg package-vc-tests-packages))))
+ (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))
+
+(defun package-vc-tests-package-head (pkg)
+ "Return HEAD revisions of a PKG."
+ (let ((default-directory (cadr (assoc pkg package-vc-tests-packages))))
+ (vc-git-working-revision nil)))
+
+(defun package-vc-tests-make-spec (pkg)
+ "Return a pkg-spec for PKG."
+ (let ((lisp-dir
+ (cadr (alist-get pkg package-vc-tests-packages))))
+ (append
+ (list pkg
+ :url (car package-vc-tests-bundle)
+ ;; Branch needs to be specified in a pkg-spec, as cloning
+ ;; from a git bundle won't checkout a default branch.
+ :branch "master"
+ :doc (let ((doc-file (format "%s.texi" pkg)))
+ (if lisp-dir
+ (file-name-concat lisp-dir doc-file)
+ doc-file))
+ :make (format "build-%s" pkg)
+ :shell-command (format "touch %s.cmd-build" pkg))
+ (and lisp-dir
+ (not (member lisp-dir '("lisp" "src")))
+ (list :lisp-dir lisp-dir)))))
+
+(defmacro with-package-vc-tests-installed (pkg &rest body)
+ "Eval BODY with PKG installed in a test environment."
+ (declare (indent 1) (debug t))
+ ;; git-bundle(1) produces test packages sources in bundle files, based
+ ;; on skeleton files in directory package-vc-resources. Before
+ ;; executing body make sure that:
+ ;;
+ ;; - `package' has been initialised, and there are no
+ ;; `package-archives' defined
+ `(let* ((package-archives (unless package--initialized
+ (let (package-archives)
+ (package-initialize)
+ (package-vc--archives-initialize))
+ nil))
+ ;; - create a temporary location for packages and test files
+ (package-vc-tests-dir
+ (expand-file-name
+ (make-temp-file "package-vc-tests-"
+ t
+ (format-time-string "-%Y%m%d.%H%M%S.%3N"))))
+ ;; - packages are installed into a test directory
+ (package-user-dir (expand-file-name "elpa"
+ package-vc-tests-dir))
+ ;; - define test packages, their checkout locations, lisp
+ ;; directories, and install functions
+ (package-vc-tests-packages
+ `(;; checkout and install with `package-vc-install' (on
+ ;; ELPA)
+ (test-package-1
+ ,(expand-file-name "test-package-1" package-user-dir)
+ nil
+ package-vc-tests-install-from-elpa)
+ ;; checkout and install with `package-vc-install' (not on
+ ;; ELPA)
+ (test-package-2
+ ,(expand-file-name "test-package-2" package-user-dir)
+ nil
+ package-vc-tests-install-from-spec)
+ ;; checkout with `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-3
+ ,(expand-file-name "test-package-3" package-vc-tests-dir)
+ nil
+ pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
+ ;; checkout with git and install with
+ ;; `package-vc-install-from-checkout'
+ (test-package-4
+ ,(expand-file-name "test-package-4" package-vc-tests-dir)
+ nil
+ package-vc-tests-checkout-with-git-install-from-checkout)
+ ;; sources in "lisp" sub directory, checkout and install
+ ;; with `package-vc-install' (not on ELPA)
+ (test-package-5
+ ,(expand-file-name "test-package-5" package-user-dir)
+ "lisp"
+ package-vc-tests-install-from-spec)
+ ;; sources in "lisp" sub directory, checkout with git and
+ ;; install with `package-vc-install-from-checkout'
+ (test-package-6
+ ,(expand-file-name "test-package-6" package-vc-tests-dir)
+ "lisp"
+ package-vc-tests-checkout-with-git-install-from-checkout)
+
+ ;; sources in "src" sub directory, checkout and install
+ ;; with `package-vc-install' (on ELPA)
+ (test-package-7
+ ,(expand-file-name "test-package-7" package-user-dir)
+ "src"
+ package-vc-tests-install-from-elpa)
+ ;; sources in "src" sub directory, checkout with
+ ;; `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-8
+ ,(expand-file-name "test-package-8" package-vc-tests-dir)
+ nil
+ pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
+ ;; sources in "custom-dir" sub directory, checkout and
+ ;; install with `package-vc-install' (on ELPA)
+ (test-package-9
+ ,(expand-file-name "test-package-9" package-user-dir)
+ "custom-dir"
+ package-vc-tests-install-from-elpa)))
+ ;; - create a test package bundle
+ (package-vc-tests-bundle
+ (let* ((pkg-name (symbol-name ,pkg))
+ (suffix (and (string-match
+ (rx ?- (group (1+ (not ?-))) eos)
+ pkg-name)
+ (match-string 1 pkg-name))))
+ (package-vc-tests-create-bundle
+ suffix (cadr (alist-get ,pkg package-vc-tests-packages)))))
+ ;; - find all packages that are present in a test ELPA
+ (package-vc-tests-elpa-packages
+ (cl-loop
+ for (name _ _ fn) in package-vc-tests-packages
+ when (memq
+ fn
+ '(package-vc-tests-install-from-elpa
+ pakcage-vc-tests-checkout-from-elpa-install-from-check=
out))
+ collect name))
+ ;; - make test packages recognisable by `package' and
+ ;; `package-vc' internals:
+ (package-archive-contents
+ (mapcar
+ (lambda (pkg)
+ (list pkg
+ (package-desc-create
+ :name pkg
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras
+ (list
+ '(:maintainer
+ ("Test Maintainer"
+ . "test-maintainer@HIDDEN"))
+ (cons :url (car package-vc-tests-bundle))
+ (cons :commit (cadr package-vc-tests-bundle))
+ (cons :revdesc (substring
+ (cadr package-vc-tests-bundle)
+ 0 12))))))
+ package-vc-tests-elpa-packages))
+ ;; Branch needs to be specified in a pkg-spec, as cloning from
+ ;; a bundle won't checkout a default branch.
+ (package-vc--archive-spec-alists
+ (list
+ (cons 'test-elpa
+ (mapcar #'package-vc-tests-make-spec
+ package-vc-tests-elpa-packages))))
+ (package-vc--archive-data-alist
+ '((test-elpa :version 1 :default-vc Git)))
+ ;; - `vc-guess-backend-url' is recognising bundles as `Git'
+ ;; repositories:
+ (vc-clone-heuristic-alist
+ `((,(rx "test-package-" (1+ digit) ".bundle" eos)
+ . Git)
+ ,@vc-clone-heuristic-alist))
+ ;; - ensure that `package-alist' and
+ ;; `package-vc-selected-packages' are empty
+ package-alist
+ package-vc-selected-packages
+ ;; - don't save any customization
+ (user-init-file nil)
+ ;; - FIXME: something sets `default-directory' to last
+ ;; checkout directory after `package-vc-checkout', which
+ ;; causes problems when this macro deletes the temporary
+ ;; directory after body execution.
+ (default-directory package-vc-tests-dir))
+ (unwind-protect
+ (progn
+ (funcall (or (caddr (alist-get ,pkg package-vc-tests-packages))
+ (lambda (pkg)
+ (ert-fail
+ (format
+ "Cannot find %s in package-vc-tests-packages"
+ pkg))))
+ ,pkg)
+ ,@body)
+ ;; Unbind package defined symbols, and remove package defined
+ ;; features and entries from `load-path',`load-history', and
+ ;; `Info-directory-list'.
+ (let ((pattern (rx string-start (literal package-vc-tests-dir))))
+ (dolist (entry load-history)
+ (when-let* ((file (car-safe entry))
+ ((stringp file))
+ ((string-match pattern file)))
+ (dolist (elt (cdr entry))
+ (pcase elt
+ (`(defun . ,fun)
+ (fmakunbound fun))
+ (`(provide . ,feat)
+ (setq features (cl-remove feat features)))
+ ((and (pred symbolp)
+ (pred boundp))
+ (makunbound elt))))))
+ (setq load-path (cl-remove-if
+ (lambda (path)
+ (and (stringp path)
+ (string-match pattern path)))
+ load-path)
+ load-history (cl-remove-if
+ (lambda (entry)
+ (and-let* ((path (car-safe entry))
+ (_ (stringp path)))
+ (string-match pattern path)))
+ load-history)
+ Info-directory-list (cl-remove-if
+ (lambda (dir)
+ (and (stringp dir)
+ (string-match pattern dir)))
+ Info-directory-list)))
+ (if (or (memq package-vc-tests-preserve-temporary '(t ,pkg))
+ (and (listp package-vc-tests-preserve-temporary)
+ (memq ,pkg package-vc-tests-preserve-temporary)))
+ (message "package-vc-tests: preserving temporary directory %s"
+ package-vc-tests-dir)
+ (delete-directory package-vc-tests-dir t)))))
+
+(defun package-vc-tests-install-from-elpa (pkg)
+ "Install PKG with `package-vc-install'."
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t (package-vc-install pkg)))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should-not (alist-get pkg package-vc-selected-packages
+ nil nil #'string=3D)))
+
+(defun package-vc-tests-install-from-spec (pkg)
+ "Install PKG with `package-vc-install' (not on ELPA)."
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t (package-vc-install (package-vc-tests-make-spec pkg))))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (car package-vc-tests-bundle)
+ (plist-get (alist-get (symbol-name pkg)
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url))))
+
+(defun pakcage-vc-tests-checkout-from-elpa-install-from-checkout (pkg)
+ "Install PKG with `package-vc-install-from-checkout'.
+Make checkout with `package-vc-checkout'."
+ (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
+ (let ((buffer (package-vc-checkout (package-vc-tests-package-desc
+ pkg)
+ checkout-dir)))
+ (should (bufferp buffer))
+ (should (string-prefix-p (symbol-name pkg) (buffer-name buffer))))
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t
+ (package-vc-install-from-checkout checkout-dir)))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (concat package-vc--url-scheme checkout-dir)
+ (plist-get (alist-get (symbol-name pkg)
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url)))))
+
+(defun package-vc-tests-checkout-with-git-install-from-checkout (pkg)
+ "Install PKG with `package-vc-install-from-checkout'.
+Make checkout with git(1)."
+ (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
+ (vc-git-clone (car package-vc-tests-bundle)
+ checkout-dir
+ "master")
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t
+ (package-vc-install-from-checkout checkout-dir
+ (symbol-name pkg))))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (concat package-vc--url-scheme checkout-dir)
+ (plist-get (alist-get (symbol-name pkg)
+ package-vc-selected-packages
+ nil nil #'string=3D)
+ :url)))))
+
+(defmacro package-vc-tests-package-vc-async-wait (seconds count flags &res=
t body)
+ "Wait up to SECONDS for COUNT async vc commands with FLAGS called by BOD=
Y.
+Return nil on timeout or the value of last form in BODY."
+ (declare (indent 3))
+ (let ((count-sym (make-symbol "count"))
+ (post-vc-command-sym (make-symbol "post-vc-command")))
+ `(let* ((,count-sym ,count)
+ (,post-vc-command-sym
+ (lambda (command _ command-flags)
+ ;; A crude filter for vc commands
+ (when (and (equal command vc-git-program)
+ (cl-every (lambda (flag)
+ (member flag command-flags))
+ ,flags))
+ (decf ,count-sym)))))
+ (add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
+ (unwind-protect
+ (with-timeout (,seconds nil)
+ (prog1 (progn ,@body)
+ (while (/=3D ,count-sym 0)
+ (accept-process-output nil 0.01))))
+ (remove-hook 'vc-post-command-functions ,post-vc-command-sym)))))
+
+(defmacro package-vc-test-deftest (name args &rest body)
+ "For each `package-vc-tests-under-test' define a test with NAME.
+Execute BODY as a test body with a package under test installed. Bind
+car of ARGS (a symbol) to name of the package. Bind cdr of ARGS
+before installing the package."
+ (declare (debug (&define [&name "test@" symbolp]
+ sexp
+ def-body))
+ (indent 2))
+ (when (length< args 1)
+ (error "`package-vc' tests have to take at least one argument"))
+ (unless (symbolp (car-safe args))
+ (error "`package-vc' tests first argument has to be a symbol"))
+ (let ((file (or (macroexp-file-name) buffer-file-name))
+ (tests '()))
+ (dolist (pkg package-vc-tests-under-test)
+ (let ((name (intern (format "package-vc-tests-%s/%s" name pkg))))
+ (push
+ `(cl-macrolet ((skip-when (form) `(ert--skip-when ,form))
+ (skip-unless (form) `(ert--skip-unless ,form)))
+ (ert-set-test
+ ',name
+ (make-ert-test
+ :name ',name
+ :tags '(package-vc)
+ :file-name ,file
+ :body
+ (lambda ()
+ (let ((,(car args) ',pkg)
+ ,@(cdr args))
+ (with-package-vc-tests-installed ,(car args)
+ ,@body))
+ nil))))
+ tests)))
+ `(progn ,@tests)))
+
+(package-vc-test-deftest install-post-conditions (pkg)
+ (let ((install-begin
+ (should (package-vc-tests-load-history-position
+ 'install-begin :marker)))
+ (install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (< install-end autoloads-pos install-begin))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled)))
+ (should (equal (package-vc--main-file
+ (package-vc-tests-package-desc pkg t))
+ (package-vc-tests-package-main-file pkg)))
+ (should (equal (package-vc-commit
+ (package-vc-tests-package-desc pkg t))
+ (cadr package-vc-tests-bundle)))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest require (pkg)
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should (require pkg))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (let ((install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (< main-compiled-pos install-end))))
+
+(package-vc-test-deftest upgrade (pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head^ pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade (package-vc-tests-package-desc pkg t))
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-end))
+ load-history)
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (< upgrade-end autoloads-pos upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest upgrade-after-require (pkg)
+ (should (require pkg))
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head^ pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade (package-vc-tests-package-desc pkg t))
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-end))
+ load-history)
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (< upgrade-end autoloads-pos upgrade-begin))
+ (should (< upgrade-end main-pos upgrade-begin))
+ (should (< upgrade-end main-compiled-pos upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest upgrade-all (pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head^ pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-end))
+ load-history)
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (< upgrade-end autoloads-pos upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest upgrade-all-after-require (pkg)
+ (should (require pkg))
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head^ pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-end))
+ load-history)
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (< upgrade-end autoloads-pos upgrade-begin))
+ (should (< upgrade-end main-pos upgrade-begin))
+ (should (< upgrade-end main-compiled-pos upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest rebuild (pkg)
+ (package-vc-tests-reset-head^ pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (let ((old-func (intern (format "%s-old-func" pkg))))
+ (should (fboundp old-func))
+ (should (autoloadp
+ (symbol-function old-func))))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "Old macro test"
+ (funcall func "test"))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 1)))
+
+(package-vc-test-deftest rebuild-after-require (pkg)
+ (should (require pkg))
+ (package-vc-tests-reset-head^ pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (let ((old-func (intern (format "%s-old-func" pkg))))
+ (should (fboundp old-func))
+ (should-not (autoloadp
+ (symbol-function old-func))))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
+ (symbol-function func)))
+ (should (equal "Old macro test"
+ (funcall func "test"))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 1)))
+
+(package-vc-test-deftest prepare-patch (pkg)
+ ;; Ensure `vc-prepare-patch' respects subject from function argument
+ (let ((vc-prepare-patches-separately nil))
+ (package-vc-prepare-patch (package-vc-tests-package-desc pkg t)
+ "test-subject"
+ (cdr package-vc-tests-bundle))
+ (let ((message-buffer
+ (should (get-buffer "*unsent mail to Test Maintainer*"))))
+ (should (bufferp message-buffer))
+ (switch-to-buffer message-buffer)
+ (goto-char (point-min))
+ (should
+ (string-match
+ (rx
+ "To: Test Maintainer <test-maintainer@HIDDEN>")
+ (buffer-substring (point) (pos-eol))))
+ (forward-line)
+ (should
+ (string-match
+ (rx "Subject: test-subject")
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer message-buffer)))))
+
+(package-vc-test-deftest log-incoming (pkg)
+ (package-vc-tests-reset-head^ pkg)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 1 '("log" "--decorate")
+ (package-vc-log-incoming (package-vc-tests-package-desc pkg t))
+ t))
+ (let ((incoming-buffer (get-buffer "*vc-incoming*"))
+ (pattern (rx (literal
+ (substring
+ (cadr package-vc-tests-bundle)
+ 0 7))
+ (one-or-more any)
+ "Second commit"
+ line-end)))
+ (should (bufferp incoming-buffer))
+ (switch-to-buffer incoming-buffer)
+ (goto-char (point-min))
+ (should
+ (string-match
+ pattern
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer incoming-buffer))))
+
+(package-vc-test-deftest pkg-spec-doc-make-shell-command
+ (pkg (package-vc-allow-build-commands t))
+ ;; Only `package-vc-install' runs make and shell command
+ (skip-unless (memq (caddr (alist-get pkg package-vc-tests-packages))
+ '(package-vc-tests-install-from-elpa
+ package-vc-tests-install-from-spec)))
+ (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
+ (should (file-exists-p
+ (expand-file-name
+ (format "%s.make-build" pkg)
+ checkout-dir)))
+ (should (file-exists-p
+ (expand-file-name
+ (format "%s.cmd-build" pkg)
+ checkout-dir))))
+ (should (cl-member-if
+ (lambda (dir)
+ (and (stringp dir)
+ (string-prefix-p package-vc-tests-dir dir)))
+ Info-directory-list))
+ (let ((info-file
+ (expand-file-name (format "%s.info" pkg)
+ (car (alist-get
+ pkg package-vc-tests-packages)))))
+ (should (file-exists-p info-file))
+ (ert-with-test-buffer
+ (:name (format "*package-vc-tests: %s.info*" pkg))
+ (insert-file-contents info-file)
+ (goto-char (point-min))
+ (should (re-search-forward
+ (format "First chapter for %s" pkg)))
+ (should (re-search-forward
+ (format "Second chapter for %s" pkg))))))
+
+(provide 'package-vc-tests)
+
+;;; package-vc-tests.el ends here
--=20
2.52.0
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Philip Kaludercic <philipk@HIDDEN> writes:
> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>
[...]
>> +(defun package-vc-tests-valid-commit-p (_pkg commit)
>> + "Return non-nil when COMMIT is a valid commit."
>> + (and (stringp commit)
>> + (not (string=3D commit "unknown"))))
>
> We can simplify this by not checking for stringp and using equal
> instead. But I'll take care of that and similar smaller points. We
> should focus on the main point of the patch for now to get this moving.
> I'll leave a few more comments like this below, parenthesised to make
> clear that they are not that important.
I have updated the assertion to check for the real commit SHA. I think
the stricter the better.
>> +
>> +(defun package-vc-tests-in-strict-order-p (_pkg &rest args)
>> + "Return non-nil when ARGS are in strict order."
>
> (I'll also mention that these predicates are here to display the package
> name in the ERT log.)
Thank you for deleting this.
[...]
>> + (if (or (eq package-vc-tests-preserve-temporary t)
>> + (eq package-vc-tests-preserve-temporary ,pkg)
>
> (Sequential occurrences like (or (eq FOO ...) (eq FOO ...)) are
> conventionally replaced by (memq FOO '(...)).)
Got it. Fixed.
[...]
>> +(defun package-vc-tests-install-from-spec (pkg)
>> + "Install PKG with `package-vc-install' (not on ELPA)."
>> + (push (list (package-vc-tests-load-history-marker 'install-begin))
>> + load-history)
>> + (package-vc-install `(,pkg
>> + :url ,(car package-vc-tests-bundle)
>> + :branch "master"))
>
> Why the explicit mention of the branch name here?
A couple of reasons for using master branch.
First I have my git configured to use main globally as a default branch.
This is what the explicit branch when creating a bundle is for.
Second, git clone from a git bundle doesn't checkout default branch. At
least I don't know how to prepare a git bundle, such that git knows what
to do (like a regular remote). When branch is omitted git checkouts
repositories in detached head. While this works for some things (e.g.,
`package-vc-install'), it doesn't allow to perform some actions, e.g.,
upgrade, log incoming, etc. I have added a short explanation to the
file.
>> + (plist-get (alist-get (symbol-name pkg)
>> + package-vc-selected-packages
>> + nil nil #'string=3D)
>> + :url)))))
>
> (This pattern appears to occur often enough, that we should extract it
> out to a helper function.)
Haven't addressed this in the current patch. But sounds like a good
idea.
>> +(defmacro package-vc-tests-package-vc-async-wait (seconds count flags &=
rest body)
>> + "Wait up to SECONDS for COUNT async vc commands with FLAGS called by =
BODY.
>> +Return nil on timeout or the value of last form in BODY."
>> + (declare (indent 3))
>> + (let ((count-sym (make-symbol "count"))
>> + (post-vc-command-sym (make-symbol "post-vc-command")))
>> + `(letrec ((,count-sym ,count)
>> + (,post-vc-command-sym
>> + (lambda (command _ command-flags)
>> + ;; A crude filter for vc commands
>> + (when (and (equal command "git")
>> + (cl-every (lambda (flag)
>> + (member flag command-flags))
>> + ,flags))
>> + (decf ,count-sym)))))
>> + (add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
>> + (unwind-protect
>> + (with-timeout (,seconds nil)
>> + (prog1
>> + (progn ,@body)
>> + (while (/=3D ,count-sym 0)
>> + (accept-process-output nil 0.01))))
>
> And it wouldn't be bad to have a comment here on the topic of our
> discussion w.r.t. timeouts in tests.
I don't really know which points of the discussion you believe are worth
mentioning. Could you propose something?
>> + (let ((func (intern (format "%s-func" pkg))))
>> + (should (fboundp func))
>> + (should (autoloadp
>> + (symbol-function func)))
>
> Does this work even if you run the tests multiple times?
It does. `fmakunbound' (called in the cleanup) takes care of it.
[...]
>> +(ert-deftest package-vc-tests-rebuild ()
>> + (dolist (pkg package-vc-tests-under-test)
>> + (with-package-vc-tests-installed pkg
>> + (package-vc-tests-reset-head pkg)
>> + (let ((head (package-vc-tests-package-head pkg)))
>> + (package-vc-rebuild
>> + (package-vc-tests-package-desc pkg t))
>> + (let ((old-func (intern (format "%s-old-func" pkg))))
>> + (should (fboundp old-func))
>> + (should (autoloadp
>> + (symbol-function old-func))))
>
> (Misindented!)
I fixed indentation across the whole file.
[...]
>> +(ert-deftest package-vc-tests-prepare-patch ()
>> + ;; Ensure `vc-prepare-patch' respects subject from function argument
>> + (let (vc-prepare-patches-separately)
>> + (dolist (pkg package-vc-tests-under-test)
>
> Just while reading this, I had an idea for an alternative to the
> `package-vc-tests-match-p'-situation. Instead of having the loop inside
> the test, we can define our own functions and symbols (that include the
> package name) and install them using `ert-set-test' -- stop me if we
> have talked about this before -- and then the tests are more granular
> and independent of another.=20
I like the idea and implementation (see comment above).
[...]
>>>> I am attaching updated patches. I re-wrote tests to be executable in
>>>> regular Emacs session (although I haven't got to a point where I run
>>>> them under a development Emacs yet). With this it was so much easier =
to
>>>> add a few more tests, and I found that there's another issue with how a
>>>> package is rebuild. It manifests itself with a compilation using
>>>> preciously defined macro definitions, i.e., when macro has been changed
>>>> then the new version is not used.
>>>
>>> Hmm, we might have to use something like `unload-feature' here,
>>
>> I checked `unload-feature' and it seems to focus on real features
>> unloading, e.g., removing hooks, timers, etc. In a process of unloading
>> it does some things as I like, but it takes a different approach to
>> functions. My main goal was to have a clean slate after a test has
>> finished, such that test check whether autoloads are correctly
>> established and resolved. `unload-feature' leaves function symbols
>> bounded, but I suspect that would make writing well encapsulated tests
>> hard. For that reason I'd rather to leave the manual cleanup. I wonder
>> if, prior to unbinding symbols, calling `loadhist-unload-element' is a
>> good idea? WDYT?
>
> I have no experience with that function. We can ask Stefan to comment
> on this.
I have not used it before either. Just read the implementation. I
think the big missing point is that it doesn't call `fmakunbound' for
functions.
[...]
>>>> I also think that using :vc-dir in :extras slot is a viable candidate.
>>>> However, I haven't had a chance to apply it yet.
>>>
>>> If you want to, I can take a shot at updating the patch to use :extras
>>> as Michelangelo proposed. That way I'll also have a better
>>> understanding of the patch, compared to just reading it.
>>
>> That would be nice. I have been thinking about it, but I spent too much
>> time on other items recently. If you have any questions about choices
>> in tests, please ask.
>
> 1+
One of the things I've been occupied with was to bring my CI build
solution to be consumable by others. I think I got to a point where I
can start sharing it. If you're using GitHub, just push your
development branch and drop a workflow file somewhere (to the Emacs's
repository, or to a new repository with just a workflow). Then you can
run tests on the three oses (Ubuntu, macOS, Windows) against your
development branch. You can find it here:
https://github.com/pkryger/setup-emacs-dev. Please ask if need any
help.
[...]
>>>> @@ -934,21 +1035,22 @@ package-vc-install-from-checkout
>>>> (package-vc--archives-initialize)
>>>> (let* ((dir (if interactive dir (expand-file-name dir))) ;avoid dou=
ble expansion
>>>> (name (or name (file-name-base (directory-file-name dir))))
>>>> - (pkg-dir (file-name-concat package-user-dir name))
>>>> - (package-vc-selected-packages
>>>> - (cons (list name :lisp-dir dir)
>>>> - package-vc-selected-packages)))
>>>> + (pkg-dir (file-name-concat package-user-dir name)))
>>>> (when (file-exists-p pkg-dir)
>>>> (if (yes-or-no-p (format "Overwrite previous checkout for packa=
ge `%s'?" name))
>>>> (package--delete-directory pkg-dir)
>>>> (error "There already exists a checkout for %s" name)))
>>>> (make-directory pkg-dir t)
>>>> + ;; We store a custom package specification so that it is available
>>>> + ;; for `package-vc--unpack-1' as well as `package-vc--checkout-di=
r'
>>>> + ;; can later retrieve the actual checkout.
>>>> + (package-vc--save-selected-packages
>>>> + name (list :url (concat package-vc--url-scheme dir)))
>>>> (package-vc--unpack-1
>>>> (package-desc-create
>>>> :name (intern name)
>>>> :dir pkg-dir
>>>> - :kind 'vc)
>>>> - (file-name-as-directory pkg-dir))))
>>>> + :kind 'vc))))
>>>
>>> The commit message doesn't appear to explain this change.
>>
>> I don't think I understood this comment. This patch removes `pkg-dir'
>> argument for `package-vc--unpack-1'. In this case I removed the value
>> of `(file-name-as-directory pkg-dir)' from the call site, and it's
>> documented in the patch:
>>
>> (package-vc-install-from-checkout): [...] Remove `pkg-dir'
>> argument from `package-vc--unpack-1' calls.
>
> A misreading again, I thought that the return value of
> `file-name-as-directory' was the return value of the function (reading
> patches in mail quotes is difficult ^^).
Indeed, it is. I usually apply them against some Emacs repository and
use difftastic to see logic changes. It makes life so much easier.
Another shameless plug: https://github.com/pkryger/difftastic.el.
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Tue, 25 Nov 2025 20:30:05 +0000
Resent-Message-ID: <handler.79188.B79188.17641025808279 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: Philip Kaludercic <philipk@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org, Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.17641025808279
(code B ref 79188); Tue, 25 Nov 2025 20:30:05 +0000
Received: (at 79188) by debbugs.gnu.org; 25 Nov 2025 20:29:40 +0000
Received: from localhost ([127.0.0.1]:42182 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vNzfM-00029K-Jq
for submit <at> debbugs.gnu.org; Tue, 25 Nov 2025 15:29:39 -0500
Received: from mail-wm1-x32e.google.com ([2a00:1450:4864:20::32e]:51310)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
(Exim 4.84_2) (envelope-from <pkryger@HIDDEN>) id 1vNpb4-0005Z6-D6
for 79188 <at> debbugs.gnu.org; Tue, 25 Nov 2025 04:44:34 -0500
Received: by mail-wm1-x32e.google.com with SMTP id
5b1f17b1804b1-477a219db05so31195205e9.2
for <79188 <at> debbugs.gnu.org>; Tue, 25 Nov 2025 01:44:30 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20230601; t=1764063863; x=1764668663; darn=debbugs.gnu.org;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
bh=4lan/dFmHAqApZcI9zZfDxRS2GInDYp2RVQCYl/q3EU=;
b=Zmb1yfTPOxXxx2m4IMFsrAJgY9Wrfp+NC35ALMPmBzERUItytIzWP30DDYNksHQ1e9
DAU00I71btDKntIxOdg69qLHHAkrDjloYpN9Gu1mcpvSk8Nb3fYIlI4ekiCYHeZoaRtW
zmMgcDbwWLlU1tfCV1RHy8QYyl4hikHCs4LX7b9Go2WjpKWtonkSnrZ6ebvDtkgRW2UM
9xgZOT1Dt2Kn512kQDbkFhFva+2JsGD+FMpkEYFLEqI4VMkQEl9uPyhvwiNmoUgL12L3
3Rcq6bzep9a5haXX+t4NN8wexnaVZ5TPX1/oUQzbF6j+GU+nVw5JemIUw34b0o3TLbzF
TQXg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1764063863; x=1764668663;
h=mime-version:user-agent:message-id:date:references:in-reply-to
:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject
:date:message-id:reply-to;
bh=4lan/dFmHAqApZcI9zZfDxRS2GInDYp2RVQCYl/q3EU=;
b=oOfj2xNCFJ/DiB/IR11PCK6005fVGod5A0OwzBLwX3Pva6tPEAuLyTDVL6HbEqPnlD
/IpRQz5v58ZA1ibdY4LhPIq9eRGTKDCyPgS5LI7z7Xfkow/F7OTlwlUlqKuDH8BRq7tj
HzT70gS7iKb2pGnwJgSPnEydHHH9tZwNoaXzdwBq/yvv5XqXElaJyhoSVKXgXsKlEWU4
/cImb3z1yC8Hq3w/1wTD2ls3FRDGmh0Gr9uEGnHZNb5iw5a4VgehAS1Xmk46/O1QB/3g
CBjdOvdJDoiMoK8gqFFuGL7HZvsFfAz8+foN8koxbq0Vo2nvg9Fy4mDDg1PdSx//wqU/
watw==
X-Forwarded-Encrypted: i=1;
AJvYcCWa/tW9FVu81CEvvEiAzF6v7+A5D1WCl/k4bARY+vIUqkvz9EPe3nUAuQ3OyUTIw8f+pDhffg==@debbugs.gnu.org
X-Gm-Message-State: AOJu0YzlMZ9oSmpUQ8g+VTS7wJV5SyToyXEQL2j2P3PmP8UhC2e7t1bk
k8asLgihS4yNQRlTI5DTmnvA9to2ryPRMA4Ho+ow/9eXn1BbgDGmxgm+oVrjCQ==
X-Gm-Gg: ASbGncsgSv2ZC0W4ZEW4OS0Jxt76Qw6s8Xt2FGo/R7lCMwTXLhJXEnWV6cCUYyLzXaA
d9dGvZUCaKDQpnvrOX2eQot9euPgcp4XXo0ELyMp0h5zf6MP8bXAghkBPdZaexZ7R9jWHrl1BDt
tjdvdAWMl/OiXPWrVPLlVw2OiJpJl1xiqEtnDmzzt/raKz9lt62AOAH0YbTWKPF8//8JIspuaNK
8uN6j3N/FfRFW6lIKpS9Tdt59N+QwwbZKGgFMEFy4rksyX/vHrlWVPrZ7cWQnlij7Tgty6tsRFz
LOO3UFbk1UrMrTxVja9xJwI+fyVFaSS987VlgVDCH6cMGqognqxYCqCGn66C5VggHUTgYDqRcFe
VNJtqFHJrr7z16QxSY15YFaEi+2tRzm928T/n7k/uQh4Y8SZlwPbnuYgjBbyQHPwPIRQHu9P0C9
mCOZ+kMDFdU7/3TN3nwlBqTmoxE9ymZ42EJsN9qfCb8wO+qRpHxUdNiJb1
X-Google-Smtp-Source: AGHT+IHH7DCrGxql4YJm3sk7jVanPOHhoPxnBAGTaY13O05hMHEPouv5hB2oGQuEJzaIWbbk9+yp2w==
X-Received: by 2002:a05:600c:529a:b0:477:8a2a:123e with SMTP id
5b1f17b1804b1-477c1133932mr139871525e9.33.1764063863242;
Tue, 25 Nov 2025 01:44:23 -0800 (PST)
Received: from Przemyslaws-MacBook-Air.local
([2a00:23c8:b1c:3801:3412:aded:fec8:ee0f])
by smtp.gmail.com with ESMTPSA id
ffacd0b85a97d-42cb7f363b0sm33858595f8f.13.2025.11.25.01.44.22
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Tue, 25 Nov 2025 01:44:22 -0800 (PST)
From: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
In-Reply-To: <87cy57kvk8.fsf@HIDDEN> (Philip Kaludercic's message of "Mon,
24 Nov 2025 20:46:48 +0000")
References: <m2ectn9xif.fsf@HIDDEN>
<m24iqzmqh6.fsf@HIDDEN> <m28qgbqsx0.fsf_-_@HIDDEN>
<m2tsyzjek4.fsf@HIDDEN> <875xbcbg0f.fsf@HIDDEN>
<m2bjl0vidc.fsf@HIDDEN> <874iqkiufc.fsf@HIDDEN>
<m2ecpnpcez.fsf@HIDDEN> <87cy57kvk8.fsf@HIDDEN>
Date: Tue, 25 Nov 2025 09:44:21 +0000
Message-ID: <m2a50aphu2.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: 0.0 (/)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Philip Kaludercic <philipk@HIDDEN> writes:
> Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
>
>> Philip Kaludercic <philipk@HIDDEN> writes:
>>
>>> I have applied the patch containing the tests locally and made a few
>>> changes that I haven't tested extensively yet: Can you take a look if
>>> you find anything to object to:
>>>
>>> diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests=
.el
>>> index 477df96416b..37eadfd4b53 100644
>>> --- a/test/lisp/package-vc-tests.el
>>> +++ b/test/lisp/package-vc-tests.el
>>
>> [...]
>>
>> I have applied your patch on top of mine. I had a similar idea in mind,
>> but I don't think I have mentioned it earlier, nor have I ever got around
>> to actually implement that. Thank you for doing it!
>>
>> While trying to run it I found things that needed fixing. Some of them
>> were typical refactoring goofs. But I also extended macro a bit to
>> support `skip-when`/`skip-unless'=20
>
> Do we actually need skip-when/unless. I did not copy the code over from
> ert.el, because it seemed unnecessary? I guess there is no harm in it
> now, just curious.
Only `package-vc-install' calls build commands and creates
documentation. When iterating over test packages used to be in test
bodies, the pkg-spec-doc-make-shell-command test used a list of packages
that met the criterion. Now, the test skips such a package. Test still
installs packages that would fail, but I don't think that's a biggie.
FWIW: I haven't tested that, but I think that making
`package-vc-install-from-checkout' to accept a pkg-spec would allow to
execute this code path for that case. E.g., change DIR to DIR-OR-SPEC,
and use similar condition as in `package-install'.
[...]
>> Please find updated patch below.
>
> You have found a number of issues that I ran into after submitting the
> patch as well. I thought about sending you a message but then fell
> asleep yesterday instead, so sorry about that. But I guess we are on
> the same page on a number of issues.
No problem at all. From my side, I have forgot to explain that I
replaced m4 with sed. For some reason m4 has been stripping some of
quotes and backquotes from the output files on my mac. E.g., m4 has
converted
(provide 'test-package-SUFFIX-lib)
into
(provide test-package-1-lib)
(note the missing quote), and converted
(provide 'test-package-SUFFIX)
correctly into
(provide 'test-package-1)
In the most recent patch (attached), I addressed the feedback below, as
well as I ditched git-bundle(1), and opted to use repository directly.
With this change I could remove :master property from package spec,
vide the question you had earlier.
With this change, the manual checkout done by
`package-vc-tests-checkout-with-git-install-from-checkout' may seem
superfluous, but I wanted to preserve symmetry of the install functions,
and I didn't want to complicate setting up let bindings done by
`with-package-vc-tests-installed'. The call to
`package-vc-tests-create-repository' requires value of lisp-dir which
comes from definition of `package-vc-tests-packages'. However, the
definition of `package-vc-tests-packages' requires a location of a
checkout directory, which - should I remove manual checkout - would be
the result of `package-vc-tests-create-repository' call.
The updated tests are below:
--=-=-=
Content-Type: text/x-patch; charset=utf-8
Content-Disposition: attachment;
filename=0001-Add-tests-for-package-vc.patch
Content-Transfer-Encoding: quoted-printable
Content-Description: tests
From 860ea8089ee695b3ad5da8507a625b79814a8836 Mon Sep 17 00:00:00 2001
From: =3D?UTF-8?q?Przemys=3DC5=3D82aw=3D20Kryger?=3D <pkryger@HIDDEN>
Date: Tue, 2 Sep 2025 09:28:13 +0100
Subject: [PATCH] Add tests for package-vc
* test/lisp/package-vc-tests.el (package-vc-tests-under-test):
Define packages names to run tests on.
(package-vc-tests-preserve-temporary): When non nil then
preserve temporary test files.
(package-vc-tests-dir, package-vc-tests-packages)
(package-vc-tests-repository): Silence byte compiler.
(package-vc-tests-add): Copy a an in file template,
update SUFFIX in it and add it to index.
(package-vc-tests-create-repository): Create a package git
repository with a test package's source.
(package-vc-tests-package-desc): Retrieve a `package-desc' for
tested package.
(package-vc-tests-package-spec): Retrieve a pkg-spec for tested
package.
(package-vc-tests-package-lisp-dir): Determine a lisp directory
for a package.
(package-vc-tests-package-main-file): Calculate expected
location of package's main file.
(package-vc-tests-load-history-marker): Create a load history
marker.
(package-vc-tests-load-history-pattern): Create a regexp pattern
to search in `load-history'.
(package-vc-tests-load-history-position): Calculate a position
in `load-history'.
(package-vc-tests-load-history-interesting-entries): Return
`load-history' entries related to the current
`package-vc-tests-dir'.
(package-vc-tests-explain-load-history-position): Return ERT
explanation for failures.
(package-vc-tests-elc-files): Check that there are elc files and
that there is no compiled autoloads file amongst them.
(package-vc-tests-assert-delete-elc): Assert that .elc files
are present for a package.
(package-vc-tests-assert-package-alist): Assert that
`pakcage-alist' contains a `package-desc' for package, and that
the `pakcage-desc' has correct slot `version' and slot `dir'.
(package-vc-tests-reset-head^): Reset head of checkout of
tested packages to HEAD^.
(package-vc-tests-packages-head): Return current checkout
revision.
(package-vc-tests-make-spec): Make a new test spec for a
test package.
(with-package-vc-tests-installed): Setup test environment,
install package, evaluate test body, and then tear down the test
environment.
(package-vc-tests-install-from-elpa)
(package-vc-tests-install-from-spec): Install a test package.
(pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
(package-vc-tests-checkout-with-git-install-from-checkout):
Checkout and install a test package.
(package-vc-tests-package-vc-async-wait): Wait for an
asynchronous VC command to finish.
(package-vc-tests-deftest): Define series tests for each package
in `package-vc-tests-under-test'.
(install-post-conditions): Tests that after installing a test
package the `load-history' entries, package's main file, commit,
elc files, and `package-alist' entry are correct.
(require): Test that after calling `require' the `load-history'
entries are correct.
(upgrade, upgrade-all): Test that after calling
`package-vc-upgrade'/`package-vc-upgrade-all' the `load-history'
entries, package's elc files, commit, and `package-alist' entry
are correct.
(upgrade-after-require, upgrade-all-after-require): Test that
after calling `require' followed by
`package-vc-upgrade'/`package-vc-upgrade-all' the `load-history'
entries, commit, package's elc files, and `package-alist' entry
are correct.
(rebuild): Test that after calling `package-vc-rebuild' on an
old version of a package, the package's old function, old macro,
elc files, and `package-alist' entry are correct.
(rebuild-after-require): Test that after calling `require'
followed by `package-vc-rebuild' on an old version of a package,
the package's old function, old macro, elc files, and
`package-alist' entry are correct.
(prepare-patch): Test that after calling
`package-vc-prepare-patch' the message buffer is correct.
(log-incoming): Test that after calling
`package-vc-log-incoming' the log buffer is correct.
(pkg-spec-doc-make-shell-command): Test that :doc, :make, and
:shell-command slots in a pkg spec are handled.
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in:
* test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in:
Code template of version 0.1 of a test package.
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in:
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.2-lib.el.in:
Code template of code of version 0.2 of a test package.
* test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in:
* test/lisp/package-vc-resources/test-package-SUFFIX.texi.in:
Documentation template of a test package.
* test/lisp/package-vc-resources/Makefile:
Makefile template of a test package.
Co-developed-by: Philip Kaludercic <philipk@HIDDEN>
---
test/lisp/package-vc-resources/Makefile.in | 4 +
.../test-package-SUFFIX-inc.texi.in | 3 +
.../test-package-SUFFIX-lib-v0.1.el.in | 16 +
.../test-package-SUFFIX-lib-v0.2.el.in | 16 +
.../test-package-SUFFIX-v0.1.el.in | 28 +
.../test-package-SUFFIX-v0.2.el.in | 24 +
.../test-package-SUFFIX.texi.in | 11 +
test/lisp/package-vc-tests.el | 962 ++++++++++++++++++
8 files changed, 1064 insertions(+)
create mode 100644 test/lisp/package-vc-resources/Makefile.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-inc.=
texi.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-lib-=
v0.1.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-lib-=
v0.2.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-v0.1=
.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX-v0.2=
.el.in
create mode 100644 test/lisp/package-vc-resources/test-package-SUFFIX.texi=
.in
create mode 100644 test/lisp/package-vc-tests.el
diff --git a/test/lisp/package-vc-resources/Makefile.in b/test/lisp/package=
-vc-resources/Makefile.in
new file mode 100644
index 00000000000..8618ae8f2f4
--- /dev/null
+++ b/test/lisp/package-vc-resources/Makefile.in
@@ -0,0 +1,4 @@
+.PHONY: build-test-package-SUFFIX
+
+build-test-package-SUFFIX:
+ @touch test-package-SUFFIX.make-build
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in=
b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in
new file mode 100644
index 00000000000..9e4e38b74a4
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in
@@ -0,0 +1,3 @@
+@c -*- texinfo -*-
+@chapter Second chapter for test-package-SUFFIX
+ Second test text.
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el=
.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in
new file mode 100644
index 00000000000..c8bfce3e8ab
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in
@@ -0,0 +1,16 @@
+;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding: t=
-*-
+
+;;; Commentary:
+;;
+;; Test package SUFFIX library.
+
+;;; Code:
+
+(defmacro test-package-SUFFIX-mac (arg)
+ ;; checkdoc-params: (arg)
+ "Old test macro for `test-package-SUFFIX'."
+ `(format "Old macro %s" ,arg))
+
+(provide 'test-package-SUFFIX-lib)
+
+;;; test-package-SUFFIX-lib.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el=
.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in
new file mode 100644
index 00000000000..bfa4c35f014
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in
@@ -0,0 +1,16 @@
+;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding: t=
-*-
+
+;;; Commentary:
+;;
+;; Test package SUFFIX library.
+
+;;; Code:
+
+(defmacro test-package-SUFFIX-mac (arg)
+ ;; checkdoc-params: (arg)
+ "Test macro for `test-package-SUFFIX'."
+ `(format "New macro %s" ,arg))
+
+(provide 'test-package-SUFFIX-lib)
+
+;;; test-package-SUFFIX-lib.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in =
b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in
new file mode 100644
index 00000000000..ddecc88e1c5
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in
@@ -0,0 +1,28 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.1
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+(require 'test-package-SUFFIX-lib)
+
+;;;###autoload
+(defun test-package-SUFFIX-func (arg)
+ ;; checkdoc-params: (arg)
+ "Test function for `test-package-SUFFIX'."
+ (test-package-SUFFIX-mac arg))
+
+;;;###autoload
+(defun test-package-SUFFIX-old-func ()
+ "Old test function for `test-package-SUFFIX'.")
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in =
b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in
new file mode 100644
index 00000000000..902066d787d
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in
@@ -0,0 +1,24 @@
+;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*-
+
+;; Homepage: https://test-domain.org
+;; Maintainer: Test Maintainer <test-maintainer@HIDDEN>
+;; Package-Requires: ((emacs "30.1"))
+;; Version: 0.2
+
+;;; Commentary:
+;;
+;; Test package SUFFIX.
+
+;;; Code:
+
+(require 'test-package-SUFFIX-lib)
+
+;;;###autoload
+(defun test-package-SUFFIX-func (arg)
+ ;; checkdoc-params: (arg)
+ "Test function for `test-package-SUFFIX'."
+ (test-package-SUFFIX-mac arg))
+
+(provide 'test-package-SUFFIX)
+
+;;; test-package-SUFFIX.el ends here
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in b/t=
est/lisp/package-vc-resources/test-package-SUFFIX.texi.in
new file mode 100644
index 00000000000..0fc4fc3653d
--- /dev/null
+++ b/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in
@@ -0,0 +1,11 @@
+\input texinfo @c -*- texinfo -*-
+@settitle Info for test-package-SUFFIX
+@direntry
+* Test-package-SUFFIX: (test-package-SUFFIX). test-package-SUFFIX.
+@end direntry
+
+@chapter First chapter for test-package-SUFFIX
+ First test text.
+
+@include test-package-SUFFIX-inc.texi
+@bye
diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el
new file mode 100644
index 00000000000..9d688aa8179
--- /dev/null
+++ b/test/lisp/package-vc-tests.el
@@ -0,0 +1,962 @@
+;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*-
+
+;; Copyright (C) 2025 Free Software Foundation, Inc.
+
+;; Author: Przemsy=C5=82aw Kryger <pkryger@HIDDEN>
+;; Keywords: package
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These tests focus on verifying post conditions for `package-vc'
+;; operations on packages. These tests install and load test packages
+;; with a sample test implementation, resulting in modification of
+;; numerous global variables, for example `load-history', `load-path',
+;; `features', etc. When run with `ert' it may contaminate current
+;; Emacs session. For this reason, tests execute their bodies in
+;; `with-package-vc-tests-installed' (which see), that takes care of
+;; cleaning up the environment.
+
+;;; Code:
+
+(require 'package-vc)
+(require 'package)
+(require 'vc-git)
+(require 'vc)
+(require 'cl-lib)
+(require 'info)
+(require 'ert-x)
+(require 'ert)
+
+(eval-and-compile
+ ;; We evaluate the definition at compile-time as well, so that
+ ;; `package-vc-test-deftest' can use the value.
+ (defvar package-vc-tests-under-test
+ '(test-package-1
+ test-package-2
+ test-package-3
+ test-package-4
+ test-package-5
+ test-package-6
+ test-package-7
+ test-package-8
+ test-package-9)))
+
+(defvar package-vc-tests-preserve-temporary nil
+ "When non-nil preserve temporary files produced by tests.
+Each test produces a new temporary directory for each package under
+test. This leads to creation of [length of
+`package-vc-tests-under-test'] times [number of tests executed]
+temporary directories for each tests run. When this variable is nil
+then delete all temporary directories as soon as they are no longer
+needed. When this variable is a symbol, then preserve temporary
+directories for the package that matches the symbol. When this variable
+is a list of symbol, then preserve temporary directories for each
+package that matches symbol in the list. When this variable is t then
+preserve all temporary directories. Tests create temporary directories
+with `make-temp-file', which see.")
+
+(defvar package-vc-tests-dir)
+(defvar package-vc-tests-packages)
+(defvar package-vc-tests-repository)
+
+;; TODO: add test for deleting packages, with asserting
+;; `package-vc-selected-packages'
+
+;; TODO: clarify `package-vc-install-all' behaviour with regards to
+;; packages installed with `package-vc' but not stored in
+;; `package-vc-selected-packages' i.e., packages from ELPAs
+
+(defun package-vc-tests-add (suffix in-file &optional lisp-dir)
+ "Create a new file from IN-FILE template updating SUFFIX in it.
+When LISP-DIR is non-nil place the NAME file under LISP-DIR."
+ (let* ((resource-dir (ert-resource-directory))
+ (suffix (if (stringp suffix) suffix (format "%s" suffix)))
+ (file (let ((file (replace-regexp-in-string
+ (rx (or "SUFFIX"
+ (: "-v" digit (* "." (1+ digit)))
+ (: ".in" string-end)) )
+ (lambda (mat)
+ (if (string=3D mat "SUFFIX") suffix ""))
+ in-file)))
+ (file-name-concat lisp-dir file))))
+ (unless (zerop (call-process
+ "sed" (expand-file-name in-file resource-dir)
+ `(:file ,file) nil
+ (format "s/SUFFIX/%s/g" suffix)))
+ (error "Failed to invoke sed on %s" in-file))
+ (vc-git-command nil 0 nil "add" ".")))
+
+(defun package-vc-tests-create-repository (suffix &optional lisp-dir)
+ "Create a test package repository with SUFFIX.
+If LISP-DIR is non-nil place sources of the package in LISP-DIR."
+ (let* ((name (format "test-package-%s" suffix))
+ (repo-dir (expand-file-name (file-name-concat "repo" name)
+ package-vc-tests-dir)))
+ (make-directory (expand-file-name (or lisp-dir ".") repo-dir) t)
+ (let ((default-directory repo-dir))
+ (vc-git-command nil 0 nil "init" "-b" "master")
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-lib-v0.1.el.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-v0.1.el.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX.texi.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-inc.texi.in" lisp-dir)
+ ;; Place Makefile in root of the repository
+ (package-vc-tests-add
+ suffix "Makefile.in" nil)
+ (vc-git-command nil 0 nil "commit" "-m" "First commit")
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-lib-v0.2.el.in" lisp-dir)
+ (package-vc-tests-add
+ suffix "test-package-SUFFIX-v0.2.el.in" lisp-dir)
+ (vc-git-command nil 0 nil "commit" "-m" "Second commit")
+ (list repo-dir (vc-git-working-revision nil)))))
+
+(defun package-vc-tests-package-desc (pkg &optional installed)
+ "Return descriptor of PKG.
+When INSTALLED is non-nil the descriptor comes from `package-alist'.
+Otherwise the descriptor comes from `package-archive-contents'. This
+is to mimic `package-vc--read-package-desc'."
+ (cadr (assq pkg (if installed package-alist package-archive-contents))))
+
+(defun package-vc-tests-package-spec (pkg)
+ "Return pkg-spec for PKG from `package-vc-selected-packages'."
+ (cdr (assoc pkg package-vc-selected-packages #'string=3D)))
+
+(defun package-vc-tests-package-lisp-dir (pkg)
+ "Return a Lisp directory of PKG."
+ (and-let* ((checkout-dir (car (alist-get pkg package-vc-tests-packages))=
))
+ (if-let* ((lisp-dir (cadr (alist-get pkg package-vc-tests-packages))))
+ (expand-file-name lisp-dir checkout-dir)
+ checkout-dir)))
+
+(defun package-vc-tests-package-main-file (pkg)
+ "Return a main file of PKG."
+ (file-name-concat (package-vc-tests-package-lisp-dir pkg)
+ (format "%s.el" pkg)))
+
+;; When `pakckage-vc-upgrade', `package-vc-rebuild', or other a
+;; package-vc function re-compiles a package's source the package also
+;; reloaded [1] to ensure that the most recent version of compiled code
+;; is available to Emacs. Some tests add markers in `load-history'
+;; before executing such functions. And then follow up tests use these
+;; markers to assert that expected package files are in correct places
+;; in the `load-history'.
+;;
+;; [1] Only when a file has been previously loaded.
+
+(defun package-vc-tests-load-history-marker (name)
+ "Return a `load-history' marker with NAME."
+ (file-truename
+ (expand-file-name (symbol-name name) package-vc-tests-dir)))
+
+(defun package-vc-tests-load-history-pattern (pkg type)
+ "Return a regexp pattern for PKG's file of TYPE."
+ (pcase type
+ (:autoloads
+ (rx (literal (file-truename
+ (file-name-concat
+ package-user-dir
+ (symbol-name pkg)
+ (format "%s-autoloads.el" pkg))))
+ eos))
+ (:main
+ (rx (literal (file-truename
+ (package-vc-tests-package-main-file pkg)))
+ eos))
+ (:main-compiled
+ (rx (literal (file-truename
+ (package-vc-tests-package-main-file pkg)))
+ "c" eos))
+ (:marker
+ (regexp-quote (file-truename
+ (package-vc-tests-load-history-marker pkg))))))
+
+(defun package-vc-tests-load-history-interesting-entries ()
+ "Return interesting entries in `load-history'.
+An entry in `load-history' is interesting when it starts with
+`package-vc-tests-dir'."
+ (let ((interesting-entry
+ (rx bos (literal (file-truename package-vc-tests-dir)))))
+ (mapcan
+ (lambda (ent)
+ (and (consp ent)
+ (stringp (car ent))
+ (let ((file-name (file-truename (car ent))))
+ (and (string-match interesting-entry file-name)
+ (list file-name)))))
+ load-history)))
+
+(defun package-vc-tests-load-history-position (pkg type)
+ "Return a PKG's file of TYPE position in `load-history'.
+If TYPE is `:autoloads' return a position of a PKG autoloads file.
+Otherwise, if TYPE is `:main' return a position of PKG main file (not
+compiled). Otherwise, if TYPE is `:main-compiled' return a position of
+PKG compiled main file. Otherwise, if TYPE is `:marker' return a
+position of a marker PKG."
+ (let ((pkg-file (package-vc-tests-load-history-pattern pkg type)))
+ (cl-position-if
+ (lambda (file) (string-match pkg-file file))
+ (package-vc-tests-load-history-interesting-entries))))
+
+(defun package-vc-tests-explain-load-history-position (pkg type)
+ "Explain `package-vc-tests-load-history' failed for PKG of TYPE."
+ (let ((pattern
+ (concat "..."
+ (substring
+ (package-vc-tests-load-history-pattern pkg type)
+ (length (regexp-quote
+ (file-truename package-vc-tests-dir))))))
+ (reason
+ (if-let* ((pos (package-vc-tests-load-history-position
+ pkg type)))
+ `(found in load-history at pos ,pos)
+ '(not found in load-history)))
+ (entries
+ (cl-loop
+ with len =3D (length (file-truename package-vc-tests-dir))
+ for hist in (package-vc-tests-load-history-interesting-entries)
+ collect (concat "..." (substring hist len)))))
+ (append (list 'pattern pattern) reason (list entries))))
+
+(put #'package-vc-tests-load-history-position
+ 'ert-explainer
+ #'package-vc-tests-explain-load-history-position)
+
+(defun package-vc-tests-elc-files (pkg)
+ "Return elc files for PKG."
+ (when-let* ((dir (package-vc-tests-package-lisp-dir pkg)))
+ (directory-files dir nil (rx ".elc" string-end))))
+
+(defun package-vc-tests-assert-elc (pkg)
+ "Assert that PKG has correct .elc files in."
+ (let* ((dir (package-vc-tests-package-lisp-dir pkg))
+ (elc-files (should (package-vc-tests-elc-files pkg)))
+ (autoloads-rx (rx (literal (format "%s-autoloads.elc" pkg))
+ string-end)))
+ (should-not (cl-find-if (lambda (elc)
+ (string-match autoloads-rx elc))
+ elc-files))
+ (dolist (elc-file elc-files)
+ (delete-file (expand-file-name elc-file dir)))))
+
+(defun package-vc-tests-assert-package-alist (pkg version)
+ "Assert that PKG entry in `package-alist' have correct VERSION and dir."
+ (let ((pkg-desc (should (cadr (assq pkg package-alist)))))
+ (should (equal (file-name-as-directory
+ (expand-file-name (format "%s" pkg)
+ package-user-dir))
+ (file-name-as-directory
+ (package-desc-dir pkg-desc))))
+ (should (equal (list pkg version)
+ (list pkg (package-desc-version pkg-desc))))))
+
+(defun package-vc-tests-reset-head^ (pkg)
+ "Reset to HEAD^ checkout for PKG."
+ (let ((default-directory (cadr (assoc pkg package-vc-tests-packages))))
+ (vc-git-command nil 0 nil "reset" "--hard" "HEAD^")))
+
+(defun package-vc-tests-package-head (pkg)
+ "Return HEAD revisions of a PKG."
+ (let ((default-directory (cadr (assoc pkg package-vc-tests-packages))))
+ (vc-git-working-revision nil)))
+
+(defun package-vc-tests-make-spec (pkg)
+ "Return a pkg-spec for PKG."
+ (let ((lisp-dir
+ (cadr (alist-get pkg package-vc-tests-packages))))
+ (append
+ (list pkg
+ :url (car package-vc-tests-repository)
+ :doc (let ((doc-file (format "%s.texi" pkg)))
+ (if lisp-dir
+ (file-name-concat lisp-dir doc-file)
+ doc-file))
+ :make (format "build-%s" pkg)
+ :shell-command (format "touch %s.cmd-build" pkg))
+ (and lisp-dir
+ (not (member lisp-dir '("lisp" "src")))
+ (list :lisp-dir lisp-dir)))))
+
+(defmacro with-package-vc-tests-installed (pkg &rest body)
+ "Eval BODY with PKG installed in a test environment."
+ (declare (indent 1) (debug t))
+ ;; Create a test package sources repository, based on skeleton files
+ ;; in directory package-vc-resources. Before executing body make sure
+ ;; that:
+ ;;
+ ;; - `package' has been initialised, and there are no
+ ;; `package-archives' defined
+ `(let* ((package-archives (unless package--initialized
+ (let (package-archives)
+ (package-initialize)
+ (package-vc--archives-initialize))
+ nil))
+ ;; - create a temporary location for packages and test files
+ (package-vc-tests-dir
+ (expand-file-name
+ (make-temp-file "package-vc-tests-"
+ t
+ (format-time-string "-%Y%m%d.%H%M%S.%3N"))))
+ ;; - packages are installed into a test directory
+ (package-user-dir (expand-file-name "elpa"
+ package-vc-tests-dir))
+ ;; - define test packages, their checkout locations, lisp
+ ;; directories, and install functions
+ (package-vc-tests-packages
+ `(;; checkout and install with `package-vc-install' (on
+ ;; ELPA)
+ (test-package-1
+ ,(expand-file-name "test-package-1" package-user-dir)
+ nil
+ package-vc-tests-install-from-elpa)
+ ;; checkout and install with `package-vc-install' (not on
+ ;; ELPA)
+ (test-package-2
+ ,(expand-file-name "test-package-2" package-user-dir)
+ nil
+ package-vc-tests-install-from-spec)
+ ;; checkout with `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-3
+ ,(expand-file-name "test-package-3" package-vc-tests-dir)
+ nil
+ pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
+ ;; checkout with git and install with
+ ;; `package-vc-install-from-checkout'
+ (test-package-4
+ ,(expand-file-name "test-package-4" package-vc-tests-dir)
+ nil
+ package-vc-tests-checkout-with-git-install-from-checkout)
+ ;; sources in "lisp" sub directory, checkout and install
+ ;; with `package-vc-install' (not on ELPA)
+ (test-package-5
+ ,(expand-file-name "test-package-5" package-user-dir)
+ "lisp"
+ package-vc-tests-install-from-spec)
+ ;; sources in "lisp" sub directory, checkout with git and
+ ;; install with `package-vc-install-from-checkout'
+ (test-package-6
+ ,(expand-file-name "test-package-6" package-vc-tests-dir)
+ "lisp"
+ package-vc-tests-checkout-with-git-install-from-checkout)
+
+ ;; sources in "src" sub directory, checkout and install
+ ;; with `package-vc-install' (on ELPA)
+ (test-package-7
+ ,(expand-file-name "test-package-7" package-user-dir)
+ "src"
+ package-vc-tests-install-from-elpa)
+ ;; sources in "src" sub directory, checkout with
+ ;; `package-vc-checktout' and install with
+ ;; `package-vc-install-from-checkout' (on ELPA)
+ (test-package-8
+ ,(expand-file-name "test-package-8" package-vc-tests-dir)
+ nil
+ pakcage-vc-tests-checkout-from-elpa-install-from-checkout)
+ ;; sources in "custom-dir" sub directory, checkout and
+ ;; install with `package-vc-install' (on ELPA)
+ (test-package-9
+ ,(expand-file-name "test-package-9" package-user-dir)
+ "custom-dir"
+ package-vc-tests-install-from-elpa)))
+ ;; - create a test package bundle
+ (package-vc-tests-repository
+ (let* ((pkg-name (symbol-name ,pkg))
+ (suffix (and (string-match
+ (rx ?- (group (1+ (not ?-))) eos)
+ pkg-name)
+ (match-string 1 pkg-name))))
+ (package-vc-tests-create-repository
+ suffix (cadr (alist-get ,pkg package-vc-tests-packages)))))
+ ;; - find all packages that are present in a test ELPA
+ (package-vc-tests-elpa-packages
+ (cl-loop
+ for (name _ _ fn) in package-vc-tests-packages
+ when (memq
+ fn
+ '(package-vc-tests-install-from-elpa
+ pakcage-vc-tests-checkout-from-elpa-install-from-check=
out))
+ collect name))
+ ;; - make test packages recognisable by `package' and
+ ;; `package-vc' internals:
+ (package-archive-contents
+ (mapcar
+ (lambda (pkg)
+ (list pkg
+ (package-desc-create
+ :name pkg
+ :version '(0 2)
+ :reqs '((emacs (30.1)))
+ :kind 'tar
+ :archive "test-elpa"
+ :extras
+ (list
+ '(:maintainer
+ ("Test Maintainer"
+ . "test-maintainer@HIDDEN"))
+ (cons :url (car package-vc-tests-repository))
+ (cons :commit (cadr package-vc-tests-repository))
+ (cons :revdesc (substring
+ (cadr package-vc-tests-repository)
+ 0 12))))))
+ package-vc-tests-elpa-packages))
+ ;; Branch needs to be specified in a pkg-spec, as cloning from
+ ;; a bundle won't checkout a default branch.
+ (package-vc--archive-spec-alists
+ (list
+ (cons 'test-elpa
+ (mapcar #'package-vc-tests-make-spec
+ package-vc-tests-elpa-packages))))
+ (package-vc--archive-data-alist
+ '((test-elpa :version 1 :default-vc Git)))
+ ;; - `vc-guess-backend-url' is recognising bundles as `Git'
+ ;; repositories:
+ (vc-clone-heuristic-alist
+ `((,(rx "test-package-" (1+ digit) ".bundle" eos)
+ . Git)
+ ,@vc-clone-heuristic-alist))
+ ;; - ensure that `package-alist' and
+ ;; `package-vc-selected-packages' are empty
+ package-alist
+ package-vc-selected-packages
+ ;; - don't save any customization
+ (user-init-file nil)
+ (custom-file nil)
+ ;; - don't register projects
+ (package-vc-register-as-project nil)
+ ;; - FIXME: something sets `default-directory' to last
+ ;; checkout directory after `package-vc-checkout', which
+ ;; causes problems when this macro deletes the temporary
+ ;; directory after body execution.
+ (default-directory package-vc-tests-dir))
+ (unwind-protect
+ (progn
+ (funcall (or (caddr (alist-get ,pkg package-vc-tests-packages))
+ (lambda (pkg)
+ (ert-fail
+ (format
+ "Cannot find %s in package-vc-tests-packages"
+ pkg))))
+ ,pkg)
+ ,@body)
+ ;; Unbind package defined symbols, and remove package defined
+ ;; features and entries from `load-path',`load-history', and
+ ;; `Info-directory-list'.
+ (let ((pattern (rx string-start (literal package-vc-tests-dir))))
+ (dolist (entry load-history)
+ (when-let* ((file (car-safe entry))
+ ((stringp file))
+ ((string-match pattern file)))
+ (dolist (elt (cdr entry))
+ (pcase elt
+ (`(defun . ,fun)
+ (fmakunbound fun))
+ (`(provide . ,feat)
+ (setq features (cl-remove feat features)))
+ ((and (pred symbolp)
+ (pred boundp))
+ (makunbound elt))))))
+ (setq load-path (cl-remove-if
+ (lambda (path)
+ (and (stringp path)
+ (string-match pattern path)))
+ load-path)
+ load-history (cl-remove-if
+ (lambda (entry)
+ (and-let* ((path (car-safe entry))
+ (_ (stringp path)))
+ (string-match pattern path)))
+ load-history)
+ Info-directory-list (cl-remove-if
+ (lambda (dir)
+ (and (stringp dir)
+ (string-match pattern dir)))
+ Info-directory-list)))
+ (if (or (memq package-vc-tests-preserve-temporary '(t ,pkg))
+ (and (listp package-vc-tests-preserve-temporary)
+ (memq ,pkg package-vc-tests-preserve-temporary)))
+ (message "package-vc-tests: preserving temporary directory %s"
+ package-vc-tests-dir)
+ (delete-directory package-vc-tests-dir t)))))
+
+(defun package-vc-tests-install-from-elpa (pkg)
+ "Install PKG with `package-vc-install'."
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t (package-vc-install pkg)))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should-not (package-vc-tests-package-spec pkg)))
+
+(defun package-vc-tests-install-from-spec (pkg)
+ "Install PKG with `package-vc-install' (not on ELPA)."
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t (package-vc-install (package-vc-tests-make-spec pkg))))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (car package-vc-tests-repository)
+ (plist-get (package-vc-tests-package-spec pkg)
+ :url))))
+
+(defun pakcage-vc-tests-checkout-from-elpa-install-from-checkout (pkg)
+ "Install PKG with `package-vc-install-from-checkout'.
+Make checkout with `package-vc-checkout'."
+ (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
+ (let* ((uniquify-buffer-name-style nil)
+ (buffer (package-vc-checkout (package-vc-tests-package-desc
+ pkg)
+ checkout-dir)))
+ (should (bufferp buffer))
+ (should (string-prefix-p (symbol-name pkg) (buffer-name buffer))))
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t
+ (package-vc-install-from-checkout checkout-dir)))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (concat package-vc--url-scheme checkout-dir)
+ (plist-get (package-vc-tests-package-spec pkg)
+ :url)))))
+
+(defun package-vc-tests-checkout-with-git-install-from-checkout (pkg)
+ "Install PKG with `package-vc-install-from-checkout'.
+Make checkout with git(1)."
+ (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
+ (vc-git-clone (car package-vc-tests-repository)
+ checkout-dir
+ "master")
+ (push (list (package-vc-tests-load-history-marker 'install-begin))
+ load-history)
+ (should (eq t
+ (package-vc-install-from-checkout checkout-dir
+ (symbol-name pkg))))
+ (push (list (package-vc-tests-load-history-marker 'install-end))
+ load-history)
+ (should (equal (concat package-vc--url-scheme checkout-dir)
+ (plist-get (package-vc-tests-package-spec pkg)
+ :url)))))
+
+;; Some of VC commands used by package-vc execute VC operations
+;; asynchronously. When such an operation executes as a part of test
+;; body, the test needs to wait for the operation to finish before
+;; asserting post conditions. The maximum wait time should be at least
+;; a single order of magnitude higher than what the operation usually
+;; takes. This decreases probability of false positives (for example
+;; when execution takes place on a busy machine). On the other hand the
+;; value cannot be too large to ensure reasonable execution time in case
+;; of a legitimate failure.
+
+(defmacro package-vc-tests-package-vc-async-wait (seconds count flags &res=
t body)
+ "Wait up to SECONDS for COUNT async vc commands with FLAGS called by BOD=
Y.
+Return nil on timeout or the value of last form in BODY."
+ (declare (indent 3))
+ (let ((count-sym (make-symbol "count"))
+ (post-vc-command-sym (make-symbol "post-vc-command")))
+ `(let* ((,count-sym ,count)
+ (,post-vc-command-sym
+ (lambda (command _ command-flags)
+ ;; A crude filter for vc commands
+ (when (and (equal command vc-git-program)
+ (cl-every (lambda (flag)
+ (member flag command-flags))
+ ,flags))
+ (decf ,count-sym)))))
+ (add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
+ (unwind-protect
+ (with-timeout (,seconds nil)
+ (prog1 (progn ,@body)
+ (while (/=3D ,count-sym 0)
+ (accept-process-output nil 0.01))))
+ (remove-hook 'vc-post-command-functions ,post-vc-command-sym)))))
+
+(defmacro package-vc-test-deftest (name args &rest body)
+ "For each `package-vc-tests-under-test' define a test with NAME.
+Execute BODY as a test body with a package under test installed. Bind
+car of ARGS (a symbol) to name of the package. Bind cdr of ARGS
+before installing the package."
+ (declare (debug (&define [&name "test@" symbolp]
+ sexp
+ def-body))
+ (indent 2))
+ (when (length< args 1)
+ (error "`package-vc' tests have to take at least one argument"))
+ (unless (symbolp (car-safe args))
+ (error "`package-vc' tests first argument has to be a symbol"))
+ (let ((file (or (macroexp-file-name) buffer-file-name))
+ (tests '()))
+ (dolist (pkg package-vc-tests-under-test)
+ (let ((name (intern (format "package-vc-tests-%s/%s" name pkg))))
+ (push
+ `(cl-macrolet ((skip-when (form) `(ert--skip-when ,form))
+ (skip-unless (form) `(ert--skip-unless ,form)))
+ (ert-set-test
+ ',name
+ (make-ert-test
+ :name ',name
+ :tags '(package-vc)
+ :file-name ,file
+ :body
+ (lambda ()
+ (let ((,(car args) ',pkg)
+ ,@(cdr args))
+ (with-package-vc-tests-installed ,(car args)
+ ,@body))
+ nil))))
+ tests)))
+ `(progn ,@tests)))
+
+(package-vc-test-deftest install-post-conditions (pkg)
+ (let ((install-begin
+ (should (package-vc-tests-load-history-position
+ 'install-begin :marker)))
+ (install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (< install-end autoloads-pos install-begin))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled)))
+ (should (equal (package-vc--main-file
+ (package-vc-tests-package-desc pkg t))
+ (package-vc-tests-package-main-file pkg)))
+ (should (equal (package-vc-commit
+ (package-vc-tests-package-desc pkg t))
+ (cadr package-vc-tests-repository)))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest require (pkg)
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should (require pkg))
+ (should (fboundp (intern (format "%s-func" pkg))))
+ (should-not (autoloadp
+ (symbol-function (intern (format "%s-func" pkg)))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (let ((install-end
+ (should (package-vc-tests-load-history-position
+ 'install-end :marker)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (< main-compiled-pos install-end))))
+
+(package-vc-test-deftest upgrade (pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head^ pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade (package-vc-tests-package-desc pkg t))
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-end))
+ load-history)
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (< upgrade-end autoloads-pos upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest upgrade-after-require (pkg)
+ (should (require pkg))
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head^ pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade (package-vc-tests-package-desc pkg t))
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-end))
+ load-history)
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (< upgrade-end autoloads-pos upgrade-begin))
+ (should (< upgrade-end main-pos upgrade-begin))
+ (should (< upgrade-end main-compiled-pos upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest upgrade-all (pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head^ pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-end))
+ load-history)
+ (should-not (package-vc-tests-load-history-position
+ pkg :main))
+ (should-not (package-vc-tests-load-history-position
+ pkg :main-compiled))
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads))))
+ (should (< upgrade-end autoloads-pos upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest upgrade-all-after-require (pkg)
+ (should (require pkg))
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-tests-reset-head^ pkg)
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-begin))
+ load-history)
+ (should
+ (package-vc-tests-package-vc-async-wait 5 1 '("pull")
+ (package-vc-upgrade-all)
+ t))
+ (push (list (package-vc-tests-load-history-marker
+ 'upgrade-all-end))
+ load-history)
+ (let ((upgrade-begin
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-begin :marker)))
+ (upgrade-end
+ (should (package-vc-tests-load-history-position
+ 'upgrade-all-end :marker)))
+ (autoloads-pos
+ (should (package-vc-tests-load-history-position
+ pkg :autoloads)))
+ (main-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main)))
+ (main-compiled-pos
+ (should (package-vc-tests-load-history-position
+ pkg :main-compiled))))
+ (should (< upgrade-end autoloads-pos upgrade-begin))
+ (should (< upgrade-end main-pos upgrade-begin))
+ (should (< upgrade-end main-compiled-pos upgrade-begin)))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
+ (symbol-function func)))
+ (should (equal "New macro test"
+ (funcall func "test"))))
+ (should-not (fboundp (intern (format "%s-old-func" pkg))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 2)))
+
+(package-vc-test-deftest rebuild (pkg)
+ (package-vc-tests-reset-head^ pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (let ((old-func (intern (format "%s-old-func" pkg))))
+ (should (fboundp old-func))
+ (should (autoloadp
+ (symbol-function old-func))))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should (autoloadp
+ (symbol-function func)))
+ (should (equal "Old macro test"
+ (funcall func "test"))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 1)))
+
+(package-vc-test-deftest rebuild-after-require (pkg)
+ (should (require pkg))
+ (package-vc-tests-reset-head^ pkg)
+ (let ((head (package-vc-tests-package-head pkg)))
+ (package-vc-rebuild
+ (package-vc-tests-package-desc pkg t))
+ (let ((old-func (intern (format "%s-old-func" pkg))))
+ (should (fboundp old-func))
+ (should-not (autoloadp
+ (symbol-function old-func))))
+ (let ((func (intern (format "%s-func" pkg))))
+ (should (fboundp func))
+ (should-not (autoloadp
+ (symbol-function func)))
+ (should (equal "Old macro test"
+ (funcall func "test"))))
+ (should (equal head
+ (package-vc-tests-package-head pkg))))
+ (package-vc-tests-assert-elc pkg)
+ (package-vc-tests-assert-package-alist pkg '(0 1)))
+
+(package-vc-test-deftest prepare-patch (pkg)
+ ;; Ensure `vc-prepare-patch' respects subject from function argument
+ (let ((vc-prepare-patches-separately nil))
+ (package-vc-prepare-patch (package-vc-tests-package-desc pkg t)
+ "test-subject"
+ (cdr package-vc-tests-repository))
+ (let ((message-buffer
+ (should (get-buffer "*unsent mail to Test Maintainer*"))))
+ (should (bufferp message-buffer))
+ (switch-to-buffer message-buffer)
+ (goto-char (point-min))
+ (should
+ (string-match
+ (rx
+ "To: Test Maintainer <test-maintainer@HIDDEN>")
+ (buffer-substring (point) (pos-eol))))
+ (forward-line)
+ (should
+ (string-match
+ (rx "Subject: test-subject")
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer message-buffer)))))
+
+(package-vc-test-deftest log-incoming (pkg)
+ (package-vc-tests-reset-head^ pkg)
+ (should
+ (package-vc-tests-package-vc-async-wait
+ 5 1 '("log" "--decorate")
+ (package-vc-log-incoming (package-vc-tests-package-desc pkg t))
+ t))
+ (let ((incoming-buffer (get-buffer "*vc-incoming*"))
+ (pattern (rx (literal
+ (substring
+ (cadr package-vc-tests-repository)
+ 0 7))
+ (one-or-more any)
+ "Second commit"
+ line-end)))
+ (should (bufferp incoming-buffer))
+ (switch-to-buffer incoming-buffer)
+ (goto-char (point-min))
+ (should
+ (string-match
+ pattern
+ (buffer-substring (point) (pos-eol))))
+ (let (kill-buffer-query-functions)
+ (kill-buffer incoming-buffer))))
+
+(package-vc-test-deftest pkg-spec-doc-make-shell-command
+ (pkg (package-vc-allow-build-commands t))
+ ;; Only `package-vc-install' runs make and shell command
+ (skip-unless (memq (caddr (alist-get pkg package-vc-tests-packages))
+ '(package-vc-tests-install-from-elpa
+ package-vc-tests-install-from-spec)))
+ (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages))))
+ (should (file-exists-p
+ (expand-file-name
+ (format "%s.make-build" pkg)
+ checkout-dir)))
+ (should (file-exists-p
+ (expand-file-name
+ (format "%s.cmd-build" pkg)
+ checkout-dir))))
+ (should (cl-member-if
+ (lambda (dir)
+ (and (stringp dir)
+ (string-prefix-p package-vc-tests-dir dir)))
+ Info-directory-list))
+ (let ((info-file
+ (expand-file-name (format "%s.info" pkg)
+ (car (alist-get
+ pkg package-vc-tests-packages)))))
+ (should (file-exists-p info-file))
+ (ert-with-test-buffer
+ (:name (format "*package-vc-tests: %s.info*" pkg))
+ (insert-file-contents info-file)
+ (goto-char (point-min))
+ (should (re-search-forward
+ (format "First chapter for %s" pkg)))
+ (should (re-search-forward
+ (format "Second chapter for %s" pkg))))))
+
+(provide 'package-vc-tests)
+
+;;; package-vc-tests.el ends here
--=20
2.52.0
--=-=-=
Content-Type: text/plain
> A couple of things I stumbled upon
> that I did not find in your patch:
>
> - In `pakcage-vc-tests-checkout-from-elpa-install-from-checkout' you are
> checking that the prefix of a buffer name matches the symbol-name of
> pkg. This breaks if the user (as I do) customized
> `uniquify-buffer-name-style'. If my analysis is correct, I would
> recommend doing something like
>
> (should (buffer-file-name buffer))
> (should (string-prefix-p
> (symbol-name pkg)
> (file-name-base (buffer-file-name buffer))))
I didn't realised this functionality can manifest here. Great catch!
The solution above seems to be doing what expected. However, the value
of `uniquify-buffer-name-style' can be any arbitrary function. And
rather then playing a whack-a-mole I think that it's better if test has
a full control. For that reason I decided to just bind the variable to
nil, for the `package-vc-checkout' call.
> - I would recommend binding `package-vc-register-as-project' to nil in
> `with-package-vc-tests-installed'. This should accelerate the tests
> because the checkouts are not being registered and remembered by
> project.el.
This is another great find. I added it. Do you think it would be worth
having a single test that asserts that a package-vc installation
registers as a project?
> - As `with-package-vc-tests-installed' is only used once if we use
> `package-vc-test-deftest', then it might make sense to transform it
> into a function that takes a lambda, to avoid the complications of
> macro-semantics. (Haven't done this yet myself)
I agree this should be possible. I have implemented is a macro, because
this seems to be a pattern for the `with-' functions. Unfortunately, I
don't think I will have time to address it in the next couple days. If
I get around to this before I hear from you, I will try to convert.
> - I think we should play it safe and set `custom-file' to nil when
> executing tests.
+1
> [...]
>
>>>> +(defmacro package-vc-tests-package-vc-async-wait (seconds count flags &rest body)
>>>> + "Wait up to SECONDS for COUNT async vc commands with FLAGS called by BODY.
>>>> +Return nil on timeout or the value of last form in BODY."
>>>> + (declare (indent 3))
>>>> + (let ((count-sym (make-symbol "count"))
>>>> + (post-vc-command-sym (make-symbol "post-vc-command")))
>>>> + `(letrec ((,count-sym ,count)
>>>> + (,post-vc-command-sym
>>>> + (lambda (command _ command-flags)
>>>> + ;; A crude filter for vc commands
>>>> + (when (and (equal command "git")
>>>> + (cl-every (lambda (flag)
>>>> + (member flag command-flags))
>>>> + ,flags))
>>>> + (decf ,count-sym)))))
>>>> + (add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
>>>> + (unwind-protect
>>>> + (with-timeout (,seconds nil)
>>>> + (prog1
>>>> + (progn ,@body)
>>>> + (while (/= ,count-sym 0)
>>>> + (accept-process-output nil 0.01))))
>>>
>>> And it wouldn't be bad to have a comment here on the topic of our
>>> discussion w.r.t. timeouts in tests.
>>
>> I don't really know which points of the discussion you believe are worth
>> mentioning. Could you propose something?
>
> I was referencing this exchange:
>
> > Having tests fail with hard-coded timeout values seems wrong as they can
> > depend on the specific decide and its available resources. Couldn't we
> > use something like `ert-skip' in this case?
>
> I am afraid that skipping in case of failure is not a good option. Too
> many times I have seen failing test that skip instead of failing being
> ignored. Ultimately it's humans who are consumers of test reports and
> they often lack of necessary context to judge if test is being skipped
> for legitimate reason (like test not being valid on a particular OS or
> configuration) vs. legitimate error.
>
> The value of 5s (per operation!) is order of magnitude higher than what
> the command is expected to execute and, from my experience. I used such
> approach in automatic tests on a very, very busy machines (echo while
> typing on SSH was in order of seconds [sic!]), where tests were run
> dozens of times daily. The 5s caused the tests not to stall too much
> when something was actually broken, yet I don't remember seeing false
> positives. One alternative I can see is to hack around `vc' commands
> and force them to run synchronously under test.
>
> But if you really think it's better to skip or have a better idea,
> please let me know I will update.
Thanks for pasting the relevant quote. Added a summary to a file. Feel
free to update if you think I missed a point.
[...]
>> One of the things I've been occupied with was to bring my CI build
>> solution to be consumable by others. I think I got to a point where I
>> can start sharing it. If you're using GitHub, just push your
>> development branch and drop a workflow file somewhere (to the Emacs's
>> repository, or to a new repository with just a workflow). Then you can
>> run tests on the three oses (Ubuntu, macOS, Windows) against your
>> development branch. You can find it here:
>> https://github.com/pkryger/setup-emacs-dev. Please ask if need any
>> help.
>
> Thanks, but I dislike GitHub and CI workflows in general, so I won't
> have a use for it.
No worries. I have highlighted it as a convenience way of running tests
on three big platforms.
[...]
>> Indeed, it is. I usually apply them against some Emacs repository and
>> use difftastic to see logic changes. It makes life so much easier.
>> Another shameless plug: https://github.com/pkryger/difftastic.el.
>
> Applying the changes and just looking at the changes via regular
> diff-mode is already a big boost to readability. My inconsistent and
> incomplete wish was to have some kind of integration into message-mode
> specifically.
I don't think difftastic is capable of transforming a regular diff into
its output. IIUC it uses tree-sitter behind the scenes, and bases its
highlights in the output on changes in AST. But I find it a great tool
to verify that logic changes are as expected.
--=-=-=--
X-Loop: help-debbugs@HIDDEN
Subject: bug#79188: 31.0.50; Cannot build packages installed from VC
Resent-From: Philip Kaludercic <philipk@HIDDEN>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@HIDDEN
Resent-Date: Tue, 25 Nov 2025 20:32:38 +0000
Resent-Message-ID: <handler.79188.B79188.176410272919842 <at> debbugs.gnu.org>
Resent-Sender: help-debbugs@HIDDEN
X-GNU-PR-Message: followup 79188
X-GNU-PR-Package: emacs
X-GNU-PR-Keywords: patch
To: =?UTF-8?Q?Przemys=C5=82aw?= Kryger <pkryger@HIDDEN>
Cc: 79188 <at> debbugs.gnu.org, Michelangelo Rodriguez <michelangelo.rodriguez@HIDDEN>
Received: via spool by 79188-submit <at> debbugs.gnu.org id=B79188.176410272919842
(code B ref 79188); Tue, 25 Nov 2025 20:32:38 +0000
Received: (at 79188) by debbugs.gnu.org; 25 Nov 2025 20:32:09 +0000
Received: from localhost ([127.0.0.1]:42360 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
id 1vNzhn-00058f-Pg
for submit <at> debbugs.gnu.org; Tue, 25 Nov 2025 15:32:09 -0500
Received: from mout02.posteo.de ([185.67.36.66]:34673)
by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
(Exim 4.84_2) (envelope-from <philipk@HIDDEN>)
id 1vNdSZ-00053c-9s
for 79188 <at> debbugs.gnu.org; Mon, 24 Nov 2025 15:46:56 -0500
Received: from submission (posteo.de [185.67.36.169])
by mout02.posteo.de (Postfix) with ESMTPS id A5517240101
for <79188 <at> debbugs.gnu.org>; Mon, 24 Nov 2025 21:46:48 +0100 (CET)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.net; s=2017;
t=1764017208; bh=Dhsf77q3HA5Z0BkYt7TKMVVJ4PJaxC1DFxT2HF15dRo=;
h=From:To:Cc:Subject:OpenPGP:Date:Message-ID:MIME-Version:
Content-Type:Content-Transfer-Encoding:From;
b=Z0Jj9bKHKEvH1d9yrgoSN0XxludtH2Pvl0Racg0If5pwKQil+1hro2geSgRhSvaq7
HAgZsWGS5hM2TqY5yuFQ22JNlENrmLDDkWn/laZu8ZIlFkheViB+ponkd0xwATfASR
QvmR03CC3sZJH03DLhAG9BhffuLtFUHmNGrXlQy+lWIq+c4yf7P/iOy1m4d6Mte4Bm
gt7a7cMMof1xHlF52cEbZNLmKrckqvAZvKanzYDoOtNneJFNsg4ETq80jGeF8Wp1Yo
QTgEM2kXXmMVENND+lPNLB4hRIL+oNT7pMjNk/CFBVjPm82/+71/56N6pqUucDKseF
B3rmjcQbJNZrQ==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 4dFdCr04NSz6txh;
Mon, 24 Nov 2025 21:46:47 +0100 (CET)
From: Philip Kaludercic <philipk@HIDDEN>
In-Reply-To: <m2ecpnpcez.fsf@HIDDEN>
References: <m2ectn9xif.fsf@HIDDEN>
<m24iqzmqh6.fsf@HIDDEN> <m28qgbqsx0.fsf_-_@HIDDEN>
<m2tsyzjek4.fsf@HIDDEN> <875xbcbg0f.fsf@HIDDEN>
<m2bjl0vidc.fsf@HIDDEN> <874iqkiufc.fsf@HIDDEN>
<m2ecpnpcez.fsf@HIDDEN>
OpenPGP: id=7126E1DE2F0CE35C770BED01F2C3CC513DB89F66;
url="https://keys.openpgp.org/vks/v1/by-fingerprint/7126E1DE2F0CE35C770BED01F2C3CC513DB89F66";
preference=signencrypt
Date: Mon, 24 Nov 2025 20:46:48 +0000
Message-ID: <87cy57kvk8.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>,
<mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)
(BTW. Michelangelo: If you don't want to be dragged along in the CCs,
just say so :))
Przemys=C5=82aw Kryger <pkryger@HIDDEN> writes:
> Philip Kaludercic <philipk@HIDDEN> writes:
>
>> I have applied the patch containing the tests locally and made a few
>> changes that I haven't tested extensively yet: Can you take a look if
>> you find anything to object to:
>>
>> diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.=
el
>> index 477df96416b..37eadfd4b53 100644
>> --- a/test/lisp/package-vc-tests.el
>> +++ b/test/lisp/package-vc-tests.el
>
> [...]
>
> I have applied your patch on top of mine. I had a similar idea in mind,
> but I don't think I have mentioned it earlier, nor have I ever got around
> to actually implement that. Thank you for doing it!
>
> While trying to run it I found things that needed fixing. Some of them
> were typical refactoring goofs. But I also extended macro a bit to
> support `skip-when`/`skip-unless'=20
Do we actually need skip-when/unless. I did not copy the code over from
ert.el, because it seemed unnecessary? I guess there is no harm in it
now, just curious.
> and extra bindings for installing a
> package. I have also added a fix for Windows execution - long story
> short: I have not found a better solution than using `file-truename' for
> `load-history' entries. On macOS adds extra /private, while Windows
> expands the ~1.
>
> Please find updated patch below.
You have found a number of issues that I ran into after submitting the
patch as well. I thought about sending you a message but then fell
asleep yesterday instead, so sorry about that. But I guess we are on
the same page on a number of issues. A couple of things I stumbled upon
that I did not find in your patch:
- In `pakcage-vc-tests-checkout-from-elpa-install-from-checkout' you are
checking that the prefix of a buffer name matches the symbol-name of
pkg. This breaks if the user (as I do) customized
`uniquify-buffer-name-style'. If my analysis is correct, I would
recommend doing something like
(should (buffer-file-name buffer))
(should (string-prefix-p
(symbol-name pkg)
(file-name-base (buffer-file-name buffer))))
- I would recommend binding `package-vc-register-as-project' to nil in
`with-package-vc-tests-installed'. This should accelerate the tests
because the checkouts are not being registered and remembered by
project.el.
- As `with-package-vc-tests-installed' is only used once if we use
`package-vc-test-deftest', then it might make sense to transform it
into a function that takes a lambda, to avoid the complications of
macro-semantics. (Haven't done this yet myself)
- I think we should play it safe and set `custom-file' to nil when
executing tests.
[...]
>>> +(defmacro package-vc-tests-package-vc-async-wait (seconds count flags =
&rest body)
>>> + "Wait up to SECONDS for COUNT async vc commands with FLAGS called by=
BODY.
>>> +Return nil on timeout or the value of last form in BODY."
>>> + (declare (indent 3))
>>> + (let ((count-sym (make-symbol "count"))
>>> + (post-vc-command-sym (make-symbol "post-vc-command")))
>>> + `(letrec ((,count-sym ,count)
>>> + (,post-vc-command-sym
>>> + (lambda (command _ command-flags)
>>> + ;; A crude filter for vc commands
>>> + (when (and (equal command "git")
>>> + (cl-every (lambda (flag)
>>> + (member flag command-flags))
>>> + ,flags))
>>> + (decf ,count-sym)))))
>>> + (add-hook 'vc-post-command-functions ,post-vc-command-sym 100)
>>> + (unwind-protect
>>> + (with-timeout (,seconds nil)
>>> + (prog1
>>> + (progn ,@body)
>>> + (while (/=3D ,count-sym 0)
>>> + (accept-process-output nil 0.01))))
>>
>> And it wouldn't be bad to have a comment here on the topic of our
>> discussion w.r.t. timeouts in tests.
>
> I don't really know which points of the discussion you believe are worth
> mentioning. Could you propose something?
I was referencing this exchange:
> Having tests fail with hard-coded timeout values seems wrong as they can
> depend on the specific decide and its available resources. Couldn't we
> use something like `ert-skip' in this case?
I am afraid that skipping in case of failure is not a good option. Too
many times I have seen failing test that skip instead of failing being
ignored. Ultimately it's humans who are consumers of test reports and
they often lack of necessary context to judge if test is being skipped
for legitimate reason (like test not being valid on a particular OS or
configuration) vs. legitimate error.
The value of 5s (per operation!) is order of magnitude higher than what
the command is expected to execute and, from my experience. I used such
approach in automatic tests on a very, very busy machines (echo while
typing on SSH was in order of seconds [sic!]), where tests were run
dozens of times daily. The 5s caused the tests not to stall too much
when something was actually broken, yet I don't remember seeing false
positives. One alternative I can see is to hack around `vc' commands
and force them to run synchronously under test.
But if you really think it's better to skip or have a better idea,
please let me know I will update.
=20=20
[...]
>>>>> I also think that using :vc-dir in :extras slot is a viable candidate.
>>>>> However, I haven't had a chance to apply it yet.
>>>>
>>>> If you want to, I can take a shot at updating the patch to use :extras
>>>> as Michelangelo proposed. That way I'll also have a better
>>>> understanding of the patch, compared to just reading it.
>>>
>>> That would be nice. I have been thinking about it, but I spent too much
>>> time on other items recently. If you have any questions about choices
>>> in tests, please ask.
>>
>> 1+
>
> One of the things I've been occupied with was to bring my CI build
> solution to be consumable by others. I think I got to a point where I
> can start sharing it. If you're using GitHub, just push your
> development branch and drop a workflow file somewhere (to the Emacs's
> repository, or to a new repository with just a workflow). Then you can
> run tests on the three oses (Ubuntu, macOS, Windows) against your
> development branch. You can find it here:
> https://github.com/pkryger/setup-emacs-dev. Please ask if need any
> help.
Thanks, but I dislike GitHub and CI workflows in general, so I won't
have a use for it.
> [...]
>>>>> @@ -934,21 +1035,22 @@ package-vc-install-from-checkout
>>>>> (package-vc--archives-initialize)
>>>>> (let* ((dir (if interactive dir (expand-file-name dir))) ;avoid do=
uble expansion
>>>>> (name (or name (file-name-base (directory-file-name dir))))
>>>>> - (pkg-dir (file-name-concat package-user-dir name))
>>>>> - (package-vc-selected-packages
>>>>> - (cons (list name :lisp-dir dir)
>>>>> - package-vc-selected-packages)))
>>>>> + (pkg-dir (file-name-concat package-user-dir name)))
>>>>> (when (file-exists-p pkg-dir)
>>>>> (if (yes-or-no-p (format "Overwrite previous checkout for pack=
age `%s'?" name))
>>>>> (package--delete-directory pkg-dir)
>>>>> (error "There already exists a checkout for %s" name)))
>>>>> (make-directory pkg-dir t)
>>>>> + ;; We store a custom package specification so that it is availab=
le
>>>>> + ;; for `package-vc--unpack-1' as well as `package-vc--checkout-d=
ir'
>>>>> + ;; can later retrieve the actual checkout.
>>>>> + (package-vc--save-selected-packages
>>>>> + name (list :url (concat package-vc--url-scheme dir)))
>>>>> (package-vc--unpack-1
>>>>> (package-desc-create
>>>>> :name (intern name)
>>>>> :dir pkg-dir
>>>>> - :kind 'vc)
>>>>> - (file-name-as-directory pkg-dir))))
>>>>> + :kind 'vc))))
>>>>
>>>> The commit message doesn't appear to explain this change.
>>>
>>> I don't think I understood this comment. This patch removes `pkg-dir'
>>> argument for `package-vc--unpack-1'. In this case I removed the value
>>> of `(file-name-as-directory pkg-dir)' from the call site, and it's
>>> documented in the patch:
>>>
>>> (package-vc-install-from-checkout): [...] Remove `pkg-dir'
>>> argument from `package-vc--unpack-1' calls.
>>
>> A misreading again, I thought that the return value of
>> `file-name-as-directory' was the return value of the function (reading
>> patches in mail quotes is difficult ^^).
>
> Indeed, it is. I usually apply them against some Emacs repository and
> use difftastic to see logic changes. It makes life so much easier.
> Another shameless plug: https://github.com/pkryger/difftastic.el.
Applying the changes and just looking at the changes via regular
diff-mode is already a big boost to readability. My inconsistent and
incomplete wish was to have some kind of integration into message-mode
specifically.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997 nCipher Corporation Ltd,
1994-97 Ian Jackson.