emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/go-mode 17bd2b2 296/495: Add GOPATH detection


From: ELPA Syncer
Subject: [nongnu] elpa/go-mode 17bd2b2 296/495: Add GOPATH detection
Date: Sat, 7 Aug 2021 09:05:35 -0400 (EDT)

branch: elpa/go-mode
commit 17bd2b28ac2db8165a7fb975890bb706f699c71c
Author: Dominik Honnef <dominik@honnef.co>
Commit: Dominik Honnef <dominik@honnef.co>

    Add GOPATH detection
    
    Add functions for detecting various build tools/package managers: wgo,
    gb, Godep and plain GOPATH.
    
    The new command go-set-project uses the result of the detection to set
    the GOPATH environment variable. This function can be used manually, or
    invoked from something like projectile's project switch hook.
    
    Initially, the idea was to set process-environment buffer-locally, but
    that's not a useful thing to do, as most elisp code first creates and
    switches to a new buffer before running a command. This new buffer would
    not inherit our modified process environment.
    
    A second idea was to use hooks to change the global GOPATH
    appropriately, for example when switching buffers. However, this would
    probably incur performance issues, as buffers are changed a lot
    internally, not just due to user interaction.
    
    Closes gh-118
---
 NEWS       |   8 +++++
 go-mode.el | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 113 insertions(+)

diff --git a/NEWS b/NEWS
index 1fe1f72..50e24dc 100644
--- a/NEWS
+++ b/NEWS
@@ -30,6 +30,14 @@ go-mode-1.4.0 (???)
    will be passed to gofmt as additional arguments. Primarily this
    allows using the -s flag with gofmt.
 
+ * Add detection of GOPATH, Godep, wgo and gb. A new non-interactive
+   function go-guess-gopath will try a list of functions
+   (go-guess-gopath-functions) to detect a suitable value for GOPATH.
+   A new interactive command go-set-project uses the result of
+   go-guess-gopath to actually set GOPATH. This interactive function
+   could be used from inside a projectile-switch-project-hook,
+   directory variables or some other way of invoking per-project code.
+
 go-mode-1.3.1 (2015-07-03)
 
  * The 1.3.0 release forgot to update the version in the package
diff --git a/go-mode.el b/go-mode.el
index 660f9d7..3fe7e2b 100644
--- a/go-mode.el
+++ b/go-mode.el
@@ -239,6 +239,21 @@ results, but can be slower than `go-packages-native'."
   :package-version '(go-mode . 1.4.0)
   :group 'go)
 
+(defcustom go-guess-gopath-functions (list #'go-godep-gopath
+                                           #'go-wgo-gopath
+                                           #'go-gb-gopath
+                                           #'go-plain-gopath)
+  "Functions to run in sequence to detect a project's GOPATH.
+
+The functions in this list will be called one after another,
+until a function returns non-nil. The order of the functions in
+this list is important, as some project layouts may superficially
+look like others. For example, a subset of wgo projects look like
+gb projects. That's why we need to detect wgo first, to avoid
+mis-identifying them as gb projects."
+  :type '(repeat function)
+  :group 'go)
+
 (defun go--kill-new-message (url)
   "Make URL the latest kill and print a message."
   (kill-new url)
@@ -1851,6 +1866,96 @@ returned."
     (go-goto-function)
     (looking-at "\\<func(")))
 
+(defun go-guess-gopath (&optional buffer)
+  "Determine a suitable GOPATH for BUFFER, or the current buffer if BUFFER is 
nil.
+
+This function supports gb-based projects as well as Godep, in
+addition to ordinary uses of GOPATH."
+  (with-current-buffer (or buffer (current-buffer))
+    (let ((gopath (cl-some (lambda (el) (funcall el))
+                           go-guess-gopath-functions)))
+      (if gopath
+          (mapconcat
+           (lambda (el) (file-truename el))
+           gopath
+           path-separator)))))
+
+(defun go-plain-gopath ()
+  "Detect a normal GOPATH, by looking for the first `src'
+directory up the directory tree."
+  (let ((d (locate-dominating-file buffer-file-name "src")))
+    (if d
+        (list d))))
+
+(defun go-godep-gopath ()
+  "Detect a Godeps workspace by looking for Godeps/_workspace up
+the directory tree. The result is combined with that of
+`go-plain-gopath'."
+  (let* ((d (locate-dominating-file buffer-file-name "Godeps"))
+         (workspace (concat d
+                            (file-name-as-directory "Godeps")
+                            (file-name-as-directory "_workspace"))))
+    (if (and d
+             (file-exists-p workspace))
+        (list workspace
+              (locate-dominating-file buffer-file-name "src")))))
+
+(defun go-gb-gopath ()
+  "Detect a gb project."
+  (or (go--gb-vendor-gopath)
+      (go--gb-vendor-gopath-reverse)))
+
+(defun go--gb-vendor-gopath ()
+  (let* ((d (locate-dominating-file buffer-file-name "src"))
+         (vendor (concat d (file-name-as-directory "vendor"))))
+    (if (and d
+             (file-exists-p vendor))
+        (list d vendor))))
+
+(defun go--gb-vendor-gopath-reverse ()
+  (let* ((d (locate-dominating-file buffer-file-name "vendor"))
+         (src (concat d (file-name-as-directory "src"))))
+    (if (and d
+             (file-exists-p src))
+        (list d (concat d
+                        (file-name-as-directory "vendor"))))))
+
+(defun go-wgo-gopath ()
+  "Detect a wgo project."
+  (or (go--wgo-gocfg "src")
+      (go--wgo-gocfg "vendor")))
+
+(defun go--wgo-gocfg (needle)
+  (let* ((d (locate-dominating-file buffer-file-name needle))
+         (gocfg (concat d (file-name-as-directory ".gocfg"))))
+    (if (and d
+             (file-exists-p gocfg))
+        (with-temp-buffer
+          (insert-file-contents (concat gocfg "gopaths"))
+          (append
+           (mapcar (lambda (el) (concat d (file-name-as-directory el))) 
(split-string (buffer-string) "\n" t))
+           (list (go-original-gopath)))))))
+
+(defun go-set-project (&optional buffer)
+  "Set GOPATH based on `go-guess-gopath' for BUFFER, or the current buffer if 
BUFFER is nil.
+
+If go-guess-gopath returns nil, that is if it couldn't determine
+a valid value for GOPATH, GOPATH will be set to the initial value
+of when Emacs was started.
+
+This function can for example be used as a
+projectile-switch-project-hook, or simply be called manually when
+switching projects."
+  (interactive)
+  (let ((gopath (or (go-guess-gopath buffer)
+                    (go-original-gopath))))
+    (setenv "GOPATH" gopath)
+    (message "Set GOPATH to %s" gopath)))
+
+(defun go-original-gopath ()
+  "Return the original value of GOPATH from when Emacs was started."
+  (let ((process-environment initial-environment)) (getenv "GOPATH")))
+
 (provide 'go-mode)
 
 ;;; go-mode.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]