diff --git a/meson_options.txt b/meson_options.txt index 128f13246429e0202084db75329977b976b480c4..4ab609e5e9d3353b9a1fb4a588f2be7e1bbf6969 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -41,6 +41,7 @@ option('plugin_git', type: 'boolean') option('plugin_gjs_symbols', type: 'boolean') option('plugin_glade', type: 'boolean') option('plugin_gnome_code_assistance', type: 'boolean') +option('plugin_golang', type: 'boolean') option('plugin_go_langserv', type: 'boolean') option('plugin_gradle', type: 'boolean') option('plugin_grep', type: 'boolean') diff --git a/src/plugins/flatpak/gbp-flatpak-build-system-discovery.c b/src/plugins/flatpak/gbp-flatpak-build-system-discovery.c index 3343605590c6a73be09de26104964bb1ce9a800d..b1a84fa919b53dab94b6e180350a5d4fada00926 100644 --- a/src/plugins/flatpak/gbp-flatpak-build-system-discovery.c +++ b/src/plugins/flatpak/gbp-flatpak-build-system-discovery.c @@ -235,3 +235,4 @@ static void gbp_flatpak_build_system_discovery_init (GbpFlatpakBuildSystemDiscovery *self) { } + diff --git a/src/plugins/golang/gbp-golang-build-system-discovery.c b/src/plugins/golang/gbp-golang-build-system-discovery.c new file mode 100644 index 0000000000000000000000000000000000000000..7b17ad9f787ac6c4a827ad47fdeb760780d31750 --- /dev/null +++ b/src/plugins/golang/gbp-golang-build-system-discovery.c @@ -0,0 +1,108 @@ +/* ide-golang--build-system-discovery.c + * + * Copyright 2019 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#define G_LOG_DOMAIN "ide-golang-build-system-discovery" + +#include "gbp-golang-build-system-discovery.h" + +#define DISCOVERY_MAX_DEPTH 3 + +struct _GbpGolangBuildSystemDiscovery +{ + GObject parent_instance; +}; + + +static gchar * +gbp_golang_build_system_discovery_discover (IdeBuildSystemDiscovery *discovery, + GFile *project_file, + GCancellable *cancellable, + gint *priority, + GError **error) +{ + g_autoptr(GFileEnumerator) enumerator = NULL; + gpointer infoptr; + g_autoptr(GPtrArray) manifests = NULL; + + IDE_ENTRY; + + g_assert (GBP_IS_GOLANG_BUILD_SYSTEM_DISCOVERY (discovery)); + g_assert (G_IS_FILE (project_file)); + g_assert (!cancellable || G_IS_CANCELLABLE (cancellable)); + g_assert (priority != NULL); + + manifests = g_ptr_array_new_with_free_func (g_object_unref); + + enumerator = g_file_enumerate_children (project_file, + G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK"," + G_FILE_ATTRIBUTE_STANDARD_NAME"," + G_FILE_ATTRIBUTE_STANDARD_TYPE, + G_FILE_QUERY_INFO_NONE, + cancellable, + NULL); + + if (enumerator == NULL) + IDE_RETURN (NULL); + + while (NULL != (infoptr = g_file_enumerator_next_file (enumerator, cancellable, NULL))) + { + g_autoptr(GFileInfo) info = infoptr; + GFileType file_type; + const gchar *name; + + if (g_file_info_get_is_symlink (info)) + continue; + + if (NULL == (name = g_file_info_get_name (info))) + continue; + + file_type = g_file_info_get_file_type (info); + + if (file_type != G_FILE_TYPE_REGULAR) + continue; + + if (g_strcmp0 (name, "go.sum") != 0) + continue; + + IDE_TRACE_MSG ("Discovered buildsystem of type \"golang\""); + IDE_RETURN (g_strdup ("golang")); + } + + IDE_RETURN (NULL); +} + +static void +build_system_discovery_iface_init (IdeBuildSystemDiscoveryInterface *iface) +{ + iface->discover = gbp_golang_build_system_discovery_discover; +} + +G_DEFINE_TYPE_WITH_CODE (GbpGolangBuildSystemDiscovery, + gbp_golang_build_system_discovery, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_SYSTEM_DISCOVERY, build_system_discovery_iface_init)) + +static void +gbp_golang_build_system_discovery_class_init (GbpGolangBuildSystemDiscoveryClass *klass) +{ +} + +static void +gbp_golang_build_system_discovery_init (GbpGolangBuildSystemDiscovery *self) +{ +} diff --git a/src/plugins/golang/gbp-golang-build-system-discovery.h b/src/plugins/golang/gbp-golang-build-system-discovery.h new file mode 100644 index 0000000000000000000000000000000000000000..ecb696ff309e352b36d22a0878be9ff6b55b2087 --- /dev/null +++ b/src/plugins/golang/gbp-golang-build-system-discovery.h @@ -0,0 +1,29 @@ +/* ide-golang--build-system-discovery.h + * + * Copyright 2019 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define TYPE_GOLANG_BUILD_SYSTEM_DISCOVERY (gbp_golang_build_system_discovery_get_type()) + +G_DECLARE_FINAL_TYPE (GbpGolangBuildSystemDiscovery, gbp_golang_build_system_discovery, GBP, GOLANG_BUILD_SYSTEM_DISCOVERY, GObject) + +G_END_DECLS diff --git a/src/plugins/golang/golang-plugin.c b/src/plugins/golang/golang-plugin.c new file mode 100644 index 0000000000000000000000000000000000000000..6d16c797f5be20ca19dbae2b1956f96ef9d52ec2 --- /dev/null +++ b/src/plugins/golang/golang-plugin.c @@ -0,0 +1,36 @@ +/* golang-plugin.c + * + * Copyright 2018 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#include +#include +#include + +#include "ide-golang-build-system.h" +#include "ide-golang-application-addin.h" +#include "ide-golang-pipeline-addin.h" +#include "ide-golang-preferences-addin.h" + +void +ide_golang_register_types (PeasObjectModule *module) +{ + peas_object_module_register_extension_type (module, IDE_TYPE_PIPELINE_ADDIN, IDE_TYPE_GOLANG_PIPELINE_ADDIN); + peas_object_module_register_extension_type (module, IDE_TYPE_BUILD_SYSTEM, IDE_TYPE_GOLANG_BUILD_SYSTEM); + peas_object_module_register_extension_type (module, IDE_TYPE_APPLICATION_ADDIN, IDE_TYPE_GOLANG_APPLICATION_ADDIN); + peas_object_module_register_extension_type (module, IDE_TYPE_PREFERENCES_ADDIN, IDE_TYPE_GOLANG_PREFERENCES_ADDIN); +} + diff --git a/src/plugins/golang/golang.gresource.xml b/src/plugins/golang/golang.gresource.xml new file mode 100644 index 0000000000000000000000000000000000000000..aa44d25b6e13807ecfd0d2480b9c6dc69573fbb8 --- /dev/null +++ b/src/plugins/golang/golang.gresource.xml @@ -0,0 +1,6 @@ + + + + golang.plugin + + diff --git a/src/plugins/golang/golang.plugin b/src/plugins/golang/golang.plugin new file mode 100644 index 0000000000000000000000000000000000000000..3177a44b74acce110f394196596f7b30abf60a59 --- /dev/null +++ b/src/plugins/golang/golang.plugin @@ -0,0 +1,12 @@ +[Plugin] +Module=golang_plugin +Name=Golang +Description=Provides integration with the Golang toolchain +Authors=Loïc BLOT +Copyright=Copyright © 2018 Loïc BLOT +Builtin=true +Embedded=ide_golang_register_types +X-Project-File-Filter-Pattern=go.mod,*.go +X-Project-File-Filter-Name=Golang project +X-Builder-ABI=@PACKAGE_ABI@ +X-Symbol-Resolver-Languages=go \ No newline at end of file diff --git a/src/plugins/golang/ide-golang-application-addin.c b/src/plugins/golang/ide-golang-application-addin.c new file mode 100644 index 0000000000000000000000000000000000000000..39579cd5829f2fbf310f417012fcb9bef2d0064d --- /dev/null +++ b/src/plugins/golang/ide-golang-application-addin.c @@ -0,0 +1,154 @@ +/* ide-golang-application-addin.h + * + * Copyright 2018 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#include +#include +#include + +#include "ide-golang-application-addin.h" + +struct _IdeGolangApplicationAddin +{ + GObject parent_instance; + gchar *golang_version; + GRegex *go_version_regex; +}; + +static void application_addin_iface_init (IdeApplicationAddinInterface *iface); +static IdeGolangApplicationAddin *golang_application_addin = NULL; +static const gchar *goversion_pattern = "^go version (.*)\n?$"; + +G_DEFINE_TYPE_EXTENDED (IdeGolangApplicationAddin, + ide_golang_application_addin, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE (IDE_TYPE_APPLICATION_ADDIN, + application_addin_iface_init)) + +static void +ide_golang_application_addin_class_init (IdeGolangApplicationAddinClass *klass) +{ +} + +static void +ide_golang_application_addin_init (IdeGolangApplicationAddin *addin) +{ + g_autoptr(GError) error = NULL; + + if (!(addin->go_version_regex = g_regex_new (goversion_pattern, G_REGEX_MULTILINE, 0, &error))) + { + g_assert(error != NULL); + g_error("Unable to create regex when parsing golang version: %s", error->message); + IDE_EXIT; + } + + addin->golang_version = g_strdup("unknown"); +} + + + +static void +ide_golang_application_addin_load (IdeApplicationAddin *addin, + IdeApplication *application) +{ + g_autoptr(IdeSubprocessLauncher) launcher = NULL; + g_autoptr(IdeSubprocess) subprocess = NULL; + g_autofree gchar *stdoutstr = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GMatchInfo) match_info = NULL; + IdeGolangApplicationAddin *self = (IdeGolangApplicationAddin *)addin; + + golang_application_addin = self; + + IDE_ENTRY; + + g_assert (IDE_IS_APPLICATION_ADDIN (addin)); + g_assert (IDE_IS_APPLICATION (application)); + + launcher = ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE); + + ide_subprocess_launcher_push_argv (launcher, "go"); + ide_subprocess_launcher_push_argv (launcher, "version"); + ide_subprocess_launcher_set_run_on_host (launcher, TRUE); + + subprocess = ide_subprocess_launcher_spawn (launcher, NULL, &error); + if (subprocess == NULL) + { + g_assert (error != NULL); + g_error ("%s", error->message); + IDE_EXIT; + } + + if (!ide_subprocess_communicate_utf8 (subprocess, NULL, NULL, &stdoutstr, NULL, &error)) + { + g_assert(error != NULL); + g_error("Unable to communicate with subprocess while fetching golang version: %s", error->message); + IDE_EXIT; + } + + if (!ide_subprocess_wait (subprocess, NULL, &error)) + { + g_assert(error != NULL); + g_error("Unable to wait when communication with go version: %s", error->message); + IDE_EXIT; + } + + // Search for golang version and return immediately when found. + g_regex_match (self->go_version_regex, stdoutstr, 0, &match_info); + while (g_match_info_matches (match_info)) + { + gint begin = 0; + gint end = 0; + + if (g_match_info_fetch_pos (match_info, 1, &begin, &end) && begin >= 0 && end > begin) + { + g_free (self->golang_version); + self->golang_version = g_strndup(&stdoutstr[begin], end - begin); + g_debug("Found golang version: %s", self->golang_version); + IDE_EXIT; + } + + g_match_info_next (match_info, &error); + } + + IDE_EXIT; +} + +static void +ide_golang_application_addin_unload (IdeApplicationAddin *addin, + IdeApplication *application) +{ + IdeGolangApplicationAddin *self = (IdeGolangApplicationAddin *)addin; + + g_assert (IDE_IS_APPLICATION_ADDIN (addin)); + g_assert (IDE_IS_APPLICATION (application)); + g_free(self->go_version_regex); +} + + +static void +application_addin_iface_init (IdeApplicationAddinInterface *iface) +{ + iface->load = ide_golang_application_addin_load; + iface->unload = ide_golang_application_addin_unload; +} + +const gchar *golang_get_go_version(void) +{ + return golang_application_addin->golang_version; +} diff --git a/src/plugins/golang/ide-golang-application-addin.h b/src/plugins/golang/ide-golang-application-addin.h new file mode 100644 index 0000000000000000000000000000000000000000..cee03a14b8d37aea52c7464a9a416957c8788869 --- /dev/null +++ b/src/plugins/golang/ide-golang-application-addin.h @@ -0,0 +1,32 @@ +/* ide-golang-application-addin.h + * + * Copyright 2018 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define IDE_TYPE_GOLANG_APPLICATION_ADDIN (ide_golang_application_addin_get_type()) + +G_DECLARE_FINAL_TYPE (IdeGolangApplicationAddin, ide_golang_application_addin, IDE, GOLANG_APPLICATION_ADDIN, GObject) + +G_END_DECLS + +const gchar *golang_get_go_version (void); + diff --git a/src/plugins/golang/ide-golang-build-system.c b/src/plugins/golang/ide-golang-build-system.c new file mode 100644 index 0000000000000000000000000000000000000000..018be4f300c433ea686c119c70cdd033df115375 --- /dev/null +++ b/src/plugins/golang/ide-golang-build-system.c @@ -0,0 +1,268 @@ +/* ide-golang-build-system.c + * + * Copyright 2018 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#define G_LOG_DOMAIN "ide-golang-build-system" + +#include "config.h" + +#include +#include + +#include "ide-golang-build-system.h" + +struct _IdeGolangBuildSystem +{ + IdeObject parent_instance; + gchar *goroot; + gchar *gopath; +}; + +static void async_initable_iface_init (GAsyncInitableIface *iface); +static void build_system_iface_init (IdeBuildSystemInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (IdeGolangBuildSystem, + ide_golang_build_system, + IDE_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init) + G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_SYSTEM, build_system_iface_init)) + +enum { + PROP_0, + PROP_PROJECT_FILE, + PROP_GOROOT, + PROP_GOPATH, + N_PROPS, +}; + +static GParamSpec *properties [N_PROPS]; + +static void +ide_golang_build_system_constructed (GObject *object) +{ + IdeGolangBuildSystem *self = (IdeGolangBuildSystem *)object; + IdeBufferManager *buffer_manager; + IdeContext *context; + + G_OBJECT_CLASS (ide_golang_build_system_parent_class)->constructed (object); + + context = ide_object_get_context (IDE_OBJECT (self)); + g_assert (IDE_IS_CONTEXT (context)); + + buffer_manager = ide_buffer_manager_from_context (context); + g_assert (IDE_IS_BUFFER_MANAGER (buffer_manager)); +} + +static void +ide_golang_build_system_finalize (GObject *object) +{ + IdeGolangBuildSystem *self = (IdeGolangBuildSystem *)object; + + g_clear_pointer (&self->goroot, g_free); + g_clear_pointer (&self->gopath, g_free); + G_OBJECT_CLASS (ide_golang_build_system_parent_class)->finalize (object); +} + +static void +ide_golang_build_system_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + IdeGolangBuildSystem *self = IDE_GOLANG_BUILD_SYSTEM (object); + + switch (prop_id) + { + case PROP_GOROOT: + g_value_set_string (value, self->goroot); + break; + + case PROP_GOPATH: + g_value_set_string (value, self->gopath); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +ide_golang_build_system_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + IdeGolangBuildSystem *self = IDE_GOLANG_BUILD_SYSTEM (object); + + switch (prop_id) + { + case PROP_GOROOT: + g_free (self->goroot); + self->goroot = g_value_dup_string (value); + break; + + case PROP_GOPATH: + g_free (self->gopath); + self->gopath = g_value_dup_string (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static gchar * +ide_golang_build_system_get_id (IdeBuildSystem *build_system) +{ + return g_strdup ("golang"); +} + +static gchar * +ide_golang_build_system_get_display_name (IdeBuildSystem *build_system) +{ + return g_strdup ("Golang"); +} + +static gint +ide_golang_build_system_get_priority (IdeBuildSystem *system) +{ + return 0; +} + + +static void +ide_golang_build_system_get_build_flags_async (IdeBuildSystem *build_system, + GFile *file, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + IdeGolangBuildSystem *self = (IdeGolangBuildSystem *)build_system; + g_autoptr(IdeTask) task = NULL; + + IDE_ENTRY; + + g_assert (IDE_IS_GOLANG_BUILD_SYSTEM (self)); + g_assert (G_IS_FILE (file)); + g_assert (!cancellable || G_IS_CANCELLABLE (cancellable)); + + task = ide_task_new (self, cancellable, callback, user_data); + ide_task_set_source_tag (task, ide_golang_build_system_get_build_flags_async); + + IDE_EXIT; +} + +static gchar ** +ide_golang_build_system_get_build_flags_finish (IdeBuildSystem *build_system, + GAsyncResult *result, + GError **error) +{ + g_assert (IDE_IS_GOLANG_BUILD_SYSTEM (build_system)); + g_assert (IDE_IS_TASK (result)); + + return ide_task_propagate_pointer (IDE_TASK (result), error); +} + +static void +ide_golang_build_system_init (IdeGolangBuildSystem *self) +{ +} + +static void +ide_golang_build_system_init_async (GAsyncInitable *initable, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + IdeGolangBuildSystem *system = (IdeGolangBuildSystem *)initable; + g_autoptr(IdeTask) task = NULL; + + IDE_ENTRY; + + g_return_if_fail (IDE_IS_GOLANG_BUILD_SYSTEM (system)); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + + task = ide_task_new (initable, cancellable, callback, user_data); + ide_task_set_source_tag (task, ide_golang_build_system_init_async); + ide_task_set_priority (task, G_PRIORITY_HIGH); + ide_task_return_boolean (task, TRUE); +} + +static gboolean +ide_golang_build_system_init_finish (GAsyncInitable *initable, + GAsyncResult *result, + GError **error) +{ + IdeTask *task = (IdeTask *)result; + + g_return_val_if_fail (IDE_IS_GOLANG_BUILD_SYSTEM (initable), FALSE); + g_return_val_if_fail (IDE_IS_TASK (task), FALSE); + + return ide_task_propagate_boolean (task, error); +} + +static void +ide_golang_build_system_class_init (IdeGolangBuildSystemClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = ide_golang_build_system_constructed; + object_class->finalize = ide_golang_build_system_finalize; + object_class->get_property = ide_golang_build_system_get_property; + object_class->set_property = ide_golang_build_system_set_property; + + properties [PROP_PROJECT_FILE] = + g_param_spec_object ("project-file", + "Go main package", + "The main package path.", + G_TYPE_FILE, + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + properties [PROP_GOROOT] = + g_param_spec_string ("project-goroot", + "Project GOROOT", + "The path to GOROOT.", + "/usr/lib/go", + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + + properties [PROP_GOPATH] = + g_param_spec_string ("project-gopath", + "Project GOPATH", + "The path to GOPATH.", + "~/go", + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +build_system_iface_init (IdeBuildSystemInterface *iface) +{ + iface->get_priority = ide_golang_build_system_get_priority; + iface->get_build_flags_async = ide_golang_build_system_get_build_flags_async; + iface->get_build_flags_finish = ide_golang_build_system_get_build_flags_finish; + iface->get_id = ide_golang_build_system_get_id; + iface->get_display_name = ide_golang_build_system_get_display_name; +} + +static void +async_initable_iface_init (GAsyncInitableIface *iface) +{ + iface->init_async = ide_golang_build_system_init_async; + iface->init_finish = ide_golang_build_system_init_finish; +} diff --git a/src/plugins/golang/ide-golang-build-system.h b/src/plugins/golang/ide-golang-build-system.h new file mode 100644 index 0000000000000000000000000000000000000000..a60f8eed07ece10bf7d3e91d449f2760905365de --- /dev/null +++ b/src/plugins/golang/ide-golang-build-system.h @@ -0,0 +1,29 @@ +/* ide-golang-build-system.h + * + * Copyright 2018 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define IDE_TYPE_GOLANG_BUILD_SYSTEM (ide_golang_build_system_get_type()) + +G_DECLARE_FINAL_TYPE (IdeGolangBuildSystem, ide_golang_build_system, IDE, GOLANG_BUILD_SYSTEM, IdeObject) + +G_END_DECLS diff --git a/src/plugins/golang/ide-golang-go-stage.c b/src/plugins/golang/ide-golang-go-stage.c new file mode 100644 index 0000000000000000000000000000000000000000..5dffe061644da3037dc8f7d6da6d3319e8cd952b --- /dev/null +++ b/src/plugins/golang/ide-golang-go-stage.c @@ -0,0 +1,420 @@ +/* ide-golang-go-stage.h + * + * Copyright 2018 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#define G_LOG_DOMAIN "ide-golang-go-stage" + +#include "ide-golang-go-stage.h" + +struct _IdeGolangGoStage +{ + IdePipelineStage parent; + + /* + * This is our primary build target. It will be run during the normal + * execute_async()/execute_finish() pair. + */ + gchar *target; + + /* + * If we have a @clean_target, then we will run this make target during the + * clean_async()/clean_finish() vfunc pair. They will not be run with + * parallelism, because that just isn't very useful. + */ + gchar *clean_target; +}; + +enum { + PROP_0, + PROP_TARGET, + PROP_CLEAN_TARGET, + N_PROPS +}; + +G_DEFINE_TYPE (IdeGolangGoStage, ide_golang_go_stage, IDE_TYPE_PIPELINE_STAGE) + +static GParamSpec *properties [N_PROPS]; + +static IdeSubprocessLauncher * +create_launcher (IdeGolangGoStage *self, + IdePipeline *pipeline, + GCancellable *cancellable, + const gchar *go_target, + GError **error) +{ + IdeConfig *config; + IdeRuntime *runtime; + const gchar *srcdir; + const gchar *goroot; + const gchar *gopath; + + g_autoptr(IdeSubprocessLauncher) launcher = NULL; + + g_assert (IDE_IS_GOLANG_GO_STAGE (self)); + g_assert (IDE_IS_PIPELINE (pipeline)); + g_assert (!cancellable || G_IS_CANCELLABLE (cancellable)); + g_assert (go_target != NULL); + + config = ide_pipeline_get_config (pipeline); + runtime = ide_config_get_runtime (config); + + if (!ide_runtime_contains_program_in_path (runtime, "go", cancellable)) + { + g_warning ("Unable to find 'go' program in path"); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Unable to find 'go' program in path"); + return NULL; + } + + if (NULL == (goroot = ide_config_getenv (config, "GOROOT"))) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "GOROOT environment variable is not set"); + return NULL; + } + + if (NULL == (gopath = ide_config_getenv (config, "GOPATH"))) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "GOPATH environment variable is not set"); + return NULL; + } + + srcdir = ide_pipeline_get_srcdir (pipeline); + + if (NULL == (launcher = ide_pipeline_create_launcher (pipeline, error))) + return NULL; + + ide_subprocess_launcher_set_cwd (launcher, srcdir); + ide_subprocess_launcher_set_flags (launcher, + G_SUBPROCESS_FLAGS_STDIN_PIPE | + G_SUBPROCESS_FLAGS_STDOUT_PIPE | + G_SUBPROCESS_FLAGS_STDERR_PIPE); + + ide_subprocess_launcher_push_argv (launcher, "go"); + ide_subprocess_launcher_push_argv (launcher, go_target); + + g_debug ("GOROOT is set to: %s", goroot); + ide_subprocess_launcher_setenv (launcher, "GOROOT", goroot, TRUE); + + g_debug ("GOPATH is set to: %s", gopath); + ide_subprocess_launcher_setenv (launcher, "GOPATH", gopath, TRUE); + return g_steal_pointer (&launcher); +} + +static void +ide_golang_go_stage_wait_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + IdeSubprocess *subprocess = (IdeSubprocess *)object; + g_autoptr(IdeTask) task = user_data; + g_autoptr(GError) error = NULL; + + IDE_ENTRY; + + g_assert (IDE_IS_SUBPROCESS (subprocess)); + g_assert (G_IS_ASYNC_RESULT (result)); + + if (!ide_subprocess_wait_check_finish (subprocess, result, &error)) + ide_task_return_error (task, g_steal_pointer (&error)); + else + ide_task_return_boolean (task, TRUE); + + IDE_EXIT; +} + +static void +ide_golang_go_stage_build_async (IdePipelineStage *stage, + IdePipeline *pipeline, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + IdeGolangGoStage *self = (IdeGolangGoStage *)stage; + g_autoptr(IdeSubprocessLauncher) launcher = NULL; + g_autoptr(IdeSubprocess) subprocess = NULL; + g_autoptr(IdeTask) task = NULL; + g_autoptr(GError) error = NULL; + g_autofree gchar *message = NULL; + const gchar * const *argv; + const gchar *target; + + IDE_ENTRY; + + g_assert (IDE_IS_GOLANG_GO_STAGE (self)); + g_assert (IDE_IS_PIPELINE (pipeline)); + g_assert (!cancellable || G_IS_CANCELLABLE (cancellable)); + + task = ide_task_new (self, cancellable, callback, user_data); + ide_task_set_source_tag (task, ide_golang_go_stage_build_async); + + target = self->target; + + if (target == NULL) + { + g_warning ("Improperly configured IdeGolangGoStage, no target set"); + ide_task_return_boolean (task, TRUE); + IDE_EXIT; + } + + launcher = create_launcher (self, pipeline, cancellable, target, &error); + + if (launcher == NULL) + { + ide_task_return_error (task, g_steal_pointer (&error)); + IDE_EXIT; + } + + /* Log the process arguments to stdout */ + argv = ide_subprocess_launcher_get_argv (launcher); + message = g_strjoinv (" ", (gchar **)argv); + ide_pipeline_stage_log (stage, IDE_BUILD_LOG_STDOUT, message, -1); + + subprocess = ide_subprocess_launcher_spawn (launcher, cancellable, &error); + + if (subprocess == NULL) + { + ide_task_return_error (task, g_steal_pointer (&error)); + IDE_EXIT; + } + + ide_pipeline_stage_log_subprocess (stage, subprocess); + + ide_subprocess_wait_check_async (subprocess, + cancellable, + ide_golang_go_stage_wait_cb, + g_steal_pointer (&task)); + + IDE_EXIT; +} + +static gboolean +ide_golang_go_stage_build_finish (IdePipelineStage *stage, + GAsyncResult *result, + GError **error) +{ + gboolean ret; + + IDE_ENTRY; + + g_assert (IDE_IS_PIPELINE_STAGE (stage)); + g_assert (IDE_IS_TASK (result)); + + ret = ide_task_propagate_boolean (IDE_TASK (result), error); + + IDE_RETURN (ret); +} + +static void +ide_golang_go_stage_clean_async (IdePipelineStage *stage, + IdePipeline *pipeline, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + IdeGolangGoStage *self = (IdeGolangGoStage *)stage; + g_autoptr(IdeSubprocessLauncher) launcher = NULL; + g_autoptr(IdeSubprocess) subprocess = NULL; + g_autoptr(IdeTask) task = NULL; + g_autoptr(GError) error = NULL; + g_autofree gchar *message = NULL; + const gchar * const *argv; + + IDE_ENTRY; + + g_assert (IDE_IS_GOLANG_GO_STAGE (self)); + g_assert (IDE_IS_PIPELINE (pipeline)); + g_assert (!cancellable || G_IS_CANCELLABLE (cancellable)); + + task = ide_task_new (self, cancellable, callback, user_data); + ide_task_set_source_tag (task, ide_golang_go_stage_clean_async); + + if (self->clean_target == NULL) + { + ide_task_return_boolean (task, TRUE); + IDE_EXIT; + } + + launcher = create_launcher (self, pipeline, cancellable, self->clean_target, &error); + + if (launcher == NULL) + { + ide_task_return_error (task, g_steal_pointer (&error)); + IDE_EXIT; + } + + /* Log the process arguments to stdout */ + argv = ide_subprocess_launcher_get_argv (launcher); + message = g_strjoinv (" ", (gchar **)argv); + ide_pipeline_stage_log (stage, IDE_BUILD_LOG_STDOUT, message, -1); + + subprocess = ide_subprocess_launcher_spawn (launcher, cancellable, &error); + + if (subprocess == NULL) + { + ide_task_return_error (task, g_steal_pointer (&error)); + IDE_EXIT; + } + + ide_pipeline_stage_log_subprocess (stage, subprocess); + + ide_subprocess_wait_check_async (subprocess, + cancellable, + ide_golang_go_stage_wait_cb, + g_steal_pointer (&task)); + + IDE_EXIT; +} + +static gboolean +ide_golang_go_stage_clean_finish (IdePipelineStage *stage, + GAsyncResult *result, + GError **error) +{ + gboolean ret; + + IDE_ENTRY; + + g_assert (IDE_IS_PIPELINE_STAGE (stage)); + g_assert (IDE_IS_TASK (result)); + + ret = ide_task_propagate_boolean (IDE_TASK (result), error); + + IDE_RETURN (ret); +} + +static void +ide_golang_go_stage_query (IdePipelineStage *stage, + IdePipeline *pipeline, + GPtrArray *targets, + GCancellable *cancellable) +{ + IDE_ENTRY; + + g_return_if_fail (IDE_IS_GOLANG_GO_STAGE (stage)); + g_return_if_fail (IDE_IS_PIPELINE (pipeline)); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + + /* We always defer to make for completed state */ + ide_pipeline_stage_set_completed (stage, FALSE); + + IDE_EXIT; +} + +static void +ide_golang_go_stage_finalize (GObject *object) +{ + IdeGolangGoStage *self = (IdeGolangGoStage *)object; + + g_clear_pointer (&self->target, g_free); + g_clear_pointer (&self->clean_target, g_free); + + G_OBJECT_CLASS (ide_golang_go_stage_parent_class)->finalize (object); +} + +static void +ide_golang_go_stage_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + IdeGolangGoStage *self = IDE_GOLANG_GO_STAGE (object); + + switch (prop_id) + { + case PROP_CLEAN_TARGET: + g_value_set_string (value, self->clean_target); + break; + + case PROP_TARGET: + g_value_set_string (value, self->target); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +ide_golang_go_stage_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + IdeGolangGoStage *self = IDE_GOLANG_GO_STAGE (object); + + switch (prop_id) + { + case PROP_CLEAN_TARGET: + g_free (self->clean_target); + self->clean_target = g_value_dup_string (value); + break; + + case PROP_TARGET: + g_free (self->target); + self->target = g_value_dup_string (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +ide_golang_go_stage_class_init (IdeGolangGoStageClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + IdePipelineStageClass *build_stage_class = IDE_PIPELINE_STAGE_CLASS (klass); + + object_class->finalize = ide_golang_go_stage_finalize; + object_class->get_property = ide_golang_go_stage_get_property; + object_class->set_property = ide_golang_go_stage_set_property; + + build_stage_class->build_async = ide_golang_go_stage_build_async; + build_stage_class->build_finish = ide_golang_go_stage_build_finish; + build_stage_class->clean_async = ide_golang_go_stage_clean_async; + build_stage_class->clean_finish = ide_golang_go_stage_clean_finish; + build_stage_class->query = ide_golang_go_stage_query; + + properties [PROP_TARGET] = + g_param_spec_string ("target", + "Target", + "A go target for normal execution", + NULL, + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + properties [PROP_CLEAN_TARGET] = + g_param_spec_string ("clean-target", + "Clean Target", + "A go clean target for normal execution", + NULL, + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +ide_golang_go_stage_init (IdeGolangGoStage *self) +{ +} diff --git a/src/plugins/golang/ide-golang-go-stage.h b/src/plugins/golang/ide-golang-go-stage.h new file mode 100644 index 0000000000000000000000000000000000000000..a97bfb90c3c54949ba0bac3deb43f6b0db725ced --- /dev/null +++ b/src/plugins/golang/ide-golang-go-stage.h @@ -0,0 +1,29 @@ +/* ide-golang-go-stage.h + * + * Copyright 2018 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define IDE_TYPE_GOLANG_GO_STAGE (ide_golang_go_stage_get_type()) + +G_DECLARE_FINAL_TYPE (IdeGolangGoStage, ide_golang_go_stage, IDE, GOLANG_GO_STAGE, IdePipelineStage) + +G_END_DECLS diff --git a/src/plugins/golang/ide-golang-pipeline-addin.c b/src/plugins/golang/ide-golang-pipeline-addin.c new file mode 100644 index 0000000000000000000000000000000000000000..77771d72241cec1aac73b00a628470b0d868563b --- /dev/null +++ b/src/plugins/golang/ide-golang-pipeline-addin.c @@ -0,0 +1,109 @@ +/* ide-golang-pipeline-addin.c + * + * Copyright 2018 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#define G_LOG_DOMAIN "ide-golang-pipeline-addin" + +#include + +#include "ide-golang-pipeline-addin.h" +#include "ide-golang-build-system.h" +#include "ide-golang-go-stage.h" + +static gboolean +register_go_stage (IdeGolangPipelineAddin *self, + IdePipeline *pipeline, + IdePipelinePhase phase, + GError **error, + const gchar *label, + const gchar *target, + const gchar *clean_target) +{ + g_autoptr(IdePipelineStage) stage = NULL; + IdeContext *context; + guint stage_id; + + g_assert (IDE_IS_GOLANG_PIPELINE_ADDIN (self)); + g_assert (IDE_IS_PIPELINE (pipeline)); + + context = ide_object_get_context (IDE_OBJECT (pipeline)); + + stage = g_object_new (IDE_TYPE_GOLANG_GO_STAGE, + "name", _(label), + "clean-target", clean_target, + "context", context, + "target", target, + NULL); + + stage_id = ide_pipeline_attach (pipeline, phase, 0, stage); + ide_pipeline_addin_track (IDE_PIPELINE_ADDIN (self), stage_id); + + return TRUE; +} + +gboolean golang_tree_action_enable_build(gboolean is_dir) +{ + return is_dir; +} + +static void +ide_golang_pipeline_addin_load (IdePipelineAddin *addin, + IdePipeline *pipeline) +{ + IdeGolangPipelineAddin *self = (IdeGolangPipelineAddin *)addin; + g_autoptr(GError) error = NULL; + IdeBuildSystem *build_system; + IdeContext *context; + + g_assert (IDE_IS_GOLANG_PIPELINE_ADDIN (self)); + g_assert (IDE_IS_PIPELINE (pipeline)); + + context = ide_object_get_context (IDE_OBJECT (addin)); + build_system = ide_build_system_from_context (context); + + if (!IDE_IS_GOLANG_BUILD_SYSTEM (build_system)) + return; + + if (!register_go_stage (self, pipeline, IDE_PIPELINE_PHASE_BUILD, &error, "Building module", "build", "clean") || + !register_go_stage (self, pipeline, IDE_PIPELINE_PHASE_INSTALL, &error, "Installing module", "install", NULL)) + { + g_assert (error != NULL); + g_warning ("Failed to create golang launcher: %s", error->message); + return; + } +} + +static void +addin_iface_init (IdePipelineAddinInterface *iface) +{ + iface->load = ide_golang_pipeline_addin_load; +} + +struct _IdeGolangPipelineAddin { IdeObject parent; }; + +G_DEFINE_TYPE_WITH_CODE (IdeGolangPipelineAddin, ide_golang_pipeline_addin, IDE_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (IDE_TYPE_PIPELINE_ADDIN, addin_iface_init)) + +static void +ide_golang_pipeline_addin_class_init (IdeGolangPipelineAddinClass *klass) +{ +} + +static void +ide_golang_pipeline_addin_init (IdeGolangPipelineAddin *self) +{ +} diff --git a/src/plugins/golang/ide-golang-pipeline-addin.h b/src/plugins/golang/ide-golang-pipeline-addin.h new file mode 100644 index 0000000000000000000000000000000000000000..03d0a37cfdd357a67ef461583013147200078071 --- /dev/null +++ b/src/plugins/golang/ide-golang-pipeline-addin.h @@ -0,0 +1,29 @@ +/* ide-golang-pipeline-addin.h + * + * Copyright 2018 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define IDE_TYPE_GOLANG_PIPELINE_ADDIN (ide_golang_pipeline_addin_get_type()) + +G_DECLARE_FINAL_TYPE (IdeGolangPipelineAddin, ide_golang_pipeline_addin, IDE, GOLANG_PIPELINE_ADDIN, IdeObject) + +G_END_DECLS diff --git a/src/plugins/golang/ide-golang-preferences-addin.c b/src/plugins/golang/ide-golang-preferences-addin.c new file mode 100644 index 0000000000000000000000000000000000000000..5c0c1a41defe72733a5054611cc95d13f10fc46e --- /dev/null +++ b/src/plugins/golang/ide-golang-preferences-addin.c @@ -0,0 +1,164 @@ +/* ide-golang-preferences-addin.h + * + * Copyright 2018 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#include + +#include "ide-golang-preferences-addin.h" +#include "ide-golang-application-addin.h" + +#include + +struct _IdeGolangPreferencesAddin +{ + GObject parent_instance; + + GArray *ids; + DzlPreferences *preferences; + GCancellable *cancellable; +}; + +static GtkWidget * +ide_golang_create_preferences_page (IdePreferencesAddin *addin) +{ + GtkWidget *box = g_object_new (GTK_TYPE_BOX, + "orientation", GTK_ORIENTATION_HORIZONTAL, + "expand", TRUE, + "spacing", 12, + "visible", TRUE, + NULL); + + GtkWidget *vbox = g_object_new (GTK_TYPE_BOX, + "orientation", GTK_ORIENTATION_VERTICAL, + "expand", TRUE, + "visible", TRUE, + NULL); + + GtkWidget *version_label = g_object_new (GTK_TYPE_LABEL, + "halign", GTK_ALIGN_START, + "expand", TRUE, + "visible", TRUE, + "label", "Version"); + + GtkWidget *version_value_label = g_object_new (GTK_TYPE_LABEL, + "halign", GTK_ALIGN_START, + "expand", TRUE, + "visible", TRUE, + "label", "unknown"); + GtkStyleContext *context; + + g_autoptr(GString) version_str = g_string_new (""); + g_string_append (version_str, golang_get_go_version()); + g_string_append(version_str, ""); + + context = gtk_widget_get_style_context (version_value_label); + gtk_style_context_add_class(context, "dim-label"); + + gtk_label_set_markup (GTK_LABEL(version_value_label), version_str->str); + + gtk_box_pack_start (GTK_BOX(vbox), version_label, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX(vbox), version_value_label, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX(box), vbox, TRUE, TRUE, 0); + return box; +} + +static void +ide_golang_preferences_addin_load (IdePreferencesAddin *addin, + DzlPreferences *preferences) +{ + IdeGolangPreferencesAddin *self = (IdeGolangPreferencesAddin *)addin; + guint id; + + IDE_ENTRY; + + g_assert (IDE_IS_GOLANG_PREFERENCES_ADDIN (self)); + g_assert (DZL_IS_PREFERENCES (preferences)); + + self->ids = g_array_new (FALSE, FALSE, sizeof (guint)); + self->preferences = preferences; + + dzl_preferences_add_list_group (preferences, "sdk", "golang", _("Golang"), GTK_SELECTION_NONE, 100); + + id = dzl_preferences_add_file_chooser (preferences, "sdk", + "golang", + "org.gnome.builder.plugins.golang", + "goroot-path", + "/org/gnome/builder/plugins/golang/", + _("GOROOT"), + _("Go ROOT library path"), + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + "", + 150); + g_array_append_val (self->ids, id); + + id = dzl_preferences_add_custom (preferences, "sdk", "golang", ide_golang_create_preferences_page (addin), NULL, 1000); + g_array_append_val (self->ids, id); + + IDE_EXIT; +} + +static void +ide_golang_preferences_addin_unload (IdePreferencesAddin *addin, + DzlPreferences *preferences) +{ + IdeGolangPreferencesAddin *self = (IdeGolangPreferencesAddin *)addin; + + IDE_ENTRY; + + g_assert (IDE_IS_GOLANG_PREFERENCES_ADDIN (self)); + g_assert (DZL_IS_PREFERENCES (preferences)); + + /* Clear preferences so reload code doesn't try to + * make forward progress updating items. + */ + self->preferences = NULL; + + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->cancellable); + + for (guint i = 0; i < self->ids->len; i++) + { + guint id = g_array_index (self->ids, guint, i); + + dzl_preferences_remove_id (preferences, id); + } + + g_clear_pointer (&self->ids, g_array_unref); + + IDE_EXIT; +} + +static void +preferences_addin_iface_init (IdePreferencesAddinInterface *iface) +{ + iface->load = ide_golang_preferences_addin_load; + iface->unload = ide_golang_preferences_addin_unload; +} + +G_DEFINE_TYPE_EXTENDED (IdeGolangPreferencesAddin, ide_golang_preferences_addin, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (IDE_TYPE_PREFERENCES_ADDIN, preferences_addin_iface_init)) + +static void +ide_golang_preferences_addin_class_init (IdeGolangPreferencesAddinClass *klass) +{ +} + +static void +ide_golang_preferences_addin_init (IdeGolangPreferencesAddin *self) +{ +} diff --git a/src/plugins/golang/ide-golang-preferences-addin.h b/src/plugins/golang/ide-golang-preferences-addin.h new file mode 100644 index 0000000000000000000000000000000000000000..0c540243f5be6bcff27a6bc1cd9ee1d1d8bb44a7 --- /dev/null +++ b/src/plugins/golang/ide-golang-preferences-addin.h @@ -0,0 +1,30 @@ +/* ide-golang-preferences-addin.h + * + * Copyright 2018 Loïc BLOT + * + * 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 this program. If not, see . + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define IDE_TYPE_GOLANG_PREFERENCES_ADDIN (ide_golang_preferences_addin_get_type()) + +G_DECLARE_FINAL_TYPE (IdeGolangPreferencesAddin, ide_golang_preferences_addin, IDE, GOLANG_PREFERENCES_ADDIN, GObject) + +G_END_DECLS + diff --git a/src/plugins/golang/meson.build b/src/plugins/golang/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..4fa02e259e865b49b6a3a5cfc4dc75f99c05d922 --- /dev/null +++ b/src/plugins/golang/meson.build @@ -0,0 +1,31 @@ +if get_option('plugin_golang') + +install_data('org.gnome.builder.plugins.golang.gschema.xml', + install_dir: schema_dir) + +golang_resources = gnome.compile_resources( + 'ide-golang-resources', + 'golang.gresource.xml', + c_name: 'ide_golang', +) + +golang_sources = [ + 'golang-plugin.c', + 'ide-golang-application-addin.c', + 'ide-golang-application-addin.h', + 'ide-golang-build-system.c', + 'ide-golang-build-system.h', + 'gbp-golang-build-system-discovery.c', + 'gbp-golang-build-system-discovery.h', + 'ide-golang-go-stage.c', + 'ide-golang-go-stage.h', + 'ide-golang-pipeline-addin.c', + 'ide-golang-pipeline-addin.h', + 'ide-golang-preferences-addin.c', + 'ide-golang-preferences-addin.h' +] + +plugins_sources += files(golang_sources) +plugins_sources += golang_resources[0] + +endif diff --git a/src/plugins/golang/org.gnome.builder.plugins.golang.gschema.xml b/src/plugins/golang/org.gnome.builder.plugins.golang.gschema.xml new file mode 100644 index 0000000000000000000000000000000000000000..05b63f18d8c5b62a1f92c14344ea4eac135c8687 --- /dev/null +++ b/src/plugins/golang/org.gnome.builder.plugins.golang.gschema.xml @@ -0,0 +1,10 @@ + + + + 'file:///' + GOROOT path + Go library ROOT to use within Go projects. + + + + diff --git a/src/plugins/meson.build b/src/plugins/meson.build index b23147cad9567ac0b840151884f188ad51bd352d..412dad61bc7bde4468cfc634f40a412845649fe9 100644 --- a/src/plugins/meson.build +++ b/src/plugins/meson.build @@ -70,6 +70,7 @@ subdir('gettext') subdir('git') subdir('glade') subdir('gnome-code-assistance') +subdir('golang') subdir('go-langserv') subdir('gjs-symbols') subdir('gradle') @@ -151,6 +152,7 @@ status += [ 'GJS Symbols ........... : @0@'.format(get_option('plugin_gjs_symbols')), 'Glade ................. : @0@'.format(get_option('plugin_glade')), 'GNOME Code Assistance . : @0@'.format(get_option('plugin_gnome_code_assistance')), + 'Go .................... : @0@'.format(get_option('plugin_golang')), 'Go Language Server .... : @0@'.format(get_option('plugin_go_langserv')), 'Gradle ................ : @0@'.format(get_option('plugin_gradle')), 'Grep .................. : @0@'.format(get_option('plugin_grep')),