[gnome-builder/wip/chergert/pipeline-merge: 42/78] makecache: require makecache file for creation



commit 334c58406da16fa6785af94283532efe254c823a
Author: Christian Hergert <chergert redhat com>
Date:   Fri Feb 3 14:00:55 2017 -0800

    makecache: require makecache file for creation
    
    We no longer want IdeMakecache to be in charge of executing the
    make -p -n -s process since that should be done anytime the configuration
    changes (and therefore belongs in the build pipeline). This simply allows
    us to create a new IdeMakecache from a makecache file on disk. We still
    use the runtime to perform various other make commands (like determining
    what needs to be rebuilt if a file changes).

 plugins/autotools/ide-makecache.c |  472 +++++++------------------------------
 plugins/autotools/ide-makecache.h |   63 +++---
 2 files changed, 113 insertions(+), 422 deletions(-)
---
diff --git a/plugins/autotools/ide-makecache.c b/plugins/autotools/ide-makecache.c
index b836714..44774c5 100644
--- a/plugins/autotools/ide-makecache.c
+++ b/plugins/autotools/ide-makecache.c
@@ -48,7 +48,6 @@ struct _IdeMakecache
 {
   IdeObject     parent_instance;
 
-  GFile        *makefile;
   GFile        *parent;
   GMappedFile  *mapped;
   EggTaskCache *file_targets_cache;
@@ -76,14 +75,6 @@ G_DEFINE_TYPE (IdeMakecache, ide_makecache, IDE_TYPE_OBJECT)
 
 EGG_DEFINE_COUNTER (instances, "IdeMakecache", "Instances", "The number of IdeMakecache")
 
-enum {
-  PROP_0,
-  PROP_MAKEFILE,
-  LAST_PROP
-};
-
-static GParamSpec *properties [LAST_PROP];
-
 static void
 file_flags_lookup_free (gpointer data)
 {
@@ -344,292 +335,6 @@ ide_makecache_validate_mapped_file (GMappedFile  *mapped,
   IDE_RETURN (TRUE);
 }
 
-static int
-ide_makecache_open_temp (IdeMakecache  *self,
-                         gchar        **name_used,
-                         GError       **error)
-{
-  IdeContext *context;
-  IdeProject *project;
-  const gchar *project_id;
-  g_autofree gchar *name = NULL;
-  g_autofree gchar *path = NULL;
-  g_autofree gchar *directory = NULL;
-  time_t now;
-  int fd;
-
-  IDE_ENTRY;
-
-  g_assert (IDE_IS_MAKECACHE (self));
-  g_assert (name_used);
-  g_assert (error);
-  g_assert (!*error);
-
-  context = ide_object_get_context (IDE_OBJECT (self));
-  project = ide_context_get_project (context);
-  project_id = ide_project_get_id (project);
-
-  directory = g_build_filename (g_get_user_cache_dir (),
-                                ide_get_program_name (),
-                                "makecache",
-                                NULL);
-
-  g_debug ("Using \"%s\" for makecache directory", directory);
-
-  if (g_mkdir_with_parents (directory, 0700) != 0)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   g_io_error_from_errno (errno),
-                   "Failed to create makecache directory");
-      IDE_RETURN (-1);
-    }
-
-  now = time (NULL);
-  name = g_strdup_printf ("%s.makecache.tmp-%u", project_id, (guint)now);
-  path = g_build_filename (directory, name, NULL);
-
-  g_debug ("Creating temporary makecache at \"%s\"", path);
-
-  fd = g_open (path, O_CREAT|O_RDWR, 0600);
-
-  if (fd == -1)
-    {
-      *name_used = NULL;
-      g_set_error (error,
-                   G_IO_ERROR,
-                   g_io_error_from_errno (errno),
-                   "Failed to open temporary file: %s",
-                   g_strerror (errno));
-      IDE_RETURN (-1);
-    }
-
-  *name_used = g_strdup (path);
-
-  IDE_RETURN (fd);
-}
-
-static void
-ide_makecache_new_worker (GTask        *task,
-                          gpointer      source_object,
-                          gpointer      task_data,
-                          GCancellable *cancellable)
-{
-  IdeMakecache *self = source_object;
-  IdeRuntime *runtime = task_data;
-  IdeContext *context;
-  IdeProject *project;
-  const gchar *project_id;
-  g_autofree gchar *name_used = NULL;
-  g_autofree gchar *name = NULL;
-  g_autofree gchar *cache_path = NULL;
-  g_autoptr(GFile) parent = NULL;
-  g_autofree gchar *workdir = NULL;
-  g_autoptr(GMappedFile) mapped = NULL;
-  g_autoptr(IdeSubprocessLauncher) launcher = NULL;
-  g_autoptr(IdeSubprocess) subprocess = NULL;
-  GError *error = NULL;
-  int fdcopy;
-  int fd;
-
-  IDE_ENTRY;
-
-  g_assert (G_IS_TASK (task));
-  g_assert (IDE_IS_MAKECACHE (self));
-  g_assert (IDE_IS_RUNTIME (runtime));
-
-  if (!self->makefile || !(parent = g_file_get_parent (self->makefile)))
-    {
-      g_task_return_new_error (task,
-                               G_IO_ERROR,
-                               G_IO_ERROR_INVALID_FILENAME,
-                               "No makefile was specified.");
-      IDE_EXIT;
-    }
-
-  workdir = g_file_get_path (parent);
-
-  if (!workdir)
-    {
-      g_task_return_new_error (task,
-                               G_IO_ERROR,
-                               G_IO_ERROR_INVALID_FILENAME,
-                               "Makefile must be accessable on local filesystem.");
-      IDE_EXIT;
-    }
-
-  /*
-   * If the runtime has a "gmake" instead of "make", we want to prefer that
-   * since we know it is GNU make.
-   */
-  if (ide_runtime_contains_program_in_path (runtime, "gmake", cancellable))
-    self->make_name = "gmake";
-
-  context = ide_object_get_context (IDE_OBJECT (self));
-  project = ide_context_get_project (context);
-  project_id = ide_project_get_id (project);
-  name = g_strdup_printf ("%s.makecache", project_id);
-  cache_path = g_build_filename (g_get_user_cache_dir (),
-                                 ide_get_program_name (),
-                                 "makecache",
-                                 name,
-                                 NULL);
-
- /*
-  * NOTE:
-  *
-  * The makecache file is a file that contains all of the output from `make -p -n -s` on an
-  * automake project. This contains everything we need to determine what make targets a file
-  * "belongs to".
-  *
-  * The process is as follows.
-  *
-  * 1) Open a new temporary file to contain the output. This needs to be in the same directory
-  *    as the target so that we can rename() it into place.
-  * 2) dup() the fd to pass to the child process.
-  * 3) Spawn `make -p -n -s` using the temporary file as stdout.
-  * 4) Wait for the subprocess to complete. It would be nice if we could do this asynchronously,
-  *    but we'd need to break this whole thing into more tasks.
-  * 5) Move the temporary file into position at ~/.cache/<prgname>/<project>.makecache
-  * 6) mmap() the cache file using g_mapped_file_new_from_fd().
-  * 7) Close the fd. This does NOT cause the mmap() region to be unmapped.
-  * 8) Validate the mmap() contents with g_utf8_validate().
-  */
-
-  /*
-   * Step 1, open our temporary file.
-   */
-  fd = ide_makecache_open_temp (self, &name_used, &error);
-
-  if (fd == -1)
-    {
-      g_assert (error != NULL);
-      g_task_return_error (task, error);
-      IDE_EXIT;
-    }
-
-  /*
-   * Step 2, make an extra fd to be passed to the child process.
-   */
-  if (-1 == (fdcopy = dup (fd)))
-    {
-      g_task_return_new_error (task,
-                               G_IO_ERROR,
-                               g_io_error_from_errno (errno),
-                               "Failed to open temporary file: %s",
-                               g_strerror (errno));
-      close (fd);
-      IDE_EXIT;
-    }
-
-  /*
-   * Step 3,
-   *
-   * Spawn `make -p -n -s` in the directory containing our makefile.
-   */
-  launcher = ide_runtime_create_launcher (runtime, &error);
-
-  if (launcher == NULL)
-    {
-      g_task_return_error (task, error);
-      close (fdcopy);
-      close (fd);
-      IDE_EXIT;
-    }
-
-  ide_subprocess_launcher_push_argv (launcher, self->make_name);
-  ide_subprocess_launcher_push_argv (launcher, "-p");
-  ide_subprocess_launcher_push_argv (launcher, "-n");
-  ide_subprocess_launcher_push_argv (launcher, "-s");
-  ide_subprocess_launcher_set_cwd (launcher, workdir);
-
-  ide_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDERR_SILENCE);
-  ide_subprocess_launcher_take_stdout_fd (launcher, fdcopy);
-  fdcopy = -1;
-
-  subprocess = ide_subprocess_launcher_spawn (launcher, cancellable, &error);
-
-  if (subprocess == NULL)
-    {
-      g_assert (error != NULL);
-      g_task_return_error (task, error);
-      close (fd);
-      IDE_EXIT;
-    }
-
-  /*
-   * Step 4, wait for the subprocess to complete.
-   */
-  IDE_TRACE_MSG ("waiting for process to exit");
-
-  if (!ide_subprocess_wait (subprocess, cancellable, &error))
-    {
-      g_assert (error != NULL);
-      g_task_return_error (task, error);
-      close (fd);
-      IDE_EXIT;
-    }
-
-  /*
-   * Step 5, move the file into location at the cache path.
-   *
-   * TODO:
-   *
-   * If we can switch to O_TMPFILE and use renameat2(), that would be neat. I'm not sure that is
-   * possible though since the O_TMPFILE will not have a filename associated with it.
-   */
-  if (0 != g_rename (name_used, cache_path))
-    {
-      g_task_return_new_error (task,
-                               G_IO_ERROR,
-                               g_io_error_from_errno (errno),
-                               "Failed to move makecache into target directory: %s",
-                               g_strerror (errno));
-      close (fd);
-      IDE_EXIT;
-    }
-
-  /*
-   * Step 6, map the makecache file into memory.
-   */
-  lseek (fd, 0, SEEK_SET);
-  mapped = g_mapped_file_new_from_fd (fd, FALSE, &error);
-
-  if (mapped == NULL)
-    {
-      g_assert (error != NULL);
-      g_task_return_error (task, error);
-      close (fd);
-      IDE_EXIT;
-    }
-
-  /*
-   * Step 7, we are done with fd, so close it now. Note that this does not have an effect on the
-   * mmap() region.
-   */
-  close (fd);
-
-  /*
-   * Step 8, validate the contents of the mmap region.
-   */
-  if (!ide_makecache_validate_mapped_file (mapped, &error))
-    {
-      g_assert (error != NULL);
-      g_task_return_error (task, error);
-      IDE_EXIT;
-    }
-
-  /*
-   * Step 9, save the mmap and runtime for future use.
-   */
-  self->mapped = g_mapped_file_ref (mapped);
-  self->runtime = g_object_ref (runtime);
-
-  g_task_return_pointer (task, g_object_ref (self), g_object_unref);
-
-  IDE_EXIT;
-}
-
 static void
 ide_makecache_parse_c_cxx_include (IdeMakecache *self,
                                    GPtrArray    *ret,
@@ -1064,27 +769,6 @@ ide_makecache_get_file_flags_worker (GTask        *task,
   IDE_EXIT;
 }
 
-static void
-ide_makecache_set_makefile (IdeMakecache *self,
-                            GFile        *makefile)
-{
-  g_autoptr(GFile) parent = NULL;
-
-  g_return_if_fail (IDE_IS_MAKECACHE (self));
-  g_return_if_fail (G_IS_FILE (makefile));
-
-  parent = g_file_get_parent (makefile);
-
-  if (!parent)
-    {
-      g_warning (_("Invalid makefile provided, ignoring."));
-      return;
-    }
-
-  g_set_object (&self->makefile, makefile);
-  g_set_object (&self->parent, parent);
-}
-
 static gchar *
 replace_suffix (const gchar *str,
                 const gchar *replace)
@@ -1336,11 +1020,12 @@ ide_makecache_finalize (GObject *object)
 {
   IdeMakecache *self = (IdeMakecache *)object;
 
-  g_clear_object (&self->makefile);
-  g_clear_pointer (&self->mapped, g_mapped_file_unref);
   g_clear_object (&self->file_targets_cache);
   g_clear_object (&self->file_flags_cache);
   g_clear_object (&self->runtime);
+  g_clear_object (&self->parent);
+
+  g_clear_pointer (&self->mapped, g_mapped_file_unref);
   g_clear_pointer (&self->build_targets, g_ptr_array_unref);
 
   G_OBJECT_CLASS (ide_makecache_parent_class)->finalize (object);
@@ -1349,60 +1034,11 @@ ide_makecache_finalize (GObject *object)
 }
 
 static void
-ide_makecache_get_property (GObject    *object,
-                            guint       prop_id,
-                            GValue     *value,
-                            GParamSpec *pspec)
-{
-  IdeMakecache *self = IDE_MAKECACHE (object);
-
-  switch (prop_id)
-    {
-    case PROP_MAKEFILE:
-      g_value_set_object (value, ide_makecache_get_makefile (self));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
-}
-
-static void
-ide_makecache_set_property (GObject      *object,
-                            guint         prop_id,
-                            const GValue *value,
-                            GParamSpec   *pspec)
-{
-  IdeMakecache *self = IDE_MAKECACHE (object);
-
-  switch (prop_id)
-    {
-    case PROP_MAKEFILE:
-      ide_makecache_set_makefile (self, g_value_get_object (value));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
-}
-
-static void
 ide_makecache_class_init (IdeMakecacheClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
   object_class->finalize = ide_makecache_finalize;
-  object_class->get_property = ide_makecache_get_property;
-  object_class->set_property = ide_makecache_set_property;
-
-  properties [PROP_MAKEFILE] =
-    g_param_spec_object ("makefile",
-                         "Makefile",
-                         "The root makefile to be cached.",
-                         G_TYPE_FILE,
-                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_properties (object_class, LAST_PROP, properties);
 }
 
 static void
@@ -1439,57 +1075,113 @@ ide_makecache_init (IdeMakecache *self)
   egg_task_cache_set_name (self->file_flags_cache, "makecache: file-flags-cache");
 }
 
-GFile *
-ide_makecache_get_makefile (IdeMakecache *self)
+static void
+ide_makecache_validate_worker (GTask        *task,
+                               gpointer      source_object,
+                               gpointer      task_data,
+                               GCancellable *cancellable)
 {
-  g_return_val_if_fail (IDE_IS_MAKECACHE (self), NULL);
+  IdeMakecache *self = task_data;
+  g_autoptr(GError) error = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAKECACHE (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  if (!ide_makecache_validate_mapped_file (self->mapped, &error))
+    g_task_return_error (task, g_steal_pointer (&error));
+  else
+    g_task_return_pointer (task, g_object_ref (self), g_object_unref);
 
-  return self->makefile;
+  IDE_EXIT;
 }
 
 void
-ide_makecache_new_for_makefile_async (IdeRuntime          *runtime,
-                                      GFile               *makefile,
-                                      GCancellable        *cancellable,
-                                      GAsyncReadyCallback  callback,
-                                      gpointer             user_data)
+ide_makecache_new_for_cache_file_async (IdeRuntime          *runtime,
+                                        GFile               *cache_file,
+                                        GCancellable        *cancellable,
+                                        GAsyncReadyCallback  callback,
+                                        gpointer             user_data)
 {
   g_autoptr(GTask) task = NULL;
   g_autoptr(IdeMakecache) self = NULL;
+  g_autoptr(GFile) parent = NULL;
+  g_autoptr(GMappedFile) mapped = NULL;
+  g_autoptr(GError) error = NULL;
+  g_autofree gchar *cache_path = NULL;
   IdeContext *context;
 
   IDE_ENTRY;
 
   g_return_if_fail (IDE_IS_RUNTIME (runtime));
-  g_return_if_fail (G_IS_FILE (makefile));
+  g_return_if_fail (G_IS_FILE (cache_file));
   g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-#ifdef IDE_ENABLE_TRACE
-  {
-    g_autofree gchar *path = g_file_get_path (makefile);
-    IDE_TRACE_MSG ("Generating makecache for %s", path);
-  }
-#endif
+  task = g_task_new (NULL, cancellable, callback, user_data);
+  g_task_set_source_tag (task, ide_makecache_new_for_cache_file_async);
+
+  if (!g_file_is_native (cache_file))
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_INVALID_FILENAME,
+                               "Makecache files must be on a native filesystem");
+      IDE_EXIT;
+    }
+
+  cache_path = g_file_get_path (cache_file);
+
+  if (cache_path == NULL)
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_INVALID_FILENAME,
+                               "Makecache files must be on a native filesystem");
+      IDE_EXIT;
+    }
+
+  parent = g_file_get_parent (cache_file);
+
+  if (parent == NULL)
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_INVALID_FILENAME,
+                               "Makecache cannot be /");
+      IDE_EXIT;
+    }
 
   context = ide_object_get_context (IDE_OBJECT (runtime));
 
   self = g_object_new (IDE_TYPE_MAKECACHE,
                        "context", context,
-                       "makefile", makefile,
                        NULL);
 
-  task = g_task_new (self, cancellable, callback, user_data);
-  g_task_set_source_tag (task, ide_makecache_new_for_makefile_async);
-  g_task_set_task_data (task, g_object_ref (runtime), g_object_unref);
+  mapped = g_mapped_file_new (cache_path, FALSE, &error);
 
-  ide_thread_pool_push_task (IDE_THREAD_POOL_COMPILER, task, ide_makecache_new_worker);
+  if (mapped == NULL)
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      IDE_EXIT;
+    }
+
+  self->parent = g_steal_pointer (&parent);
+  self->mapped = g_steal_pointer (&mapped);
+  self->runtime = g_object_ref (runtime);
+
+  if (ide_runtime_contains_program_in_path (runtime, "gmake", NULL))
+    self->make_name = "gmake";
+
+  g_task_set_task_data (task, g_steal_pointer (&self), g_object_unref);
+  g_task_run_in_thread (task, ide_makecache_validate_worker);
 
   IDE_EXIT;
 }
 
 IdeMakecache *
-ide_makecache_new_for_makefile_finish (GAsyncResult  *result,
-                                       GError       **error)
+ide_makecache_new_for_cache_file_finish (GAsyncResult  *result,
+                                         GError       **error)
 {
   GTask *task = (GTask *)result;
   IdeMakecache *ret;
diff --git a/plugins/autotools/ide-makecache.h b/plugins/autotools/ide-makecache.h
index d069b48..151d138 100644
--- a/plugins/autotools/ide-makecache.h
+++ b/plugins/autotools/ide-makecache.h
@@ -29,38 +29,37 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeMakecache, ide_makecache, IDE, MAKECACHE, IdeObject)
 
-void                 ide_makecache_new_for_makefile_async   (IdeRuntime           *runtime,
-                                                             GFile                *makefile,
-                                                             GCancellable         *cancellable,
-                                                             GAsyncReadyCallback   callback,
-                                                             gpointer              user_data);
-IdeMakecache        *ide_makecache_new_for_makefile_finish  (GAsyncResult         *result,
-                                                             GError              **error);
-GFile               *ide_makecache_get_makefile             (IdeMakecache         *self);
-void                 ide_makecache_get_file_flags_async     (IdeMakecache         *self,
-                                                             GFile                *file,
-                                                             GCancellable         *cancellable,
-                                                             GAsyncReadyCallback   callback,
-                                                             gpointer              user_data);
-gchar              **ide_makecache_get_file_flags_finish    (IdeMakecache         *self,
-                                                             GAsyncResult         *result,
-                                                             GError              **error);
-void                 ide_makecache_get_file_targets_async   (IdeMakecache         *self,
-                                                             GFile                *file,
-                                                             GCancellable         *cancellable,
-                                                             GAsyncReadyCallback   callback,
-                                                             gpointer              user_data);
-GPtrArray           *ide_makecache_get_file_targets_finish  (IdeMakecache         *self,
-                                                             GAsyncResult         *result,
-                                                             GError              **error);
-void                 ide_makecache_get_build_targets_async  (IdeMakecache         *self,
-                                                             GFile                *build_dir,
-                                                             GCancellable         *cancellable,
-                                                             GAsyncReadyCallback   callback,
-                                                             gpointer              user_data);
-GPtrArray           *ide_makecache_get_build_targets_finish (IdeMakecache         *self,
-                                                             GAsyncResult         *result,
-                                                             GError              **error);
+void                 ide_makecache_new_for_cache_file_async  (IdeRuntime           *runtime,
+                                                              GFile                *cache_file,
+                                                              GCancellable         *cancellable,
+                                                              GAsyncReadyCallback   callback,
+                                                              gpointer              user_data);
+IdeMakecache        *ide_makecache_new_for_cache_file_finish (GAsyncResult         *result,
+                                                              GError              **error);
+void                 ide_makecache_get_file_flags_async      (IdeMakecache         *self,
+                                                              GFile                *file,
+                                                              GCancellable         *cancellable,
+                                                              GAsyncReadyCallback   callback,
+                                                              gpointer              user_data);
+gchar              **ide_makecache_get_file_flags_finish     (IdeMakecache         *self,
+                                                              GAsyncResult         *result,
+                                                              GError              **error);
+void                 ide_makecache_get_file_targets_async    (IdeMakecache         *self,
+                                                              GFile                *file,
+                                                              GCancellable         *cancellable,
+                                                              GAsyncReadyCallback   callback,
+                                                              gpointer              user_data);
+GPtrArray           *ide_makecache_get_file_targets_finish   (IdeMakecache         *self,
+                                                              GAsyncResult         *result,
+                                                              GError              **error);
+void                 ide_makecache_get_build_targets_async   (IdeMakecache         *self,
+                                                              GFile                *build_dir,
+                                                              GCancellable         *cancellable,
+                                                              GAsyncReadyCallback   callback,
+                                                              gpointer              user_data);
+GPtrArray           *ide_makecache_get_build_targets_finish  (IdeMakecache         *self,
+                                                              GAsyncResult         *result,
+                                                              GError              **error);
 
 G_END_DECLS
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]