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