1 /* gbp-cmake-build-target-provider.c
2 *
3 * Copyright 2021 Günther Wagner <info@gunibert.de>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: GPL-3.0-or-later
19 */
20
21 #include "gbp-cmake-build-target-provider.h"
22 #include "gbp-cmake-build-target.h"
23 #include <json-glib/json-glib.h>
24
25 struct _GbpCmakeBuildTargetProvider
26 {
27 IdeObject parent_instance;
28 };
29
30 static void build_target_provider_iface_init (IdeBuildTargetProviderInterface *iface);
31
G_DEFINE_TYPE_WITH_CODE(GbpCmakeBuildTargetProvider,gbp_cmake_build_target_provider,IDE_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_TARGET_PROVIDER,build_target_provider_iface_init))32 G_DEFINE_TYPE_WITH_CODE (GbpCmakeBuildTargetProvider, gbp_cmake_build_target_provider, IDE_TYPE_OBJECT,
33 G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_TARGET_PROVIDER, build_target_provider_iface_init))
34
35 GbpCmakeBuildTargetProvider *
36 gbp_cmake_build_target_provider_new (void)
37 {
38 return g_object_new (GBP_TYPE_CMAKE_BUILD_TARGET_PROVIDER, NULL);
39 }
40
41 static void
gbp_cmake_build_target_provider_class_init(GbpCmakeBuildTargetProviderClass * klass)42 gbp_cmake_build_target_provider_class_init (GbpCmakeBuildTargetProviderClass *klass)
43 {
44 }
45
46 static void
gbp_cmake_build_target_provider_init(GbpCmakeBuildTargetProvider * self)47 gbp_cmake_build_target_provider_init (GbpCmakeBuildTargetProvider *self)
48 {
49 }
50
51 static void
gbp_cmake_build_target_provider_create_target(GbpCmakeBuildTargetProvider * self,GPtrArray ** ret,IdeContext * context,JsonObject * obj)52 gbp_cmake_build_target_provider_create_target (GbpCmakeBuildTargetProvider *self,
53 GPtrArray **ret,
54 IdeContext *context,
55 JsonObject *obj)
56 {
57 g_autoptr(IdeBuildTarget) target = NULL;
58 g_autoptr(GFile) install_directory = NULL;
59 g_autofree gchar *install_dir = NULL;
60 g_autofree gchar *install_dir_abs = NULL;
61 g_autofree gchar *name = NULL;
62 JsonArray *artefacts;
63 JsonObject *path_object;
64 JsonObject *install;
65 JsonObject *prefix;
66 const gchar *artefacts_path;
67 const gchar *prefix_path;
68
69 g_return_if_fail (GBP_IS_CMAKE_BUILD_TARGET_PROVIDER (self));
70
71 /* ignore target if no install rule is present */
72 if (!json_object_has_member (obj, "install"))
73 return;
74
75 artefacts = json_object_get_array_member (obj, "artifacts");
76 /* currently we support only one artefact executable */
77 path_object = json_array_get_object_element (artefacts, 0);
78 artefacts_path = json_object_get_string_member (path_object, "path");
79
80 install = json_object_get_object_member (obj, "install");
81 prefix = json_object_get_object_member (install, "prefix");
82 prefix_path = json_object_get_string_member (prefix, "path");
83
84 install_dir = g_path_get_dirname (artefacts_path);
85 install_dir_abs = g_build_path (G_DIR_SEPARATOR_S, prefix_path, install_dir, NULL);
86 install_directory = g_file_new_for_path (install_dir_abs);
87
88 name = g_path_get_basename (artefacts_path);
89 target = gbp_cmake_build_target_new (context, install_directory, name);
90
91 g_debug ("Found target %s with install directory %s", name, install_dir_abs);
92
93 g_ptr_array_add (*ret, g_steal_pointer (&target));
94 }
95
96 static void
gbp_cmake_build_target_provider_get_targets_async(IdeBuildTargetProvider * provider,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)97 gbp_cmake_build_target_provider_get_targets_async (IdeBuildTargetProvider *provider,
98 GCancellable *cancellable,
99 GAsyncReadyCallback callback,
100 gpointer user_data)
101 {
102 GbpCmakeBuildTargetProvider *self = GBP_CMAKE_BUILD_TARGET_PROVIDER (provider);
103 g_autoptr(IdeTask) task = NULL;
104 g_autoptr(GPtrArray) ret = NULL;
105 g_autoptr(GFile) reply = NULL;
106 g_autoptr(GFileEnumerator) enumerator = NULL;
107 g_autofree gchar *replydir = NULL;
108 IdeContext *context;
109 IdeBuildManager *build_manager;
110 IdePipeline *pipeline;
111 const gchar *builddir;
112
113 IDE_ENTRY;
114
115 g_assert (GBP_IS_CMAKE_BUILD_TARGET_PROVIDER (self));
116 g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
117
118 task = ide_task_new (self, cancellable, callback, user_data);
119 ide_task_set_source_tag (task, gbp_cmake_build_target_provider_get_targets_async);
120 ide_task_set_priority (task, G_PRIORITY_LOW);
121
122 context = ide_object_get_context (IDE_OBJECT (self));
123 build_manager = ide_build_manager_from_context (context);
124 pipeline = ide_build_manager_get_pipeline (build_manager);
125 builddir = ide_pipeline_get_builddir (pipeline);
126
127 replydir = g_build_path (G_DIR_SEPARATOR_S, builddir, ".cmake", "api", "v1", "reply", NULL);
128
129 if (!g_file_test (replydir, G_FILE_TEST_EXISTS))
130 {
131 ide_task_return_new_error (task,
132 G_IO_ERROR,
133 G_IO_ERROR_EXISTS,
134 "Response codemodel does not exists, ignoring");
135 IDE_EXIT;
136 }
137
138 ret = g_ptr_array_new_with_free_func (g_object_unref);
139 reply = g_file_new_for_path (replydir);
140 enumerator = g_file_enumerate_children (reply, G_FILE_ATTRIBUTE_STANDARD_NAME, G_FILE_QUERY_INFO_NONE, cancellable, NULL);
141
142 while (TRUE)
143 {
144 g_autoptr(GFileInputStream) stream = NULL;
145 g_autoptr(JsonParser) parser = NULL;
146 GFile *file;
147 JsonNode *root;
148 JsonObject *jobject;
149
150 if (!g_file_enumerator_iterate (enumerator, NULL, &file, cancellable, NULL))
151 goto out;
152 if (!file)
153 break;
154
155 stream = g_file_read (file, cancellable, NULL);
156 parser = json_parser_new ();
157 json_parser_load_from_stream (parser, G_INPUT_STREAM (stream), cancellable, NULL);
158
159 root = json_parser_get_root (parser);
160 jobject = json_node_get_object (root);
161 if (json_object_has_member (jobject, "type") &&
162 ide_str_equal0 (json_object_get_string_member (jobject, "type"), "EXECUTABLE"))
163 {
164 gbp_cmake_build_target_provider_create_target (self, &ret, context, jobject);
165 }
166 }
167
168 out:
169 IDE_PROBE;
170 ide_task_return_pointer (task, g_steal_pointer (&ret), g_ptr_array_unref);
171
172 IDE_EXIT;
173 }
174
175 static GPtrArray *
gbp_cmake_build_target_provider_get_targets_finish(IdeBuildTargetProvider * provider,GAsyncResult * result,GError ** error)176 gbp_cmake_build_target_provider_get_targets_finish (IdeBuildTargetProvider *provider,
177 GAsyncResult *result,
178 GError **error)
179 {
180 GPtrArray *ret;
181
182 IDE_ENTRY;
183
184 g_assert (GBP_IS_CMAKE_BUILD_TARGET_PROVIDER (provider));
185 g_assert (IDE_IS_TASK (result));
186 g_assert (ide_task_is_valid (IDE_TASK (result), provider));
187
188 ret = ide_task_propagate_pointer (IDE_TASK (result), error);
189
190 IDE_RETURN (IDE_PTR_ARRAY_STEAL_FULL (&ret));
191 }
192
193 static void
build_target_provider_iface_init(IdeBuildTargetProviderInterface * iface)194 build_target_provider_iface_init (IdeBuildTargetProviderInterface *iface)
195 {
196 iface->get_targets_async = gbp_cmake_build_target_provider_get_targets_async;
197 iface->get_targets_finish = gbp_cmake_build_target_provider_get_targets_finish;
198 }
199