Compare commits

..

7 commits

Author SHA1 Message Date
Michael Catanzaro
644271fd57 Drop unapplied patch
This patch was dropped nearly 14 years ago, and we just never deleted
it.
2025-08-25 17:20:19 -05:00
Zbigniew Jędrzejewski-Szmek
265871658f Add patch to lock output file for writing
The previous patch that we had, to use a temporary file, is useful:
it prevents the situation where a half-written file is present on disk under the
name that the readers expect. For example, this solves the scenario where the
write is interrupted, and then the build process is restarted and something
reads the partially written file. This could happen when using intltool-merge
during development.

Nevertheless, the existing patch doesn't actually solve the problem of
concurrent writes: the name of the temporary file is fixed, so if two writers
attempt to write the file, they may open the same temporary file and then
finally rename the temporary file to destination. Readers will then read a
corrupted file. This happens in
https://bugzilla.redhat.com/show_bug.cgi?id=2268342, where we get a message that
indicates the cache file is corrupted ("odd number of elements"), and a desktop
file with some missing translations is written.

Patch was verified by rebuilding xfce4-terminal 10 times with an inserted check
that the two desktop files contain the expected number of elements.

The patch was written by Bernhard Wiedemann and is available in the intltool
repo on launchpad (but misattributed).
2025-08-25 17:15:28 -05:00
Fedora Release Engineering
85219b527e Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild 2025-07-24 17:43:32 +00:00
raveit65
bee4fe5f9f Convert to %autorelease and %autochangelog
[skip changelog]
2025-02-27 23:14:26 +01:00
Fedora Release Engineering
c582ed6f03 Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild 2025-01-17 07:17:00 +00:00
matiwari
1abb945489 CI gating tests migration to tmt 2024-08-06 23:45:01 +05:30
Fedora Release Engineering
f8d4ee0272 Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild 2024-07-18 10:28:59 +00:00
14 changed files with 278 additions and 165 deletions

1
.fmf/version Normal file
View file

@ -0,0 +1 @@
1

View file

@ -1,3 +1,12 @@
* Fri Jan 17 2025 Fedora Release Engineering <releng@fedoraproject.org> - 0.51.0-29
- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild
* Tue Aug 6 2024 Manish Tiwari <matiwari@redhat.com> - 0.51.0-28
- CI gating tests migration to tmt
* Thu Jul 18 2024 Fedora Release Engineering <releng@fedoraproject.org> - 0.51.0-27
- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild
* Wed Jan 24 2024 Fedora Release Engineering <releng@fedoraproject.org> - 0.51.0-26
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild

46
intltool-cache-race.patch Normal file
View file

@ -0,0 +1,46 @@
From 7355bdbca18c95a2b99cb254434ad2c2248d6747 Mon Sep 17 00:00:00 2001
From: Gianfranco Costamagna <locutusofborg@debian.org>
Date: Wed, 2 Dec 2020 16:52:53 +0100
Subject: [PATCH] [PATCH] Avoid a race where some processes try to use a
partial cache
Gbp-Pq: 0001-Avoid-a-race-where-some-processes-try-to-use-a-parti.patch.
---
intltool-merge.in | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/intltool-merge.in b/intltool-merge.in
index 05db7cf930..89923a7da1 100644
--- a/intltool-merge.in
+++ b/intltool-merge.in
@@ -43,6 +43,7 @@ use Getopt::Long;
use Text::Wrap;
use File::Basename;
use Encode;
+use Fcntl qw(:flock);
my $must_end_tag = -1;
my $last_depth = -1;
@@ -392,11 +393,14 @@ sub load_cache
sub get_cached_translation_database
{
+ open(my $lockfh, ">", "$cache_file.lock") or die $!;
+ flock($lockfh, LOCK_EX) or die "Could not lock '$cache_file.lock' - $!";
my $cache_file_age = -M $cache_file;
if (defined $cache_file_age)
{
if ($cache_file_age <= &get_newest_po_age)
{
+ close($lockfh);
&load_cache;
return;
}
@@ -404,6 +408,7 @@ sub get_cached_translation_database
}
&create_cache;
+ close($lockfh);
}
sub add_translation

View file

@ -18,19 +18,18 @@ BuildRequires: perl(Getopt::Long)
BuildRequires: perl(XML::Parser)
BuildRequires: gettext
BuildRequires: make
# http://bugzilla.gnome.org/show_bug.cgi?id=568845
# Dropping this patch per the last comment on that thread:
# Martin Pitt: As the reporter of the bug I close this, as the new API du jour is gsettings,
# which has a sensible gettext integration.
#Patch0: schemas-merge.patch
# Fix intltool-update to work with perl 5.26. Patch taken from
# Debian's intltool_0.51.0-4.debian.tar.xz
Patch1: intltool-perl5.26-regex-fixes.patch
Patch: intltool-perl5.26-regex-fixes.patch
# https://bugs.launchpad.net/intltool/+bug/1505260
# https://bugzilla.redhat.com/show_bug.cgi?id=1249051
Patch2: intltool-merge-Create-cache-file-atomically.patch
Patch: intltool-merge-Create-cache-file-atomically.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1318674
Patch3: intltool_distcheck-fix.patch
Patch: intltool_distcheck-fix.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2268342
# https://bugs.launchpad.net/intltool/+bug/1687644
Patch: intltool-cache-race.patch
%description
This tool automatically extracts translatable strings from oaf, glade,
@ -38,10 +37,7 @@ bonobo ui, nautilus theme, .desktop, and other data files and puts
them in the po files.
%prep
%setup -q
%patch 1 -p1
%patch 2 -p1
%patch 3 -p1
%autosetup -p1
%build
%configure

5
plans/basic.fmf Normal file
View file

@ -0,0 +1,5 @@
summary: Basic smoke test
discover:
how: fmf
execute:
how: tmt

View file

@ -1,153 +0,0 @@
diff -up intltool-0.40.6/intltool-merge.in.schemas intltool-0.40.6/intltool-merge.in
--- intltool-0.40.6/intltool-merge.in.schemas 2009-02-14 17:12:28.000000000 -0500
+++ intltool-0.40.6/intltool-merge.in 2009-04-27 01:41:11.099450891 -0400
@@ -38,8 +38,9 @@ my $PACKAGE = "@PACKAGE@";
my $VERSION = "@VERSION@";
## Loaded modules
-use strict;
+use strict;
use Getopt::Long;
+use Cwd;
use Text::Wrap;
use File::Basename;
use Encode;
@@ -68,6 +69,9 @@ my $PASS_THROUGH_ARG = 0;
my $UTF8_ARG = 0;
my $MULTIPLE_OUTPUT = 0;
my $cache_file;
+my $GETTEXT_PACKAGE = "";
+my %varhash = ();
+my $SRCDIR = $ENV{"srcdir"} || ".";
## Handle options
GetOptions
@@ -87,7 +91,8 @@ GetOptions
"pass-through|p" => \$PASS_THROUGH_ARG,
"utf8|u" => \$UTF8_ARG,
"multiple-output|m" => \$MULTIPLE_OUTPUT,
- "cache|c=s" => \$cache_file
+ "cache|c=s" => \$cache_file,
+ "gettext-package|g=s" => \$GETTEXT_PACKAGE
) or &error;
my $PO_DIR;
@@ -103,6 +108,8 @@ my $w = "[-A-Za-z0-9._:]";
# XML quoted string contents
my $q = "[^\\\"]*";
+my $MODULE = $GETTEXT_PACKAGE || FindPackageName() || "unknown";
+
## Check for options.
if ($VERSION_ARG)
@@ -216,6 +223,8 @@ Other options:
a single file containing all localized elements
-c, --cache=FILE specify cache file name
(usually \$top_builddir/po/.intltool-merge-cache)
+ -g, --gettext-package=NAME
+ specify gettext domain, needed for --schemas-style
-q, --quiet suppress most messages
--help display this help and exit
--version output version information and exit
@@ -241,6 +250,25 @@ sub print_message
}
+sub FindPackageName
+{
+ my $name = "";
+
+ my $conf_source; {
+ local (*IN);
+ open (IN, "<Makefile") || return $name;
+ seek (IN, 0, 0);
+ local $/; # slurp mode
+ $conf_source = <IN>;
+ close IN;
+ }
+
+ $name = $1 if $conf_source =~ /^GETTEXT_PACKAGE = \[?([^\n\]]+)/m;
+
+ return $name if $name;
+}
+
+
sub preparation
{
$PO_DIR = $ARGV[0];
@@ -1246,50 +1274,41 @@ sub schemas_merge_translations
my $short_string = $9 ? $9 : '';
my $long_string = $12 ? $12 : '';
- print OUTPUT "$locale_start_spaces$c_default_block";
-
$default_string =~ s/\s+/ /g;
- $default_string = entity_decode($default_string);
$short_string =~ s/\s+/ /g;
- $short_string = entity_decode($short_string);
$long_string =~ s/\s+/ /g;
- $long_string = entity_decode($long_string);
- for my $lang (sort keys %po_files_by_lang)
- {
- my $default_translation = $translations{$lang, $default_string};
- my $short_translation = $translations{$lang, $short_string};
- my $long_translation = $translations{$lang, $long_string};
-
- next if (!$default_translation && !$short_translation &&
- !$long_translation);
-
- print OUTPUT "\n$locale_start_spaces<locale name=\"$lang\">";
+ print OUTPUT "$locale_start_spaces<gettext_domain>$MODULE</gettext_domain>";
+ print OUTPUT "$locale_start_spaces<locale name=\"C\">";
print OUTPUT "$default_spaces";
-
- if ($default_translation)
- {
- $default_translation = entity_encode($default_translation);
- print OUTPUT "<default>$default_translation</default>";
+ if ($default_string) {
+ print OUTPUT "<default>$default_string</default>";
}
+ print OUTPUT "$short_spaces";
+ if ($short_string) {
+ print OUTPUT "<short>$short_string</short>";
+ }
+ print OUTPUT "$long_spaces";
+ if ($long_string) {
+ print OUTPUT "<long>$long_string</long>";
+ }
+ print OUTPUT "$locale_end_spaces</locale>";
- print OUTPUT "$short_spaces";
+ $default_string = entity_decode($default_string);
+ $short_string = entity_decode($short_string);
+ $long_string = entity_decode($long_string);
- if ($short_translation)
- {
- $short_translation = entity_encode($short_translation);
- print OUTPUT "<short>$short_translation</short>";
- }
+ for my $lang (sort keys %po_files_by_lang)
+ {
+ my $default_translation = $translations{$lang, $default_string};
- print OUTPUT "$long_spaces";
+ next if (!$default_translation || ($default_translation eq $default_string));
- if ($long_translation)
- {
- $long_translation = entity_encode($long_translation);
- print OUTPUT "<long>$long_translation</long>";
- }
+ $default_translation = entity_encode($default_translation);
+ print OUTPUT "\n$locale_start_spaces<locale name=\"$lang\">";
+ print OUTPUT "$default_spaces<default>$default_translation</default>";
print OUTPUT "$locale_end_spaces</locale>";
}
}
diff -up intltool-0.40.6/tests/results/test.schemas intltool-0.40.6/tests/results/test

19
tests/cases/context.xml Normal file
View file

@ -0,0 +1,19 @@
<test>
<entry>
<_name>Foo</_name>
</entry>
<entry>
<!-- This is the comment on the first Bar -->
<_name msgctxt="1">
Bar</_name>
</entry>
<entry>
<!-- This is the comment on the second Bar -->
<_name msgctxt="2">
Bar</_name>
</entry>
<entry>
<!-- This is the comment on Baz -->
<_name>Baz</_name>
</entry>
</test>

View file

@ -0,0 +1,17 @@
<test>
<entry>
<_name>Foo</_name>
</entry>
<entry>
<!-- This is the comment on the first Bar -->
<_name msgctxt="1">Bar</_name>
</entry>
<entry>
<!-- This is the comment on the second Bar -->
<_name msgctxt="2">Bar</_name>
</entry>
<entry>
<!-- This is the comment on Baz -->
<_name>Baz</_name>
</entry>
</test>

View file

@ -0,0 +1,7 @@
char *s = N_("Foo");
/* This is the comment on the first Bar */
char *s = C_("1", "Bar");
/* This is the comment on the second Bar */
char *s = C_("2", "Bar");
/* This is the comment on Baz */
char *s = N_("Baz");

109
tests/intltool_tests.py Normal file
View file

@ -0,0 +1,109 @@
#!/usr/bin/python3
import logging
import subprocess
from difflib import Differ
logging.basicConfig(level=logging.INFO)
COMMANDS = [
"intltool-extract",
"intltool-merge"
]
INPUT_FILE = "cases/context.xml.in"
def test_intltool_installation(cmd: str):
"""
Check if intltool is installed correctly
"""
try:
intltool_cmd = subprocess.Popen([cmd], stdout=subprocess.PIPE)
intltool_cmd_execution_response = intltool_cmd.communicate()
assert "Usage" in str(intltool_cmd_execution_response)
except FileNotFoundError:
logging.error(f"Either {cmd} is not installed or not accessible.")
except OSError:
logging.error(f"Some OSError occurred while executing {cmd}")
except AssertionError:
logging.error(f"[CMD] output does not include text: Usage.")
else:
logging.info(f"Execution of {cmd} succeed. Test Passed.")
def test_intltool_extract(cmd, input_file):
"""
Check intltool extract behavior
"""
try:
intltool_extract = subprocess.Popen(
[cmd, "--type=gettext/xml", input_file, "--update"],
stdout=subprocess.PIPE)
intltool_extract_execution_response = intltool_extract.communicate()
assert "Wrote" in str(intltool_extract_execution_response)
except AssertionError:
logging.error(f"Writing output file for {input_file} file failed.")
except Exception as e:
logging.error(e)
else:
logging.info(f"Writing output file for {input_file} succeed.")
comparison_test_pass = True
with open("{}.h".format(input_file)) as output_file, open("results/{}.h".format("context.xml.in")) as refer_file:
differ = Differ()
for line in differ.compare(output_file.readlines(), refer_file.readlines()):
if line.startswith("+") or line.startswith("-"):
comparison_test_pass = False
try:
assert comparison_test_pass
except AssertionError:
logging.error("Extracted file does NOT match with the result. Test failed.")
else:
logging.info("Extracted file does match with the result. Test passed.")
def test_intltool_merge(cmd, input_file):
"""
Check intltool merge behavior
"""
merged_file = "context.xml"
try:
intltool_merge = subprocess.Popen(
[cmd, "-o", "cases", input_file, "cases/{}".format(merged_file)],
stdout=subprocess.PIPE)
intltool_merge_execution_response = intltool_merge.communicate()
assert "Merging" in str(intltool_merge_execution_response)
except AssertionError:
logging.error(f"Writing output file for {input_file} file failed.")
except Exception as e:
logging.error(e)
else:
logging.info(f"Writing output file for {input_file} succeed.")
comparison_test_pass = True
with open("cases/{}".format(merged_file)) as output_file, open("results/{}".format(merged_file)) as refer_file:
differ = Differ()
for line in differ.compare(output_file.readlines(), refer_file.readlines()):
if line.startswith("+") or line.startswith("-"):
comparison_test_pass = False
try:
assert comparison_test_pass
except AssertionError:
logging.error("Merged file does NOT match with the result. Test failed.")
else:
logging.info("Merged file does match with the result. Test passed.")
if __name__ == "__main__":
"""
Executes test cases
"""
logging.info("Executing test cases for Intltool..")
for CMD in COMMANDS:
test_intltool_installation(CMD)
test_intltool_extract(COMMANDS[0], INPUT_FILE)
test_intltool_merge(COMMANDS[1], INPUT_FILE)
logging.info("Tests execution of Intltool completed!")

6
tests/main.fmf Normal file
View file

@ -0,0 +1,6 @@
summary: Run intltool test
test: ./test.sh
framework: beakerlib
require:
- intltool
- python3

19
tests/results/context.xml Normal file
View file

@ -0,0 +1,19 @@
<test>
<entry>
<_name>Foo</_name>
</entry>
<entry>
<!-- This is the comment on the first Bar -->
<_name msgctxt="1">
Bar</_name>
</entry>
<entry>
<!-- This is the comment on the second Bar -->
<_name msgctxt="2">
Bar</_name>
</entry>
<entry>
<!-- This is the comment on Baz -->
<_name>Baz</_name>
</entry>
</test>

View file

@ -0,0 +1,7 @@
char *s = N_("Foo");
/* This is the comment on the first Bar */
char *s = C_("1", "Bar");
/* This is the comment on the second Bar */
char *s = C_("2", "Bar");
/* This is the comment on Baz */
char *s = N_("Baz");

25
tests/test.sh Executable file
View file

@ -0,0 +1,25 @@
#!/bin/bash
# vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k
. /usr/share/beakerlib/beakerlib.sh || exit 1
PACKAGE="intltool"
rlJournalStart
rlPhaseStartSetup
rlAssertRpm $PACKAGE
rlRun "TmpDir=\`mktemp -d\`" 0 "Creating tmp directory"
rlRun "cp -r cases results intltool_tests.py $TmpDir"
rlRun "pushd $TmpDir"
rlPhaseEnd
rlPhaseStartTest
rlLog "Run intltool_tests.py"
rlRun "python3 intltool_tests.py"
rlPhaseEnd
rlPhaseStartCleanup
rlRun "popd"
rlRun "rm -r $TmpDir" 0 "Removing tmp directory"
rlPhaseEnd
rlJournalPrintText
rlJournalEnd