Commit 95e0c9e7 authored by Claude Paroz's avatar Claude Paroz

Add support for building Docbook docs

parent d72a2264
...@@ -787,7 +787,7 @@ class Domain(models.Model): ...@@ -787,7 +787,7 @@ class Domain(models.Model):
def can_build_docs(self, branch): def can_build_docs(self, branch):
try: try:
return self.dtype == 'doc' and self.doc_format(branch).format == 'mallard' return self.dtype == 'doc' and self.doc_format(branch)
except utils.UndetectableDocFormat: except utils.UndetectableDocFormat:
return False return False
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<!ENTITY lastversion "2.30"> <!ENTITY lastversion "2.30">
]> ]>
<article lang="en" id="index"> <article lang="en" id="release-notes">
<articleinfo> <articleinfo>
<title>GNOME &gnomeversion; Release Notes</title> <title>GNOME &gnomeversion; Release Notes</title>
......
...@@ -451,6 +451,13 @@ class TestModuleBase(TestCase): ...@@ -451,6 +451,13 @@ class TestModuleBase(TestCase):
cls.branch = Branch(module=cls.mod, name="master") cls.branch = Branch(module=cls.mod, name="master")
cls.branch.save(update_statistics=False) cls.branch.save(update_statistics=False)
@classmethod
def tearDownClass(cls):
html_dir = Path(settings.SCRATCHDIR) / 'HTML'
if html_dir.exists():
shutil.rmtree(str(html_dir))
super().tearDownClass()
class DomainTests(TestModuleBase): class DomainTests(TestModuleBase):
def setUp(self): def setUp(self):
......
...@@ -18,6 +18,7 @@ from people.models import Person ...@@ -18,6 +18,7 @@ from people.models import Person
from teams.models import Role from teams.models import Role
from teams.tests import TeamsAndRolesMixin from teams.tests import TeamsAndRolesMixin
from stats.models import Module, Branch, Release, Category, CategoryName, Domain, Statistics from stats.models import Module, Branch, Release, Category, CategoryName, Domain, Statistics
from stats.tests.tests import TestModuleBase
from stats.tests.utils import patch_shell_command, test_scratchdir from stats.tests.utils import patch_shell_command, test_scratchdir
from vertimus.models import ( from vertimus.models import (
Action, ActionArchived, ActionCI, ActionUNDO, ActionWC, State, StateCommitted, Action, ActionArchived, ActionCI, ActionUNDO, ActionWC, State, StateCommitted,
...@@ -741,32 +742,6 @@ class VertimusTest(TeamsAndRolesMixin, TestCase): ...@@ -741,32 +742,6 @@ class VertimusTest(TeamsAndRolesMixin, TestCase):
response = self.client.get(reverse('stats-quality-check', args=[po_stat.pk])) response = self.client.get(reverse('stats-quality-check', args=[po_stat.pk]))
self.assertContains(response, "The po file looks good!") self.assertContains(response, "The po file looks good!")
@test_scratchdir
def test_doc_building(self):
dom = Domain.objects.create(
module=self.m, name='help', description='User Guide', dtype='doc',
layout='help/{lang}/{lang}.po'
)
state = StateTranslating(branch=self.b, domain=dom, language=self.l, person=self.pt)
state.save()
file_path = Path(__file__).parent / "gnome-hello.help.fr.po"
with file_path.open() as test_file:
action = Action.new_by_name('UT', person=self.pt, file=File(test_file))
action.apply_on(state, {'send_to_ml': action.send_mail_to_ml, 'comment': "Done by translator."})
self.assertTrue(action.can_build)
self.assertIsNone(action.build_url)
response = self.client.post(reverse('action-build-help', args=[action.pk]))
self.assertRedirects(
response, '/HTML/%d/index.html' % action.pk, fetch_redirect_response=False
)
self.assertEqual(action.build_url, '/HTML/%d/index.html' % action.pk)
index_file = Path(
settings.SCRATCHDIR, 'HTML', str(action.pk), 'index.html'
)
with index_file.open('r') as ifile:
self.assertIn('<h2><span class="title">À propos</span></h2>', ifile.read())
def test_mysql(self): def test_mysql(self):
# Copied from test_action_undo() with minor changes # Copied from test_action_undo() with minor changes
state = StateNone(branch=self.b, domain=self.d, language=self.l) state = StateNone(branch=self.b, domain=self.d, language=self.l)
...@@ -802,3 +777,55 @@ class VertimusTest(TeamsAndRolesMixin, TestCase): ...@@ -802,3 +777,55 @@ class VertimusTest(TeamsAndRolesMixin, TestCase):
# Here be dragons! A call to len() workaround the Django/MySQL bug! # Here be dragons! A call to len() workaround the Django/MySQL bug!
len(actions_db) len(actions_db)
self.assertIsInstance(actions_db[0], ActionUNDO) self.assertIsInstance(actions_db[0], ActionUNDO)
class DocsBuildingTests(TeamsAndRolesMixin, TestModuleBase):
def test_doc_building(self):
dom = Domain.objects.create(
module=self.mod, name='help', description='User Guide', dtype='doc',
layout='help_mallard/{lang}/{lang}.po'
)
state = StateTranslating(branch=self.branch, domain=dom, language=self.l, person=self.pt)
state.save()
file_path = Path(__file__).parent / "gnome-hello.help.fr.po"
with file_path.open() as test_file:
action = Action.new_by_name('UT', person=self.pt, file=File(test_file))
action.apply_on(state, {'send_to_ml': action.send_mail_to_ml, 'comment': "Done by translator."})
self.assertTrue(action.can_build)
self.assertIsNone(action.build_url)
response = self.client.post(reverse('action-build-help', args=[action.pk]))
self.assertRedirects(
response, '/HTML/%d/index.html' % action.pk, fetch_redirect_response=False
)
self.assertEqual(action.build_url, '/HTML/%d/index.html' % action.pk)
index_file = Path(
settings.SCRATCHDIR, 'HTML', str(action.pk), 'index.html'
)
with index_file.open('r') as ifile:
self.assertIn('<h2><span class="title">À propos</span></h2>', ifile.read())
def test_docbook_building(self):
dom = Domain.objects.create(
module=self.mod, name='help', description='User Guide', dtype='doc',
layout='help_docbook/{lang}/{lang}.po'
)
state = StateTranslating(branch=self.branch, domain=dom, language=self.l, person=self.pt)
state.save()
file_path = Path(__file__).parent / "gnome-hello.help.fr.po"
with file_path.open() as test_file:
action = Action.new_by_name('UT', person=self.pt, file=File(test_file))
action.apply_on(state, {'send_to_ml': action.send_mail_to_ml, 'comment': "Done by translator."})
self.assertTrue(action.can_build)
self.assertIsNone(action.build_url)
response = self.client.post(reverse('action-build-help', args=[action.pk]))
self.assertRedirects(
response, '/HTML/%d/index.html' % action.pk, fetch_redirect_response=False
)
self.assertEqual(action.build_url, '/HTML/%d/index.html' % action.pk)
index_file = Path(
settings.SCRATCHDIR, 'HTML', str(action.pk), 'index.html'
)
with index_file.open('r') as ifile:
self.assertIn('<h2><span class="title">À propos</span></h2>', ifile.read())
...@@ -4,6 +4,7 @@ import re ...@@ -4,6 +4,7 @@ import re
import subprocess import subprocess
import tempfile import tempfile
from pathlib import Path from pathlib import Path
from xml.dom.minidom import parse
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
...@@ -16,7 +17,7 @@ from django.utils.translation import gettext as _ ...@@ -16,7 +17,7 @@ from django.utils.translation import gettext as _
from django.views.generic import View from django.views.generic import View
from stats.models import Statistics, FakeLangStatistics, Module, Branch, Domain, Language from stats.models import Statistics, FakeLangStatistics, Module, Branch, Domain, Language
from stats.utils import DocFormat, check_po_quality, is_po_reduced from stats.utils import DocFormat, UndetectableDocFormat, check_po_quality, is_po_reduced
from vertimus.models import State, Action, ActionArchived, SendMailFailed from vertimus.models import State, Action, ActionArchived, SendMailFailed
from vertimus.forms import ActionForm from vertimus.forms import ActionForm
...@@ -296,14 +297,14 @@ class BuildTranslatedDocsView(PoFileActionBase): ...@@ -296,14 +297,14 @@ class BuildTranslatedDocsView(PoFileActionBase):
raise Http404('No target po file for this action') raise Http404('No target po file for this action')
html_dir = Path(settings.SCRATCHDIR, 'HTML', str(self.kwargs['action_pk'])) html_dir = Path(settings.SCRATCHDIR, 'HTML', str(self.kwargs['action_pk']))
if (html_dir / 'index.html').exists(): if html_dir.exists():
# If the build already ran, redirect to the static results # If the build already ran, redirect to the static results
return HttpResponseRedirect(self.action.build_url) return HttpResponseRedirect(self.action.build_url)
state = self.action.state_db state = self.action.state_db
try: try:
doc_format = DocFormat(state.domain, state.branch) doc_format = DocFormat(state.domain, state.branch)
except Exception as err: except UndetectableDocFormat as err:
messages.error(request, err) messages.error(request, err)
return HttpResponseRedirect(state.get_absolute_url()) return HttpResponseRedirect(state.get_absolute_url())
build_error = _('Build failed (%(program)s): %(err)s') build_error = _('Build failed (%(program)s): %(err)s')
...@@ -333,15 +334,32 @@ class BuildTranslatedDocsView(PoFileActionBase): ...@@ -333,15 +334,32 @@ class BuildTranslatedDocsView(PoFileActionBase):
# Now build the html version # Now build the html version
if not html_dir.exists(): if not html_dir.exists():
html_dir.mkdir(parents=True) html_dir.mkdir(parents=True)
if doc_format.format == 'mallard':
# With mallard, specifying the directory is enough.
build_ref = [str(build_dir)]
else:
build_ref = [os.path.join(build_dir, s.name) for s in sources]
cmd = [ cmd = [
'yelp-build', 'html', '-o', str(html_dir), 'yelp-build', 'html', '-o', str(html_dir),
'-p', str(doc_format.vcs_path / 'C'), '-p', str(doc_format.vcs_path / 'C'),
str(build_dir) *build_ref
] ]
result = subprocess.run(cmd, cwd=str(build_dir), stderr=subprocess.PIPE) result = subprocess.run(cmd, cwd=str(build_dir), stderr=subprocess.PIPE)
if result.returncode != 0: if result.returncode != 0:
messages.error(request, build_error % { messages.error(request, build_error % {
'program': 'yelp-build', 'err': result.stderr.decode() 'program': 'yelp-build', 'err': result.stderr.decode()
}) })
shutil.rmtree(str(html_dir))
return HttpResponseRedirect(state.get_absolute_url()) return HttpResponseRedirect(state.get_absolute_url())
if not (html_dir / 'index.html').exists():
# Create an index.html symlink to the base html doc if needed
try:
doc = parse(build_ref[0])
base_name = doc.getElementsByTagName("article")[0].attributes.get('id').value
except (AttributeError, IndexError):
pass
else:
html_name = '%s.html' % base_name
(html_dir / 'index.html').symlink_to(html_dir / html_name)
return HttpResponseRedirect(self.action.build_url) return HttpResponseRedirect(self.action.build_url)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment