~ubuntu-branches/debian/stretch/gnome-builder/stretch

« back to all changes in this revision

Viewing changes to libide/autotools/ide-autotools-build-task.c

  • Committer: Package Import Robot
  • Author(s): Andreas Henriksson
  • Date: 2015-10-11 12:38:45 UTC
  • Revision ID: package-import@ubuntu.com-20151011123845-a0hvkz01se0p1p5a
Tags: upstream-3.16.3
ImportĀ upstreamĀ versionĀ 3.16.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ide-autotools-build-task.c
 
2
 *
 
3
 * Copyright (C) 2015 Christian Hergert <christian@hergert.me>
 
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
 
 
19
#ifdef HAVE_CONFIG_H
 
20
#include "config.h"
 
21
#endif
 
22
 
 
23
#include <fcntl.h>
 
24
#include <glib/gi18n.h>
 
25
#include <unistd.h>
 
26
 
 
27
#include "ide-autotools-build-task.h"
 
28
#include "ide-context.h"
 
29
#include "ide-device.h"
 
30
#include "ide-project.h"
 
31
 
 
32
typedef struct
 
33
{
 
34
  GKeyFile  *config;
 
35
  IdeDevice *device;
 
36
  GFile     *directory;
 
37
  guint      require_autogen : 1;
 
38
  guint      require_configure : 1;
 
39
  guint      executed : 1;
 
40
} IdeAutotoolsBuildTaskPrivate;
 
41
 
 
42
typedef struct
 
43
{
 
44
  gchar  *directory_path;
 
45
  gchar  *project_path;
 
46
  gchar  *parallel;
 
47
  gchar  *system_type;
 
48
  gchar **configure_argv;
 
49
  gchar **make_targets;
 
50
  guint   require_autogen : 1;
 
51
  guint   require_configure : 1;
 
52
  guint   bootstrap_only : 1;
 
53
} WorkerState;
 
54
 
 
55
typedef gboolean (*WorkStep) (GTask                 *task,
 
56
                              IdeAutotoolsBuildTask *self,
 
57
                              WorkerState           *state,
 
58
                              GCancellable          *cancellable);
 
59
 
 
60
G_DEFINE_TYPE_WITH_PRIVATE (IdeAutotoolsBuildTask, ide_autotools_build_task,
 
61
                            IDE_TYPE_BUILD_RESULT)
 
62
 
 
63
enum {
 
64
  PROP_0,
 
65
  PROP_CONFIG,
 
66
  PROP_DEVICE,
 
67
  PROP_DIRECTORY,
 
68
  PROP_REQUIRE_AUTOGEN,
 
69
  PROP_REQUIRE_CONFIGURE,
 
70
  LAST_PROP
 
71
};
 
72
 
 
73
static GSubprocess *log_and_spawn  (IdeAutotoolsBuildTask  *self,
 
74
                                    GSubprocessLauncher    *launcher,
 
75
                                    GError                **error,
 
76
                                    const gchar            *argv0,
 
77
                                    ...) G_GNUC_NULL_TERMINATED;
 
78
static gboolean step_mkdirs        (GTask                  *task,
 
79
                                    IdeAutotoolsBuildTask  *self,
 
80
                                    WorkerState            *state,
 
81
                                    GCancellable           *cancellable);
 
82
static gboolean step_autogen       (GTask                  *task,
 
83
                                    IdeAutotoolsBuildTask  *self,
 
84
                                    WorkerState            *state,
 
85
                                    GCancellable           *cancellable);
 
86
static gboolean step_configure     (GTask                  *task,
 
87
                                    IdeAutotoolsBuildTask  *self,
 
88
                                    WorkerState            *state,
 
89
                                    GCancellable           *cancellable);
 
90
static gboolean step_make_all      (GTask                  *task,
 
91
                                    IdeAutotoolsBuildTask  *self,
 
92
                                    WorkerState            *state,
 
93
                                    GCancellable           *cancellable);
 
94
 
 
95
static GParamSpec *gParamSpecs [LAST_PROP];
 
96
static WorkStep gWorkSteps [] = {
 
97
  step_mkdirs,
 
98
  step_autogen,
 
99
  step_configure,
 
100
  step_make_all,
 
101
  NULL
 
102
};
 
103
 
 
104
gboolean
 
105
ide_autotools_build_task_get_require_autogen (IdeAutotoolsBuildTask *task)
 
106
{
 
107
  IdeAutotoolsBuildTaskPrivate *priv;
 
108
 
 
109
  g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (task), FALSE);
 
110
 
 
111
  priv = ide_autotools_build_task_get_instance_private (task);
 
112
 
 
113
  return priv->require_autogen;
 
114
}
 
115
 
 
116
static void
 
117
ide_autotools_build_task_set_require_autogen (IdeAutotoolsBuildTask *task,
 
118
                                              gboolean               require_autogen)
 
119
{
 
120
  IdeAutotoolsBuildTaskPrivate *priv;
 
121
 
 
122
  g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (task));
 
123
 
 
124
  priv = ide_autotools_build_task_get_instance_private (task);
 
125
 
 
126
  priv->require_autogen = !!require_autogen;
 
127
}
 
128
 
 
129
gboolean
 
130
ide_autotools_build_task_get_require_configure (IdeAutotoolsBuildTask *task)
 
131
{
 
132
  IdeAutotoolsBuildTaskPrivate *priv;
 
133
 
 
134
  g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (task), FALSE);
 
135
 
 
136
  priv = ide_autotools_build_task_get_instance_private (task);
 
137
 
 
138
  return priv->require_configure;
 
139
}
 
140
 
 
141
static void
 
142
ide_autotools_build_task_set_require_configure (IdeAutotoolsBuildTask *task,
 
143
                                                gboolean               require_configure)
 
144
{
 
145
  IdeAutotoolsBuildTaskPrivate *priv;
 
146
 
 
147
  g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (task));
 
148
 
 
149
  priv = ide_autotools_build_task_get_instance_private (task);
 
150
 
 
151
  priv->require_autogen = !!require_configure;
 
152
}
 
153
 
 
154
/**
 
155
 * ide_autotools_build_task_get_config:
 
156
 * @self: A #IdeAutotoolsBuildTask.
 
157
 *
 
158
 * Gets the "config" property of the task. This is the overlay config to be
 
159
 * applied on top of the device config when compiling.
 
160
 *
 
161
 * Returns: (transfer none) (nullable): A #GKeyFile or %NULL.
 
162
 */
 
163
GKeyFile *
 
164
ide_autotools_build_task_get_config (IdeAutotoolsBuildTask *self)
 
165
{
 
166
  IdeAutotoolsBuildTaskPrivate *priv;
 
167
 
 
168
  g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self), NULL);
 
169
 
 
170
  priv = ide_autotools_build_task_get_instance_private (self);
 
171
 
 
172
  return priv->config;
 
173
}
 
174
 
 
175
static void
 
176
ide_autotools_build_task_set_config (IdeAutotoolsBuildTask *self,
 
177
                                     GKeyFile              *config)
 
178
{
 
179
  IdeAutotoolsBuildTaskPrivate *priv;
 
180
 
 
181
  g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
 
182
 
 
183
  priv = ide_autotools_build_task_get_instance_private (self);
 
184
 
 
185
  if (priv->config != config)
 
186
    {
 
187
      g_clear_pointer (&priv->config, g_key_file_unref);
 
188
      priv->config = config ? g_key_file_ref (config) : NULL;
 
189
      g_object_notify_by_pspec (G_OBJECT (self),
 
190
                                gParamSpecs [PROP_CONFIG]);
 
191
    }
 
192
}
 
193
 
 
194
/**
 
195
 * ide_autotools_build_task_get_device:
 
196
 * @self: A #IdeAutotoolsBuildTask.
 
197
 *
 
198
 * Gets the "device" property. This is the device we are compiling for,
 
199
 * which may involve cross-compiling.
 
200
 *
 
201
 * Returns: (transfer none): An #IdeDevice.
 
202
 */
 
203
IdeDevice *
 
204
ide_autotools_build_task_get_device (IdeAutotoolsBuildTask *self)
 
205
{
 
206
  IdeAutotoolsBuildTaskPrivate *priv;
 
207
 
 
208
  g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self), NULL);
 
209
 
 
210
  priv = ide_autotools_build_task_get_instance_private (self);
 
211
 
 
212
  return priv->device;
 
213
}
 
214
 
 
215
static void
 
216
ide_autotools_build_task_set_device (IdeAutotoolsBuildTask *self,
 
217
                                     IdeDevice             *device)
 
218
{
 
219
  IdeAutotoolsBuildTaskPrivate *priv;
 
220
 
 
221
  g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
 
222
 
 
223
  priv = ide_autotools_build_task_get_instance_private (self);
 
224
 
 
225
  if (g_set_object (&priv->device, device))
 
226
    g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_DEVICE]);
 
227
}
 
228
 
 
229
/**
 
230
 * ide_autotools_build_task_get_directory:
 
231
 *
 
232
 * Fetches the build directory that was used.
 
233
 *
 
234
 * Returns: (transfer none): A #GFile.
 
235
 */
 
236
GFile *
 
237
ide_autotools_build_task_get_directory (IdeAutotoolsBuildTask *self)
 
238
{
 
239
  IdeAutotoolsBuildTaskPrivate *priv;
 
240
 
 
241
  g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self), NULL);
 
242
 
 
243
  priv = ide_autotools_build_task_get_instance_private (self);
 
244
 
 
245
  return priv->directory;
 
246
}
 
247
 
 
248
static void
 
249
ide_autotools_build_task_set_directory (IdeAutotoolsBuildTask *self,
 
250
                                        GFile                 *directory)
 
251
{
 
252
  IdeAutotoolsBuildTaskPrivate *priv;
 
253
 
 
254
  g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
 
255
  g_return_if_fail (!directory || G_IS_FILE (directory));
 
256
 
 
257
  priv = ide_autotools_build_task_get_instance_private (self);
 
258
 
 
259
  /*
 
260
   * We require a build directory that is accessable via a native path.
 
261
   */
 
262
  if (directory)
 
263
    {
 
264
      g_autofree gchar *path = NULL;
 
265
 
 
266
      path = g_file_get_path (directory);
 
267
 
 
268
      if (!path)
 
269
        {
 
270
          g_warning (_("Directory must be on a locally mounted filesystem."));
 
271
          return;
 
272
        }
 
273
    }
 
274
 
 
275
  if (priv->directory != directory)
 
276
    if (g_set_object (&priv->directory, directory))
 
277
      g_object_notify_by_pspec (G_OBJECT (self),
 
278
                                gParamSpecs [PROP_DIRECTORY]);
 
279
}
 
280
 
 
281
static void
 
282
ide_autotools_build_task_finalize (GObject *object)
 
283
{
 
284
  IdeAutotoolsBuildTask *self = (IdeAutotoolsBuildTask *)object;
 
285
  IdeAutotoolsBuildTaskPrivate *priv;
 
286
 
 
287
  priv = ide_autotools_build_task_get_instance_private (self);
 
288
 
 
289
  g_clear_object (&priv->device);
 
290
  g_clear_object (&priv->directory);
 
291
  g_clear_pointer (&priv->config, g_key_file_unref);
 
292
 
 
293
  G_OBJECT_CLASS (ide_autotools_build_task_parent_class)->finalize (object);
 
294
}
 
295
 
 
296
static void
 
297
ide_autotools_build_task_get_property (GObject    *object,
 
298
                                       guint       prop_id,
 
299
                                       GValue     *value,
 
300
                                       GParamSpec *pspec)
 
301
{
 
302
  IdeAutotoolsBuildTask *self = IDE_AUTOTOOLS_BUILD_TASK (object);
 
303
 
 
304
  switch (prop_id)
 
305
    {
 
306
    case PROP_CONFIG:
 
307
      g_value_set_object (value, ide_autotools_build_task_get_config (self));
 
308
      break;
 
309
 
 
310
    case PROP_DEVICE:
 
311
      g_value_set_object (value, ide_autotools_build_task_get_device (self));
 
312
      break;
 
313
 
 
314
    case PROP_DIRECTORY:
 
315
      g_value_set_object (value, ide_autotools_build_task_get_directory (self));
 
316
      break;
 
317
 
 
318
    case PROP_REQUIRE_AUTOGEN:
 
319
      g_value_set_boolean (value, ide_autotools_build_task_get_require_autogen (self));
 
320
      break;
 
321
 
 
322
    case PROP_REQUIRE_CONFIGURE:
 
323
      g_value_set_boolean (value, ide_autotools_build_task_get_require_configure (self));
 
324
      break;
 
325
 
 
326
    default:
 
327
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
328
    }
 
329
}
 
330
 
 
331
static void
 
332
ide_autotools_build_task_set_property (GObject      *object,
 
333
                                       guint         prop_id,
 
334
                                       const GValue *value,
 
335
                                       GParamSpec   *pspec)
 
336
{
 
337
  IdeAutotoolsBuildTask *self = IDE_AUTOTOOLS_BUILD_TASK (object);
 
338
 
 
339
  switch (prop_id)
 
340
    {
 
341
    case PROP_CONFIG:
 
342
      ide_autotools_build_task_set_config (self, g_value_get_boxed (value));
 
343
      break;
 
344
 
 
345
    case PROP_DEVICE:
 
346
      ide_autotools_build_task_set_device (self, g_value_get_object (value));
 
347
      break;
 
348
 
 
349
    case PROP_DIRECTORY:
 
350
      ide_autotools_build_task_set_directory (self, g_value_get_object (value));
 
351
      break;
 
352
 
 
353
    case PROP_REQUIRE_AUTOGEN:
 
354
      ide_autotools_build_task_set_require_autogen (self, g_value_get_boolean (value));
 
355
      break;
 
356
 
 
357
    case PROP_REQUIRE_CONFIGURE:
 
358
      ide_autotools_build_task_set_require_configure (self, g_value_get_boolean (value));
 
359
      break;
 
360
 
 
361
    default:
 
362
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
363
    }
 
364
}
 
365
 
 
366
static void
 
367
ide_autotools_build_task_class_init (IdeAutotoolsBuildTaskClass *klass)
 
368
{
 
369
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
370
 
 
371
  object_class->finalize = ide_autotools_build_task_finalize;
 
372
  object_class->get_property = ide_autotools_build_task_get_property;
 
373
  object_class->set_property = ide_autotools_build_task_set_property;
 
374
 
 
375
  gParamSpecs [PROP_CONFIG] =
 
376
    g_param_spec_boxed ("config",
 
377
                        _("Config"),
 
378
                        _("The overlay config for the compilation."),
 
379
                        G_TYPE_KEY_FILE,
 
380
                        (G_PARAM_READWRITE |
 
381
                         G_PARAM_CONSTRUCT_ONLY |
 
382
                         G_PARAM_STATIC_STRINGS));
 
383
 
 
384
  gParamSpecs [PROP_DEVICE] =
 
385
    g_param_spec_object ("device",
 
386
                         _("Device"),
 
387
                         _("The device to build for."),
 
388
                         IDE_TYPE_DEVICE,
 
389
                         (G_PARAM_READWRITE |
 
390
                          G_PARAM_CONSTRUCT_ONLY |
 
391
                          G_PARAM_STATIC_STRINGS));
 
392
 
 
393
  gParamSpecs [PROP_DIRECTORY] =
 
394
    g_param_spec_object ("directory",
 
395
                         _("Directory"),
 
396
                         _("The directory to perform the build within."),
 
397
                         G_TYPE_FILE,
 
398
                         (G_PARAM_READWRITE |
 
399
                          G_PARAM_CONSTRUCT_ONLY |
 
400
                          G_PARAM_STATIC_STRINGS));
 
401
 
 
402
  gParamSpecs [PROP_REQUIRE_AUTOGEN] =
 
403
    g_param_spec_boolean ("require-autogen",
 
404
                          _("Require Autogen"),
 
405
                          _("If autogen.sh should be forced to execute."),
 
406
                          FALSE,
 
407
                          (G_PARAM_READWRITE |
 
408
                           G_PARAM_CONSTRUCT_ONLY |
 
409
                           G_PARAM_STATIC_STRINGS));
 
410
 
 
411
  gParamSpecs [PROP_REQUIRE_CONFIGURE] =
 
412
    g_param_spec_boolean ("require-configure",
 
413
                          _("Require Configure"),
 
414
                          _("If configure should be forced to execute."),
 
415
                          FALSE,
 
416
                          (G_PARAM_READWRITE |
 
417
                           G_PARAM_CONSTRUCT_ONLY |
 
418
                           G_PARAM_STATIC_STRINGS));
 
419
 
 
420
  g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
 
421
}
 
422
 
 
423
static void
 
424
ide_autotools_build_task_init (IdeAutotoolsBuildTask *self)
 
425
{
 
426
}
 
427
 
 
428
static gchar **
 
429
gen_configure_argv (IdeAutotoolsBuildTask *self,
 
430
                    WorkerState           *state)
 
431
{
 
432
  IdeAutotoolsBuildTaskPrivate *priv;
 
433
  IdeDevice *device;
 
434
  const gchar *system_type;
 
435
  GKeyFile *configs[2];
 
436
  GPtrArray *ar;
 
437
  GHashTable *ht;
 
438
  gpointer k, v;
 
439
  GHashTableIter iter;
 
440
  gchar *configure_path;
 
441
  guint j;
 
442
 
 
443
  g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self), NULL);
 
444
 
 
445
  priv = ide_autotools_build_task_get_instance_private (self);
 
446
 
 
447
  ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
448
 
 
449
  configs [0] = ide_device_get_config (priv->device);
 
450
  configs [1] = priv->config;
 
451
 
 
452
  for (j = 0; j < G_N_ELEMENTS (configs); j++)
 
453
    {
 
454
      GKeyFile *config = configs [j];
 
455
 
 
456
      if (config)
 
457
        {
 
458
          if (g_key_file_has_group (config, "autoconf"))
 
459
            {
 
460
              gchar **keys;
 
461
              gsize len;
 
462
              gsize i;
 
463
 
 
464
              keys = g_key_file_get_keys (config, "autoconf", &len, NULL);
 
465
 
 
466
              for (i = 0; i < len; i++)
 
467
                {
 
468
                  gchar *value;
 
469
 
 
470
                  if (*keys [i] == '-')
 
471
                    {
 
472
                      value = g_key_file_get_string (config,
 
473
                                                     "autoconf", keys [i],
 
474
                                                     NULL);
 
475
                      if (value)
 
476
                        g_hash_table_replace (ht, g_strdup (keys [i]), value);
 
477
                    }
 
478
                }
 
479
 
 
480
              g_strfreev (keys);
 
481
            }
 
482
        }
 
483
    }
 
484
 
 
485
  ar = g_ptr_array_new ();
 
486
  configure_path = g_build_filename (state->project_path, "configure", NULL);
 
487
  g_ptr_array_add (ar, configure_path);
 
488
 
 
489
  g_hash_table_iter_init (&iter, ht);
 
490
 
 
491
  while (g_hash_table_iter_next (&iter, &k, &v))
 
492
    {
 
493
      g_ptr_array_add (ar, g_strdup (k));
 
494
      if (v && *(gchar *)v)
 
495
        g_ptr_array_add (ar, g_strdup (v));
 
496
    }
 
497
 
 
498
  if (!g_hash_table_lookup (ht, "--prefix"))
 
499
    {
 
500
      gchar *prefix;
 
501
 
 
502
      prefix = g_build_filename (state->project_path, "_install", NULL);
 
503
      g_ptr_array_add (ar, g_strdup_printf ("--prefix=%s", prefix));
 
504
      g_free (prefix);
 
505
    }
 
506
 
 
507
  device = ide_autotools_build_task_get_device (self);
 
508
  system_type = ide_device_get_system_type (device);
 
509
  g_ptr_array_add (ar, g_strdup_printf ("--host=%s", system_type));
 
510
 
 
511
  g_ptr_array_add (ar, NULL);
 
512
  g_hash_table_unref (ht);
 
513
 
 
514
  return (gchar **)g_ptr_array_free (ar, FALSE);
 
515
}
 
516
 
 
517
static WorkerState *
 
518
worker_state_new (IdeAutotoolsBuildTask *self)
 
519
{
 
520
  IdeAutotoolsBuildTaskPrivate *priv;
 
521
  g_autofree gchar *name = NULL;
 
522
  IdeContext *context;
 
523
  GPtrArray *make_targets;
 
524
  GFile *project_dir;
 
525
  GFile *project_file;
 
526
  WorkerState *state;
 
527
  gint val32;
 
528
 
 
529
  g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self), NULL);
 
530
 
 
531
  priv = ide_autotools_build_task_get_instance_private (self);
 
532
 
 
533
  context = ide_object_get_context (IDE_OBJECT (self));
 
534
  project_file = ide_context_get_project_file (context);
 
535
 
 
536
  name = g_file_get_basename (project_file);
 
537
 
 
538
  if (g_str_has_prefix (name, "configure."))
 
539
    project_dir = g_file_get_parent (project_file);
 
540
  else
 
541
    project_dir = g_object_ref (project_file);
 
542
 
 
543
  state = g_slice_new0 (WorkerState);
 
544
  state->require_autogen = priv->require_autogen;
 
545
  state->require_configure = priv->require_configure;
 
546
  state->directory_path = g_file_get_path (priv->directory);
 
547
  state->project_path = g_file_get_path (project_dir);
 
548
  state->system_type = g_strdup (ide_device_get_system_type (priv->device));
 
549
 
 
550
  if ((val32 = g_key_file_get_integer (priv->config, "parallel", "workers", NULL)))
 
551
    state->parallel = g_strdup_printf ("-j%u", val32);
 
552
  else
 
553
    state->parallel = g_strdup ("-j1");
 
554
 
 
555
  make_targets = g_ptr_array_new ();
 
556
 
 
557
  if (priv->config && g_key_file_get_boolean (priv->config, "autotools", "rebuild", NULL))
 
558
    {
 
559
      state->require_autogen = TRUE;
 
560
      state->require_configure = TRUE;
 
561
      g_ptr_array_add (make_targets, g_strdup ("clean"));
 
562
    }
 
563
 
 
564
  g_ptr_array_add (make_targets, g_strdup ("all"));
 
565
  g_ptr_array_add (make_targets, NULL);
 
566
  state->make_targets = (gchar **)g_ptr_array_free (make_targets, FALSE);
 
567
 
 
568
  if (g_key_file_get_boolean (priv->config, "autotools", "bootstrap-only", NULL))
 
569
    {
 
570
      state->require_autogen = TRUE;
 
571
      state->require_configure = TRUE;
 
572
      state->bootstrap_only = TRUE;
 
573
      g_clear_pointer (&state->make_targets, (GDestroyNotify)g_strfreev);
 
574
    }
 
575
 
 
576
  state->configure_argv = gen_configure_argv (self, state);
 
577
 
 
578
  return state;
 
579
}
 
580
 
 
581
static void
 
582
worker_state_free (void *data)
 
583
{
 
584
  WorkerState *state = data;
 
585
 
 
586
  g_free (state->directory_path);
 
587
  g_free (state->project_path);
 
588
  g_free (state->system_type);
 
589
  g_free (state->parallel);
 
590
  g_strfreev (state->configure_argv);
 
591
  g_strfreev (state->make_targets);
 
592
  g_slice_free (WorkerState, state);
 
593
}
 
594
 
 
595
static void
 
596
ide_autotools_build_task_execute_worker (GTask        *task,
 
597
                                         gpointer      source_object,
 
598
                                         gpointer      task_data,
 
599
                                         GCancellable *cancellable)
 
600
{
 
601
  IdeAutotoolsBuildTask *self = source_object;
 
602
  WorkerState *state = task_data;
 
603
  guint i;
 
604
 
 
605
  g_return_if_fail (G_IS_TASK (task));
 
606
  g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
 
607
  g_return_if_fail (state);
 
608
  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
609
 
 
610
  for (i = 0; gWorkSteps [i]; i++)
 
611
    {
 
612
      if (g_cancellable_is_cancelled (cancellable) ||
 
613
          !gWorkSteps [i] (task, self, state, cancellable))
 
614
        return;
 
615
    }
 
616
 
 
617
  g_task_return_boolean (task, TRUE);
 
618
}
 
619
 
 
620
void
 
621
ide_autotools_build_task_execute_async (IdeAutotoolsBuildTask *self,
 
622
                                        GCancellable          *cancellable,
 
623
                                        GAsyncReadyCallback    callback,
 
624
                                        gpointer               user_data)
 
625
{
 
626
  IdeAutotoolsBuildTaskPrivate *priv;
 
627
  g_autoptr(GTask) task = NULL;
 
628
  WorkerState *state;
 
629
 
 
630
  g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
 
631
  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
632
 
 
633
  priv = ide_autotools_build_task_get_instance_private (self);
 
634
 
 
635
  if (priv->executed)
 
636
    {
 
637
      g_task_report_new_error (self, callback, user_data,
 
638
                               ide_autotools_build_task_execute_async,
 
639
                               G_IO_ERROR,
 
640
                               G_IO_ERROR_FAILED,
 
641
                               _("Cannot execute build task more than once."));
 
642
      return;
 
643
    }
 
644
 
 
645
  priv->executed = TRUE;
 
646
 
 
647
  state = worker_state_new (self);
 
648
 
 
649
  task = g_task_new (self, cancellable, callback, user_data);
 
650
  g_task_set_task_data (task, state, worker_state_free);
 
651
  g_task_run_in_thread (task, ide_autotools_build_task_execute_worker);
 
652
}
 
653
 
 
654
gboolean
 
655
ide_autotools_build_task_execute_finish (IdeAutotoolsBuildTask  *self,
 
656
                                         GAsyncResult           *result,
 
657
                                         GError                **error)
 
658
{
 
659
  GTask *task = (GTask *)result;
 
660
 
 
661
  g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self), FALSE);
 
662
  g_return_val_if_fail (G_IS_TASK (result), FALSE);
 
663
  g_return_val_if_fail (G_IS_TASK (task), FALSE);
 
664
 
 
665
  return g_task_propagate_boolean (task, error);
 
666
}
 
667
 
 
668
static GSubprocess *
 
669
log_and_spawn (IdeAutotoolsBuildTask  *self,
 
670
               GSubprocessLauncher    *launcher,
 
671
               GError                **error,
 
672
               const gchar           *argv0,
 
673
               ...)
 
674
{
 
675
  GSubprocess *ret;
 
676
  GPtrArray *argv;
 
677
  GString *log;
 
678
  gchar *item;
 
679
  va_list args;
 
680
 
 
681
  log = g_string_new (NULL);
 
682
  g_string_append (log, argv0);
 
683
 
 
684
  argv = g_ptr_array_new ();
 
685
  g_ptr_array_add (argv, (gchar *)argv0);
 
686
 
 
687
  va_start (args, argv0);
 
688
  while ((item = va_arg (args, gchar *)))
 
689
    {
 
690
      g_ptr_array_add (argv, item);
 
691
      g_string_append_printf (log, " '%s'", item);
 
692
    }
 
693
  va_end (args);
 
694
 
 
695
  g_ptr_array_add (argv, NULL);
 
696
 
 
697
  ide_build_result_log_stdout (IDE_BUILD_RESULT (self), "%s", log->str);
 
698
  ret = g_subprocess_launcher_spawnv (launcher,
 
699
                                      (const gchar * const *)argv->pdata,
 
700
                                      error);
 
701
 
 
702
  g_string_free (log, TRUE);
 
703
  g_ptr_array_unref (argv);
 
704
 
 
705
  return ret;
 
706
}
 
707
 
 
708
static gboolean
 
709
step_mkdirs (GTask                 *task,
 
710
             IdeAutotoolsBuildTask *self,
 
711
             WorkerState           *state,
 
712
             GCancellable          *cancellable)
 
713
{
 
714
  g_assert (G_IS_TASK (task));
 
715
  g_assert (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
 
716
  g_assert (state);
 
717
  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
718
 
 
719
  if (!g_file_test (state->directory_path, G_FILE_TEST_EXISTS))
 
720
    {
 
721
      if (g_mkdir_with_parents (state->directory_path, 0750) != 0)
 
722
        {
 
723
          g_task_return_new_error (task,
 
724
                                   G_IO_ERROR,
 
725
                                   G_IO_ERROR_FAILED,
 
726
                                   _("Failed to create build directory."));
 
727
          return FALSE;
 
728
        }
 
729
    }
 
730
  else if (!g_file_test (state->directory_path, G_FILE_TEST_IS_DIR))
 
731
    {
 
732
      g_task_return_new_error (task,
 
733
                               G_IO_ERROR,
 
734
                               G_IO_ERROR_NOT_DIRECTORY,
 
735
                               _("'%s' is not a directory."),
 
736
                               state->directory_path);
 
737
      return FALSE;
 
738
    }
 
739
 
 
740
  return TRUE;
 
741
}
 
742
 
 
743
static gboolean
 
744
step_autogen (GTask                 *task,
 
745
              IdeAutotoolsBuildTask *self,
 
746
              WorkerState           *state,
 
747
              GCancellable          *cancellable)
 
748
{
 
749
  g_autofree gchar *autogen_sh_path = NULL;
 
750
  g_autofree gchar *configure_path = NULL;
 
751
  g_autoptr(GSubprocessLauncher) launcher = NULL;
 
752
  g_autoptr(GSubprocess) process = NULL;
 
753
  GError *error = NULL;
 
754
 
 
755
  g_assert (G_IS_TASK (task));
 
756
  g_assert (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
 
757
  g_assert (state);
 
758
  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
759
 
 
760
  configure_path = g_build_filename (state->project_path, "configure", NULL);
 
761
 
 
762
  if (!state->require_autogen)
 
763
    {
 
764
      if (g_file_test (configure_path, G_FILE_TEST_IS_REGULAR))
 
765
        return TRUE;
 
766
    }
 
767
 
 
768
  autogen_sh_path = g_build_filename (state->project_path, "autogen.sh", NULL);
 
769
  if (!g_file_test (autogen_sh_path, G_FILE_TEST_EXISTS))
 
770
    {
 
771
      g_task_return_new_error (task,
 
772
                               G_IO_ERROR,
 
773
                               G_IO_ERROR_FAILED,
 
774
                               _("autogen.sh is missing from project directory (%s)."),
 
775
                               state->project_path);
 
776
      return FALSE;
 
777
    }
 
778
 
 
779
  if (!g_file_test (autogen_sh_path, G_FILE_TEST_IS_EXECUTABLE))
 
780
    {
 
781
      g_task_return_new_error (task,
 
782
                               G_IO_ERROR,
 
783
                               G_IO_ERROR_FAILED,
 
784
                               _("autogen.sh is not executable."));
 
785
      return FALSE;
 
786
    }
 
787
 
 
788
  launcher = g_subprocess_launcher_new ((G_SUBPROCESS_FLAGS_STDOUT_PIPE |
 
789
                                         G_SUBPROCESS_FLAGS_STDERR_PIPE));
 
790
  g_subprocess_launcher_set_cwd (launcher, state->project_path);
 
791
  g_subprocess_launcher_setenv (launcher, "NOCONFIGURE", "1", TRUE);
 
792
 
 
793
  process = log_and_spawn (self, launcher, &error, autogen_sh_path, NULL);
 
794
 
 
795
  if (!process)
 
796
    {
 
797
      g_task_return_error (task, error);
 
798
      return FALSE;
 
799
    }
 
800
 
 
801
  ide_build_result_log_subprocess (IDE_BUILD_RESULT (self), process);
 
802
 
 
803
  if (!g_subprocess_wait_check (process, cancellable, &error))
 
804
    {
 
805
      g_task_return_error (task, error);
 
806
      return FALSE;
 
807
    }
 
808
 
 
809
  if (!g_file_test (configure_path, G_FILE_TEST_IS_EXECUTABLE))
 
810
    {
 
811
      g_task_return_new_error (task,
 
812
                               G_IO_ERROR,
 
813
                               G_IO_ERROR_FAILED,
 
814
                               _("autogen.sh failed to create configure (%s)"),
 
815
                               configure_path);
 
816
      return FALSE;
 
817
    }
 
818
 
 
819
  return TRUE;
 
820
}
 
821
 
 
822
static gboolean
 
823
step_configure (GTask                 *task,
 
824
                IdeAutotoolsBuildTask *self,
 
825
                WorkerState           *state,
 
826
                GCancellable          *cancellable)
 
827
{
 
828
  g_autoptr(GSubprocessLauncher) launcher = NULL;
 
829
  g_autoptr(GSubprocess) process = NULL;
 
830
  g_autofree gchar *makefile_path = NULL;
 
831
  g_autofree gchar *config_log = NULL;
 
832
  GError *error = NULL;
 
833
 
 
834
  g_assert (G_IS_TASK (task));
 
835
  g_assert (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
 
836
  g_assert (state);
 
837
  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
838
 
 
839
  if (!state->require_configure)
 
840
    {
 
841
      /*
 
842
       * Skip configure if we already have a makefile.
 
843
       */
 
844
      makefile_path = g_build_filename (state->directory_path, "Makefile", NULL);
 
845
      if (g_file_test (makefile_path, G_FILE_TEST_EXISTS))
 
846
        return TRUE;
 
847
    }
 
848
 
 
849
  launcher = g_subprocess_launcher_new ((G_SUBPROCESS_FLAGS_STDERR_PIPE |
 
850
                                         G_SUBPROCESS_FLAGS_STDOUT_PIPE));
 
851
  g_subprocess_launcher_set_cwd (launcher, state->directory_path);
 
852
 
 
853
  config_log = g_strjoinv (" ", state->configure_argv);
 
854
  ide_build_result_log_stdout (IDE_BUILD_RESULT (self), "%s", config_log);
 
855
 
 
856
  process = g_subprocess_launcher_spawnv (
 
857
      launcher,
 
858
      (const gchar * const *)state->configure_argv,
 
859
      &error);
 
860
 
 
861
  if (!process)
 
862
    {
 
863
      g_task_return_error (task, error);
 
864
      return FALSE;
 
865
    }
 
866
 
 
867
  ide_build_result_log_subprocess (IDE_BUILD_RESULT (self), process);
 
868
 
 
869
  if (!g_subprocess_wait_check (process, cancellable, &error))
 
870
    {
 
871
      g_task_return_error (task, error);
 
872
      return FALSE;
 
873
    }
 
874
 
 
875
  if (state->bootstrap_only)
 
876
    {
 
877
      g_task_return_boolean (task, TRUE);
 
878
      return FALSE;
 
879
    }
 
880
 
 
881
  return TRUE;
 
882
}
 
883
 
 
884
static gboolean
 
885
step_make_all  (GTask                 *task,
 
886
                IdeAutotoolsBuildTask *self,
 
887
                WorkerState           *state,
 
888
                GCancellable          *cancellable)
 
889
{
 
890
  g_autoptr(GSubprocessLauncher) launcher = NULL;
 
891
  g_autoptr(GSubprocess) process = NULL;
 
892
  const gchar * const *targets;
 
893
  gchar *default_targets[] = { "all", NULL };
 
894
  GError *error = NULL;
 
895
  guint i;
 
896
 
 
897
  g_assert (G_IS_TASK (task));
 
898
  g_assert (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
 
899
  g_assert (state);
 
900
  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
901
 
 
902
  launcher = g_subprocess_launcher_new ((G_SUBPROCESS_FLAGS_STDERR_PIPE |
 
903
                                         G_SUBPROCESS_FLAGS_STDOUT_PIPE));
 
904
  g_subprocess_launcher_set_cwd (launcher, state->directory_path);
 
905
 
 
906
  if (!g_strv_length (state->make_targets))
 
907
    targets = (const gchar * const *)default_targets;
 
908
  else
 
909
    targets = (const gchar * const *)state->make_targets;
 
910
 
 
911
  for (i = 0; targets [i]; i++)
 
912
    {
 
913
      const gchar *target = targets [i];
 
914
 
 
915
      process = log_and_spawn (self, launcher, &error, GNU_MAKE_NAME, target, state->parallel, NULL);
 
916
 
 
917
      if (!process)
 
918
        {
 
919
          g_task_return_error (task, error);
 
920
          return FALSE;
 
921
        }
 
922
 
 
923
      ide_build_result_log_subprocess (IDE_BUILD_RESULT (self), process);
 
924
 
 
925
      if (!g_subprocess_wait_check (process, cancellable, &error))
 
926
        {
 
927
          g_task_return_error (task, error);
 
928
          return FALSE;
 
929
        }
 
930
    }
 
931
 
 
932
  return TRUE;
 
933
}