Provide a per-document status file in the format expected by idnits2. Rework the rfc status blob and obsoleted file to manage the long generation times. Commit ready for merge.

- Legacy-Id: 19265
This commit is contained in:
Robert Sparks 2021-07-30 16:13:15 +00:00
parent d283b9674a
commit 1eb46361a0
9 changed files with 188 additions and 46 deletions

View file

@ -85,6 +85,8 @@ mv $TMPFILE9 $DERIVED/1id-index.txt
mv $TMPFILEA $DERIVED/1id-abstracts.txt mv $TMPFILEA $DERIVED/1id-abstracts.txt
mv $TMPFILEB $DERIVED/all_id2.txt mv $TMPFILEB $DERIVED/all_id2.txt
$DTDIR/ietf/manage.py generate_idnits2_rfc_status
$DTDIR/ietf/manage.py generate_idnits2_rfcs_obsoleted
CHARTER=/a/www/ietf-ftp/charter CHARTER=/a/www/ietf-ftp/charter
wget -q https://datatracker.ietf.org/wg/1wg-charters-by-acronym.txt -O $CHARTER/1wg-charters-by-acronym.txt wget -q https://datatracker.ietf.org/wg/1wg-charters-by-acronym.txt -O $CHARTER/1wg-charters-by-acronym.txt

View file

@ -0,0 +1,23 @@
# Copyright The IETF Trust 2021 All Rights Reserved
import os
from django.conf import settings
from django.core.management.base import BaseCommand
from ietf.doc.utils import generate_idnits2_rfc_status
from ietf.utils.log import log
class Command(BaseCommand):
help = ('Generate the rfc_status blob used by idnits2')
def handle(self, *args, **options):
filename=os.path.join(settings.DERIVED_DIR,'idnits2-rfc-status')
blob = generate_idnits2_rfc_status()
try:
bytes = blob.encode('utf-8')
with open(filename,'wb') as f:
f.write(bytes)
except Exception as e:
log('failed to write idnits2-rfc-status: '+str(e))
raise e

View file

@ -0,0 +1,23 @@
# Copyright The IETF Trust 2021 All Rights Reserved
import os
from django.conf import settings
from django.core.management.base import BaseCommand
from ietf.doc.utils import generate_idnits2_rfcs_obsoleted
from ietf.utils.log import log
class Command(BaseCommand):
help = ('Generate the rfcs-obsoleted file used by idnits2')
def handle(self, *args, **options):
filename=os.path.join(settings.DERIVED_DIR,'idnits2-rfcs-obsoleted')
blob = generate_idnits2_rfcs_obsoleted()
try:
bytes = blob.encode('utf-8')
with open(filename,'wb') as f:
f.write(bytes)
except Exception as e:
log('failed to write idnits2-rfcs-obsoleted: '+str(e))
raise e

View file

@ -2380,20 +2380,58 @@ class MaterialsTests(TestCase):
class Idnits2SupportTests(TestCase): class Idnits2SupportTests(TestCase):
def setUp(self):
self.derived_dir = self.tempdir('derived')
self.saved_derived_dir = settings.DERIVED_DIR
settings.DERIVED_DIR = self.derived_dir
def tearDown(self):
settings.DERIVED_DIR = self.saved_derived_dir
shutil.rmtree(self.derived_dir)
def test_obsoleted(self): def test_obsoleted(self):
rfc = WgRfcFactory(alias2__name='rfc1001') rfc = WgRfcFactory(alias2__name='rfc1001')
WgRfcFactory(alias2__name='rfc1003',relations=[('obs',rfc)]) WgRfcFactory(alias2__name='rfc1003',relations=[('obs',rfc)])
rfc = WgRfcFactory(alias2__name='rfc1005') rfc = WgRfcFactory(alias2__name='rfc1005')
WgRfcFactory(alias2__name='rfc1007',relations=[('obs',rfc)]) WgRfcFactory(alias2__name='rfc1007',relations=[('obs',rfc)])
url = urlreverse('ietf.doc.views_doc.idnits2_rfcs_obsoleted')
r = self.client.get(url)
self.assertEqual(r.status_code, 404)
call_command('generate_idnits2_rfcs_obsoleted')
url = urlreverse('ietf.doc.views_doc.idnits2_rfcs_obsoleted') url = urlreverse('ietf.doc.views_doc.idnits2_rfcs_obsoleted')
r = self.client.get(url) r = self.client.get(url)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertEqual(r.content, b'1001 1003\n1005 1007\n') self.assertEqual(r.content, b'1001 1003\n1005 1007\n')
def test_rfc_status(self): def test_rfc_status(self):
for slug in ('bcp', 'ds', 'exp', 'hist', 'inf', 'std', 'ps', 'unkn'):
WgRfcFactory(std_level_id=slug)
url = urlreverse('ietf.doc.views_doc.idnits2_rfc_status') url = urlreverse('ietf.doc.views_doc.idnits2_rfc_status')
r = self.client.get(url) r = self.client.get(url)
self.assertEqual(r.status_code,404)
call_command('generate_idnits2_rfc_status')
r = self.client.get(url)
self.assertEqual(r.status_code,200) self.assertEqual(r.status_code,200)
blob = unicontent(r).replace('\n','') blob = unicontent(r).replace('\n','')
self.assertEqual(blob[6312-1],'O') self.assertEqual(blob[6312-1],'O')
def test_idnits2_state(self):
rfc = WgRfcFactory()
url = urlreverse('ietf.doc.views_doc.idnits2_state', kwargs=dict(name=rfc.canonical_name()))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertContains(r,'rfcnum')
draft = WgDraftFactory()
url = urlreverse('ietf.doc.views_doc.idnits2_state', kwargs=dict(name=draft.canonical_name()))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertNotContains(r,'rfcnum')
self.assertContains(r,'Unknown')
draft = WgDraftFactory(intended_std_level_id='ps')
url = urlreverse('ietf.doc.views_doc.idnits2_state', kwargs=dict(name=draft.canonical_name()))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertContains(r,'Proposed')

View file

@ -80,6 +80,7 @@ urlpatterns = [
url(r'^%(name)s(?:/%(rev)s)?/$' % settings.URL_REGEXPS, views_doc.document_main), url(r'^%(name)s(?:/%(rev)s)?/$' % settings.URL_REGEXPS, views_doc.document_main),
url(r'^%(name)s(?:/%(rev)s)?/bibtex/$' % settings.URL_REGEXPS, views_doc.document_bibtex), url(r'^%(name)s(?:/%(rev)s)?/bibtex/$' % settings.URL_REGEXPS, views_doc.document_bibtex),
url(r'^%(name)s(?:/%(rev)s)?/idnits2-state/$' % settings.URL_REGEXPS, views_doc.idnits2_state),
url(r'^bibxml3/reference.I-D.%(name)s(?:-%(rev)s)?.xml$' % settings.URL_REGEXPS, views_doc.document_bibxml_ref), url(r'^bibxml3/reference.I-D.%(name)s(?:-%(rev)s)?.xml$' % settings.URL_REGEXPS, views_doc.document_bibxml_ref),
url(r'^bibxml3/%(name)s(?:-%(rev)s)?.xml$' % settings.URL_REGEXPS, views_doc.document_bibxml), url(r'^bibxml3/%(name)s(?:-%(rev)s)?.xml$' % settings.URL_REGEXPS, views_doc.document_bibxml),
url(r'^%(name)s/history/$' % settings.URL_REGEXPS, views_doc.document_history), url(r'^%(name)s/history/$' % settings.URL_REGEXPS, views_doc.document_history),

View file

@ -9,6 +9,7 @@ import json
import math import math
import os import os
import re import re
import textwrap
from collections import defaultdict from collections import defaultdict
from urllib.parse import quote from urllib.parse import quote
@ -16,9 +17,11 @@ from urllib.parse import quote
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.forms import ValidationError from django.forms import ValidationError
from django.template.loader import render_to_string
from django.utils.html import escape from django.utils.html import escape
from django.urls import reverse as urlreverse from django.urls import reverse as urlreverse
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.community.models import CommunityList from ietf.community.models import CommunityList
from ietf.community.utils import docs_tracked_by_community_list from ietf.community.utils import docs_tracked_by_community_list
@ -1232,3 +1235,54 @@ def update_doc_extresources(doc, new_resources, by):
e.save() e.save()
doc.save_with_history([e]) doc.save_with_history([e])
return True return True
def generate_idnits2_rfc_status():
blob=['N']*10000
symbols={
'ps': 'P',
'inf': 'I',
'exp': 'E',
'ds': 'D',
'hist': 'H',
'std': 'S',
'bcp': 'B',
'unkn': 'U',
}
rfcs = Document.objects.filter(type_id='draft',states__slug='rfc',states__type='draft')
for rfc in rfcs:
offset = int(rfc.rfcnum)-1
blob[offset] = symbols[rfc.std_level_id]
if rfc.related_that('obs'):
blob[offset] = 'O'
# Workarounds for unusual states in the datatracker
# Document.get(docalias='rfc6312').rfcnum == 6342
# 6312 was published with the wrong rfc number in it
# weird workaround in the datatracker - there are two
# DocAliases starting with rfc - the canonical name code
# searches for the lexically highest alias starting with rfc
# which is getting lucky.
blob[6312 - 1] = 'O'
# RFC200 is an old RFC List by Number
blob[200 -1] = 'O'
# End Workarounds
blob = re.sub('N*$','',''.join(blob))
blob = textwrap.fill(blob, width=64)
return blob
def generate_idnits2_rfcs_obsoleted():
obsdict = defaultdict(list)
for r in RelatedDocument.objects.filter(relationship_id='obs'):
obsdict[int(r.target.document.rfc_number())].append(int(r.source.rfc_number()))
for k in obsdict:
obsdict[k] = sorted(obsdict[k])
return render_to_string('doc/idnits2-rfcs-obsoleted.txt', context={'obsitems':sorted(obsdict.items())})

View file

@ -41,9 +41,7 @@ import json
import os import os
import re import re
import markdown import markdown
import textwrap
from collections import defaultdict
from urllib.parse import quote from urllib.parse import quote
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
@ -52,14 +50,13 @@ from django.template.loader import render_to_string
from django.urls import reverse as urlreverse from django.urls import reverse as urlreverse
from django.conf import settings from django.conf import settings
from django import forms from django import forms
from django.views.decorators.cache import cache_page
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import ( Document, DocAlias, DocHistory, DocEvent, BallotDocEvent, BallotType, from ietf.doc.models import ( Document, DocAlias, DocHistory, DocEvent, BallotDocEvent, BallotType,
ConsensusDocEvent, NewRevisionDocEvent, TelechatDocEvent, WriteupDocEvent, IanaExpertDocEvent, ConsensusDocEvent, NewRevisionDocEvent, TelechatDocEvent, WriteupDocEvent, IanaExpertDocEvent,
IESG_BALLOT_ACTIVE_STATES, STATUSCHANGE_RELATIONS, DocumentActionHolder, DocumentAuthor, RelatedDocument) IESG_BALLOT_ACTIVE_STATES, STATUSCHANGE_RELATIONS, DocumentActionHolder, DocumentAuthor)
from ietf.doc.utils import (add_links_in_new_revision_events, augment_events_with_revision, from ietf.doc.utils import (add_links_in_new_revision_events, augment_events_with_revision,
can_adopt_draft, can_unadopt_draft, get_chartering_type, get_tags_for_stream_id, can_adopt_draft, can_unadopt_draft, get_chartering_type, get_tags_for_stream_id,
needed_ballot_positions, nice_consensus, prettify_std_name, update_telechat, has_same_ballot, needed_ballot_positions, nice_consensus, prettify_std_name, update_telechat, has_same_ballot,
@ -83,6 +80,7 @@ from ietf.review.models import ReviewAssignment
from ietf.review.utils import can_request_review_of_doc, review_assignments_to_list_for_docs from ietf.review.utils import can_request_review_of_doc, review_assignments_to_list_for_docs
from ietf.review.utils import no_review_from_teams_on_doc from ietf.review.utils import no_review_from_teams_on_doc
from ietf.utils import markup_txt, log from ietf.utils import markup_txt, log
from ietf.utils.draft import Draft
from ietf.utils.response import permission_denied from ietf.utils.response import permission_denied
from ietf.utils.text import maybe_split from ietf.utils.text import maybe_split
@ -1719,57 +1717,53 @@ def all_presentations(request, name):
'past' : past+recent, 'past' : past+recent,
}) })
@cache_page ( 60 * 60, cache="slowpages" )
def idnits2_rfcs_obsoleted(request): def idnits2_rfcs_obsoleted(request):
filename = os.path.join(settings.DERIVED_DIR,'idnits2-rfcs-obsoleted')
try:
with open(filename,'rb') as f:
blob = f.read()
return HttpResponse(blob,content_type='text/plain;charset=utf-8')
except Exception as e:
log.log('Failed to read idnits2-rfcs-obsoleted:'+str(e))
raise Http404
obsdict = defaultdict(list)
for r in RelatedDocument.objects.filter(relationship_id='obs'):
obsdict[int(r.target.document.rfc_number())].append(int(r.source.rfc_number()))
for k in obsdict:
obsdict[k] = sorted(obsdict[k])
return render(request, 'doc/idnits2-rfcs-obsoleted.txt', context={'obsitems':sorted(obsdict.items())},content_type='text/plain;charset=utf-8')
@cache_page ( 60 * 60, cache="slowpages" )
def idnits2_rfc_status(request): def idnits2_rfc_status(request):
filename = os.path.join(settings.DERIVED_DIR,'idnits2-rfc-status')
try:
with open(filename,'rb') as f:
blob = f.read()
return HttpResponse(blob,content_type='text/plain;charset=utf-8')
except Exception as e:
log.log('Failed to read idnits2-rfc-status:'+str(e))
raise Http404
blob=['N']*10000
symbols={ def idnits2_state(request, name, rev=None):
'ps': 'P', doc = get_object_or_404(Document, docalias__name=name)
'inf': 'I', if doc.type_id!='draft':
'exp': 'E', raise Http404
'ds': 'D', zero_revision = NewRevisionDocEvent.objects.filter(doc=doc,rev='00').first()
'hist': 'H', if zero_revision:
'std': 'S', doc.created = zero_revision.time
'bcp': 'B', else:
'unkn': 'U', doc.created = doc.docevent_set.order_by('-time').first().time
} if doc.std_level:
doc.deststatus = doc.std_level.name
elif doc.intended_std_level:
doc.deststatus = doc.intended_std_level.name
else:
text = doc.text()
if text:
parsed_draft = Draft(text=doc.text(), source=name, name_from_source=False)
doc.deststatus = parsed_draft.get_status()
else:
doc.deststatus="Unknown"
return render(request, 'doc/idnits2-state.txt', context={'doc':doc}, content_type='text/plain;charset=utf-8')
rfcs = Document.objects.filter(type_id='draft',states__slug='rfc',states__type='draft')
for rfc in rfcs:
offset = int(rfc.rfcnum)-1
blob[offset] = symbols[rfc.std_level_id]
if rfc.related_that('obs'):
blob[offset] = 'O'
# Workarounds for unusual states in the datatracker
# Document.get(docalias='rfc6312').rfcnum == 6342
# 6312 was published with the wrong rfc number in it
# weird workaround in the datatracker - there are two
# DocAliases starting with rfc - the canonical name code
# searches for the lexically highest alias starting with rfc
# which is getting lucky.
blob[6312 - 1] = 'O'
# RFC200 is an old RFC List by Number
blob[200 -1] = 'O'
# End Workarounds
blob = re.sub('N*$','',''.join(blob))
return HttpResponse(textwrap.fill(blob, width=64),content_type='text/plain;charset=utf-8')

View file

@ -682,6 +682,7 @@ INTERNET_DRAFT_ARCHIVE_DIR = '/a/ietfdata/doc/draft/collection/draft-archive/'
# write anything to this directory -- its content is maintained by ghostlinkd: # write anything to this directory -- its content is maintained by ghostlinkd:
INTERNET_ALL_DRAFTS_ARCHIVE_DIR = '/a/ietfdata/doc/draft/archive' INTERNET_ALL_DRAFTS_ARCHIVE_DIR = '/a/ietfdata/doc/draft/archive'
MEETING_RECORDINGS_DIR = '/a/www/audio' MEETING_RECORDINGS_DIR = '/a/www/audio'
DERIVED_DIR = '/a/ietfdata/derived'
DOCUMENT_FORMAT_WHITELIST = ["txt", "ps", "pdf", "xml", "html", ] DOCUMENT_FORMAT_WHITELIST = ["txt", "ps", "pdf", "xml", "html", ]

View file

@ -0,0 +1,6 @@
{% load ietf_filters %}{% filter linebreaks_lf %}{% comment %}
{% endcomment %}Doc-created: {{doc.created|date:"Y-m-d"}};datatracker
Doc-deststatus: {{doc.deststatus}};datatracker
Doc-rev: {{doc.rev}};datatracker{% if doc.rfcnum %}
Doc-rfcnum: {{doc.rfcnum}};datatracker{%endif%}
{% endfilter %}