From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: =?utf-8?Q?Bj=C3=B6rn?= Bidar Newsgroups: gmane.emacs.devel Subject: Re: [GNU ELPA] New package: tramp-locproc Date: Wed, 01 Jan 2025 22:41:49 +0200 Message-ID: <46570.1820956141$1735764177@news.gmane.org> References: <87r05p3ztq.fsf@gmx.de> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="5008"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: emacs-devel@gnu.org To: Michael Albinus Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Wed Jan 01 21:42:48 2025 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1tT5YF-00018f-Ss for ged-emacs-devel@m.gmane-mx.org; Wed, 01 Jan 2025 21:42:48 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tT5XT-0002K2-KZ; Wed, 01 Jan 2025 15:41:59 -0500 Original-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 ) id 1tT5XQ-0002Jn-G5 for emacs-devel@gnu.org; Wed, 01 Jan 2025 15:41:56 -0500 Original-Received: from thaodan.de ([2a03:4000:4f:f15::1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tT5XN-0000sz-Sy for emacs-devel@gnu.org; Wed, 01 Jan 2025 15:41:56 -0500 Original-Received: from odin (dsl-trebng12-50dc7b-49.dhcp.inet.fi [80.220.123.49]) by thaodan.de (Postfix) with ESMTPSA id F162ED00051; Wed, 1 Jan 2025 22:41:49 +0200 (EET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=thaodan.de; s=mail; t=1735764110; bh=yaf0od+LKgmOuet7B97TVx+TjLvX0hnFRN/EuDpeXDc=; h=From:To:Cc:Subject:In-Reply-To:References:Date; b=E8tADcZ1MdmnYgmmTUT585/6JmxmTX5rFjF7To02fsw6ILX7mOh/LN2MYsoJCERf5 4bnilp5Bq6ooYQU/zKFYvjWcEvYLUuWYH3knre4XbH1/IXoHJqUWT0ZfMkhKeNBMde 6jnEjc4p7YXCZMRZe5A81/P+zxC6ioEtYtu5H+NpOzH9P2VxxAU7IN1ceCF1WojYju LN5ZT0fpKn/wrD8zq04eZwVF/7/pOgEfgVAFaAyIuRl2rKtYk9Js/u7zMRWlCB+OgM FfjPh6UUu4uhMQ6xKPDOPC4Rf+uksuXN5cgrKrj+IjXolMFL5stnQboG7gtDpzvSb0 QCGaby/JVOEdmo4mHtLEEhTkmF7sQ9hAyF/nVwpC+E7EyQJdbTv9fMmYLniBoQ/QW6 3FWWxhghnI8gR4F4CMTVwY+gdpcLiQ8UD4vWLvqAcMXTK1gtPyYXH4zArFRffxWfmN nnRaewidIW8gVeXBOSHVj29soYNlbrVq/qtZZN4faVxRbRe5IE2FPacVL1DWs3bSgY Mk96dIbRrqj1O5FVWhx5SJrMtbMFFZmQyaWBpxMZh/LzIxv1Wthd12eUJS/XzRr34b VwX7+jY2KBooIU0mS7lTzXwie6w2AaYa8glQ+NOgKdDLr2aoiXjpm4LrztlCqtnWeY bzxZxFZLmXiilWxkCtn4rWUg= In-Reply-To: <87r05p3ztq.fsf@gmx.de> (Michael Albinus's message of "Mon, 30 Dec 2024 17:22:57 +0100") Autocrypt: addr=bjorn.bidar@thaodan.de; prefer-encrypt=nopreference; keydata= mDMEZNfpPhYJKwYBBAHaRw8BAQdACBEmr+0xwIIHZfIDlZmm7sa+lHHSb0g9FZrN6qE6ru60JUJq w7ZybiBCaWRhciA8Ympvcm4uYmlkYXJAdGhhb2Rhbi5kZT6IlgQTFgoAPgIbAwULCQgHAgIiAgYV CgkICwIEFgIDAQIeBwIXgBYhBFHxdut1RzAepymoq1wbdKFlHF9oBQJk1/YmAhkBAAoJEFwbdKFl HF9oB9cBAJoIIGQKXm4cpap+Flxc/EGnYl0123lcEyzuduqvlDT0AQC3OlFKm/OiqJ8IMTrzJRZ8 phFssTkSrrFXnM2jm5PYDoiTBBMWCgA7FiEEUfF263VHMB6nKairXBt0oWUcX2gFAmTX6T4CGwMF CwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQXBt0oWUcX2hbCQEAtru7kvM8hi8zo6z9ux2h K+B5xViKuo7Z8K3IXuK5ugwA+wUfKzomzdBPhfxDsqLcEziGRxoyx0Q3ld9aermBUccHtBxCasO2 cm4gQmlkYXIgPG1lQHRoYW9kYW4uZGU+iJMEExYKADsCGwMFCwkIBwICIgIGFQoJCAsCBBYCAwEC HgcCF4AWIQRR8XbrdUcwHqcpqKtcG3ShZRxfaAUCZNf2FQAKCRBcG3ShZRxfaCzSAP4hZ7cSp0YN XYpcjHdsySh2MuBhhoPeLGXs+2kSiqBiOwD/TP8AgPEg/R+SI9GI9on7fBJJ0mp2IT8kZ2rhDOjg gA6IkwQTFgoAOxYhBFHxdut1RzAepymoq1wbdKFlH Received-SPF: pass client-ip=2a03:4000:4f:f15::1; envelope-from=bjorn.bidar@thaodan.de; helo=thaodan.de X-Spam_score_int: -14 X-Spam_score: -1.5 X-Spam_bar: - X-Spam_report: (-1.5 / 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, INVALID_MSGID=0.568, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:327550 Archived-At: Michael Albinus writes: > Hi, > > I would like to submit a new package to GNU ELPA: tramp-locproc. > Why not make this a opt-in tramp-module? I wonder if a longer name would be better as it does speak better for it self. Why not tramp-local-process? > > Beside the obvious advantage to run local processes over remote files, > there is also the disadvantage that file names are adapted in order to > reflect their local mount location. When displayed in Emacs or for the processes executed?=20 > Therefore, I would appreciate to get feedback, whether people find this > useful. > > Thanks, and best regards, Michael. > > ;;; tramp-locproc.el --- Tramp local processes for FUSE mounts -*- lexic= al-binding:t -*- > > ;; Copyright (C) 2025 Free Software Foundation, Inc. > > ;; Author: Michael Albinus > ;; Keywords: comm, processes > ;; Package: tramp-locproc > ;; Version: 0 > ;; Package-Requires: ((tramp "2.7.2")) > > ;; This file is not part of GNU Emacs. > > ;; This program 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. > > ;; This program 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 . > > ;;; Commentary: > > ;; This package adds process support for "sshfs", "rclone" and all > ;; methods defined in `tramp-gvfs-methods'. It overwrites the remote > ;; process support in "sshfs"; the other methods have no process > ;; support otherwise. > > ;; A remote process runs as a local process, using the local mount > ;; name of `default-directory'. The program name is used literally, > ;; after piping through `file-local-name'. As a consequence, programs > ;; on the local host are called, which might not exist on the remote > ;; host. > > ;; Arguments of the process, which are an absolute file name, are > ;; transformed to the respective local mount name. That is, a file > ;; name "/path/to/file" is located on the local host as > ;; "/mount_point/path/to/file". This is suppressed if user option > ;; `tramp-locproc-extend-arguments' is nil. > > ;; Although not strictly remote, Tramp archive files are also > ;; supported. That is, a local process can run over the file system > ;; which is defined by a file archive, see (info "(tramp) Archive file > ;; names") . > > ;; If this package is unloaded via `M-x unload-feature RET tramp-locproc', > ;; the original implementation of the different Tramp backends is restore= d. > > ;;; Code: > > (require 'tramp) > > (defvar tramp-locproc-unload-file-name-handler-alist nil > "Variable keeping unload information.") > > (defun tramp-locproc-massage-file-name-handler-alist (fnha) > "Adapt FNHA to the needs of `tramp-locproc'. > FNHA is the variable symbol, collecting handler functions for a Tramp bac= kend." > (let ((val (symbol-value fnha))) > ;; Prepare unloading. This must be performed prior modifying FNHA. > (unless (assq fnha tramp-locproc-unload-file-name-handler-alist) > (add-to-list > 'tramp-locproc-unload-file-name-handler-alist > `(,fnha > ,(copy-tree (assq 'exec-path val)) > ,(copy-tree (assq 'make-process val)) > ,(copy-tree (assq 'process-file val)) > ,(copy-tree (assq 'shell-command val)) > ,(copy-tree (assq 'start-file-process val)))) > (add-hook > 'tramp-locproc-unload-hook > (lambda () > (dolist > (entry > (alist-get fnha tramp-locproc-unload-file-name-handler-alist)) > (setcdr (assq (car entry) (symbol-value fnha)) (cdr entry)))))) > > ;; Replace handler functions. > (setcdr (assq 'exec-path val) #'tramp-locproc-handle-exec-path) > (setcdr (assq 'make-process val) #'tramp-locproc-handle-make-process) > (setcdr (assq 'process-file val) #'tramp-locproc-handle-process-file) > (setcdr (assq 'shell-command val) #'tramp-locproc-handle-shell-comman= d) > (setcdr (assq 'start-file-process val) #'tramp-handle-start-file-proc= ess))) You it be possible to make this a default or fallback action depending on the users intention? E.g. by using a prefix arg to invert the default. The default then being either to call the command as a local process by default or explicitly by using a prefix argument. > ;; `tramp-archive-local-file-name' is introduced in Tramp 2.7.2. > (with-eval-after-load 'tramp-archive > (when (fboundp 'tramp-archive-local-file-name) > (tramp-locproc-massage-file-name-handler-alist > 'tramp-archive-file-name-handler-alist))) > > ;; `tramp-gvfs-local-file-name' is introduced in Tramp 2.7.2. > (with-eval-after-load 'tramp-gvfs > (when (fboundp 'tramp-gvfs-local-file-name) > (tramp-locproc-massage-file-name-handler-alist > 'tramp-gvfs-file-name-handler-alist))) > > (with-eval-after-load 'tramp-rclone > (tramp-locproc-massage-file-name-handler-alist > 'tramp-rclone-file-name-handler-alist)) > > (with-eval-after-load 'tramp-sshfs > (tramp-locproc-massage-file-name-handler-alist > 'tramp-sshfs-file-name-handler-alist)) > > (declare-function tramp-archive-local-file-name 'tramp-arechive) > (declare-function tramp-fuse-local-file-name 'tramp-fuse) > (declare-function tramp-gvfs-local-file-name 'tramp-gvfs) > > (defun tramp-locproc-local-file-name (filename) > "Return local mount name of remote FILENAME." > (funcall > (cond > ((tramp-archive-file-name-p filename) #'tramp-archive-local-file-name) > ((tramp-gvfs-file-name-p filename) #'tramp-gvfs-local-file-name) > (t #'tramp-fuse-local-file-name)) > filename)) > > (defun tramp-locproc-mount-point (filename) > "Return mount point of remote FILENAME." > (tramp-locproc-local-file-name > (funcall > (cond > ((tramp-archive-file-name-p filename) > (lambda (string) > (file-name-as-directory (tramp-archive-file-name-archive string)))) > (t #'file-remote-p)) > filename))) > > (defun tramp-locproc-file-name-p (filename) > "Check if it=E2=80=99s a FILENAME handled by local processes." > ;; FIXME: Check, that it is activated for the repective backend. > (or (tramp-archive-file-name-p filename) > (tramp-gvfs-file-name-p filename) > (tramp-rclone-file-name-p filename) > (tramp-sshfs-file-name-p filename))) > > (defcustom tramp-locproc-extend-arguments t > "Whether to prefix arguments of remote processes by the mount-point." > :group 'tramp > :type 'boolean) > > (defun tramp-locproc-extend-arguments (mount-point args) > "Return ARGS, a list of local file names, prefixed with MOUNT-POINT. > This can be suppressed by setting user option > `tramp-locproc-extend-arguments' to nil." > (if tramp-locproc-extend-arguments > (mapcar > (lambda (file) > (if (and (stringp file) (file-name-absolute-p file)) > (concat mount-point file) file)) > args) > args)) > > (defun tramp-locproc-handle-exec-path () > "Like `exec-path' for Tramp files." > exec-path) > > (defun tramp-locproc-handle-make-process (&rest args) > "An alternative `make-process' implementation for Tramp files." > (let ((mount-point (tramp-locproc-mount-point default-directory)) > (default-directory (tramp-locproc-local-file-name default-directory)) > (command (plist-get args :command))) > ;; The car in COMMAND is the program name. We don't manipulate it. > (setcdr command (tramp-locproc-extend-arguments mount-point (cdr comm= and))) > (apply #'make-process (plist-put args :command command)))) > > (defun tramp-locproc-handle-process-file > (program &optional infile buffer display &rest args) > "Like `process-file' for Tramp files." > (let ((mount-point (tramp-locproc-mount-point default-directory)) > (default-directory (tramp-locproc-local-file-name default-directory))) > (apply > #'process-file (file-local-name program) infile buffer display > (tramp-locproc-extend-arguments mount-point args)))) > > (defun tramp-locproc-handle-shell-command > (command &optional output-buffer error-buffer) > "An alternative `shell-command' implementation for Tramp files." > (let ((mount-point (tramp-locproc-mount-point default-directory)) > (default-directory (tramp-locproc-local-file-name default-directory)) > (command (split-string command))) > ;; The first word in COMMAND is the program name. We don't > ;; manipulate it. > (setcdr command (tramp-locproc-extend-arguments mount-point (cdr comm= and))) > (setq command (mapconcat #'identity command " ")) > (shell-command command output-buffer error-buffer))) > > ;;; Integration of compile.el: > > (defun tramp-locproc-compilation-mode-function () > "Setup compilation buffer properly." > (when (and (compilation-buffer-p (current-buffer)) > (tramp-locproc-file-name-p default-directory)) > (trace-values (current-buffer) default-directory comint-file-name-pre= fix) > (setq default-directory (tramp-locproc-local-file-name default-direct= ory)) > (setq-local comint-file-name-prefix ""))) > > (with-eval-after-load 'compile > (trace-function-background 'compilation-setup) > (trace-function-background 'compilation-get-file-structure) > (add-hook 'compilation-mode-hook > #'tramp-locproc-compilation-mode-function) > (add-hook 'tramp-locproc-unload-hook > (lambda () > (remove-hook 'compilation-mode-hook > #'tramp-locproc-compilation-mode-function)))) > > ;;; Integration of shell.el: > > (defun tramp-locproc-shell-function (&rest args) > (let ((default-directory (tramp-locproc-local-file-name default-directo= ry))) > (apply args))) > > (with-eval-after-load 'shell > (trace-function-background 'shell) > (advice-add #'shell :around #'tramp-locproc-shell-function) > (add-hook 'tramp-locproc-unload-hook > (lambda () > (advice-remove #'shell :around #'tramp-locproc-shell-function)))) > > ;; FIXME: Do we need this? > ;;; Integration of comint.el: > > ;; (defun tramp-locproc-comint-mode-function () > ;; "Setup comint mode properly." > ;; (trace-values (current-buffer) default-directory comint-file-name-pr= efix) > ;; (setq default-directory (tramp-locproc-local-file-name default-direc= tory)) > ;; (setq-local comint-file-name-prefix "")) > > ;; (with-eval-after-load 'comint > ;; (add-hook 'comint-mode-hook > ;; #'tramp-locproc-comint-mode-function) > ;; (add-hook 'tramp-locproc-unload-hook > ;; (lambda () > ;; (remove-hook 'comint-mode-hook > ;; #'tramp-locproc-comint-mode-function)))) > > ;; Development settings. > (require 'trace) > (mapc > #'trace-function-background > (mapcar #'intern (all-completions "tramp-locproc-" obarray #'functionp))) > > (add-hook 'tramp-unload-hook > (lambda () > (unload-feature 'tramp-locproc 'force))) > > (provide 'tramp-locproc) > > ;;; tramp-locproc.el ends here