1
0
mirror of https://github.com/profanity-im/profanity.git synced 2024-07-21 18:24:14 -04:00

Allow installing plugins from directory

This commit is contained in:
James Booth 2017-02-05 21:09:03 +00:00
parent c405367dfe
commit 286fecf38d
8 changed files with 144 additions and 33 deletions

View File

@ -6214,49 +6214,77 @@ cmd_xa(ProfWin *window, const char *const command, gchar **args)
gboolean
cmd_plugins_install(ProfWin *window, const char *const command, gchar **args)
{
char *filename = args[1];
if (filename == NULL) {
char *path = args[1];
if (path == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
// expand ~ to $HOME
if (filename[0] == '~' && filename[1] == '/') {
if (asprintf(&filename, "%s/%s", getenv("HOME"), filename+2) == -1) {
if (path[0] == '~' && path[1] == '/') {
if (asprintf(&path, "%s/%s", getenv("HOME"), path+2) == -1) {
return TRUE;
}
} else {
filename = strdup(filename);
path = strdup(path);
}
if (access(filename, R_OK) != 0) {
cons_show("File not found: %s", filename);
free(filename);
if (access(path, R_OK) != 0) {
cons_show("File not found: %s", path);
free(path);
return TRUE;
}
if (!is_regular_file(filename)) {
cons_show("Not a file: %s", filename);
free(filename);
if (is_regular_file(path)) {
if (!g_str_has_suffix(path, ".py") && !g_str_has_suffix(path, ".so")) {
cons_show("Plugins must have one of the following extensions: '.py' '.so'");
free(path);
return TRUE;
}
gchar *plugin_name = g_path_get_basename(path);
gboolean result = plugins_install(plugin_name, path);
if (result) {
cons_show("Plugin installed: %s", plugin_name);
} else {
cons_show("Failed to install plugin: %s", plugin_name);
}
g_free(plugin_name);
free(path);
return TRUE;
}
if (!g_str_has_suffix(filename, ".py") && !g_str_has_suffix(filename, ".so")) {
cons_show("Plugins must have one of the following extensions: '.py' '.so'");
free(filename);
if (is_dir(path)) {
PluginsInstallResult* result = plugins_install_all(path);
if (result->installed || result->failed) {
if (result->installed) {
cons_show("");
cons_show("Installed plugins:");
GSList *curr = result->installed;
while (curr) {
cons_show(" %s", curr->data);
curr = g_slist_next(curr);
}
}
if (result->failed) {
cons_show("");
cons_show("Failed installs:");
GSList *curr = result->failed;
while (curr) {
cons_show(" %s", curr->data);
curr = g_slist_next(curr);
}
}
} else {
cons_show("No plugins found in: %s", path);
}
free(path);
plugins_free_install_result(result);
return TRUE;
}
gchar *plugin_name = g_path_get_basename(filename);
gboolean result = plugins_install(plugin_name, filename);
if (result) {
cons_show("Plugin installed: %s", plugin_name);
} else {
cons_show("Failed to install plugin: %s", plugin_name);
}
g_free(plugin_name);
free(filename);
cons_show("Argument must be a file or directory.");
return TRUE;
}

View File

@ -536,3 +536,45 @@ prof_occurrences(const char *const needle, const char *const haystack, int offse
return *result;
}
int
is_regular_file(const char *path)
{
struct stat st;
stat(path, &st);
return S_ISREG(st.st_mode);
}
int
is_dir(const char *path)
{
struct stat st;
stat(path, &st);
return S_ISDIR(st.st_mode);
}
void
get_file_paths_recursive(const char *path, GSList **contents)
{
if (!is_dir(path)) {
return;
}
GDir* directory = g_dir_open(path, 0, NULL);
const gchar *entry = g_dir_read_name(directory);
while (entry) {
GString *full = g_string_new(path);
if (!g_str_has_suffix(full->str, "/")) {
g_string_append(full, "/");
}
g_string_append(full, entry);
if (is_dir(full->str)) {
get_file_paths_recursive(full->str, contents);
} else if (is_regular_file(full->str)) {
*contents = g_slist_append(*contents, full->str);
}
g_string_free(full, FALSE);
entry = g_dir_read_name(directory);
}
}

View File

@ -123,4 +123,8 @@ gboolean is_notify_enabled(void);
GSList* prof_occurrences(const char *const needle, const char *const haystack, int offset, gboolean whole_word,
GSList **result);
int is_regular_file(const char *path);
int is_dir(const char *path);
void get_file_paths_recursive(const char *directory, GSList **contents);
#endif

View File

@ -129,6 +129,43 @@ plugins_init(void)
return;
}
void
plugins_free_install_result(PluginsInstallResult *result)
{
if (!result) {
return;
}
g_slist_free_full(result->installed, free);
g_slist_free_full(result->failed, free);
}
PluginsInstallResult*
plugins_install_all(const char *const path)
{
PluginsInstallResult *result = malloc(sizeof(PluginsInstallResult));
result->installed = NULL;
result->failed = NULL;
GSList *contents = NULL;
get_file_paths_recursive(path, &contents);
GSList *curr = contents;
while (curr) {
if (g_str_has_suffix(curr->data, ".py") || g_str_has_suffix(curr->data, ".so")) {
gchar *plugin_name = g_path_get_basename(curr->data);
if (plugins_install(plugin_name, curr->data)) {
result->installed = g_slist_append(result->installed, strdup(curr->data));
} else {
result->failed = g_slist_append(result->failed, strdup(curr->data));
}
}
curr = g_slist_next(curr);
}
g_slist_free_full(contents, g_free);
return result;
}
gboolean
plugins_install(const char *const plugin_name, const char *const filename)
{

View File

@ -42,6 +42,11 @@ typedef enum {
LANG_C
} lang_t;
typedef struct prof_plugins_install_t {
GSList *installed;
GSList *failed;
} PluginsInstallResult;
typedef struct prof_plugin_t {
char *name;
lang_t lang;
@ -107,7 +112,10 @@ char* plugins_autocomplete(const char *const input);
void plugins_reset_autocomplete(void);
void plugins_shutdown(void);
void plugins_free_install_result(PluginsInstallResult *result);
gboolean plugins_install(const char *const plugin_name, const char *const filename);
PluginsInstallResult* plugins_install_all(const char *const path);
gboolean plugins_load(const char *const name);
GSList* plugins_load_all(void);
gboolean plugins_unload(const char *const name);

View File

@ -52,6 +52,7 @@
#include "config/preferences.h"
#include "ui/ui.h"
#include "ui/window.h"
#include "common.h"
#define FALLBACK_MIMETYPE "application/octet-stream"
#define FALLBACK_CONTENTTYPE_HEADER "Content-Type: application/octet-stream"
@ -330,10 +331,3 @@ off_t file_size(const char* const filename)
stat(filename, &st);
return st.st_size;
}
int is_regular_file(const char *filename)
{
struct stat st;
stat(filename, &st);
return S_ISREG(st.st_mode);
}

View File

@ -62,6 +62,5 @@ void* http_file_put(void *userdata);
char* file_mime_type(const char* const file_name);
off_t file_size(const char* const file_name);
int is_regular_file(const char *filename);
#endif

View File

@ -24,6 +24,5 @@ void* http_file_put(void *userdata) {}
char* file_mime_type(const char* const file_name) {}
off_t file_size(const char* const file_name) {}
int is_regular_file(const char *filename) {}
#endif