public inbox for libabigail@sourceware.org
 help / color / mirror / Atom feed
* [Bug default/19082] Make abipkgdiff recognize suppression specifications to apply to comparisons
  2015-01-01  0:00 [Bug default/19082] New: Make abipkgdiff recognize suppression specifications to apply to comparisons dodji at redhat dot com
                   ` (2 preceding siblings ...)
  2015-01-01  0:00 ` ooprala at redhat dot com
@ 2015-01-01  0:00 ` ooprala at redhat dot com
  2015-01-01  0:00 ` ooprala at redhat dot com
  4 siblings, 0 replies; 9+ messages in thread
From: ooprala at redhat dot com @ 2015-01-01  0:00 UTC (permalink / raw)
  To: libabigail

https://sourceware.org/bugzilla/show_bug.cgi?id=19082

Ondrej Oprala <ooprala at redhat dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|ASSIGNED                    |RESOLVED
         Resolution|---                         |FIXED

--- Comment #3 from Ondrej Oprala <ooprala at redhat dot com> ---
This RFE is resolved by upstream commit b2a5bf6.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug default/19082] Make abipkgdiff recognize suppression specifications to apply to comparisons
  2015-01-01  0:00 [Bug default/19082] New: Make abipkgdiff recognize suppression specifications to apply to comparisons dodji at redhat dot com
                   ` (3 preceding siblings ...)
  2015-01-01  0:00 ` ooprala at redhat dot com
@ 2015-01-01  0:00 ` ooprala at redhat dot com
  4 siblings, 0 replies; 9+ messages in thread
From: ooprala at redhat dot com @ 2015-01-01  0:00 UTC (permalink / raw)
  To: libabigail

https://sourceware.org/bugzilla/show_bug.cgi?id=19082

--- Comment #2 from Ondrej Oprala <ooprala at redhat dot com> ---
Hey, here's my take on this issue.
I went a little nuts with testing, but I guess it can't hurt ;).

minor patch comment:
I realize taking suppression_paths out of opts isn't very forward-looking
if we're gonna roll in with pthreads soon, but it makes sense for this patch
and I didn't want to feed every function with every single local object 
(yet).

On 07.10.2015 11:54, dodji at redhat dot com wrote:
> https://sourceware.org/bugzilla/show_bug.cgi?id=19082
>
>              Bug ID: 19082
>             Summary: Make abipkgdiff recognize suppression specifications
>                      to apply to comparisons
>             Product: libabigail
>             Version: unspecified
>              Status: NEW
>            Severity: enhancement
>            Priority: P2
>           Component: default
>            Assignee: dodji at redhat dot com
>            Reporter: dodji at redhat dot com
>                  CC: libabigail at sourceware dot org
>    Target Milestone: ---
>
> When abipkgdiff encounters files with the name pattern *.abignore inside the
> package it's analyzing, it should consider that as a suppression specification
> and apply it to all the comparisons that happens inside that package.
>

Thanks,
   Ondrej

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug default/19082] New: Make abipkgdiff recognize suppression specifications to apply to comparisons
@ 2015-01-01  0:00 dodji at redhat dot com
  2015-01-01  0:00 ` Ondrej Oprala
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: dodji at redhat dot com @ 2015-01-01  0:00 UTC (permalink / raw)
  To: libabigail

https://sourceware.org/bugzilla/show_bug.cgi?id=19082

            Bug ID: 19082
           Summary: Make abipkgdiff recognize suppression specifications
                    to apply to comparisons
           Product: libabigail
           Version: unspecified
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: default
          Assignee: dodji at redhat dot com
          Reporter: dodji at redhat dot com
                CC: libabigail at sourceware dot org
  Target Milestone: ---

When abipkgdiff encounters files with the name pattern *.abignore inside the
package it's analyzing, it should consider that as a suppression specification
and apply it to all the comparisons that happens inside that package.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug default/19082] Make abipkgdiff recognize suppression specifications to apply to comparisons
  2015-01-01  0:00 [Bug default/19082] New: Make abipkgdiff recognize suppression specifications to apply to comparisons dodji at redhat dot com
  2015-01-01  0:00 ` Ondrej Oprala
@ 2015-01-01  0:00 ` dodji at redhat dot com
  2015-01-01  0:00 ` ooprala at redhat dot com
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: dodji at redhat dot com @ 2015-01-01  0:00 UTC (permalink / raw)
  To: libabigail

https://sourceware.org/bugzilla/show_bug.cgi?id=19082

--- Comment #1 from dodji at redhat dot com ---
Note that the .abignore file to take in account is the one present in the
latest package of the two being compared.

If the first package has an .abignore file and not the second one, then the
.abignore file of the first package is ignored.

Note also that additional suppression specification files can be passed to the
command line of the tool.  They are going to be taken in account in *addition*
to the *.abignore file found in the second package.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Bug default/19082] New: Make abipkgdiff recognize suppression specifications to apply to comparisons
  2015-01-01  0:00 ` Ondrej Oprala
@ 2015-01-01  0:00   ` Dodji Seketeli
  2015-01-01  0:00     ` Ondrej Oprala
  0 siblings, 1 reply; 9+ messages in thread
From: Dodji Seketeli @ 2015-01-01  0:00 UTC (permalink / raw)
  To: Ondrej Oprala; +Cc: libabigail

Hi!

Thank you for the nice patch, it's really appreciated!

Please see my comments below.

> --- a/tools/abipkgdiff.cc

[...]

> +static vector<string> suppression_paths;

Rather than putting this here, I'd rather declare a (global) variable of
type (called, e.g, prog_options) pointer to the options type, right
before the main() and initialize that pointer in main(), right after
we've parsed the command line options.  That pointer to the options
would then be globally accessible to the walker functions, if need be.

I believe that could have some interesting consequences, which I talk
about below.

[...]

>  /// Abstract the result of comparing two packages.
>  ///
>  /// This contains the the paths of the set of added binaries, removed
> @@ -653,9 +660,9 @@ extract_package(const package& package)
>  ///
>  /// @param stat the stat struct of the file.
>  static int
> -file_tree_walker_callback_fn(const char *fpath,
> -			     const struct stat *,
> -			     int /*flag*/)
> +file_tree_walker_elf_callback_fn(const char *fpath,
> +				 const struct stat *,
> +				 int /*flag*/)

[...]

> +static int
> +file_tree_walker_suppr_callback_fn(const char *fpath,
> +				   const struct stat *,
> +				   int /*flag*/)
> +{

I would call the two functions above first_package_tree_walker_callback_fn and
second_package_tree_walker_callback_fn, because I think that really is
the intent of having two walker functions.  One is to walk the content
of the first package, and the other is to walk the content of the second
package.

In the second walking function:

> +  struct stat s;
> +  lstat(fpath, &s);
> +
> +  if (!S_ISLNK(s.st_mode))
> +    {
> +      if (guess_file_type(fpath) == abigail::tools_utils::FILE_TYPE_ELF)
> +	elf_file_paths.push_back(fpath);

> +      else if (string_ends_with(fpath, ".abignore"))
> +	suppression_paths.push_back(fpath);

... I would conditionalize the action of recognizing the suppression
specification here to prog_options->abignore

So that it would read something like:

    if (prog_options->abignore
        && string_ends_with(fpath, ".abignore"))
      prog_options->suppression_paths.push_back(fpath);

> +    }
> +  return 0;
> +}

[...]

@@ -696,8 +727,8 @@ set_diff_context_from_opts(diff_context_sptr ctxt,
      | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY);
 
>    suppressions_type supprs;
> -  for (vector<string>::const_iterator i = opts.suppression_paths.begin();
> -       i != opts.suppression_paths.end();
> +  for (vector<string>::const_iterator i = suppression_paths.begin();
> +       i != suppression_paths.end();
>         ++i)

This change would then become unnecessary.

[...]
 
> @@ -947,8 +979,14 @@ prepare_packages(package&	first_package,
>  		 package&	second_package,
>  		 const options& opts)
>  {
> -  if (!extract_package_and_map_its_content(first_package, opts)
> -      || !extract_package_and_map_its_content(second_package, opts))
> +  if (!extract_package_and_map_its_content(first_package, opts,
> +					   file_tree_walker_elf_callback_fn)
> +  /// We go through the files of the newer (second) pkg to look for suppression
> +  /// specifications, matching the "*.abignore" name pattern.
> +      || !extract_package_and_map_its_content(second_package, opts,
> +					      opts.abignore ?
> +					      file_tree_walker_suppr_callback_fn
> +					      : file_tree_walker_elf_callback_fn))

Here, the change would then look like:

> +  if (!extract_package_and_map_its_content(first_package, opts,
> +					   first_package_tree_walker_callback_fn)
> +      || !extract_package_and_map_its_content(second_package, opts,
> +					      second_package_tree_walker_callback_fn))

which I think is simpler because there is no condition any more.  The
condition happens at a lower logical level, where we really need to act
depending on that condition: take the suppression specification into
account, if the user asked for it.

[...]

> @@ -1142,13 +1180,15 @@ parse_command_line(int argc, char* argv[], options& opts)
>  	opts.fail_if_no_debug_info = true;
>        else if (!strcmp(argv[i], "--verbose"))
>  	verbose = true;
> +      else if (!strcmp(argv[i], "--no-abignore"))
> +	opts.abignore = false;
>        else if (!strcmp(argv[i], "--suppressions")
>  	       || !strcmp(argv[i], "--suppr"))
>  	{
>  	  int j = i + 1;
>  	  if (j >= argc)
>  	    return false;
> -	  opts.suppression_paths.push_back(argv[j]);
> +	  suppression_paths.push_back(argv[j]);

This change would then be unnecessary.

What do you think?

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug default/19082] Make abipkgdiff recognize suppression specifications to apply to comparisons
  2015-01-01  0:00 [Bug default/19082] New: Make abipkgdiff recognize suppression specifications to apply to comparisons dodji at redhat dot com
  2015-01-01  0:00 ` Ondrej Oprala
  2015-01-01  0:00 ` [Bug default/19082] " dodji at redhat dot com
@ 2015-01-01  0:00 ` ooprala at redhat dot com
  2015-01-01  0:00 ` ooprala at redhat dot com
  2015-01-01  0:00 ` ooprala at redhat dot com
  4 siblings, 0 replies; 9+ messages in thread
From: ooprala at redhat dot com @ 2015-01-01  0:00 UTC (permalink / raw)
  To: libabigail

https://sourceware.org/bugzilla/show_bug.cgi?id=19082

Ondrej Oprala <ooprala at redhat dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |ASSIGNED
                 CC|                            |ooprala at redhat dot com
           Assignee|dodji at redhat dot com            |ooprala at redhat dot com

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Bug default/19082] New: Make abipkgdiff recognize suppression specifications to apply to comparisons
  2015-01-01  0:00 [Bug default/19082] New: Make abipkgdiff recognize suppression specifications to apply to comparisons dodji at redhat dot com
@ 2015-01-01  0:00 ` Ondrej Oprala
  2015-01-01  0:00   ` Dodji Seketeli
  2015-01-01  0:00 ` [Bug default/19082] " dodji at redhat dot com
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Ondrej Oprala @ 2015-01-01  0:00 UTC (permalink / raw)
  To: dodji at redhat dot com, libabigail

[-- Attachment #1: Type: text/plain, Size: 1237 bytes --]

Hey, here's my take on this issue.
I went a little nuts with testing, but I guess it can't hurt ;).

minor patch comment:
I realize taking suppression_paths out of opts isn't very forward-looking
if we're gonna roll in with pthreads soon, but it makes sense for this patch
and I didn't want to feed every function with every single local object 
(yet).

On 07.10.2015 11:54, dodji at redhat dot com wrote:
> https://sourceware.org/bugzilla/show_bug.cgi?id=19082
>
>              Bug ID: 19082
>             Summary: Make abipkgdiff recognize suppression specifications
>                      to apply to comparisons
>             Product: libabigail
>             Version: unspecified
>              Status: NEW
>            Severity: enhancement
>            Priority: P2
>           Component: default
>            Assignee: dodji at redhat dot com
>            Reporter: dodji at redhat dot com
>                  CC: libabigail at sourceware dot org
>    Target Milestone: ---
>
> When abipkgdiff encounters files with the name pattern *.abignore inside the
> package it's analyzing, it should consider that as a suppression specification
> and apply it to all the comparisons that happens inside that package.
>

Thanks,
   Ondrej


[-- Attachment #2: 0001-Bug-19082-Recognize-suppression-spec-files.patch --]
[-- Type: text/x-patch, Size: 51665 bytes --]

From a9317b8c79305cb066f4c7c94b02065b2b197bf2 Mon Sep 17 00:00:00 2001
From: Ondrej Oprala <ooprala@redhat.com>
Date: Thu, 8 Oct 2015 10:43:20 +0200
Subject: [PATCH] Bug 19082 - Recognize suppression spec files

When abipkgdiff is invoked on a set of packages, the newer (second) one is also
inspected for files matching the pattern '*.abignore', whose contents are read
and interpreted as suppression specifications.

	* tests/data/Makefile.am: Add new test material to the build system.
	* tests/data/test-diff-pkg/dirpkg-{0-dir1,{1,2}-dir2}/dir.abignore:
	A test suppression specification.
	* tests/data/test-diff-pkg/dirpkg-{2,3}-dir2/.abignore: Likewise.
	* tests/data/test-diff-pkg/dirpkg-3.suppr: Likewise.
	* tests/data/test-diff-pkg/dirpkg-{1,2,3}-dir{1,2}/libobj-v0.so: New
	binary test inputs.
	* tests/data/test-diff-pkg/dirpkg-{1,2,3}-dir{1,2}/obj-v0.cc: New test
	source files
	* tests/data/test-diff-pkg/dirpkg-{1,2,3}-report-{0,1}.txt: New
	reference outputs
	* tests/test-diff-pkg.cc: Adjust to run the new tests.
	* tools/abipkgdiff.cc (file_tree_walker_callback_fn): Rename to
	file_tree_walker_elf_callback_fn.
	(file_tree_walker_suppr_callback_fn): Check for ELF files just
	like the previous function but additionally check for files
	ending with ".abignore".
	({create_maps_of_package,extract_package_and_map_its}_content):
	Add a callback as a new argument.
	(main) handle the new "--no-abignore" option, which turns off
	the search for suppression files within the new package.

Signed-off-by: Ondrej Oprala <ooprala@redhat.com>
---
 tests/data/Makefile.am                             |  28 +++++-
 .../data/test-diff-pkg/dirpkg-0-dir1/dir.abignore  |   4 +
 .../data/test-diff-pkg/dirpkg-1-dir1/libobj-v0.so  | Bin 0 -> 8951 bytes
 tests/data/test-diff-pkg/dirpkg-1-dir1/obj-v0.cc   |  15 ++++
 .../data/test-diff-pkg/dirpkg-1-dir2/dir.abignore  |   4 +
 .../data/test-diff-pkg/dirpkg-1-dir2/libobj-v0.so  | Bin 0 -> 8991 bytes
 tests/data/test-diff-pkg/dirpkg-1-dir2/obj-v0.cc   |  17 ++++
 tests/data/test-diff-pkg/dirpkg-1-report-0.txt     |   0
 tests/data/test-diff-pkg/dirpkg-1-report-1.txt     |  16 ++++
 .../data/test-diff-pkg/dirpkg-2-dir1/libobj-v0.so  | Bin 0 -> 9088 bytes
 tests/data/test-diff-pkg/dirpkg-2-dir1/obj-v0.cc   |  22 +++++
 tests/data/test-diff-pkg/dirpkg-2-dir2/.abignore   |   2 +
 .../data/test-diff-pkg/dirpkg-2-dir2/dir.abignore  |   2 +
 .../data/test-diff-pkg/dirpkg-2-dir2/libobj-v0.so  | Bin 0 -> 9136 bytes
 tests/data/test-diff-pkg/dirpkg-2-dir2/obj-v0.cc   |  25 ++++++
 tests/data/test-diff-pkg/dirpkg-2-report-0.txt     |   0
 tests/data/test-diff-pkg/dirpkg-2-report-1.txt     |  16 ++++
 .../data/test-diff-pkg/dirpkg-3-dir1/libobj-v0.so  | Bin 0 -> 9088 bytes
 tests/data/test-diff-pkg/dirpkg-3-dir1/obj-v0.cc   |  22 +++++
 tests/data/test-diff-pkg/dirpkg-3-dir2/.abignore   |   2 +
 .../data/test-diff-pkg/dirpkg-3-dir2/libobj-v0.so  | Bin 0 -> 9136 bytes
 tests/data/test-diff-pkg/dirpkg-3-dir2/obj-v0.cc   |  25 ++++++
 tests/data/test-diff-pkg/dirpkg-3-report-0.txt     |   0
 tests/data/test-diff-pkg/dirpkg-3-report-1.txt     |  16 ++++
 tests/data/test-diff-pkg/dirpkg-3.suppr            |   2 +
 tests/test-diff-pkg.cc                             |  94 ++++++++++++++++++++-
 tools/abipkgdiff.cc                                |  74 ++++++++++++----
 27 files changed, 364 insertions(+), 22 deletions(-)
 create mode 100644 tests/data/test-diff-pkg/dirpkg-0-dir1/dir.abignore
 create mode 100755 tests/data/test-diff-pkg/dirpkg-1-dir1/libobj-v0.so
 create mode 100644 tests/data/test-diff-pkg/dirpkg-1-dir1/obj-v0.cc
 create mode 100644 tests/data/test-diff-pkg/dirpkg-1-dir2/dir.abignore
 create mode 100755 tests/data/test-diff-pkg/dirpkg-1-dir2/libobj-v0.so
 create mode 100644 tests/data/test-diff-pkg/dirpkg-1-dir2/obj-v0.cc
 create mode 100644 tests/data/test-diff-pkg/dirpkg-1-report-0.txt
 create mode 100644 tests/data/test-diff-pkg/dirpkg-1-report-1.txt
 create mode 100755 tests/data/test-diff-pkg/dirpkg-2-dir1/libobj-v0.so
 create mode 100644 tests/data/test-diff-pkg/dirpkg-2-dir1/obj-v0.cc
 create mode 100644 tests/data/test-diff-pkg/dirpkg-2-dir2/.abignore
 create mode 100644 tests/data/test-diff-pkg/dirpkg-2-dir2/dir.abignore
 create mode 100755 tests/data/test-diff-pkg/dirpkg-2-dir2/libobj-v0.so
 create mode 100644 tests/data/test-diff-pkg/dirpkg-2-dir2/obj-v0.cc
 create mode 100644 tests/data/test-diff-pkg/dirpkg-2-report-0.txt
 create mode 100644 tests/data/test-diff-pkg/dirpkg-2-report-1.txt
 create mode 100755 tests/data/test-diff-pkg/dirpkg-3-dir1/libobj-v0.so
 create mode 100644 tests/data/test-diff-pkg/dirpkg-3-dir1/obj-v0.cc
 create mode 100644 tests/data/test-diff-pkg/dirpkg-3-dir2/.abignore
 create mode 100755 tests/data/test-diff-pkg/dirpkg-3-dir2/libobj-v0.so
 create mode 100644 tests/data/test-diff-pkg/dirpkg-3-dir2/obj-v0.cc
 create mode 100644 tests/data/test-diff-pkg/dirpkg-3-report-0.txt
 create mode 100644 tests/data/test-diff-pkg/dirpkg-3-report-1.txt
 create mode 100644 tests/data/test-diff-pkg/dirpkg-3.suppr

diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 73d02e1..967e225 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -892,11 +892,35 @@ test-diff-pkg/libsigc++-2.0-0c2a_2.4.0-1_amd64--libsigc++-2.0-0v5_2.4.1-1ubuntu2
 test-diff-pkg/libsigc++-2.0-0c2a_2.4.0-1_amd64.deb \
 test-diff-pkg/libsigc++-2.0-0v5-dbgsym_2.4.1-1ubuntu2_amd64.ddeb \
 test-diff-pkg/libsigc++-2.0-0v5_2.4.1-1ubuntu2_amd64.deb \
+test-diff-pkg/dirpkg-0-dir1/dir.abignore \
 test-diff-pkg/dirpkg-0-dir1/libobj-v0.so \
-test-diff-pkg/dirpkg-0-dir2/libobj-v0.so \
-test-diff-pkg/dirpkg-0-report-0.txt \
 test-diff-pkg/dirpkg-0-dir1/obj-v0.cc \
+test-diff-pkg/dirpkg-0-dir2/libobj-v0.so \
 test-diff-pkg/dirpkg-0-dir2/obj-v0.cc \
+test-diff-pkg/dirpkg-0-report-0.txt \
+test-diff-pkg/dirpkg-1-dir1/libobj-v0.so \
+test-diff-pkg/dirpkg-1-dir1/obj-v0.cc \
+test-diff-pkg/dirpkg-1-dir2/dir.abignore \
+test-diff-pkg/dirpkg-1-dir2/libobj-v0.so \
+test-diff-pkg/dirpkg-1-dir2/obj-v0.cc \
+test-diff-pkg/dirpkg-1-report-0.txt \
+test-diff-pkg/dirpkg-1-report-1.txt \
+test-diff-pkg/dirpkg-2-dir1/libobj-v0.so \
+test-diff-pkg/dirpkg-2-dir1/obj-v0.cc \
+test-diff-pkg/dirpkg-2-dir2/.abignore \
+test-diff-pkg/dirpkg-2-dir2/dir.abignore \
+test-diff-pkg/dirpkg-2-dir2/libobj-v0.so \
+test-diff-pkg/dirpkg-2-dir2/obj-v0.cc \
+test-diff-pkg/dirpkg-2-report-0.txt \
+test-diff-pkg/dirpkg-2-report-1.txt \
+test-diff-pkg/dirpkg-3-dir1/libobj-v0.so \
+test-diff-pkg/dirpkg-3-dir1/obj-v0.cc \
+test-diff-pkg/dirpkg-3-dir2/.abignore \
+test-diff-pkg/dirpkg-3-dir2/libobj-v0.so \
+test-diff-pkg/dirpkg-3-dir2/obj-v0.cc \
+test-diff-pkg/dirpkg-3-report-0.txt \
+test-diff-pkg/dirpkg-3-report-1.txt \
+test-diff-pkg/dirpkg-3.suppr \
 test-diff-pkg/tarpkg-0-dir1.tar \
 test-diff-pkg/tarpkg-0-dir1.ta \
 test-diff-pkg/tarpkg-0-dir1.tar.bz2 \
diff --git a/tests/data/test-diff-pkg/dirpkg-0-dir1/dir.abignore b/tests/data/test-diff-pkg/dirpkg-0-dir1/dir.abignore
new file mode 100644
index 0000000..d03917d
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-0-dir1/dir.abignore
@@ -0,0 +1,4 @@
+#taken from test5-fn-supprt-0.suppr
+[suppress_function]
+  # suppress change reports for a function which name is 'bar' ...
+  name = bar
diff --git a/tests/data/test-diff-pkg/dirpkg-1-dir1/libobj-v0.so b/tests/data/test-diff-pkg/dirpkg-1-dir1/libobj-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..7373521ef7c791bf631ef74c0fb45ba841aa46b4
GIT binary patch
literal 8951
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

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-pkg/dirpkg-1-dir1/obj-v0.cc b/tests/data/test-diff-pkg/dirpkg-1-dir1/obj-v0.cc
new file mode 100644
index 0000000..5a016dd
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-1-dir1/obj-v0.cc
@@ -0,0 +1,15 @@
+// Compile with:
+// g++ -g -shared -o libobj-v0.so obj-v0.cc
+
+struct S
+{
+  int mem0;
+
+  S()
+    : mem0()
+  {}
+};
+
+void
+bar(S&)
+{}
diff --git a/tests/data/test-diff-pkg/dirpkg-1-dir2/dir.abignore b/tests/data/test-diff-pkg/dirpkg-1-dir2/dir.abignore
new file mode 100644
index 0000000..d03917d
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-1-dir2/dir.abignore
@@ -0,0 +1,4 @@
+#taken from test5-fn-supprt-0.suppr
+[suppress_function]
+  # suppress change reports for a function which name is 'bar' ...
+  name = bar
diff --git a/tests/data/test-diff-pkg/dirpkg-1-dir2/libobj-v0.so b/tests/data/test-diff-pkg/dirpkg-1-dir2/libobj-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..0032f73fb7c5b6cfbcb254c896089d10962a826d
GIT binary patch
literal 8991
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
LH{X2At^L0N){!i+

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-pkg/dirpkg-1-dir2/obj-v0.cc b/tests/data/test-diff-pkg/dirpkg-1-dir2/obj-v0.cc
new file mode 100644
index 0000000..65f6bab
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-1-dir2/obj-v0.cc
@@ -0,0 +1,17 @@
+// Compile with:
+// g++ -g -shared -o libobj-v0.so obj-v0.cc
+
+struct S
+{
+  int  mem0;
+  char mem1;
+
+  S()
+    : mem0(),
+      mem1()
+  {}
+};
+
+void
+bar(S&)
+{}
diff --git a/tests/data/test-diff-pkg/dirpkg-1-report-0.txt b/tests/data/test-diff-pkg/dirpkg-1-report-0.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/data/test-diff-pkg/dirpkg-1-report-1.txt b/tests/data/test-diff-pkg/dirpkg-1-report-1.txt
new file mode 100644
index 0000000..c7c9226
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-1-report-1.txt
@@ -0,0 +1,16 @@
+================ changes of 'libobj-v0.so'===============
+  Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+  Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+  1 function with some indirect sub-type change:
+
+    [C]'function void bar(S&)' has some indirect sub-type changes:
+      parameter 1 of type 'S&' has sub-type changes:
+        in referenced type 'struct S':
+          type size changed from 32 to 64 bits
+          1 data member insertion:
+            'char S::mem1', at offset 32 (in bits)
+
+
+================ end of changes of 'libobj-v0.so'===============
+
diff --git a/tests/data/test-diff-pkg/dirpkg-2-dir1/libobj-v0.so b/tests/data/test-diff-pkg/dirpkg-2-dir1/libobj-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..327577dc2e9a41bf33616b98398b6dbb7c05e40d
GIT binary patch
literal 9088
zcmeHMYiwLc6`s56$2x1T?KlZ}6tYxKa7ev=G>J?TC+la{!AXnbh_(=J?(SZDx9r2+
zz3Vy^v{n;PLKP|Srw<h=AdreEs09g?@@Ps>)E|`y&{hWZho!3EKqV4TQ7DzockZ3D
zxjVb71_|-YW8Hh^d~+T%b7yDH96vfTKI+jl!Nn`~3*r`Q9V9Fp=C{ZSNLciVdc1?;
zqqeLRy(!?TJy-8AOa-*4kdHb%uQm}!G+07Ucx+ZABxOBfNpDH&ElEA5*T^smQ=h|%
z8c=#(mF+5RmvT%=mdZWvSaGV?$Z@EY<(abHXP`&@yw%bo1t+AxYV*=3=Yy#njy<+@
zu;ImX@W?Uo{?ASi7hZn7{}0#R{NBOuzc=&fYxjPdTu?g=h3Egw#r6i#9^OG%10Fw~
zm)`!ymxe~(cz5B!dvE*cx$A)swtwuwzx@7hfgcQCx(&@$ix(EoD~o~r1S@D5Rd8}p
zNxrWNJ^}o8JZkw3fEKYqbhiXcntpEM>qUoxUy|}FPTys1g>lW>xL^ELeq@?ADjV>u
z6^-JC^6?8c?iY)SywLUObT*^sEhA^?y3muEq$Ttz5TTDv9@gV#&YVu>Ei*THcqo<4
zn3F~{Wjbw@TlCnRK?aOe@?i)bn$;(yg`t#@&zpIn-+yP+$W8Pf?WXEfHj8SHNF}3r
zD<0dqGnCJU_7Iyc)}~`IJx`o17ISdjj2o7L5k&KOX8=MsGjVZnd~9$??+x{acGHv;
ziwCRD{YMSN{|J=Ve_?YH%g`fUms-3p@bCC}Ie%B=@1F4)i7zTR^9#*E+aie-w-nSD
zT{!(VxGcGF{!LTcH5cw)>Ni}t?22t_qg-e7`*QmYx^TCA<kY*q$m6yBYl0&3m5WyG
z679Q@Q@{4n0!3NbJ%Of`ZIgI6Zw;eHe1e*;F0P<#J48JF?5<t`8#&iM03dR%mdLTl
zjvJA)??g`B2+XdBn?E%;ZW@lSEKW6V9TwvFr70?*=B=m6CKUTMTYvZakcIv->A$k<
zjhwv}d1dK9M7tdM?XtBI#=a$uH9E!|ebwH4{|gWkg-=9I^*=<lW3Xp6!p%f|P%QPM
z%S#cwj$f`lgJ$g?<^B0M1S6*oh=Tv>7a-~M8~$6R|Epwj<;wA^VYE^`a`wwN&L6+z
zs$yI;&vII|E#AH8iM=;Ix4g2l5B0a88wdR}D2;^nRw~-V6GEG7(Y7?!`_5yQ+kw%Z
zm4IG12?Sb30~-%D`ycYnivyeYe)7(CdwU|8VLUUi=O?*=K+9J>Lrry~Fa(y`$=~Oy
zw4-UYtj@sd46M$;>I|&TK-mm%T*Pq@3vm2H0RffA9fGLKDNif>cNCstGb)V^DaQBm
z`c;f`H_3L6*Z8_fXB(Bx4iOx;(RoLO+uvJW$r8`^Hjb_4Wl+X3Qnw7E){rpDqWyO6
zEmYko`C=?5<1CK7>@ylNe4bNWM&%<85htW$#xK-34cyO*QjYFQRM;Pmf4l$lQXa>+
z&GS58ll%$U{x8WF`{|hbzrXq3tUA6d=iyCB4-O6873{#xaz}7?s3+7D?CtK^-My!$
zFW50*#)A>Va`4VwJH#C@=FGP<YkcRSyHTY=vA#1cK8<3dn)~pI;i;tP!KI}}vqij<
zkkRT$TGRm6Y<F}ctUW=PsH>?>W-L+f>jdM&6-U#W8gTOwTI-L2uz5Qk1Ft>v1m0`D
ziI?Z=3E{WZ8VPH_9Z6{GpG8%@@M+JyMoPacDovr*NEp0m+X8KVZ(vKHRa;x%f;Hx8
z)4V>v|1SStzt)C`vq^XZ#EiA|p%*nF?Z76lkAO^I-=;VuYHP(<+b;aN>e_|hzu)i0
z80(u+9Ydq9O|Uie(XCAW!W*9$+(cg1kPQ!3s=q}lHf{%k9`3{A5kcy!_U}Lw-gYVo
zi&hia=mVXz-JuwL2$Tj7PnWk<do28z#|vrw{v)_V4(%G5rKCe}Xy?ukT^+&Bv{lHM
z{nKW~%q3%Bja)3zKi9XXbI-0|=d?(h>28<vu0%F%c4f0OIU{9s<q}<mF5FCwXmZ*}
zrn)RMZ{@q_8fsTN<H@P1&Y3Sxcg2%Akj`EpxgPf|*LC+5q5R3TWkf-(oI?{_%VaGx
zG@U7gqJ?BC-kFRGn@bq^gb2k?W}xX%E9bP#nz?*3n<-&*wB^i{K?<@qld?p}zT<~1
za}IU;rXMmB`c%$Hn|dM+9p)TK-N@yPla3_UABaJWhE4WExvbq6Bb|)Fe->8p3fZo3
zH5Z{+Hk~%{LkPvqXki*QjLbCB0Fq5+rbypuibiwhEOV)3#^gFC##so}-&hgF{F+<J
zi#5jkdMWM|yq}liHG=p3QoL61{#lCG3Ep>0@p^GV?zg45uei^b;^p}(YWIpY;(56b
zmdYcaQxPxE|2TG<ih0CRI|0$b2ac=3E1HXWQ5TH<v=q<LQoL0xGzHy|UH2j*#c_bU
z(JR`JN3A5kPH?`YRDL}YHI?Kyl;zV%&s#iI-Bt+aQ&Yt`icoQm9#ov83>D|-;wDb#
zaE-XWauacCjUbvRpEv4>2iZ{d`-UVQ<bcF6BL*a{#$TTWt|2SPc}4066*?uf3g7V@
zaPrIX9LZ973XfJ{J-i6K(zvRP_gA)^fOu9}Z&z%*d>#N-wEvbZU%npxE^!_&=~G$8
zqg7akesol;unyM&UyFHAkK3)lgJe)Cp(^;GZKwSA7^xy3uYx}U{C34Bu}|Cf%k#S5
z1y1>Absk=jxSE&#iH(=%rGH`Dudpx0a#r3dAX67Z0`}0*gg!oYbP@^VoB3khO6xJo
z80Q5iid~Sd$Fur$DjPLYdfdw9^14x&6F4bmQl@3bLwi2ey9<^p2-(SL=O9A5*UFs~
z&e0Vwq|+y%;^ORVc8TcCs6y9ACk76W=p#plDerBMLDmnB-#s`muHQX6dURw`pBxw*
zA0Y`Oz>CuHd{$2wnK-4whwnQwaCmH}<dj#k>Xnk<|Fax>IPA`Ny8?`|%s6Mv?Es*{
zYWnXX+5zdO%=epW|JP#6>TyW>**|d?VSPTQnTDkz-&353o~;S|C(yZju|A*YOz*+^
zr9ys5hV}Ub2m>SAtUoUuF<nHPyGV0ID1sW@wOIdz93WFZ3Aq0($MhKV>F&n-ywqnJ
zl%5DC-`sx*+c{ev8(|luKGTa*ko~hhk3WNUQW=zTeE($1_f^uTJFlug2aNi~#}WVk
zjj4Ka%I-nKDR~gLKF2vs*+0v-$O_X(6n#D~nQl-%80)dU(~3U--;62Wvsqs4|JS5G
zf4^$~pRK0<q@vGp7*pz>yYT!o_H9%Gc=-Er{)7L2tIDhV524%a(&zlh6`5dB<yHPA
z=+YFke~$kaZc+bbMW5ru#aq;;i!QA__RsMo|9_tM5&mx6e_jV~DE>L_T%buo>2OH#
z&H7CLh!*$wi}9&+@L~FIL!WGM|M|S`koxS0JD@CQu_XO>vw)<me}{szKGW+`Ul9|N
z(!Xk#^@{QU$}lvZmih}tL8qe1HdfL9e5)f*>)Tya{moVMm!*E#t&F;=zg_C9<J`a2
zQT$~UeYQhx_}jTfKal!8EGQcl*6t7Q9d7+@nIJqP?{{0#*oBAJ1MlCoKUMPoqP)sn
JQXDF*_z%jLSP}pL

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-pkg/dirpkg-2-dir1/obj-v0.cc b/tests/data/test-diff-pkg/dirpkg-2-dir1/obj-v0.cc
new file mode 100644
index 0000000..206a265
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-2-dir1/obj-v0.cc
@@ -0,0 +1,22 @@
+// Compile with:
+// g++ -g -shared -o libobj-v0.so obj-v0.cc
+
+struct S0
+{
+  int mem0;
+
+  S0()
+    : mem0()
+  {}
+};
+
+struct S1
+{
+};
+void
+bar(S0&)
+{}
+
+void
+foo(S1&)
+{}
diff --git a/tests/data/test-diff-pkg/dirpkg-2-dir2/.abignore b/tests/data/test-diff-pkg/dirpkg-2-dir2/.abignore
new file mode 100644
index 0000000..b8f8197
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-2-dir2/.abignore
@@ -0,0 +1,2 @@
+[suppress_function]
+  name = foo
diff --git a/tests/data/test-diff-pkg/dirpkg-2-dir2/dir.abignore b/tests/data/test-diff-pkg/dirpkg-2-dir2/dir.abignore
new file mode 100644
index 0000000..c06dd56
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-2-dir2/dir.abignore
@@ -0,0 +1,2 @@
+[suppress_function]
+  name = bar
diff --git a/tests/data/test-diff-pkg/dirpkg-2-dir2/libobj-v0.so b/tests/data/test-diff-pkg/dirpkg-2-dir2/libobj-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..de46f91bef99b1871dc16acecf5e314b2f500df6
GIT binary patch
literal 9136
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

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-pkg/dirpkg-2-dir2/obj-v0.cc b/tests/data/test-diff-pkg/dirpkg-2-dir2/obj-v0.cc
new file mode 100644
index 0000000..b96530e
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-2-dir2/obj-v0.cc
@@ -0,0 +1,25 @@
+// Compile with:
+// g++ -g -shared -o libobj-v0.so obj-v0.cc
+
+struct S0
+{
+  int  mem0;
+  char mem1;
+
+  S0()
+    : mem0(),
+      mem1()
+  {}
+};
+
+struct S1
+{
+  int mem2;
+};
+void
+bar(S0&)
+{}
+
+void
+foo(S1&)
+{}
diff --git a/tests/data/test-diff-pkg/dirpkg-2-report-0.txt b/tests/data/test-diff-pkg/dirpkg-2-report-0.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/data/test-diff-pkg/dirpkg-2-report-1.txt b/tests/data/test-diff-pkg/dirpkg-2-report-1.txt
new file mode 100644
index 0000000..c7c9226
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-2-report-1.txt
@@ -0,0 +1,16 @@
+================ changes of 'libobj-v0.so'===============
+  Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+  Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+  1 function with some indirect sub-type change:
+
+    [C]'function void bar(S&)' has some indirect sub-type changes:
+      parameter 1 of type 'S&' has sub-type changes:
+        in referenced type 'struct S':
+          type size changed from 32 to 64 bits
+          1 data member insertion:
+            'char S::mem1', at offset 32 (in bits)
+
+
+================ end of changes of 'libobj-v0.so'===============
+
diff --git a/tests/data/test-diff-pkg/dirpkg-3-dir1/libobj-v0.so b/tests/data/test-diff-pkg/dirpkg-3-dir1/libobj-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..327577dc2e9a41bf33616b98398b6dbb7c05e40d
GIT binary patch
literal 9088
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
JQXDF*_z%jLSP}pL

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-pkg/dirpkg-3-dir1/obj-v0.cc b/tests/data/test-diff-pkg/dirpkg-3-dir1/obj-v0.cc
new file mode 100644
index 0000000..206a265
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-3-dir1/obj-v0.cc
@@ -0,0 +1,22 @@
+// Compile with:
+// g++ -g -shared -o libobj-v0.so obj-v0.cc
+
+struct S0
+{
+  int mem0;
+
+  S0()
+    : mem0()
+  {}
+};
+
+struct S1
+{
+};
+void
+bar(S0&)
+{}
+
+void
+foo(S1&)
+{}
diff --git a/tests/data/test-diff-pkg/dirpkg-3-dir2/.abignore b/tests/data/test-diff-pkg/dirpkg-3-dir2/.abignore
new file mode 100644
index 0000000..b8f8197
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-3-dir2/.abignore
@@ -0,0 +1,2 @@
+[suppress_function]
+  name = foo
diff --git a/tests/data/test-diff-pkg/dirpkg-3-dir2/libobj-v0.so b/tests/data/test-diff-pkg/dirpkg-3-dir2/libobj-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..de46f91bef99b1871dc16acecf5e314b2f500df6
GIT binary patch
literal 9136
zcmeHMU2I%O6`s4-zgc_j#7S_H7B7_(98#};ngr9tjelZi9XV-n96^iH>+9WX@0R^>
zckjA(MT^x0lu$)Vc>$_E1OyTf1*JS72vj7biYh@w5EMly50<Ke1C>aMs0>s#-??|r
z=I-pS5+uZv$GZ2-`R4r0%$=P%bNuC@(P5va2`;*LOc1wN=^}ly;legq0qGMxq8jg@
zc+ioRqIU&6wb!d%hN*xS74lJq=k0pphz1MjgwJ6`Oj6b(mh_gS-jdW~dYcTRFs*S}
zQ2|QN+p=Aytx}FD$x?aZJv&PE3ONpyvOH7P`z-XRpZ8lDrQn$KS8iT<<a{ud!*Ry8
z5jJ!@hmIZ>*IGV(v3`49?&5>KJBMGm+4j~4zq&>)sGWww^MCqMYprPQ+euh09zULo
z?|%JDgG2AUf8*KDKk(DDcLE>n`1rGb`Q6_FKR9^h0W_B_IxL)176bVSme4TE;N+l`
zd`}sC4ERHM)bbkujbgLtYz!7O{oKJfi8cklBIQ+_zRQLZ<63ZVzxb>C$TV+MHsjeK
z>cq10@pBID7mJF#FpTMBI%Q;SGh-WuFyg7WEsQA;VT_C)F``z+nvQ2}D>Hs%Fp*AK
z<K|?-a@$I`7?C-X448@d^AJ2dYm7+?g9$U6wX(u^>XAt^GuC~qld4ncG^$-95ueQ3
z(a5e{p=>&|m)K;!HXVr=S>hbAh>IIm)U-{EU^1I^2Otb96%~g@M+OFs?ofAV4^2tF
z_^|4{f7C$yk3f0-=eEYN41MDFQj7Nm{vBVC^LJhT?irtv_@aU{f1@GjSR}FhmV)}C
z2dCc#mn9F*ziDc_?ZLfEec6M{t~jQe<vOF^m)CF5gL~z}C*Q9Lzg*e7E-1oZxnx%^
z(Y_l#`Bn`rP?Xg@V`y64K8|-oOCM^)$EfMn;wsAa!^G3i?$&j%;j_K{0K#W0i5w5_
zTn?XkFMM)2FuMtE{#5I_sXei}IMvW{P>2&(rl^D(T27HoDE4ZO{+@q97Wylse|bd@
zpSc~rymTO}T@C+s#cqbNZ%bo!t}$0%wYSjw2E;_}li`!S&r$6-?Adj2GgciGOTFmw
zQW&ojS1V7WS^Il&e?9@h@W}%r=fCwdB;9_)|9a{F7MWbVe&SXiTB#mB^TP7E6IVP{
zjEm-3POG*}--n(!d*kaXtE>A_zX{za=$}DpB(%3u(Via@+FYZyt**M}9A>!{80}dx
z=yj4npm8|Re7M2?T+M<wuyx<39%*&9Cz3gcX9o8CB-bBk{HkxTzG@hTz*0N;`$Cy^
zG_94j8CaWvwHa8OfwdVZngNcBI1XX~j(;d1pz^Xy5OulbRfYeq!c%NUrOqY!_+DPW
z@^S7K+0OAAUl-|Yqq5Z{g5x$i@2GJ5KUP-L#Phw4W2*%jlyQvIDTAnWB#g4?yxn^X
zRhuQBkL6^X#j%%jMni_rbBfETe9R?cLON#re1+S<{k$aQ=&nSC{o(j``oAFMaf~}W
z&+~1`PssLvN<QCD*WCa8&G%;2@l`nwe~|Rh;NYXdHry<C2KR)zLS4b`&aOS3d%Jpq
zZDUq67&dJeZ{NLBJPc#*e7m#8cOJSMl`6{s-D#=OC^o8i60anlQi?uYT57Zk3(fjC
zURo7Zg&w1Nbpr2-3W#XV2YMQ8Wfm_a4Js<*DO*%)Rd0f;scFaChg(mD*6<3ddIT?R
zy<<z%;&vpojkNZ;3r@^NBCq`n?{$~)^1Tuhe#cH7VYRqN39b2;sH&Gj?X}ya^kH6U
z9<@5c;8NQjX!7fUZGrXLhU!MFLtm4o*ZBR9`uF*@CiJXc=mBCzntITSija0-i(W%O
zDzJY`6cUw{Vx(y|et}i3!tZ~~uVdP)Wi^1YHUJ%gT&-7?y!ADIV_*yUSVtCoSj+xK
zDO<M#2>Q1lk52@tr`o>*^>{nUA}ni7q$i(gpY04qXzEaEeLPwEM(w4(mwY;;ji-*{
znmM?8XqM6v!NFa-?zw(~?MXYAvU;bjl$D7`z?zvztaq+wZ~NZe!S-p9w33}3=U}@D
z>k=KYbkgcbr)M%|!tBVzI&vMj#hR1xX)~Vau&u0}?Vu~GQ*DpNr>5FxzBt_xjb}jG
zyMbi7y_e%i4C}yiLl&Xze9|^2LG6r7V_Zw6Z7VdL%7rF#@kF#e9u*E3GqW)fiq5B?
z=~6r6w#-_YY&@MRU<|Zntb|DlvNn^jMaW4CgluaLbtg3tvSP+m#!Om9ED9awTuH;s
zWXyS2lIzbzAVy;+`=LzQ>5G|+N8mpVt9XSRSGdcIP$Zp9TKKhuqSj<?8aB+-H1Y<L
zji;ta-))+l%viI`CE_WI>zEjKU6g%eedP0TULhSTj?aNYTo=6m7vdFy&xu03Qt*CT
zh*t^Trwj3FabE7vg?LT=Tqwkg^Ig=gi*@2crB~9e>&UKgUe(*G<8)Q?Mbxf~`h4E8
zP(C2q_<-^>=%OK?NA<w4)0jVZ3-R^hMt#r=IdvTwERGwzjk;(;-nEqcM#1@&LitTd
z?39w<T$Fz!Jw1O4d#w=8r>u%|)S==WZKya$B`VI*$X%Sy?Fw;c^)BMp>OeG6Ja5z!
zUy1J<l6a5<7}t#Gm$(|QeGa&WEF$M2sUK9P@MtBz<5}S3m*YQ@rSdI2T8Z`W6X2!B
zRc^d=oM|E;zOSse>keK#4}eSBzv;*quZIsL&f_J0Dl2%j66?^9j%p>=;YQ#aFc0d{
z+X6gD29**jgAX`%ihqycGV;+f_=~_FQhXBos$;)65Bxpgl&@Cj;SGtadF&rMcyS*4
zO~-zTeJPT$vvv-dy$BMvhX==u(UD{0NI2ikFB^8!h){+(D>$+2fea&>Hl`ElNi$(Y
z?Q|w<n7KKDgJLFO*;X{P_cPtQVY!5mlgxI{A*6@x%)D?<u4pcqoQH~sbF$wBqIY8q
z!x$dxKQd$t9X&{Sa%T*(erWXZf&NkB@!{cPL*vGH|G?-FNg!dKmyTxBM$Ak_DRqAE
z$)o*8Mh3knyPAbBl{EjK<>dSNycu$DGG5K3bB5hH|4Xc<{~n?pkbcT;d|v$juvW#S
zdK}Vz_95;rtk35((>|%s_Zq%8vDqF}D3)e@KF^sxf%Qv;{E`go^9j%gjBK<1f^@`m
z5pCWg&E=smYIHYa{RufhrhF1`|5=Xdap==skNE|u&on4K5lp_h{}Og`ygW9-&P#o!
zm!u&3XMG-j3hksaAm#YJ%9QW7q)&HbReuf`^^1=q{(l`)_2iV@gN9qOAYOfrbC|M!
zmT#05rY|b`91k(wtb8!mV|%9*eU6)$^1Ynp)&74?>ht$2_y62-`rlOaISyk={qq){
zf5yIp3hrdi8YYbMCH((hRbJ(P2%QFxKIc=e%Y=+7uksh6OH<72i{rl=_o@F2MW5ru
z#rxF%HS}riv44&y`TzO6kMMWn{_{F`NAb^b=M9<^ls1>-->lE{k7)6ZKOdh;2lvu{
z7y4w2`_Jcfo787N+yP}dizVs5lLaJY{f8Bt^_kw0`ihtsm;P0|te2MuP=ulJl+^zy
zFX&cO*}5|N3+r9^^Y_r-T1G#(!By<LhyD(!ua0v<>R&6P&*PwO^0)Jfwo|eLrHch!
qwrH-XnfDGU;*bfMP&_T~eJwyc@bG%z{hRiuQvR3ZRp!b){Qn1>uU&co

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-pkg/dirpkg-3-dir2/obj-v0.cc b/tests/data/test-diff-pkg/dirpkg-3-dir2/obj-v0.cc
new file mode 100644
index 0000000..b96530e
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-3-dir2/obj-v0.cc
@@ -0,0 +1,25 @@
+// Compile with:
+// g++ -g -shared -o libobj-v0.so obj-v0.cc
+
+struct S0
+{
+  int  mem0;
+  char mem1;
+
+  S0()
+    : mem0(),
+      mem1()
+  {}
+};
+
+struct S1
+{
+  int mem2;
+};
+void
+bar(S0&)
+{}
+
+void
+foo(S1&)
+{}
diff --git a/tests/data/test-diff-pkg/dirpkg-3-report-0.txt b/tests/data/test-diff-pkg/dirpkg-3-report-0.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/data/test-diff-pkg/dirpkg-3-report-1.txt b/tests/data/test-diff-pkg/dirpkg-3-report-1.txt
new file mode 100644
index 0000000..d0135b4
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-3-report-1.txt
@@ -0,0 +1,16 @@
+================ changes of 'libobj-v0.so'===============
+  Functions changes summary: 0 Removed, 1 Changed (1 filtered out), 0 Added function
+  Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+  1 function with some indirect sub-type change:
+
+    [C]'function void foo(S1&)' has some indirect sub-type changes:
+      parameter 1 of type 'S1&' has sub-type changes:
+        in referenced type 'struct S1':
+          type size changed from 8 to 32 bits
+          1 data member insertion:
+            'int S1::mem2', at offset 0 (in bits)
+
+
+================ end of changes of 'libobj-v0.so'===============
+
diff --git a/tests/data/test-diff-pkg/dirpkg-3.suppr b/tests/data/test-diff-pkg/dirpkg-3.suppr
new file mode 100644
index 0000000..c06dd56
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-3.suppr
@@ -0,0 +1,2 @@
+[suppress_function]
+  name = bar
diff --git a/tests/test-diff-pkg.cc b/tests/test-diff-pkg.cc
index 2e56d31..f788282 100644
--- a/tests/test-diff-pkg.cc
+++ b/tests/test-diff-pkg.cc
@@ -40,12 +40,14 @@
 
 using std::string;
 using std::cerr;
+using abigail::tests::get_src_dir;
 
 struct InOutSpec
 {
   const char* first_in_package_path;
   const char* second_in_package_path;
   const char* prog_options;
+  const char* suppression_path;
   const char* first_in_debug_package_path;
   const char* second_in_debug_package_path;
   const char* ref_report_path;
@@ -54,15 +56,79 @@ struct InOutSpec
 
 static InOutSpec in_out_specs[] =
 {
+  // dir1 contains a suppr spec - it should be ignored.
   {
     "data/test-diff-pkg/dirpkg-0-dir1",
     "data/test-diff-pkg/dirpkg-0-dir2",
     "",
     "",
     "",
+    "",
     "data/test-diff-pkg/dirpkg-0-report-0.txt",
     "output/test-diff-pkg/dirpkg-0-report-0.txt"
   },
+  // dir2 contains a suppr spec - it should be recognized.
+  {
+    "data/test-diff-pkg/dirpkg-1-dir1",
+    "data/test-diff-pkg/dirpkg-1-dir2",
+    "",
+    "",
+    "",
+    "",
+    "data/test-diff-pkg/dirpkg-1-report-0.txt",
+    "output/test-diff-pkg/dirpkg-1-report-0.txt"
+  },
+  // dir2 contains a suppr spec but --no-abignore is specified,
+  // the file should be ignored.
+  {
+    "data/test-diff-pkg/dirpkg-1-dir1",
+    "data/test-diff-pkg/dirpkg-1-dir2",
+    "--no-abignore",
+    "",
+    "",
+    "",
+    "data/test-diff-pkg/dirpkg-1-report-1.txt",
+    "output/test-diff-pkg/dirpkg-1-report-1.txt"
+  },
+  // dir2 contains several suppr spec files, ".abignore" and
+  // "dir.abignore", so the specs should be merged.
+  {
+    "data/test-diff-pkg/dirpkg-2-dir1",
+    "data/test-diff-pkg/dirpkg-2-dir2",
+    "",
+    "",
+    "",
+    "",
+    "data/test-diff-pkg/dirpkg-2-report-0.txt",
+    "output/test-diff-pkg/dirpkg-2-report-0.txt"
+  },
+  // dir2 contains a suppr spec file, ".abignore" and
+  // an additional suppr file is specified on the command line,
+  // so the specs should be merged.
+  {
+    "data/test-diff-pkg/dirpkg-3-dir1",
+    "data/test-diff-pkg/dirpkg-3-dir2",
+    "",
+    "data/test-diff-pkg/dirpkg-3.suppr",
+    "",
+    "",
+    "data/test-diff-pkg/dirpkg-3-report-0.txt",
+    "output/test-diff-pkg/dirpkg-3-report-0.txt"
+  },
+  // dir2 contains a suppr spec file, ".abignore", which should
+  // be ignored because of the program options  and
+  // an additional suppr file is specified on the command line,
+  // which should be recognized.
+  {
+    "data/test-diff-pkg/dirpkg-3-dir1",
+    "data/test-diff-pkg/dirpkg-3-dir2",
+    "--no-abignore",
+    "data/test-diff-pkg/dirpkg-3.suppr",
+    "",
+    "",
+    "data/test-diff-pkg/dirpkg-3-report-1.txt",
+    "output/test-diff-pkg/dirpkg-3-report-1.txt"
+  },
 
 #if WITH_TAR
   {
@@ -71,6 +137,7 @@ static InOutSpec in_out_specs[] =
     "",
     "",
     "",
+    "",
     "data/test-diff-pkg/tarpkg-0-report-0.txt",
     "output/test-diff-pkg/tarpkg-0-report-0.txt"
   },
@@ -80,6 +147,7 @@ static InOutSpec in_out_specs[] =
     "",
     "",
     "",
+    "",
     "data/test-diff-pkg/tarpkg-0-report-0.txt",
     "output/test-diff-pkg/tarpkg-0-report-0.txt"
   },
@@ -89,6 +157,7 @@ static InOutSpec in_out_specs[] =
     "",
     "",
     "",
+    "",
     "data/test-diff-pkg/tarpkg-0-report-0.txt",
     "output/test-diff-pkg/tarpkg-0-report-0.txt"
   },
@@ -98,6 +167,7 @@ static InOutSpec in_out_specs[] =
     "",
     "",
     "",
+    "",
     "data/test-diff-pkg/tarpkg-0-report-0.txt",
     "output/test-diff-pkg/tarpkg-0-report-0.txt"
   },
@@ -109,6 +179,7 @@ static InOutSpec in_out_specs[] =
     "data/test-diff-pkg/dbus-glib-0.80-3.fc12.x86_64.rpm",
     "data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64.rpm",
     "",
+    "",
     "data/test-diff-pkg/dbus-glib-debuginfo-0.80-3.fc12.x86_64.rpm",
     "data/test-diff-pkg/dbus-glib-debuginfo-0.104-3.fc23.x86_64.rpm",
     "data/test-diff-pkg/test-rpm-report-0.txt",
@@ -119,6 +190,7 @@ static InOutSpec in_out_specs[] =
   "data/test-diff-pkg/dbus-glib-0.80-3.fc12.x86_64.rpm",
   "data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64.rpm",
   "",
+  "",
   "data/test-diff-pkg/dbus-glib-debuginfo-0.80-3.fc12.x86_64.rpm",
   "",
   "data/test-diff-pkg/test-rpm-report-1.txt",
@@ -131,6 +203,7 @@ static InOutSpec in_out_specs[] =
   "data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64.rpm",
   "",
   "",
+  "",
   "data/test-diff-pkg/dbus-glib-debuginfo-0.104-3.fc23.x86_64.rpm",
   "data/test-diff-pkg/test-rpm-report-2.txt",
   "output/test-diff-pkg/test-rpm-report-2.txt"
@@ -143,6 +216,7 @@ static InOutSpec in_out_specs[] =
   "",
   "",
   "",
+  "",
   "data/test-diff-pkg/test-rpm-report-3.txt",
   "output/test-diff-pkg/test-rpm-report-3.txt"
   },
@@ -152,6 +226,7 @@ static InOutSpec in_out_specs[] =
   "data/test-diff-pkg/dbus-glib-0.80-3.fc12.x86_64.rpm",
   "data/test-diff-pkg/dbus-glib-0.80-3.fc12.x86_64.rpm",
   "",
+  "",
   "data/test-diff-pkg/dbus-glib-debuginfo-0.80-3.fc12.x86_64.rpm",
   "data/test-diff-pkg/dbus-glib-debuginfo-0.80-3.fc12.x86_64.rpm",
   "data/test-diff-pkg/test-rpm-report-4.txt",
@@ -163,6 +238,7 @@ static InOutSpec in_out_specs[] =
     "data/test-diff-pkg/dbus-glib-0.80-3.fc12.x86_64.rpm",
     "data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64.rpm",
     "--no-added-syms",
+    "",
     "data/test-diff-pkg/dbus-glib-debuginfo-0.80-3.fc12.x86_64.rpm",
     "data/test-diff-pkg/dbus-glib-debuginfo-0.104-3.fc23.x86_64.rpm",
     "data/test-diff-pkg/test-rpm-report-5.txt",
@@ -176,6 +252,7 @@ static InOutSpec in_out_specs[] =
     "data/test-diff-pkg/libsigc++-2.0-0c2a_2.4.0-1_amd64.deb",
     "data/test-diff-pkg/libsigc++-2.0-0v5_2.4.1-1ubuntu2_amd64.deb",
     "--fail-no-dbg",
+    "",
     "data/test-diff-pkg/libsigc++-2.0-0c2a-dbgsym_2.4.0-1_amd64.ddeb",
     "data/test-diff-pkg/libsigc++-2.0-0v5-dbgsym_2.4.1-1ubuntu2_amd64.ddeb",
     "data/test-diff-pkg/libsigc++-2.0-0c2a_2.4.0-1_amd64--libsigc++-2.0-0v5_2.4.1-1ubuntu2_amd64-report-0.txt",
@@ -183,13 +260,12 @@ static InOutSpec in_out_specs[] =
   },
 #endif // WITH_DEB
   // This should be the last entry.
-  {0, 0, 0, 0, 0, 0, 0}
+  {0, 0, 0, 0, 0, 0, 0, 0}
 };
 
 int
 main()
 {
-  using abigail::tests::get_src_dir;
   using abigail::tests::get_build_dir;
   using abigail::tools_utils::ensure_parent_dir_created;
 
@@ -197,7 +273,8 @@ main()
   string first_in_package_path, second_in_package_path,
     prog_options,
     ref_abi_diff_report_path, out_abi_diff_report_path, cmd, abipkgdiff,
-    first_in_debug_package_path, second_in_debug_package_path;
+    first_in_debug_package_path, second_in_debug_package_path,
+    suppression_path;
   for (InOutSpec *s = in_out_specs; s->first_in_package_path; ++s)
     {
       first_in_package_path =
@@ -220,6 +297,14 @@ main()
           get_src_dir() + "/tests/" + s->second_in_debug_package_path;
       else
         second_in_debug_package_path.clear();
+
+      if (s->suppression_path
+          && strcmp(s->suppression_path, ""))
+        suppression_path =
+          get_src_dir() + "/tests/" + s->suppression_path;
+      else
+        suppression_path.clear();
+
       ref_abi_diff_report_path = get_src_dir() + "/tests/" + s->ref_report_path;
       out_abi_diff_report_path =
         get_build_dir() + "/tests/" + s->out_report_path;
@@ -242,6 +327,9 @@ main()
       if (!second_in_debug_package_path.empty())
         abipkgdiff += " --d2 " + second_in_debug_package_path;
 
+      if (!suppression_path.empty())
+        abipkgdiff += " --suppressions " + suppression_path;
+
       cmd =
         abipkgdiff + " " + first_in_package_path + " " + second_in_package_path;
       cmd += " > " + out_abi_diff_report_path;
diff --git a/tools/abipkgdiff.cc b/tools/abipkgdiff.cc
index 8dd8997..4e7acda 100644
--- a/tools/abipkgdiff.cc
+++ b/tools/abipkgdiff.cc
@@ -60,6 +60,7 @@ using std::vector;
 using std::map;
 using std::tr1::shared_ptr;
 using abigail::tools_utils::guess_file_type;
+using abigail::tools_utils::string_ends_with;
 using abigail::tools_utils::file_type;
 using abigail::tools_utils::make_path_absolute;
 using abigail::tools_utils::abidiff_status;
@@ -82,16 +83,18 @@ static bool verbose;
 /// This contains the set of files of a given package.  It's populated
 /// by a worker function that is invoked on each file contained in the
 /// package.  So this global variable is filled by the
-/// file_tree_walker_callback_fn() function.  Its content is relevant
-/// only during the time after which the current package has been
+/// file_tree_walker_callback_{elf,suppr}_fn() functions.  Its content is
+/// relevant only during the time after which the current package has been
 /// analyzed and before we start analyzing the next package.
 static vector<string> elf_file_paths;
+static vector<string> suppression_paths;
 
 /// The options passed to the current program.
 struct options
 {
   bool		display_usage;
   bool		missing_operand;
+  bool		abignore;
   string	package1;
   string	package2;
   string	debug_package1;
@@ -103,11 +106,11 @@ struct options
   bool		show_added_syms;
   bool		show_added_binaries;
   bool		fail_if_no_debug_info;
-  vector<string> suppression_paths;
 
   options()
     : display_usage(),
       missing_operand(),
+      abignore(true),
       keep_tmp_files(),
       compare_dso_only(),
       show_linkage_names(true),
@@ -146,6 +149,10 @@ public:
 /// A convenience typedef for a shared pointer to elf_file.
 typedef shared_ptr<elf_file> elf_file_sptr;
 
+/// A convenience typedef for a pointer to a function type that
+/// the ftw() function accepts.
+typedef int (*ftw_cb_type)(const char *, const struct stat*, int);
+
 /// Abstract the result of comparing two packages.
 ///
 /// This contains the the paths of the set of added binaries, removed
@@ -653,9 +660,9 @@ extract_package(const package& package)
 ///
 /// @param stat the stat struct of the file.
 static int
-file_tree_walker_callback_fn(const char *fpath,
-			     const struct stat *,
-			     int /*flag*/)
+file_tree_walker_elf_callback_fn(const char *fpath,
+				 const struct stat *,
+				 int /*flag*/)
 {
   struct stat s;
   lstat(fpath, &s);
@@ -668,6 +675,30 @@ file_tree_walker_callback_fn(const char *fpath,
   return 0;
 }
 
+/// A callback function invoked by the ftw() function while walking
+/// the directory of files extracted from the second package, unless
+/// "--no-abignore" is specified on the command line.
+///
+/// @param fpath the path to the file being considered.
+///
+/// @param stat the stat struct of the file.
+static int
+file_tree_walker_suppr_callback_fn(const char *fpath,
+				   const struct stat *,
+				   int /*flag*/)
+{
+  struct stat s;
+  lstat(fpath, &s);
+
+  if (!S_ISLNK(s.st_mode))
+    {
+      if (guess_file_type(fpath) == abigail::tools_utils::FILE_TYPE_ELF)
+	elf_file_paths.push_back(fpath);
+      else if (string_ends_with(fpath, ".abignore"))
+	suppression_paths.push_back(fpath);
+    }
+  return 0;
+}
 /// Update the diff context from the @ref options data structure.
 ///
 /// @param ctxt the diff context to update.
@@ -696,8 +727,8 @@ set_diff_context_from_opts(diff_context_sptr ctxt,
      | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY);
 
   suppressions_type supprs;
-  for (vector<string>::const_iterator i = opts.suppression_paths.begin();
-       i != opts.suppression_paths.end();
+  for (vector<string>::const_iterator i = suppression_paths.begin();
+       i != suppression_paths.end();
        ++i)
     read_suppressions(*i, supprs);
   ctxt->add_suppressions(supprs);
@@ -858,9 +889,11 @@ compare(const elf_file& elf1,
 /// @param opts the options the current program has been called with.
 ///
 /// @param true upon successful completion, false otherwise.
+
 static bool
 create_maps_of_package_content(package& package,
-			       const options& opts)
+			       const options& opts,
+			       ftw_cb_type callback)
 {
   elf_file_paths.clear();
   if (verbose)
@@ -870,9 +903,7 @@ create_maps_of_package_content(package& package,
 	 << package.extracted_dir_path()
 	 << " ...";
 
-  if (ftw(package.extracted_dir_path().c_str(),
-	  file_tree_walker_callback_fn,
-	  16))
+  if (ftw(package.extracted_dir_path().c_str(), callback, 16))
     {
       cerr << "Error while inspecting files in package"
 	   << package.extracted_dir_path() << "\n";
@@ -919,14 +950,15 @@ create_maps_of_package_content(package& package,
 /// @return true upon successful completion, false otherwise.
 static bool
 extract_package_and_map_its_content(package& package,
-				    const options& opts)
+				    const options& opts,
+				    ftw_cb_type callback)
 {
   if (!extract_package(package))
     return false;
 
   bool result = true;
   if (!package.is_debug_info())
-    result |= create_maps_of_package_content(package, opts);
+    result |= create_maps_of_package_content(package, opts, callback);
 
   return result;
 }
@@ -947,8 +979,14 @@ prepare_packages(package&	first_package,
 		 package&	second_package,
 		 const options& opts)
 {
-  if (!extract_package_and_map_its_content(first_package, opts)
-      || !extract_package_and_map_its_content(second_package, opts))
+  if (!extract_package_and_map_its_content(first_package, opts,
+					   file_tree_walker_elf_callback_fn)
+  /// We go through the files of the newer (second) pkg to look for suppression
+  /// specifications, matching the "*.abignore" name pattern.
+      || !extract_package_and_map_its_content(second_package, opts,
+					      opts.abignore ?
+					      file_tree_walker_suppr_callback_fn
+					      : file_tree_walker_elf_callback_fn))
     return false;
 
   if ((first_package.debug_info_package()
@@ -1142,13 +1180,15 @@ parse_command_line(int argc, char* argv[], options& opts)
 	opts.fail_if_no_debug_info = true;
       else if (!strcmp(argv[i], "--verbose"))
 	verbose = true;
+      else if (!strcmp(argv[i], "--no-abignore"))
+	opts.abignore = false;
       else if (!strcmp(argv[i], "--suppressions")
 	       || !strcmp(argv[i], "--suppr"))
 	{
 	  int j = i + 1;
 	  if (j >= argc)
 	    return false;
-	  opts.suppression_paths.push_back(argv[j]);
+	  suppression_paths.push_back(argv[j]);
 	  ++i;
 	}
       else if (!strcmp(argv[i], "--help")
-- 
2.4.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Bug default/19082] New: Make abipkgdiff recognize suppression specifications to apply to comparisons
  2015-01-01  0:00     ` Ondrej Oprala
@ 2015-01-01  0:00       ` Dodji Seketeli
  0 siblings, 0 replies; 9+ messages in thread
From: Dodji Seketeli @ 2015-01-01  0:00 UTC (permalink / raw)
  To: Ondrej Oprala; +Cc: libabigail

Ondrej Oprala <ooprala@redhat.com> a écrit:

> diff --git a/tools/abipkgdiff.cc b/tools/abipkgdiff.cc

[...]

> @@ -82,16 +83,21 @@ static bool verbose;
>  /// This contains the set of files of a given package.  It's populated
>  /// by a worker function that is invoked on each file contained in the
>  /// package.  So this global variable is filled by the
> -/// file_tree_walker_callback_fn() function.  Its content is relevant
> -/// only during the time after which the current package has been
> +/// file_tree_walker_callback_{elf,suppr}_fn() functions.  Its content is
> +/// relevant only during the time after which the current package has been

This change should now be adjusted to the newer names of the callback
functions.

[...]

> @@ -108,13 +114,15 @@ struct options
>    options()
>      : display_usage(),
>        missing_operand(),
> +      abignore(true),
>        keep_tmp_files(),
>        compare_dso_only(),
>        show_linkage_names(true),
>        show_redundant_changes(),
>        show_added_syms(true),
>        show_added_binaries(true),
> -      fail_if_no_debug_info()
> +      fail_if_no_debug_info(),
> +      suppression_paths()

default-initializing the suppression_paths member here is not necessary
because the default constructor of the vector type is going to be
invoked by the default constructor of the option type.  Or am I missing
something?

>    {}
>  };
>  
> @@ -146,6 +154,10 @@ public:
>  /// A convenience typedef for a shared pointer to elf_file.
>  typedef shared_ptr<elf_file> elf_file_sptr;
>  
> +/// A convenience typedef for a pointer to a function type that
> +/// the ftw() function accepts.
> +typedef int (*ftw_cb_type)(const char *, const struct stat*, int);
> +
>  /// Abstract the result of comparing two packages.
>  ///
>  /// This contains the the paths of the set of added binaries, removed
> @@ -653,9 +665,9 @@ extract_package(const package& package)
>  ///
>  /// @param stat the stat struct of the file.
>  static int
> -file_tree_walker_callback_fn(const char *fpath,
> -			     const struct stat *,
> -			     int /*flag*/)
> +first_package_tree_walker_callback_fn(const char *fpath,
> +				      const struct stat *,
> +				      int /*flag*/)

Please update the comment of this function to say that this callback is
invoked when walking the *first* package.

[...]

>  {
>    struct stat s;
>    lstat(fpath, &s);
> @@ -668,6 +680,30 @@ file_tree_walker_callback_fn(const char *fpath,
>    return 0;
>  }
>  
> +/// A callback function invoked by the ftw() function while walking
> +/// the directory of files extracted from the second package, unless
> +/// "--no-abignore" is specified on the command line.
> +///
> +/// @param fpath the path to the file being considered.
> +///
> +/// @param stat the stat struct of the file.
> +static int
> +second_package_tree_walker_callback_fn(const char *fpath,
> +				       const struct stat *,
> +				       int /*flag*/)
> +{
> +  struct stat s;
> +  lstat(fpath, &s);
> +
> +  if (!S_ISLNK(s.st_mode))
> +    {
> +      if (guess_file_type(fpath) == abigail::tools_utils::FILE_TYPE_ELF)
> +	elf_file_paths.push_back(fpath);
> +      else if (prog_options->abignore && string_ends_with(fpath, ".abignore"))
> +	prog_options->suppression_paths.push_back(fpath);
> +    }
> +  return 0;
> +}
>  /// Update the diff context from the @ref options data structure.
>  ///
>  /// @param ctxt the diff context to update.
> @@ -858,9 +894,11 @@ compare(const elf_file& elf1,
>  /// @param opts the options the current program has been called with.
>  ///
>  /// @param true upon successful completion, false otherwise.
> +

This is an unnecessary white space change.

>  static bool
>  create_maps_of_package_content(package& package,
> -			       const options& opts)
> +			       const options& opts,
> +			       ftw_cb_type callback)
>  {
>    elf_file_paths.clear();
>    if (verbose)
> @@ -870,9 +908,7 @@ create_maps_of_package_content(package& package,
>  	 << package.extracted_dir_path()
>  	 << " ...";
>  
> -  if (ftw(package.extracted_dir_path().c_str(),
> -	  file_tree_walker_callback_fn,
> -	  16))
> +  if (ftw(package.extracted_dir_path().c_str(), callback, 16))
>      {
>        cerr << "Error while inspecting files in package"
>  	   << package.extracted_dir_path() << "\n";
> @@ -919,14 +955,15 @@ create_maps_of_package_content(package& package,
>  /// @return true upon successful completion, false otherwise.
>  static bool
>  extract_package_and_map_its_content(package& package,
> -				    const options& opts)
> +				    const options& opts,
> +				    ftw_cb_type callback)
>  {
>    if (!extract_package(package))
>      return false;
>  
>    bool result = true;
>    if (!package.is_debug_info())
> -    result |= create_maps_of_package_content(package, opts);
> +    result |= create_maps_of_package_content(package, opts, callback);
>  
>    return result;
>  }
> @@ -947,8 +984,12 @@ prepare_packages(package&	first_package,
>  		 package&	second_package,
>  		 const options& opts)
>  {
> -  if (!extract_package_and_map_its_content(first_package, opts)
> -      || !extract_package_and_map_its_content(second_package, opts))
> +  if (!extract_package_and_map_its_content(first_package, opts,
> +					   first_package_tree_walker_callback_fn)
> +      /// We go through the files of the newer (second) pkg to look for
> +      /// suppression specifications, matching the "*.abignore" name pattern.

I think this comment should rather be inside the function
second_package_tree_walker_callback_fn.  Because at this level, the
second_package_tree_walker_callback_fn can do more (and does more) than
looking for suppression specifications.

Oh, and thank you very much for the test great quantity of new tests!
That is really cool (and useful, haha) :-)

So this patch is OK to commit to master with the changes above, if the
result still passes "make distcheck", of course.

Cheers!

-- 
		Dodji

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Bug default/19082] New: Make abipkgdiff recognize suppression specifications to apply to comparisons
  2015-01-01  0:00   ` Dodji Seketeli
@ 2015-01-01  0:00     ` Ondrej Oprala
  2015-01-01  0:00       ` Dodji Seketeli
  0 siblings, 1 reply; 9+ messages in thread
From: Ondrej Oprala @ 2015-01-01  0:00 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: libabigail

[-- Attachment #1: Type: text/plain, Size: 4912 bytes --]

Hey, thanks for the review, I've addressed all your concerns
and distcheck (still) passes.

I'm attaching the redone patch.

Thanks,
   Ondrej

On 12.10.2015 16:02, Dodji Seketeli wrote:
> Hi!
>
> Thank you for the nice patch, it's really appreciated!
>
> Please see my comments below.
>
>> --- a/tools/abipkgdiff.cc
> [...]
>
>> +static vector<string> suppression_paths;
> Rather than putting this here, I'd rather declare a (global) variable of
> type (called, e.g, prog_options) pointer to the options type, right
> before the main() and initialize that pointer in main(), right after
> we've parsed the command line options.  That pointer to the options
> would then be globally accessible to the walker functions, if need be.
>
> I believe that could have some interesting consequences, which I talk
> about below.
>
> [...]
>
>>   /// Abstract the result of comparing two packages.
>>   ///
>>   /// This contains the the paths of the set of added binaries, removed
>> @@ -653,9 +660,9 @@ extract_package(const package& package)
>>   ///
>>   /// @param stat the stat struct of the file.
>>   static int
>> -file_tree_walker_callback_fn(const char *fpath,
>> -			     const struct stat *,
>> -			     int /*flag*/)
>> +file_tree_walker_elf_callback_fn(const char *fpath,
>> +				 const struct stat *,
>> +				 int /*flag*/)
> [...]
>
>> +static int
>> +file_tree_walker_suppr_callback_fn(const char *fpath,
>> +				   const struct stat *,
>> +				   int /*flag*/)
>> +{
> I would call the two functions above first_package_tree_walker_callback_fn and
> second_package_tree_walker_callback_fn, because I think that really is
> the intent of having two walker functions.  One is to walk the content
> of the first package, and the other is to walk the content of the second
> package.
>
> In the second walking function:
>
>> +  struct stat s;
>> +  lstat(fpath, &s);
>> +
>> +  if (!S_ISLNK(s.st_mode))
>> +    {
>> +      if (guess_file_type(fpath) == abigail::tools_utils::FILE_TYPE_ELF)
>> +	elf_file_paths.push_back(fpath);
>> +      else if (string_ends_with(fpath, ".abignore"))
>> +	suppression_paths.push_back(fpath);
> ... I would conditionalize the action of recognizing the suppression
> specification here to prog_options->abignore
>
> So that it would read something like:
>
>      if (prog_options->abignore
>          && string_ends_with(fpath, ".abignore"))
>        prog_options->suppression_paths.push_back(fpath);
>
>> +    }
>> +  return 0;
>> +}
> [...]
>
> @@ -696,8 +727,8 @@ set_diff_context_from_opts(diff_context_sptr ctxt,
>        | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY);
>   
>>     suppressions_type supprs;
>> -  for (vector<string>::const_iterator i = opts.suppression_paths.begin();
>> -       i != opts.suppression_paths.end();
>> +  for (vector<string>::const_iterator i = suppression_paths.begin();
>> +       i != suppression_paths.end();
>>          ++i)
> This change would then become unnecessary.
>
> [...]
>   
>> @@ -947,8 +979,14 @@ prepare_packages(package&	first_package,
>>   		 package&	second_package,
>>   		 const options& opts)
>>   {
>> -  if (!extract_package_and_map_its_content(first_package, opts)
>> -      || !extract_package_and_map_its_content(second_package, opts))
>> +  if (!extract_package_and_map_its_content(first_package, opts,
>> +					   file_tree_walker_elf_callback_fn)
>> +  /// We go through the files of the newer (second) pkg to look for suppression
>> +  /// specifications, matching the "*.abignore" name pattern.
>> +      || !extract_package_and_map_its_content(second_package, opts,
>> +					      opts.abignore ?
>> +					      file_tree_walker_suppr_callback_fn
>> +					      : file_tree_walker_elf_callback_fn))
> Here, the change would then look like:
>
>> +  if (!extract_package_and_map_its_content(first_package, opts,
>> +					   first_package_tree_walker_callback_fn)
>> +      || !extract_package_and_map_its_content(second_package, opts,
>> +					      second_package_tree_walker_callback_fn))
> which I think is simpler because there is no condition any more.  The
> condition happens at a lower logical level, where we really need to act
> depending on that condition: take the suppression specification into
> account, if the user asked for it.
>
> [...]
>
>> @@ -1142,13 +1180,15 @@ parse_command_line(int argc, char* argv[], options& opts)
>>   	opts.fail_if_no_debug_info = true;
>>         else if (!strcmp(argv[i], "--verbose"))
>>   	verbose = true;
>> +      else if (!strcmp(argv[i], "--no-abignore"))
>> +	opts.abignore = false;
>>         else if (!strcmp(argv[i], "--suppressions")
>>   	       || !strcmp(argv[i], "--suppr"))
>>   	{
>>   	  int j = i + 1;
>>   	  if (j >= argc)
>>   	    return false;
>> -	  opts.suppression_paths.push_back(argv[j]);
>> +	  suppression_paths.push_back(argv[j]);
> This change would then be unnecessary.
>
> What do you think?
>
> Cheers,
>


[-- Attachment #2: 0001-Bug-19082-Recognize-suppression-spec-files.patch --]
[-- Type: text/x-patch, Size: 51435 bytes --]

From 4392c2b5a9a82171ae8726de8704d6f95d72ff87 Mon Sep 17 00:00:00 2001
From: Ondrej Oprala <ooprala@redhat.com>
Date: Thu, 8 Oct 2015 10:43:20 +0200
Subject: [PATCH] Bug 19082 - Recognize suppression spec files

When abipkgdiff is invoked on a set of packages, the newer (second) one is also
inspected for files matching the pattern '*.abignore', whose contents are read
and interpreted as suppression specifications.

	* tests/data/Makefile.am: Add new test material to the build system.
	* tests/data/test-diff-pkg/dirpkg-{0-dir1,{1,2}-dir2}/dir.abignore:
	A test suppression specification.
	* tests/data/test-diff-pkg/dirpkg-{2,3}-dir2/.abignore: Likewise.
	* tests/data/test-diff-pkg/dirpkg-3.suppr: Likewise.
	* tests/data/test-diff-pkg/dirpkg-{1,2,3}-dir{1,2}/libobj-v0.so: New
	binary test inputs.
	* tests/data/test-diff-pkg/dirpkg-{1,2,3}-dir{1,2}/obj-v0.cc: New test
	source files
	* tests/data/test-diff-pkg/dirpkg-{1,2,3}-report-{0,1}.txt: New
	reference outputs
	* tests/test-diff-pkg.cc: Adjust to run the new tests.
	* tools/abipkgdiff.cc (prog_options): New static pointer to struct
	opts.
	(file_tree_walker_callback_fn): Rename to
	first_package_tree_walker_callback_fn.
	(second_package_tree_walker_callback_fn): Check for ELF files just
	like the previous function but additionally check for files
	ending with ".abignore", unless disabled from the command line.
	({create_maps_of_package,extract_package_and_map_its}_content):
	Add a callback as a new argument.
	(main) handle the new "--no-abignore" option, which turns off
	the search for suppression files within the new package.

Signed-off-by: Ondrej Oprala <ooprala@redhat.com>
---
 tests/data/Makefile.am                             |  28 +++++-
 .../data/test-diff-pkg/dirpkg-0-dir1/dir.abignore  |   4 +
 .../data/test-diff-pkg/dirpkg-1-dir1/libobj-v0.so  | Bin 0 -> 8951 bytes
 tests/data/test-diff-pkg/dirpkg-1-dir1/obj-v0.cc   |  15 ++++
 .../data/test-diff-pkg/dirpkg-1-dir2/dir.abignore  |   4 +
 .../data/test-diff-pkg/dirpkg-1-dir2/libobj-v0.so  | Bin 0 -> 8991 bytes
 tests/data/test-diff-pkg/dirpkg-1-dir2/obj-v0.cc   |  17 ++++
 tests/data/test-diff-pkg/dirpkg-1-report-0.txt     |   0
 tests/data/test-diff-pkg/dirpkg-1-report-1.txt     |  16 ++++
 .../data/test-diff-pkg/dirpkg-2-dir1/libobj-v0.so  | Bin 0 -> 9088 bytes
 tests/data/test-diff-pkg/dirpkg-2-dir1/obj-v0.cc   |  22 +++++
 tests/data/test-diff-pkg/dirpkg-2-dir2/.abignore   |   2 +
 .../data/test-diff-pkg/dirpkg-2-dir2/dir.abignore  |   2 +
 .../data/test-diff-pkg/dirpkg-2-dir2/libobj-v0.so  | Bin 0 -> 9136 bytes
 tests/data/test-diff-pkg/dirpkg-2-dir2/obj-v0.cc   |  25 ++++++
 tests/data/test-diff-pkg/dirpkg-2-report-0.txt     |   0
 tests/data/test-diff-pkg/dirpkg-2-report-1.txt     |  16 ++++
 .../data/test-diff-pkg/dirpkg-3-dir1/libobj-v0.so  | Bin 0 -> 9088 bytes
 tests/data/test-diff-pkg/dirpkg-3-dir1/obj-v0.cc   |  22 +++++
 tests/data/test-diff-pkg/dirpkg-3-dir2/.abignore   |   2 +
 .../data/test-diff-pkg/dirpkg-3-dir2/libobj-v0.so  | Bin 0 -> 9136 bytes
 tests/data/test-diff-pkg/dirpkg-3-dir2/obj-v0.cc   |  25 ++++++
 tests/data/test-diff-pkg/dirpkg-3-report-0.txt     |   0
 tests/data/test-diff-pkg/dirpkg-3-report-1.txt     |  16 ++++
 tests/data/test-diff-pkg/dirpkg-3.suppr            |   2 +
 tests/test-diff-pkg.cc                             |  94 ++++++++++++++++++++-
 tools/abipkgdiff.cc                                |  72 +++++++++++++---
 27 files changed, 365 insertions(+), 19 deletions(-)
 create mode 100644 tests/data/test-diff-pkg/dirpkg-0-dir1/dir.abignore
 create mode 100755 tests/data/test-diff-pkg/dirpkg-1-dir1/libobj-v0.so
 create mode 100644 tests/data/test-diff-pkg/dirpkg-1-dir1/obj-v0.cc
 create mode 100644 tests/data/test-diff-pkg/dirpkg-1-dir2/dir.abignore
 create mode 100755 tests/data/test-diff-pkg/dirpkg-1-dir2/libobj-v0.so
 create mode 100644 tests/data/test-diff-pkg/dirpkg-1-dir2/obj-v0.cc
 create mode 100644 tests/data/test-diff-pkg/dirpkg-1-report-0.txt
 create mode 100644 tests/data/test-diff-pkg/dirpkg-1-report-1.txt
 create mode 100755 tests/data/test-diff-pkg/dirpkg-2-dir1/libobj-v0.so
 create mode 100644 tests/data/test-diff-pkg/dirpkg-2-dir1/obj-v0.cc
 create mode 100644 tests/data/test-diff-pkg/dirpkg-2-dir2/.abignore
 create mode 100644 tests/data/test-diff-pkg/dirpkg-2-dir2/dir.abignore
 create mode 100755 tests/data/test-diff-pkg/dirpkg-2-dir2/libobj-v0.so
 create mode 100644 tests/data/test-diff-pkg/dirpkg-2-dir2/obj-v0.cc
 create mode 100644 tests/data/test-diff-pkg/dirpkg-2-report-0.txt
 create mode 100644 tests/data/test-diff-pkg/dirpkg-2-report-1.txt
 create mode 100755 tests/data/test-diff-pkg/dirpkg-3-dir1/libobj-v0.so
 create mode 100644 tests/data/test-diff-pkg/dirpkg-3-dir1/obj-v0.cc
 create mode 100644 tests/data/test-diff-pkg/dirpkg-3-dir2/.abignore
 create mode 100755 tests/data/test-diff-pkg/dirpkg-3-dir2/libobj-v0.so
 create mode 100644 tests/data/test-diff-pkg/dirpkg-3-dir2/obj-v0.cc
 create mode 100644 tests/data/test-diff-pkg/dirpkg-3-report-0.txt
 create mode 100644 tests/data/test-diff-pkg/dirpkg-3-report-1.txt
 create mode 100644 tests/data/test-diff-pkg/dirpkg-3.suppr

diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 73d02e1..967e225 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -892,11 +892,35 @@ test-diff-pkg/libsigc++-2.0-0c2a_2.4.0-1_amd64--libsigc++-2.0-0v5_2.4.1-1ubuntu2
 test-diff-pkg/libsigc++-2.0-0c2a_2.4.0-1_amd64.deb \
 test-diff-pkg/libsigc++-2.0-0v5-dbgsym_2.4.1-1ubuntu2_amd64.ddeb \
 test-diff-pkg/libsigc++-2.0-0v5_2.4.1-1ubuntu2_amd64.deb \
+test-diff-pkg/dirpkg-0-dir1/dir.abignore \
 test-diff-pkg/dirpkg-0-dir1/libobj-v0.so \
-test-diff-pkg/dirpkg-0-dir2/libobj-v0.so \
-test-diff-pkg/dirpkg-0-report-0.txt \
 test-diff-pkg/dirpkg-0-dir1/obj-v0.cc \
+test-diff-pkg/dirpkg-0-dir2/libobj-v0.so \
 test-diff-pkg/dirpkg-0-dir2/obj-v0.cc \
+test-diff-pkg/dirpkg-0-report-0.txt \
+test-diff-pkg/dirpkg-1-dir1/libobj-v0.so \
+test-diff-pkg/dirpkg-1-dir1/obj-v0.cc \
+test-diff-pkg/dirpkg-1-dir2/dir.abignore \
+test-diff-pkg/dirpkg-1-dir2/libobj-v0.so \
+test-diff-pkg/dirpkg-1-dir2/obj-v0.cc \
+test-diff-pkg/dirpkg-1-report-0.txt \
+test-diff-pkg/dirpkg-1-report-1.txt \
+test-diff-pkg/dirpkg-2-dir1/libobj-v0.so \
+test-diff-pkg/dirpkg-2-dir1/obj-v0.cc \
+test-diff-pkg/dirpkg-2-dir2/.abignore \
+test-diff-pkg/dirpkg-2-dir2/dir.abignore \
+test-diff-pkg/dirpkg-2-dir2/libobj-v0.so \
+test-diff-pkg/dirpkg-2-dir2/obj-v0.cc \
+test-diff-pkg/dirpkg-2-report-0.txt \
+test-diff-pkg/dirpkg-2-report-1.txt \
+test-diff-pkg/dirpkg-3-dir1/libobj-v0.so \
+test-diff-pkg/dirpkg-3-dir1/obj-v0.cc \
+test-diff-pkg/dirpkg-3-dir2/.abignore \
+test-diff-pkg/dirpkg-3-dir2/libobj-v0.so \
+test-diff-pkg/dirpkg-3-dir2/obj-v0.cc \
+test-diff-pkg/dirpkg-3-report-0.txt \
+test-diff-pkg/dirpkg-3-report-1.txt \
+test-diff-pkg/dirpkg-3.suppr \
 test-diff-pkg/tarpkg-0-dir1.tar \
 test-diff-pkg/tarpkg-0-dir1.ta \
 test-diff-pkg/tarpkg-0-dir1.tar.bz2 \
diff --git a/tests/data/test-diff-pkg/dirpkg-0-dir1/dir.abignore b/tests/data/test-diff-pkg/dirpkg-0-dir1/dir.abignore
new file mode 100644
index 0000000..d03917d
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-0-dir1/dir.abignore
@@ -0,0 +1,4 @@
+#taken from test5-fn-supprt-0.suppr
+[suppress_function]
+  # suppress change reports for a function which name is 'bar' ...
+  name = bar
diff --git a/tests/data/test-diff-pkg/dirpkg-1-dir1/libobj-v0.so b/tests/data/test-diff-pkg/dirpkg-1-dir1/libobj-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..7373521ef7c791bf631ef74c0fb45ba841aa46b4
GIT binary patch
literal 8951
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

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-pkg/dirpkg-1-dir1/obj-v0.cc b/tests/data/test-diff-pkg/dirpkg-1-dir1/obj-v0.cc
new file mode 100644
index 0000000..5a016dd
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-1-dir1/obj-v0.cc
@@ -0,0 +1,15 @@
+// Compile with:
+// g++ -g -shared -o libobj-v0.so obj-v0.cc
+
+struct S
+{
+  int mem0;
+
+  S()
+    : mem0()
+  {}
+};
+
+void
+bar(S&)
+{}
diff --git a/tests/data/test-diff-pkg/dirpkg-1-dir2/dir.abignore b/tests/data/test-diff-pkg/dirpkg-1-dir2/dir.abignore
new file mode 100644
index 0000000..d03917d
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-1-dir2/dir.abignore
@@ -0,0 +1,4 @@
+#taken from test5-fn-supprt-0.suppr
+[suppress_function]
+  # suppress change reports for a function which name is 'bar' ...
+  name = bar
diff --git a/tests/data/test-diff-pkg/dirpkg-1-dir2/libobj-v0.so b/tests/data/test-diff-pkg/dirpkg-1-dir2/libobj-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..0032f73fb7c5b6cfbcb254c896089d10962a826d
GIT binary patch
literal 8991
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
LH{X2At^L0N){!i+

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-pkg/dirpkg-1-dir2/obj-v0.cc b/tests/data/test-diff-pkg/dirpkg-1-dir2/obj-v0.cc
new file mode 100644
index 0000000..65f6bab
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-1-dir2/obj-v0.cc
@@ -0,0 +1,17 @@
+// Compile with:
+// g++ -g -shared -o libobj-v0.so obj-v0.cc
+
+struct S
+{
+  int  mem0;
+  char mem1;
+
+  S()
+    : mem0(),
+      mem1()
+  {}
+};
+
+void
+bar(S&)
+{}
diff --git a/tests/data/test-diff-pkg/dirpkg-1-report-0.txt b/tests/data/test-diff-pkg/dirpkg-1-report-0.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/data/test-diff-pkg/dirpkg-1-report-1.txt b/tests/data/test-diff-pkg/dirpkg-1-report-1.txt
new file mode 100644
index 0000000..c7c9226
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-1-report-1.txt
@@ -0,0 +1,16 @@
+================ changes of 'libobj-v0.so'===============
+  Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+  Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+  1 function with some indirect sub-type change:
+
+    [C]'function void bar(S&)' has some indirect sub-type changes:
+      parameter 1 of type 'S&' has sub-type changes:
+        in referenced type 'struct S':
+          type size changed from 32 to 64 bits
+          1 data member insertion:
+            'char S::mem1', at offset 32 (in bits)
+
+
+================ end of changes of 'libobj-v0.so'===============
+
diff --git a/tests/data/test-diff-pkg/dirpkg-2-dir1/libobj-v0.so b/tests/data/test-diff-pkg/dirpkg-2-dir1/libobj-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..327577dc2e9a41bf33616b98398b6dbb7c05e40d
GIT binary patch
literal 9088
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
JQXDF*_z%jLSP}pL

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-pkg/dirpkg-2-dir1/obj-v0.cc b/tests/data/test-diff-pkg/dirpkg-2-dir1/obj-v0.cc
new file mode 100644
index 0000000..206a265
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-2-dir1/obj-v0.cc
@@ -0,0 +1,22 @@
+// Compile with:
+// g++ -g -shared -o libobj-v0.so obj-v0.cc
+
+struct S0
+{
+  int mem0;
+
+  S0()
+    : mem0()
+  {}
+};
+
+struct S1
+{
+};
+void
+bar(S0&)
+{}
+
+void
+foo(S1&)
+{}
diff --git a/tests/data/test-diff-pkg/dirpkg-2-dir2/.abignore b/tests/data/test-diff-pkg/dirpkg-2-dir2/.abignore
new file mode 100644
index 0000000..b8f8197
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-2-dir2/.abignore
@@ -0,0 +1,2 @@
+[suppress_function]
+  name = foo
diff --git a/tests/data/test-diff-pkg/dirpkg-2-dir2/dir.abignore b/tests/data/test-diff-pkg/dirpkg-2-dir2/dir.abignore
new file mode 100644
index 0000000..c06dd56
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-2-dir2/dir.abignore
@@ -0,0 +1,2 @@
+[suppress_function]
+  name = bar
diff --git a/tests/data/test-diff-pkg/dirpkg-2-dir2/libobj-v0.so b/tests/data/test-diff-pkg/dirpkg-2-dir2/libobj-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..de46f91bef99b1871dc16acecf5e314b2f500df6
GIT binary patch
literal 9136
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

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-pkg/dirpkg-2-dir2/obj-v0.cc b/tests/data/test-diff-pkg/dirpkg-2-dir2/obj-v0.cc
new file mode 100644
index 0000000..b96530e
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-2-dir2/obj-v0.cc
@@ -0,0 +1,25 @@
+// Compile with:
+// g++ -g -shared -o libobj-v0.so obj-v0.cc
+
+struct S0
+{
+  int  mem0;
+  char mem1;
+
+  S0()
+    : mem0(),
+      mem1()
+  {}
+};
+
+struct S1
+{
+  int mem2;
+};
+void
+bar(S0&)
+{}
+
+void
+foo(S1&)
+{}
diff --git a/tests/data/test-diff-pkg/dirpkg-2-report-0.txt b/tests/data/test-diff-pkg/dirpkg-2-report-0.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/data/test-diff-pkg/dirpkg-2-report-1.txt b/tests/data/test-diff-pkg/dirpkg-2-report-1.txt
new file mode 100644
index 0000000..c7c9226
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-2-report-1.txt
@@ -0,0 +1,16 @@
+================ changes of 'libobj-v0.so'===============
+  Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+  Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+  1 function with some indirect sub-type change:
+
+    [C]'function void bar(S&)' has some indirect sub-type changes:
+      parameter 1 of type 'S&' has sub-type changes:
+        in referenced type 'struct S':
+          type size changed from 32 to 64 bits
+          1 data member insertion:
+            'char S::mem1', at offset 32 (in bits)
+
+
+================ end of changes of 'libobj-v0.so'===============
+
diff --git a/tests/data/test-diff-pkg/dirpkg-3-dir1/libobj-v0.so b/tests/data/test-diff-pkg/dirpkg-3-dir1/libobj-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..327577dc2e9a41bf33616b98398b6dbb7c05e40d
GIT binary patch
literal 9088
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
JQXDF*_z%jLSP}pL

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-pkg/dirpkg-3-dir1/obj-v0.cc b/tests/data/test-diff-pkg/dirpkg-3-dir1/obj-v0.cc
new file mode 100644
index 0000000..206a265
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-3-dir1/obj-v0.cc
@@ -0,0 +1,22 @@
+// Compile with:
+// g++ -g -shared -o libobj-v0.so obj-v0.cc
+
+struct S0
+{
+  int mem0;
+
+  S0()
+    : mem0()
+  {}
+};
+
+struct S1
+{
+};
+void
+bar(S0&)
+{}
+
+void
+foo(S1&)
+{}
diff --git a/tests/data/test-diff-pkg/dirpkg-3-dir2/.abignore b/tests/data/test-diff-pkg/dirpkg-3-dir2/.abignore
new file mode 100644
index 0000000..b8f8197
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-3-dir2/.abignore
@@ -0,0 +1,2 @@
+[suppress_function]
+  name = foo
diff --git a/tests/data/test-diff-pkg/dirpkg-3-dir2/libobj-v0.so b/tests/data/test-diff-pkg/dirpkg-3-dir2/libobj-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..de46f91bef99b1871dc16acecf5e314b2f500df6
GIT binary patch
literal 9136
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

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-pkg/dirpkg-3-dir2/obj-v0.cc b/tests/data/test-diff-pkg/dirpkg-3-dir2/obj-v0.cc
new file mode 100644
index 0000000..b96530e
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-3-dir2/obj-v0.cc
@@ -0,0 +1,25 @@
+// Compile with:
+// g++ -g -shared -o libobj-v0.so obj-v0.cc
+
+struct S0
+{
+  int  mem0;
+  char mem1;
+
+  S0()
+    : mem0(),
+      mem1()
+  {}
+};
+
+struct S1
+{
+  int mem2;
+};
+void
+bar(S0&)
+{}
+
+void
+foo(S1&)
+{}
diff --git a/tests/data/test-diff-pkg/dirpkg-3-report-0.txt b/tests/data/test-diff-pkg/dirpkg-3-report-0.txt
new file mode 100644
index 0000000..e69de29
diff --git a/tests/data/test-diff-pkg/dirpkg-3-report-1.txt b/tests/data/test-diff-pkg/dirpkg-3-report-1.txt
new file mode 100644
index 0000000..d0135b4
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-3-report-1.txt
@@ -0,0 +1,16 @@
+================ changes of 'libobj-v0.so'===============
+  Functions changes summary: 0 Removed, 1 Changed (1 filtered out), 0 Added function
+  Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+  1 function with some indirect sub-type change:
+
+    [C]'function void foo(S1&)' has some indirect sub-type changes:
+      parameter 1 of type 'S1&' has sub-type changes:
+        in referenced type 'struct S1':
+          type size changed from 8 to 32 bits
+          1 data member insertion:
+            'int S1::mem2', at offset 0 (in bits)
+
+
+================ end of changes of 'libobj-v0.so'===============
+
diff --git a/tests/data/test-diff-pkg/dirpkg-3.suppr b/tests/data/test-diff-pkg/dirpkg-3.suppr
new file mode 100644
index 0000000..c06dd56
--- /dev/null
+++ b/tests/data/test-diff-pkg/dirpkg-3.suppr
@@ -0,0 +1,2 @@
+[suppress_function]
+  name = bar
diff --git a/tests/test-diff-pkg.cc b/tests/test-diff-pkg.cc
index 2e56d31..f788282 100644
--- a/tests/test-diff-pkg.cc
+++ b/tests/test-diff-pkg.cc
@@ -40,12 +40,14 @@
 
 using std::string;
 using std::cerr;
+using abigail::tests::get_src_dir;
 
 struct InOutSpec
 {
   const char* first_in_package_path;
   const char* second_in_package_path;
   const char* prog_options;
+  const char* suppression_path;
   const char* first_in_debug_package_path;
   const char* second_in_debug_package_path;
   const char* ref_report_path;
@@ -54,15 +56,79 @@ struct InOutSpec
 
 static InOutSpec in_out_specs[] =
 {
+  // dir1 contains a suppr spec - it should be ignored.
   {
     "data/test-diff-pkg/dirpkg-0-dir1",
     "data/test-diff-pkg/dirpkg-0-dir2",
     "",
     "",
     "",
+    "",
     "data/test-diff-pkg/dirpkg-0-report-0.txt",
     "output/test-diff-pkg/dirpkg-0-report-0.txt"
   },
+  // dir2 contains a suppr spec - it should be recognized.
+  {
+    "data/test-diff-pkg/dirpkg-1-dir1",
+    "data/test-diff-pkg/dirpkg-1-dir2",
+    "",
+    "",
+    "",
+    "",
+    "data/test-diff-pkg/dirpkg-1-report-0.txt",
+    "output/test-diff-pkg/dirpkg-1-report-0.txt"
+  },
+  // dir2 contains a suppr spec but --no-abignore is specified,
+  // the file should be ignored.
+  {
+    "data/test-diff-pkg/dirpkg-1-dir1",
+    "data/test-diff-pkg/dirpkg-1-dir2",
+    "--no-abignore",
+    "",
+    "",
+    "",
+    "data/test-diff-pkg/dirpkg-1-report-1.txt",
+    "output/test-diff-pkg/dirpkg-1-report-1.txt"
+  },
+  // dir2 contains several suppr spec files, ".abignore" and
+  // "dir.abignore", so the specs should be merged.
+  {
+    "data/test-diff-pkg/dirpkg-2-dir1",
+    "data/test-diff-pkg/dirpkg-2-dir2",
+    "",
+    "",
+    "",
+    "",
+    "data/test-diff-pkg/dirpkg-2-report-0.txt",
+    "output/test-diff-pkg/dirpkg-2-report-0.txt"
+  },
+  // dir2 contains a suppr spec file, ".abignore" and
+  // an additional suppr file is specified on the command line,
+  // so the specs should be merged.
+  {
+    "data/test-diff-pkg/dirpkg-3-dir1",
+    "data/test-diff-pkg/dirpkg-3-dir2",
+    "",
+    "data/test-diff-pkg/dirpkg-3.suppr",
+    "",
+    "",
+    "data/test-diff-pkg/dirpkg-3-report-0.txt",
+    "output/test-diff-pkg/dirpkg-3-report-0.txt"
+  },
+  // dir2 contains a suppr spec file, ".abignore", which should
+  // be ignored because of the program options  and
+  // an additional suppr file is specified on the command line,
+  // which should be recognized.
+  {
+    "data/test-diff-pkg/dirpkg-3-dir1",
+    "data/test-diff-pkg/dirpkg-3-dir2",
+    "--no-abignore",
+    "data/test-diff-pkg/dirpkg-3.suppr",
+    "",
+    "",
+    "data/test-diff-pkg/dirpkg-3-report-1.txt",
+    "output/test-diff-pkg/dirpkg-3-report-1.txt"
+  },
 
 #if WITH_TAR
   {
@@ -71,6 +137,7 @@ static InOutSpec in_out_specs[] =
     "",
     "",
     "",
+    "",
     "data/test-diff-pkg/tarpkg-0-report-0.txt",
     "output/test-diff-pkg/tarpkg-0-report-0.txt"
   },
@@ -80,6 +147,7 @@ static InOutSpec in_out_specs[] =
     "",
     "",
     "",
+    "",
     "data/test-diff-pkg/tarpkg-0-report-0.txt",
     "output/test-diff-pkg/tarpkg-0-report-0.txt"
   },
@@ -89,6 +157,7 @@ static InOutSpec in_out_specs[] =
     "",
     "",
     "",
+    "",
     "data/test-diff-pkg/tarpkg-0-report-0.txt",
     "output/test-diff-pkg/tarpkg-0-report-0.txt"
   },
@@ -98,6 +167,7 @@ static InOutSpec in_out_specs[] =
     "",
     "",
     "",
+    "",
     "data/test-diff-pkg/tarpkg-0-report-0.txt",
     "output/test-diff-pkg/tarpkg-0-report-0.txt"
   },
@@ -109,6 +179,7 @@ static InOutSpec in_out_specs[] =
     "data/test-diff-pkg/dbus-glib-0.80-3.fc12.x86_64.rpm",
     "data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64.rpm",
     "",
+    "",
     "data/test-diff-pkg/dbus-glib-debuginfo-0.80-3.fc12.x86_64.rpm",
     "data/test-diff-pkg/dbus-glib-debuginfo-0.104-3.fc23.x86_64.rpm",
     "data/test-diff-pkg/test-rpm-report-0.txt",
@@ -119,6 +190,7 @@ static InOutSpec in_out_specs[] =
   "data/test-diff-pkg/dbus-glib-0.80-3.fc12.x86_64.rpm",
   "data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64.rpm",
   "",
+  "",
   "data/test-diff-pkg/dbus-glib-debuginfo-0.80-3.fc12.x86_64.rpm",
   "",
   "data/test-diff-pkg/test-rpm-report-1.txt",
@@ -131,6 +203,7 @@ static InOutSpec in_out_specs[] =
   "data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64.rpm",
   "",
   "",
+  "",
   "data/test-diff-pkg/dbus-glib-debuginfo-0.104-3.fc23.x86_64.rpm",
   "data/test-diff-pkg/test-rpm-report-2.txt",
   "output/test-diff-pkg/test-rpm-report-2.txt"
@@ -143,6 +216,7 @@ static InOutSpec in_out_specs[] =
   "",
   "",
   "",
+  "",
   "data/test-diff-pkg/test-rpm-report-3.txt",
   "output/test-diff-pkg/test-rpm-report-3.txt"
   },
@@ -152,6 +226,7 @@ static InOutSpec in_out_specs[] =
   "data/test-diff-pkg/dbus-glib-0.80-3.fc12.x86_64.rpm",
   "data/test-diff-pkg/dbus-glib-0.80-3.fc12.x86_64.rpm",
   "",
+  "",
   "data/test-diff-pkg/dbus-glib-debuginfo-0.80-3.fc12.x86_64.rpm",
   "data/test-diff-pkg/dbus-glib-debuginfo-0.80-3.fc12.x86_64.rpm",
   "data/test-diff-pkg/test-rpm-report-4.txt",
@@ -163,6 +238,7 @@ static InOutSpec in_out_specs[] =
     "data/test-diff-pkg/dbus-glib-0.80-3.fc12.x86_64.rpm",
     "data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64.rpm",
     "--no-added-syms",
+    "",
     "data/test-diff-pkg/dbus-glib-debuginfo-0.80-3.fc12.x86_64.rpm",
     "data/test-diff-pkg/dbus-glib-debuginfo-0.104-3.fc23.x86_64.rpm",
     "data/test-diff-pkg/test-rpm-report-5.txt",
@@ -176,6 +252,7 @@ static InOutSpec in_out_specs[] =
     "data/test-diff-pkg/libsigc++-2.0-0c2a_2.4.0-1_amd64.deb",
     "data/test-diff-pkg/libsigc++-2.0-0v5_2.4.1-1ubuntu2_amd64.deb",
     "--fail-no-dbg",
+    "",
     "data/test-diff-pkg/libsigc++-2.0-0c2a-dbgsym_2.4.0-1_amd64.ddeb",
     "data/test-diff-pkg/libsigc++-2.0-0v5-dbgsym_2.4.1-1ubuntu2_amd64.ddeb",
     "data/test-diff-pkg/libsigc++-2.0-0c2a_2.4.0-1_amd64--libsigc++-2.0-0v5_2.4.1-1ubuntu2_amd64-report-0.txt",
@@ -183,13 +260,12 @@ static InOutSpec in_out_specs[] =
   },
 #endif // WITH_DEB
   // This should be the last entry.
-  {0, 0, 0, 0, 0, 0, 0}
+  {0, 0, 0, 0, 0, 0, 0, 0}
 };
 
 int
 main()
 {
-  using abigail::tests::get_src_dir;
   using abigail::tests::get_build_dir;
   using abigail::tools_utils::ensure_parent_dir_created;
 
@@ -197,7 +273,8 @@ main()
   string first_in_package_path, second_in_package_path,
     prog_options,
     ref_abi_diff_report_path, out_abi_diff_report_path, cmd, abipkgdiff,
-    first_in_debug_package_path, second_in_debug_package_path;
+    first_in_debug_package_path, second_in_debug_package_path,
+    suppression_path;
   for (InOutSpec *s = in_out_specs; s->first_in_package_path; ++s)
     {
       first_in_package_path =
@@ -220,6 +297,14 @@ main()
           get_src_dir() + "/tests/" + s->second_in_debug_package_path;
       else
         second_in_debug_package_path.clear();
+
+      if (s->suppression_path
+          && strcmp(s->suppression_path, ""))
+        suppression_path =
+          get_src_dir() + "/tests/" + s->suppression_path;
+      else
+        suppression_path.clear();
+
       ref_abi_diff_report_path = get_src_dir() + "/tests/" + s->ref_report_path;
       out_abi_diff_report_path =
         get_build_dir() + "/tests/" + s->out_report_path;
@@ -242,6 +327,9 @@ main()
       if (!second_in_debug_package_path.empty())
         abipkgdiff += " --d2 " + second_in_debug_package_path;
 
+      if (!suppression_path.empty())
+        abipkgdiff += " --suppressions " + suppression_path;
+
       cmd =
         abipkgdiff + " " + first_in_package_path + " " + second_in_package_path;
       cmd += " > " + out_abi_diff_report_path;
diff --git a/tools/abipkgdiff.cc b/tools/abipkgdiff.cc
index 8dd8997..5e7956f 100644
--- a/tools/abipkgdiff.cc
+++ b/tools/abipkgdiff.cc
@@ -60,6 +60,7 @@ using std::vector;
 using std::map;
 using std::tr1::shared_ptr;
 using abigail::tools_utils::guess_file_type;
+using abigail::tools_utils::string_ends_with;
 using abigail::tools_utils::file_type;
 using abigail::tools_utils::make_path_absolute;
 using abigail::tools_utils::abidiff_status;
@@ -82,16 +83,21 @@ static bool verbose;
 /// This contains the set of files of a given package.  It's populated
 /// by a worker function that is invoked on each file contained in the
 /// package.  So this global variable is filled by the
-/// file_tree_walker_callback_fn() function.  Its content is relevant
-/// only during the time after which the current package has been
+/// file_tree_walker_callback_{elf,suppr}_fn() functions.  Its content is
+/// relevant only during the time after which the current package has been
 /// analyzed and before we start analyzing the next package.
 static vector<string> elf_file_paths;
 
+/// This points to the set of options shared by all the routines of the
+/// program.
+static struct options *prog_options;
+
 /// The options passed to the current program.
 struct options
 {
   bool		display_usage;
   bool		missing_operand;
+  bool		abignore;
   string	package1;
   string	package2;
   string	debug_package1;
@@ -108,13 +114,15 @@ struct options
   options()
     : display_usage(),
       missing_operand(),
+      abignore(true),
       keep_tmp_files(),
       compare_dso_only(),
       show_linkage_names(true),
       show_redundant_changes(),
       show_added_syms(true),
       show_added_binaries(true),
-      fail_if_no_debug_info()
+      fail_if_no_debug_info(),
+      suppression_paths()
   {}
 };
 
@@ -146,6 +154,10 @@ public:
 /// A convenience typedef for a shared pointer to elf_file.
 typedef shared_ptr<elf_file> elf_file_sptr;
 
+/// A convenience typedef for a pointer to a function type that
+/// the ftw() function accepts.
+typedef int (*ftw_cb_type)(const char *, const struct stat*, int);
+
 /// Abstract the result of comparing two packages.
 ///
 /// This contains the the paths of the set of added binaries, removed
@@ -653,9 +665,9 @@ extract_package(const package& package)
 ///
 /// @param stat the stat struct of the file.
 static int
-file_tree_walker_callback_fn(const char *fpath,
-			     const struct stat *,
-			     int /*flag*/)
+first_package_tree_walker_callback_fn(const char *fpath,
+				      const struct stat *,
+				      int /*flag*/)
 {
   struct stat s;
   lstat(fpath, &s);
@@ -668,6 +680,30 @@ file_tree_walker_callback_fn(const char *fpath,
   return 0;
 }
 
+/// A callback function invoked by the ftw() function while walking
+/// the directory of files extracted from the second package, unless
+/// "--no-abignore" is specified on the command line.
+///
+/// @param fpath the path to the file being considered.
+///
+/// @param stat the stat struct of the file.
+static int
+second_package_tree_walker_callback_fn(const char *fpath,
+				       const struct stat *,
+				       int /*flag*/)
+{
+  struct stat s;
+  lstat(fpath, &s);
+
+  if (!S_ISLNK(s.st_mode))
+    {
+      if (guess_file_type(fpath) == abigail::tools_utils::FILE_TYPE_ELF)
+	elf_file_paths.push_back(fpath);
+      else if (prog_options->abignore && string_ends_with(fpath, ".abignore"))
+	prog_options->suppression_paths.push_back(fpath);
+    }
+  return 0;
+}
 /// Update the diff context from the @ref options data structure.
 ///
 /// @param ctxt the diff context to update.
@@ -858,9 +894,11 @@ compare(const elf_file& elf1,
 /// @param opts the options the current program has been called with.
 ///
 /// @param true upon successful completion, false otherwise.
+
 static bool
 create_maps_of_package_content(package& package,
-			       const options& opts)
+			       const options& opts,
+			       ftw_cb_type callback)
 {
   elf_file_paths.clear();
   if (verbose)
@@ -870,9 +908,7 @@ create_maps_of_package_content(package& package,
 	 << package.extracted_dir_path()
 	 << " ...";
 
-  if (ftw(package.extracted_dir_path().c_str(),
-	  file_tree_walker_callback_fn,
-	  16))
+  if (ftw(package.extracted_dir_path().c_str(), callback, 16))
     {
       cerr << "Error while inspecting files in package"
 	   << package.extracted_dir_path() << "\n";
@@ -919,14 +955,15 @@ create_maps_of_package_content(package& package,
 /// @return true upon successful completion, false otherwise.
 static bool
 extract_package_and_map_its_content(package& package,
-				    const options& opts)
+				    const options& opts,
+				    ftw_cb_type callback)
 {
   if (!extract_package(package))
     return false;
 
   bool result = true;
   if (!package.is_debug_info())
-    result |= create_maps_of_package_content(package, opts);
+    result |= create_maps_of_package_content(package, opts, callback);
 
   return result;
 }
@@ -947,8 +984,12 @@ prepare_packages(package&	first_package,
 		 package&	second_package,
 		 const options& opts)
 {
-  if (!extract_package_and_map_its_content(first_package, opts)
-      || !extract_package_and_map_its_content(second_package, opts))
+  if (!extract_package_and_map_its_content(first_package, opts,
+					   first_package_tree_walker_callback_fn)
+      /// We go through the files of the newer (second) pkg to look for
+      /// suppression specifications, matching the "*.abignore" name pattern.
+      || !extract_package_and_map_its_content(second_package, opts,
+					      second_package_tree_walker_callback_fn))
     return false;
 
   if ((first_package.debug_info_package()
@@ -1142,6 +1183,8 @@ parse_command_line(int argc, char* argv[], options& opts)
 	opts.fail_if_no_debug_info = true;
       else if (!strcmp(argv[i], "--verbose"))
 	verbose = true;
+      else if (!strcmp(argv[i], "--no-abignore"))
+	opts.abignore = false;
       else if (!strcmp(argv[i], "--suppressions")
 	       || !strcmp(argv[i], "--suppr"))
 	{
@@ -1168,6 +1211,7 @@ int
 main(int argc, char* argv[])
 {
   options opts;
+  prog_options = &opts;
   vector<package_sptr> packages;
   if (!parse_command_line(argc, argv, opts))
     {
-- 
2.4.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2015-10-13  7:25 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-01  0:00 [Bug default/19082] New: Make abipkgdiff recognize suppression specifications to apply to comparisons dodji at redhat dot com
2015-01-01  0:00 ` Ondrej Oprala
2015-01-01  0:00   ` Dodji Seketeli
2015-01-01  0:00     ` Ondrej Oprala
2015-01-01  0:00       ` Dodji Seketeli
2015-01-01  0:00 ` [Bug default/19082] " dodji at redhat dot com
2015-01-01  0:00 ` ooprala at redhat dot com
2015-01-01  0:00 ` ooprala at redhat dot com
2015-01-01  0:00 ` ooprala at redhat dot com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).