1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
|
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this,
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import argparse
import logging
import os.path
from pathlib import Path
from mutlh.decorators import Command, CommandArgument
# https://stackoverflow.com/a/14117511
def _positive_int(value):
value = int(value)
if value <= 0:
raise argparse.ArgumentTypeError(f"{value} must be a positive integer.")
return value
def _retry_run_process(command_context, *args, error_msg=None, **kwargs):
try:
return command_context.run_process(*args, **kwargs)
except Exception as exc:
raise Exception(error_msg or str(exc)) from exc
def _get_rev(command_context, strings_path):
result = []
def save_output(line):
result.append(line)
status = _retry_run_process(
command_context,
[
"hg",
"--cwd",
str(strings_path),
"log",
"-r",
".",
"--template",
"{node}\n",
],
line_handler=save_output,
)
if status == 0:
return "\n".join(result)
raise Exception(f"Failed to get head revision: {status}")
@Command(
"tb-l10n-x-channel",
category="thunderbird",
description="Create cross-channel content for Thunderbird (comm-strings).",
)
@CommandArgument(
"--strings-path",
"-s",
metavar="en-US",
type=Path,
default=Path("en-US"),
help="Path to mercurial repository for comm-strings-quarantine",
)
@CommandArgument(
"--outgoing-path",
"-o",
type=Path,
help="create an outgoing() patch if there are changes",
)
@CommandArgument(
"--attempts",
type=_positive_int,
default=1,
help="Number of times to try (for automation)",
)
@CommandArgument(
"--ssh-secret",
action="store",
help="Taskcluster secret to use to push (for automation)",
)
@CommandArgument(
"actions",
choices=("prep", "create", "push", "clean"),
nargs="+",
# This help block will be poorly formatted until we fix bug 1714239
help="""
"prep": clone repos and pull heads.
"create": create the en-US strings commit an optionally create an
outgoing() patch.
"push": push the en-US strings to the quarantine repo.
"clean": clean up any sub-repos.
""",
)
def tb_cross_channel(
command_context,
strings_path,
outgoing_path,
actions,
attempts,
ssh_secret,
**kwargs,
):
"""Run Thunderbird's l10n cross-channel content generation."""
from tbxchannel import TB_XC_NOTIFICATION_TMPL, get_thunderbird_xc_config
from tbxchannel.l10n_merge import COMM_STRINGS_QUARANTINE
from rocbuild.notify import email_notification
kwargs.update(
{
"strings_path": strings_path,
"outgoing_path": outgoing_path,
"actions": actions,
"attempts": attempts,
"ssh_secret": ssh_secret,
"get_config": get_thunderbird_xc_config,
}
)
command_context._mach_context.commands.dispatch(
"l10n-cross-channel", command_context._mach_context, **kwargs
)
if os.path.exists(outgoing_path):
head_rev = _get_rev(command_context, strings_path)
rev_url = f"{COMM_STRINGS_QUARANTINE}/rev/{head_rev}"
notification_body = TB_XC_NOTIFICATION_TMPL.format(rev_url=rev_url)
email_notification("X-channel comm-strings-quarantine updated", notification_body)
@Command(
"tb-add-missing-ftls",
category="thunderbird",
description="Add missing FTL files after l10n merge.",
)
@CommandArgument(
"--merge",
type=Path,
help="Merge path base",
)
@CommandArgument(
"locale",
type=str,
help="Locale code",
)
def tb_add_missing_ftls(command_context, merge, locale):
"""
Command to create empty FTL files for incomplete localizations to
avoid over-zealous en-US fallback as described in bug 1586984. This
mach command is based on the script used to update the l10n-central
repositories. It gets around the need to have write access to those
repositories in favor of creating the files during l10m-repackaging.
This code assumes that mach compare-locales --merge has already run.
"""
from missing_ftl import add_missing_ftls, get_lang_ftls, get_source_ftls
print("Checking for missing .ftl files in locale {}".format(locale))
comm_src_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
source_files = get_source_ftls(comm_src_dir)
l10n_path = os.path.join(merge, locale)
locale_files = get_lang_ftls(l10n_path)
add_missing_ftls(l10n_path, source_files, locale_files)
@Command(
"tb-fluent-migration-test",
category="thunderbird",
description="Test Fluent migration recipes.",
)
@CommandArgument("test_paths", nargs="*", metavar="N", help="Recipe paths to test.")
def run_migration_tests(command_context, test_paths=None, **kwargs):
if not test_paths:
test_paths = []
command_context.activate_virtualenv()
from tbxchannel.tb_migration_test import inspect_migration, prepare_object_dir, test_migration
rv = 0
with_context = []
for to_test in test_paths:
try:
context = inspect_migration(to_test)
for issue in context["issues"]:
command_context.log(
logging.ERROR,
"tb-fluent-migration-test",
{
"error": issue["msg"],
"file": to_test,
},
"ERROR in {file}: {error}",
)
if context["issues"]:
continue
with_context.append(
{
"to_test": to_test,
"references": context["references"],
}
)
except Exception as e:
command_context.log(
logging.ERROR,
"tb-fluent-migration-test",
{"error": str(e), "file": to_test},
"ERROR in {file}: {error}",
)
rv |= 1
obj_dir = prepare_object_dir(command_context)
for context in with_context:
rv |= test_migration(command_context, obj_dir, **context)
return rv
from mutlh.decorators import Command, CommandArgument
@Command(
"tb-l10n-quarantine-to-strings",
category="thunderbird",
description="Publish quarantines strings to comm-l10n.",
)
@CommandArgument(
"--quarantine-path",
"-q",
type=Path,
help="Path to comm-strings-quarantine repo",
)
@CommandArgument(
"--comm-l10n-path",
"-l",
type=Path,
help="Path to comm-l10n repo",
)
@CommandArgument(
"actions",
choices=("clean", "prep", "migrate", "push"),
nargs="+",
# This help block will be poorly formatted until we fix bug 1714239
help="""
"clean": remove existing clones of quarantine and comm-l10n repos
"prep": clone a new repository or update an existing one to latest rev
"migrate": update comm-l10n en_US from quarantine
"push": push comm-l10n
""",
)
def quarantine_to_strings(
command_context,
quarantine_path,
comm_l10n_path,
actions,
**kwargs,
):
"""Publish strings in Thunderbird's comm-l10n cross-channel repository from
comm-strings-quarantine."""
from tbxchannel.quarantine_to_strings import publish_strings
command_context._set_log_level(True)
command_context.activate_virtualenv()
command_context.log_manager.enable_unstructured()
publish_strings(command_context, quarantine_path, comm_l10n_path, actions, **kwargs)
|