Commit 1ec1e221 authored by Christian Hergert's avatar Christian Hergert Committed by Matthew Leeds
Browse files

gcc: port to IdeBuildPipeline

This reduces the GCC diagnostics to simply register the regex for
extraction when the build pipeline executes. This means that we do not
need to many handlers for logs which should keep overhead low as we add
additional error formats (such as for vala).
parent 19516480
......@@ -7,8 +7,8 @@ plugin_LTLIBRARIES = libgcc-plugin.la
dist_plugin_DATA = gcc.plugin
libgcc_plugin_la_SOURCES = \
gbp-gcc-build-result-addin.c \
gbp-gcc-build-result-addin.h \
gbp-gcc-pipeline-addin.c \
gbp-gcc-pipeline-addin.h \
gbp-gcc-plugin.c
libgcc_plugin_la_CFLAGS = $(PLUGIN_CFLAGS)
......
/* gbp-gcc-build-result-addin.c
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "egg-signal-group.h"
#include "gbp-gcc-build-result-addin.h"
#define ERROR_FORMAT_REGEX \
"(?<filename>[a-zA-Z0-9\\-\\.\\/]+):" \
"(?<line>\\d+):" \
"(?<column>\\d+): " \
"(?<level>[\\w\\s]+): " \
"(?<message>.*)"
struct _GbpGccBuildResultAddin
{
IdeObject parent_instance;
EggSignalGroup *signals;
gchar *current_dir;
gchar *top_dir;
};
static void build_result_addin_iface_init (IdeBuildResultAddinInterface *iface);
G_DEFINE_TYPE_EXTENDED (GbpGccBuildResultAddin, gbp_gcc_build_result_addin, IDE_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_RESULT_ADDIN,
build_result_addin_iface_init))
static GRegex *errfmt;
static IdeDiagnosticSeverity
parse_severity (const gchar *str)
{
g_autofree gchar *lower = NULL;
if (str == NULL)
return IDE_DIAGNOSTIC_WARNING;
lower = g_utf8_strdown (str, -1);
if (strstr (lower, "fatal") != NULL)
return IDE_DIAGNOSTIC_FATAL;
if (strstr (lower, "error") != NULL)
return IDE_DIAGNOSTIC_ERROR;
if (strstr (lower, "warning") != NULL)
return IDE_DIAGNOSTIC_WARNING;
if (strstr (lower, "ignored") != NULL)
return IDE_DIAGNOSTIC_IGNORED;
if (strstr (lower, "deprecated") != NULL)
return IDE_DIAGNOSTIC_DEPRECATED;
if (strstr (lower, "note") != NULL)
return IDE_DIAGNOSTIC_NOTE;
return IDE_DIAGNOSTIC_WARNING;
}
static IdeDiagnostic *
create_diagnostic (GbpGccBuildResultAddin *self,
GMatchInfo *match_info)
{
g_autofree gchar *filename = NULL;
g_autofree gchar *line = NULL;
g_autofree gchar *column = NULL;
g_autofree gchar *message = NULL;
g_autofree gchar *level = NULL;
g_autoptr(IdeFile) file = NULL;
g_autoptr(IdeSourceLocation) location = NULL;
IdeDiagnostic *diagnostic;
IdeContext *context;
struct {
gint64 line;
gint64 column;
IdeDiagnosticSeverity severity;
} parsed;
g_assert (GBP_IS_GCC_BUILD_RESULT_ADDIN (self));
g_assert (match_info != NULL);
message = g_match_info_fetch_named (match_info, "message");
/* Ignore _FORTIFY_SOURCE warnings which require optimization */
if (message != NULL && (strncmp (message, "#warning _FORTIFY_SOURCE requires compiling with optimization", 61) == 0))
return NULL;
filename = g_match_info_fetch_named (match_info, "filename");
line = g_match_info_fetch_named (match_info, "line");
column = g_match_info_fetch_named (match_info, "column");
level = g_match_info_fetch_named (match_info, "level");
parsed.line = g_ascii_strtoll (line, NULL, 10);
if (parsed.line < 1 || parsed.line > G_MAXINT32)
return NULL;
parsed.line--;
parsed.column = g_ascii_strtoll (column, NULL, 10);
if (parsed.column < 1 || parsed.column > G_MAXINT32)
return NULL;
parsed.column--;
parsed.severity = parse_severity (level);
context = ide_object_get_context (IDE_OBJECT (self));
if (!g_path_is_absolute (filename) && self->current_dir != NULL)
{
const gchar *basedir = self->current_dir;
gchar *path;
if (g_str_has_prefix (basedir, self->top_dir))
{
basedir += strlen (self->top_dir);
if (*basedir == '/')
basedir++;
}
path = g_build_filename (basedir, filename, NULL);
g_free (filename);
filename = path;
}
if (!g_path_is_absolute (filename))
{
g_autoptr(GFile) child = NULL;
IdeVcs *vcs;
GFile *workdir;
gchar *path;
vcs = ide_context_get_vcs (context);
workdir = ide_vcs_get_working_directory (vcs);
child = g_file_get_child (workdir, filename);
path = g_file_get_path (child);
g_free (filename);
filename = path;
}
file = ide_file_new_for_path (context, filename);
location = ide_source_location_new (file, parsed.line, parsed.column, 0);
diagnostic = ide_diagnostic_new (parsed.severity, message, location);
return diagnostic;
}
static void
gbp_gcc_build_result_addin_log (GbpGccBuildResultAddin *self,
IdeBuildResultLog log,
const gchar *message,
IdeBuildResult *result)
{
GMatchInfo *match_info = NULL;
const gchar *enterdir;
g_assert (GBP_IS_GCC_BUILD_RESULT_ADDIN (self));
g_assert (IDE_IS_BUILD_RESULT (result));
#define ENTERING_DIRECTORY_BEGIN "Entering directory '"
#define ENTERING_DIRECTORY_END "'\n"
/*
* This expects LANG=C, which is defined in the autotools Builder.
* Not the most ideal decoupling of logic, but we don't have a whole
* lot to work with here.
*/
if (NULL != (enterdir = strstr (message, ENTERING_DIRECTORY_BEGIN)) &&
g_str_has_suffix (enterdir, ENTERING_DIRECTORY_END))
{
gssize len;
enterdir += IDE_LITERAL_LENGTH (ENTERING_DIRECTORY_BEGIN);
len = strlen (enterdir) - IDE_LITERAL_LENGTH (ENTERING_DIRECTORY_END);
if (len > 0)
{
g_free (self->current_dir);
self->current_dir = g_strndup (enterdir, len);
if (self->top_dir == NULL)
self->top_dir = g_strndup (enterdir, len);
}
}
if (g_regex_match (errfmt, message, 0, &match_info))
{
IdeDiagnostic *diagnostic;
if (NULL != (diagnostic = create_diagnostic (self, match_info)))
{
ide_build_result_emit_diagnostic (result, diagnostic);
ide_diagnostic_unref (diagnostic);
}
}
g_match_info_free (match_info);
#undef ENTERING_DIRECTORY_BEGIN
#undef ENTERING_DIRECTORY_END
}
static void
gbp_gcc_build_result_addin_class_init (GbpGccBuildResultAddinClass *klass)
{
errfmt = g_regex_new (ERROR_FORMAT_REGEX, G_REGEX_OPTIMIZE | G_REGEX_CASELESS, 0, NULL);
g_assert (errfmt != NULL);
}
static void
gbp_gcc_build_result_addin_init (GbpGccBuildResultAddin *self)
{
self->signals = egg_signal_group_new (IDE_TYPE_BUILD_RESULT);
egg_signal_group_connect_object (self->signals,
"log",
G_CALLBACK (gbp_gcc_build_result_addin_log),
self,
G_CONNECT_SWAPPED);
}
static void
gbp_gcc_build_result_addin_load (IdeBuildResultAddin *addin,
IdeBuildResult *result)
{
GbpGccBuildResultAddin *self = (GbpGccBuildResultAddin *)addin;
egg_signal_group_set_target (self->signals, result);
}
static void
gbp_gcc_build_result_addin_unload (IdeBuildResultAddin *addin,
IdeBuildResult *result)
{
GbpGccBuildResultAddin *self = (GbpGccBuildResultAddin *)addin;
egg_signal_group_set_target (self->signals, NULL);
g_clear_pointer (&self->current_dir, g_free);
g_clear_pointer (&self->top_dir, g_free);
}
static void
build_result_addin_iface_init (IdeBuildResultAddinInterface *iface)
{
iface->load = gbp_gcc_build_result_addin_load;
iface->unload = gbp_gcc_build_result_addin_unload;
}
/* gbp-gcc-pipeline-addin.c
*
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#define G_LOG_DOMAIN "gbp-gcc-pipeline-addin"
#include "gbp-gcc-pipeline-addin.h"
#define ERROR_FORMAT_REGEX \
"(?<filename>[a-zA-Z0-9\\-\\.\\/]+):" \
"(?<line>\\d+):" \
"(?<column>\\d+): " \
"(?<level>[\\w\\s]+): " \
"(?<message>.*)"
struct _GbpGccPipelineAddin
{
IdeObject parent_instance;
guint error_format_id;
};
static void
gbp_gcc_pipeline_addin_load (IdeBuildPipelineAddin *addin,
IdeBuildPipeline *pipeline)
{
GbpGccPipelineAddin *self = (GbpGccPipelineAddin *)addin;
g_assert (GBP_IS_GCC_PIPELINE_ADDIN (self));
g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
self->error_format_id = ide_build_pipeline_add_error_format (pipeline,
ERROR_FORMAT_REGEX,
G_REGEX_CASELESS);
}
static void
gbp_gcc_pipeline_addin_unload (IdeBuildPipelineAddin *addin,
IdeBuildPipeline *pipeline)
{
GbpGccPipelineAddin *self = (GbpGccPipelineAddin *)addin;
g_assert (GBP_IS_GCC_PIPELINE_ADDIN (self));
g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
ide_build_pipeline_remove_error_format (pipeline, self->error_format_id);
self->error_format_id = 0;
}
static void
addin_iface_init (IdeBuildPipelineAddinInterface *iface)
{
iface->load = gbp_gcc_pipeline_addin_load;
iface->unload = gbp_gcc_pipeline_addin_unload;
}
G_DEFINE_TYPE_WITH_CODE (GbpGccPipelineAddin, gbp_gcc_pipeline_addin, IDE_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_PIPELINE_ADDIN, addin_iface_init))
static void gbp_gcc_pipeline_addin_class_init (GbpGccPipelineAddinClass *klass) { }
static void gbp_gcc_pipeline_addin_init (GbpGccPipelineAddin *self) { }
/* gbp-gcc-build-result-addin.h
/* gbp-gcc-pipeline-addin.h
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* 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
......@@ -16,17 +16,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GBP_GCC_BUILD_RESULT_ADDIN_H
#define GBP_GCC_BUILD_RESULT_ADDIN_H
#ifndef GBP_GCC_PIPELINE_ADDIN_H
#define GBP_GCC_PIPELINE_ADDIN_H
#include <ide.h>
G_BEGIN_DECLS
#define GBP_TYPE_GCC_BUILD_RESULT_ADDIN (gbp_gcc_build_result_addin_get_type())
#define GBP_TYPE_GCC_PIPELINE_ADDIN (gbp_gcc_pipeline_addin_get_type())
G_DECLARE_FINAL_TYPE (GbpGccBuildResultAddin, gbp_gcc_build_result_addin, GBP, GCC_BUILD_RESULT_ADDIN, IdeObject)
G_DECLARE_FINAL_TYPE (GbpGccPipelineAddin, gbp_gcc_pipeline_addin, GBP, GCC_PIPELINE_ADDIN, IdeObject)
G_END_DECLS
#endif /* GBP_GCC_BUILD_RESULT_ADDIN_H */
#endif /* GBP_GCC_PIPELINE_ADDIN_H */
......@@ -19,12 +19,10 @@
#include <ide.h>
#include <libpeas/peas.h>
#include "gbp-gcc-build-result-addin.h"
#include "gbp-gcc-pipeline-addin.h"
void
peas_register_types (PeasObjectModule *module)
{
peas_object_module_register_extension_type (module,
IDE_TYPE_BUILD_RESULT_ADDIN,
GBP_TYPE_GCC_BUILD_RESULT_ADDIN);
peas_object_module_register_extension_type (module, IDE_TYPE_BUILD_PIPELINE_ADDIN, GBP_TYPE_GCC_PIPELINE_ADDIN);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment