DEV: support symlinked plugins in bin/rake autospec

DEV: support symlinked plugins in bin/rake autospec

Previously autospec would not pick up save if you saved a plugin in a symlinked path, this broke quite a few workflows

We now maintain a reverse map so we can correctly re-run specs in plugins

diff --git a/bin/notify_file_change b/bin/notify_file_change
index 1ece7a0..e408e6e 100755
--- a/bin/notify_file_change
+++ b/bin/notify_file_change
@@ -18,15 +18,18 @@ fi
 # 2. Add VIM_AUTOSPEC=1 to your environment
 # 3. Add the following to your .vimrc
 #
-# function s:notify_file_change()
-#   let root = rails#app().path()
-#   let notify = root . "/bin/notify_file_change"
+
+# function! s:notify_file_change_discourse()
+#   let notify = getcwd() . "/bin/notify_file_change"
+#   if ! executable(notify)
+#     let root = rails#app().path()
+#     notify = root . "/bin/notify_file_change"
+#   end
 #   if executable(notify)
 #     if executable('socat')
 #       execute "!" . notify . ' ' . expand("%:p") . " " . line(".")
 #     end
 #   end
-#   " redraw!
 # endfunction
 
 # autocmd BufWritePost * silent! call s:notify_file_change()
diff --git a/lib/autospec/manager.rb b/lib/autospec/manager.rb
index b7810fe..b570bfa 100644
--- a/lib/autospec/manager.rb
+++ b/lib/autospec/manager.rb
@@ -170,6 +170,35 @@ class Autospec::Manager
     @queue.unshift ["focus", failed_specs.join(" "), runner] if failed_specs.length > 0
   end
 
+  def root_path
+    root_path ||= File.expand_path(File.dirname(__FILE__) + "../../..")
+  end
+
+  def reverse_symlink_map
+    map = {}
+    Dir[root_path + "/plugins/*"].each do |f|
+      next if !File.directory? f
+      resolved = File.realpath(f)
+      if resolved != f
+        map[resolved] = f
+      end
+    end
+    map
+  end
+
+  # plugins can be symlinked, try to figure out which plugin this is
+  def reverse_symlink(file)
+    resolved = file
+    @reverse_map ||= reverse_symlink_map
+    @reverse_map.each do |location, discourse_location|
+      if file.start_with?(location)
+        resolved = discourse_location + file[location.length..-1]
+      end
+    end
+
+    resolved
+  end
+
   def listen_for_changes
     puts "@@@@@@@@@@@@ listen_for_changes" if @debug
 
@@ -182,7 +211,7 @@ class Autospec::Manager
       options[:latency] = @opts[:latency] || 3
     end
 
-    path = File.expand_path(File.dirname(__FILE__) + "../../..")
+    path = root_path
 
     if ENV['VIM_AUTOSPEC']
       STDERR.puts "Using VIM file listener"
@@ -192,6 +221,7 @@ class Autospec::Manager
       server = SocketServer.new(socket_path)
       server.start do |line|
         file, line = line.split(' ')
+        file = reverse_symlink(file)
         file = file.sub(Rails.root.to_s << "/", "")
         # process_change can aquire a mutex and block
         # the acceptor
@@ -216,7 +246,10 @@ class Autospec::Manager
           listener = Listen.to("#{path}/#{watch}", options) do |modified, added, _|
             paths = [modified, added].flatten
             paths.compact!
-            paths.map! { |long| long[(path.length + 1)..-1] }
+            paths.map! do |long|
+              long = reverse_symlink(long)
+              long[(path.length + 1)..-1]
+            end
             process_change(paths)
           end
           listener.start

GitHub sha: 3b77fb1f

1 Like

This commit has been mentioned on Discourse Meta. There might be relevant details there:

So now… this works … which is awesome:

1 Like