Skip to content

Instantly share code, notes, and snippets.

@SamSaffron
Created November 21, 2023 20:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SamSaffron/000e1905dfc741491c835ea1a2d84974 to your computer and use it in GitHub Desktop.
Save SamSaffron/000e1905dfc741491c835ea1a2d84974 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require "curses"
require "fileutils"
require "open-uri"
require "shellwords"
plugin_dir = File.expand_path("~/Source/discourse/plugins")
disabled_plugin_dir = File.expand_path("~/Source/discourse-plugins")
Curses.init_screen
Curses.noecho
Curses.cbreak
Curses.stdscr.keypad = true
Curses.curs_set(0)
begin
selected = 0
while true
Curses.clear
Curses.setpos(0, 0)
Curses.addstr("Discourse Plugin Manager")
Curses.setpos(1, 0)
Curses.addstr("Enabled plugins:")
excluded_plugins =
`cd #{plugin_dir}/../ && git ls-files | grep ^plugins | awk -F '/' '{ print $2 }' | uniq`.split(
"\n"
).map(&:strip)
enabled_plugins =
Dir
.entries(plugin_dir)
.sort
.select do |entry|
plugin_path = File.join(plugin_dir, entry)
!entry.start_with?(".") && File.directory?(plugin_path) &&
!excluded_plugins.include?(entry.to_s)
end
disabled_plugins =
Dir
.entries(disabled_plugin_dir)
.sort
.reject { |entry| entry.start_with?(".") }
enabled_plugins.each_with_index do |plugin, idx|
Curses.setpos(idx + 2, 2)
Curses.attron(Curses::A_REVERSE) if idx == selected
Curses.addstr(plugin)
Curses.attroff(Curses::A_REVERSE) if idx == selected
end
Curses.setpos(enabled_plugins.length + 3, 0)
Curses.addstr("Disabled plugins:")
disabled_plugins.each_with_index do |plugin, idx|
Curses.setpos(idx + enabled_plugins.length + 4, 2)
if idx + enabled_plugins.length + 1 == selected
Curses.attron(Curses::A_REVERSE)
end
Curses.addstr(plugin)
if idx + enabled_plugins.length + 1 == selected
Curses.attroff(Curses::A_REVERSE)
end
end
key = Curses.getch
case key
when Curses::KEY_DOWN
selected =
(selected + 1) % (enabled_plugins.length + disabled_plugins.length + 1)
when Curses::KEY_UP
selected =
(selected - 1) % (enabled_plugins.length + disabled_plugins.length + 1)
when "q"
break
when "a"
Curses.setpos(enabled_plugins.length + disabled_plugins.length + 5, 0)
Curses.addstr("Fetching plugin list...")
Curses.refresh
plugins_txt_url =
"https://raw.githubusercontent.com/discourse/all-the-plugins/main/official.txt"
plugin_list = URI.open(plugins_txt_url).read.split("\n").sort
plugins_txt_url =
"https://raw.githubusercontent.com/discourse/all-the-plugins/main/third-party.txt"
plugin_list.concat URI.open(plugins_txt_url).read.split("\n").sort
# Exclude existing plugins
existing_plugins = enabled_plugins + disabled_plugins
plugin_list.reject! do |plugin|
existing_plugins.include?(plugin.split("/").last)
end
# Suspend Curses and use fzf for plugin selection
Curses.close_screen
selected_plugin = nil
IO.popen(
"printf '%s\n' #{plugin_list.map(&:shellescape).join(" ")} | fzf"
) { |fzf_io| selected_plugin = fzf_io.read.strip }
Curses.init_screen
# Check if a plugin was selected
if selected_plugin.empty?
Curses.setpos(enabled_plugins.length + disabled_plugins.length + 5, 0)
Curses.addstr("No plugin selected.")
Curses.refresh
sleep(2)
next
end
# Clone selected plugin
plugin_name = selected_plugin.split("/").last
plugin_path = File.join(plugin_dir, plugin_name)
Curses.setpos(enabled_plugins.length + disabled_plugins.length + 5, 0)
Curses.addstr("Cloning #{selected_plugin}...")
Curses.refresh
prefix =
(
if selected_plugin.start_with?("discourse/")
"git@github.com:"
else
"https://github.com/"
end
)
git_clone_result =
`cd #{plugin_dir} && git clone #{prefix}#{selected_plugin}`
success = $?.success?
Curses.setpos(enabled_plugins.length + disabled_plugins.length + 6, 0)
if success
Curses.addstr("Clone successful: #{git_clone_result.strip}")
enabled_plugins << plugin_name
enabled_plugins.sort!
else
Curses.addstr("Clone failed: #{git_clone_result.strip}")
end
Curses.refresh
sleep(2)
when "p"
if selected < enabled_plugins.length
plugin_to_update = enabled_plugins[selected]
else
plugin_to_update =
disabled_plugins[selected - enabled_plugins.length - 1]
end
plugin_path =
File.join(
selected < enabled_plugins.length ? plugin_dir : disabled_plugin_dir,
plugin_to_update
)
Curses.setpos(enabled_plugins.length + disabled_plugins.length + 5, 0)
Curses.addstr("Updating #{plugin_to_update}...")
Curses.refresh
git_pull_result = `cd #{plugin_path} && git pull`
success = $?.success?
Curses.setpos(enabled_plugins.length + disabled_plugins.length + 6, 0)
if success
Curses.addstr("Update successful: #{git_pull_result.strip}")
else
Curses.addstr("Update failed: #{git_pull_result.strip}")
end
Curses.refresh
sleep(0.5)
when ?\n.ord
if selected < enabled_plugins.length
plugin_to_disable = enabled_plugins[selected]
FileUtils.mv(
File.join(plugin_dir, plugin_to_disable),
disabled_plugin_dir
)
else
plugin_to_enable =
disabled_plugins[selected - enabled_plugins.length - 1]
FileUtils.mv(
File.join(disabled_plugin_dir, plugin_to_enable),
plugin_dir
)
end
end
end
ensure
Curses.close_screen
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment