Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/workflows/smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,30 @@ jobs:
exit 1
fi

# A Lua module runs at build time and its answer is baked into the page that invoked it
# (#465). Module:Example answers with the title of the page it ran on, so this says both
# that Scribunto rendered at all -- without it the invocation is left in the page as
# "{{#invoke:Example|thisPage}}", which is what used to happen quietly -- and that the
# module saw which page it was on, per language.
# Spelled out per language rather than looped, because the file name has underscores where
# the title the module answers with has spaces.
if ! grep -q '<code>Lua modules</code>' dist/Lua_modules.html; then
echo "::error::dist/Lua_modules.html does not carry Module:Example's answer"
exit 1
fi
if ! grep -q '<code>Lua modules/ko</code>' dist/Lua_modules/ko.html; then
echo "::error::dist/Lua_modules/ko.html does not carry Module:Example's answer for Korean"
exit 1
fi

# And the module itself is not a page of the site: Module: is not a content namespace, so
# nothing should export the Lua source. Without Scribunto it does, percent-encoded.
if ls dist/Module* >/dev/null 2>&1; then
echo "::error::the Lua module was exported as a page:"
ls dist/Module*
exit 1
fi

# Every printfooter "Retrieved from" link must resolve from the page that carries it
# (#394). Core builds it from the page's own URL and expands away the "./" wikven writes,
# so a page exported into a subdirectory needs the "../" per level rename.php adds; the
Expand Down
3 changes: 3 additions & 0 deletions docs/.wikven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ extensions:
- Gadgets
- MobileFrontend
- ParserFunctions
# This site has one Lua module, and Special:MyLanguage/Lua modules is about it. Listing Scribunto
# is all it takes: MediaWiki bundles the extension and the image compiles luasandbox into its PHP.
- Scribunto
- SyntaxHighlight_GeSHi
- TabberNeue
- TemplateStyles
Expand Down
2 changes: 2 additions & 0 deletions docs/Development.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ The division is what makes the passes safe to run beside each other: the orchest
=== Phase 1: filling the wiki ===

<!--T:29-->
; <code>checkLuaAgainstThisBuild</code>
: Says what this site's [[<tvar name="1">Special:MyLanguage/Lua modules</tvar>|Lua]] and this build's Lua make of each other, before anything else happens. A site that lists Scribunto where no engine can run it ends the build, because it asked for something this build cannot do; a site with <code>Module:</code> files that never listed Scribunto is only told what those files come to. Both used to pass quietly and publish pages with the invocation showing in them. It runs first so the last bake is still in place when a site is refused.
; <code>clearOutputDirectory</code>
: Empties the output directory, so a bake never inherits a file from the last one.
; <code>setMainPage</code>
Expand Down
4 changes: 3 additions & 1 deletion docs/Development/ko.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@
<!--T:28 @c83107bc-->
=== 1단계: 위키 채우기 ===

<!--T:29 @9cd82bce-->
<!--T:29 @cae4b534-->
; <code>checkLuaAgainstThisBuild</code>
: 이 사이트의 [[$1|Lua]]와 이 빌드의 Lua가 서로를 어떻게 보는지를, 다른 어떤 일이 벌어지기 전에 말합니다. Scribunto를 나열했지만 그것을 실행할 엔진이 없는 사이트는 빌드를 끝내는데, 이 빌드가 할 수 없는 일을 요구했기 때문입니다. 반면 Scribunto를 나열한 적 없이 <code>Module:</code> 파일만 있는 사이트에는 그 파일들이 무엇이 되는지를 알려주기만 합니다. 둘 다 예전에는 조용히 통과해 호출문이 그대로 보이는 문서를 게시했습니다. 가장 먼저 실행되므로, 사이트가 거부될 때 지난 빌드 결과가 아직 그대로 남아 있습니다.
; <code>clearOutputDirectory</code>
: 출력 디렉터리를 비워, 이전 빌드의 파일이 남지 않도록 합니다.
; <code>setMainPage</code>
Expand Down
5 changes: 4 additions & 1 deletion docs/Extensions.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,11 @@ An extension has to do its work during the build, because the published site is
<!--T:15-->
Extensions that only change how wikitext renders — parser tags, parser functions, styling, templating — are the ones that work best, because their whole job is over by the time the page is written out.

<!--T:17-->
Scribunto is one of those, and the one most wikis reach for: it has a page of its own at [[<tvar name="1">Special:MyLanguage/Lua modules</tvar>|Lua modules]], because a Lua module is content as well as configuration and the [[<tvar name="2">Special:MyLanguage/Standalone binary</tvar>|standalone binary]] cannot render it.

<!--T:16-->
An extension of your own can also be made to survive a build deliberately; [[<tvar name="1">Special:MyLanguage/Writing an extension</tvar>|Writing an extension]] is the contract for that.
</translate>

{{prevnext|Skins|JavaScript}}
{{prevnext|Skins|Lua modules}}
3 changes: 3 additions & 0 deletions docs/Extensions/ko.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,6 @@

<!--T:16 @ee84ffc6-->
여러분의 확장 기능을 빌드에서 살아남도록 일부러 만들 수도 있습니다. [[$1|확장 기능 만들기]]가 그에 대한 계약입니다.

<!--T:17 @116a5db5-->
Scribunto가 그중 하나이며, 대부분의 위키가 손을 뻗는 것입니다. [[$1|Lua 모듈]]에 별도 문서가 있는데, Lua 모듈은 설정이면서 콘텐츠이기도 하고 [[$2|단독 실행 바이너리]]가 그것을 렌더링할 수 없기 때문입니다.
2 changes: 1 addition & 1 deletion docs/JavaScript.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ Only gadgets marked <code>default</code> are loaded: a static site has no logged
These docs ship one such gadget, <code>PersistTabber</code>, which remembers whether you pick the Docker or the binary tab in the install steps. Every other tabber on the page switches to the tab you picked, and the choice is still there when you move to another page.
</translate>

{{prevnext|Extensions|Searching}}
{{prevnext|Lua modules|Searching}}
121 changes: 121 additions & 0 deletions docs/Lua modules.wikitext
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
__TOC__

<languages />
<translate>
<!--T:1-->
A great many wikis keep their templates' logic in Lua, and {{SITENAME}} runs a real MediaWiki at build time, so a module runs the way it always does. The page that invokes it is written out with the module's answer already in it; the module itself never becomes a page of the published site. Lua on a MediaWiki is [<tvar name="1">https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:Scribunto</tvar> Scribunto], which MediaWiki bundles.

<!--T:2-->
{{note|The [[<tvar name="1">Special:MyLanguage/Standalone binary</tvar>|standalone binary]] cannot render Lua, and only the Docker image can. A build that is asked to do the impossible now stops and says so, rather than publishing pages with <code><nowiki>{{#invoke:}}</nowiki></code> showing in them.}}

<!--T:3-->
== Enabling it ==

<!--T:4-->
Name it in [[<tvar name="1">Special:MyLanguage/Configuration</tvar>|<code>.wikven.yaml</code>]] and that is all. Scribunto ships inside the image, so it needs no [[<tvar name="2">Special:MyLanguage/Configuration#WikvenRepositories</tvar>|<code>WikvenRepositories</code>]] entry, and the engine needs no configuration: the image compiles <code>luasandbox</code> into its PHP and Scribunto finds it.
</translate>

<syntaxhighlight lang="yaml" copy>
extensions:
- Scribunto
</syntaxhighlight>

<translate>
<!--T:5-->
== Writing a module ==

<!--T:6-->
A module is content, so it lives in your source tree beside your pages. Its file carries no <code>.wikitext</code> marker, because a <code>Module:</code> page's content model is Lua and not wikitext:
</translate>

<syntaxhighlight lang="text">
src/
Module:Example
Home.wikitext
</syntaxhighlight>

<translate>
<!--T:7-->
A file named <code>Module:Example.wikitext</code> is imported too, but the bare name is the convention, and it is the one {{SITENAME}} maps a page back to when it needs the file that page came from.

<!--T:8-->
The module is ordinary Lua. This one is the module this site really has, in full:
</translate>

<syntaxhighlight lang="lua" copy>
local p = {}

function p.thisPage( frame )
return '<code>' .. mw.title.getCurrentTitle().text .. '</code>'
end

return p
</syntaxhighlight>

<translate>
<!--T:9-->
and the page invokes it the ordinary way:
</translate>

<syntaxhighlight lang="wikitext" copy>
{{#invoke:Example|thisPage}}
</syntaxhighlight>

<translate>
<!--T:10-->
Which, run on this page as you read it, answered:
</translate>

{{#invoke:Example|thisPage}}

<translate>
<!--T:11-->
The invocation sits outside the <code><nowiki><translate></nowiki></code> tags, because a module's return value is not a translation unit. It reaches a reader of any language exactly as the module wrote it, so the words belong in the sentence around it and not in the module.

<!--T:12-->
== What reaches the published site ==

<!--T:13-->
The module's output, and nothing else. <code>Module:</code> is not a content namespace, so the module is never exported as a page and its Lua source is not published; what a reader downloads is the page with that answer already in it. Nothing runs in the reader's browser, because nothing is left to run: the module ran once, at build time.

<!--T:14-->
That is worth knowing when you decide what to put in a module. Anything a module computes from the wiki's own content — a table assembled from other pages, a sorted list, a page's own order in a series — is computed once and frozen. Anything a module would need at read time, like the reader's clock or a query, has nowhere to run.

<!--T:15-->
== When the build and the site disagree ==

<!--T:16-->
Two mismatches used to pass quietly and produce a broken site. One of them ends the build; the other is only reported, and the bake goes on.

<!--T:17-->
'''Modules with no Scribunto.''' A source tree with <code>Module:</code> files and no <code>Scribunto</code> in <code>extensions</code> is built, and told what those files come to: a <code><nowiki>{{#invoke:}}</nowiki></code> is left in the page as its own source text, and a module named with the <code>.wikitext</code> marker is published as a page — your Lua, exported for the world to read. The build says what it sees rather than deciding for you, because a <code>Module:</code> file is a guess read off a name and may be on its way in, on its way out, or kept for something else.
</translate>

<syntaxhighlight lang="console">
Wikven: the source has 1 Lua module file(s) (Module:Example) and Scribunto is not in
extensions, so a {{#invoke:}} is left in the page as its own source text, and a module
named with the .wikitext marker is exported as a page. Add Scribunto to extensions if
those modules are meant to run.
</syntaxhighlight>

<translate>
<!--T:18-->
'''Scribunto with no engine.''' A site that lists Scribunto is refused wherever no Lua engine can run it, which is the [[<tvar name="1">Special:MyLanguage/Standalone binary</tvar>|standalone binary]]. The PHP it is built from carries no <code>luasandbox</code>, and Scribunto's other engine runs an external <code>lua</code> program that a single executable has no way to ship. This one is refused rather than reported: the site asked for Lua in so many words, and this build cannot give it.
</translate>

<syntaxhighlight lang="console">
Wikven: this site lists Scribunto and no Lua engine is available here. The Docker image
has one; the standalone binary has none, so it cannot bake a site that uses Lua modules.
Bake this one with the image, or drop Scribunto from extensions and the Module: pages
with it.
</syntaxhighlight>

<translate>
<!--T:19-->
So a site with Lua modules is a site built with the image. If you need the binary, keep the logic in [<tvar name="1">https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Templates</tvar> wikitext templates] and [<tvar name="2">https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:ParserFunctions</tvar> ParserFunctions], both of which every product renders.

<!--T:20-->
This documentation site uses a module itself, which is what keeps the two answers above honest: it is built with the image, and it could not be built with the binary.
</translate>

{{prevnext|Extensions|JavaScript}}
62 changes: 62 additions & 0 deletions docs/Lua modules/ko.wikitext
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!--T:title @da99129d-->
Lua 모듈

<!--T:1 @6c25c1ed-->
많은 위키가 틀의 논리를 Lua로 관리하며, {{SITENAME}}은 빌드 시점에 진짜 MediaWiki를 실행하므로 모듈도 늘 그렇듯 작동합니다. 모듈을 호출한 문서는 모듈의 답이 이미 담긴 상태로 기록되고, 모듈 자체는 게시된 사이트의 문서가 되지 않습니다. MediaWiki에서 Lua는 [$1 Scribunto]이며, MediaWiki에 함께 들어 있습니다.

<!--T:2 @0bbf0aa8-->
{{note|[[$1|단독 실행 바이너리]]는 Lua를 렌더링할 수 없고, Docker 이미지만 할 수 있습니다. 불가능한 일을 요구받은 빌드는 이제 <code><nowiki>{{#invoke:}}</nowiki></code>가 그대로 보이는 문서를 게시하는 대신 중단하고 그 사실을 말합니다.}}

<!--T:3 @3625682d-->
== 켜기 ==

<!--T:4 @805e40b8-->
[[$1|<code>.wikven.yaml</code>]]에 이름을 적으면 그것으로 끝입니다. Scribunto는 이미지 안에 들어 있으므로 [[$2|<code>WikvenRepositories</code>]] 항목이 필요 없고, 엔진도 설정할 것이 없습니다. 이미지는 <code>luasandbox</code>를 자신의 PHP에 컴파일해 넣으며 Scribunto가 그것을 찾아냅니다.

<!--T:5 @d00c605f-->
== 모듈 작성하기 ==

<!--T:6 @d50c98fe-->
모듈은 콘텐츠이므로 다른 문서와 나란히 소스 트리에 놓입니다. 파일에는 <code>.wikitext</code> 표시를 붙이지 않는데, <code>Module:</code> 문서의 콘텐츠 모델은 위키텍스트가 아니라 Lua이기 때문입니다:

<!--T:7 @039410bd-->
<code>Module:Example.wikitext</code>라는 이름도 가져오기는 하지만, 표시 없는 이름이 관례이며 {{SITENAME}}이 어떤 문서가 어느 파일에서 왔는지 되짚을 때 쓰는 이름도 그것입니다.

<!--T:8 @013b7437-->
모듈은 평범한 Lua입니다. 아래는 이 사이트가 실제로 가진 모듈 전체입니다:

<!--T:9 @4e1f73e4-->
그리고 문서는 평범한 방식으로 호출합니다:

<!--T:10 @1ace3ab4-->
지금 읽고 있는 이 문서에서 실행된 결과는 이렇습니다:

<!--T:11 @a84733a1-->
호출문은 <code><nowiki><translate></nowiki></code> 태그 밖에 있습니다. 모듈의 반환값은 번역 단위가 아니기 때문입니다. 어떤 언어의 독자에게든 모듈이 쓴 그대로 전달되므로, 말은 모듈이 아니라 그것을 감싼 문장이 담당해야 합니다.

<!--T:12 @660a3fb6-->
== 게시된 사이트에 남는 것 ==

<!--T:13 @0078e7ad-->
모듈의 출력뿐입니다. <code>Module:</code>은 콘텐츠 이름공간이 아니므로 모듈은 결코 문서로 내보내지지 않고 Lua 소스도 게시되지 않습니다. 독자가 받는 것은 그 답이 이미 담긴 문서입니다. 독자의 브라우저에서는 아무것도 실행되지 않는데, 실행될 것이 남아 있지 않기 때문입니다. 모듈은 빌드 시점에 한 번 실행되었습니다.

<!--T:14 @16c7a319-->
모듈에 무엇을 담을지 정할 때 알아둘 만한 점입니다. 모듈이 위키 자체의 내용에서 계산해 내는 것, 다른 문서들에서 모은 표나 정렬된 목록이나 연속물 안에서 그 문서가 놓인 순서 같은 것은 한 번 계산되어 고정됩니다. 독자의 시계나 질의처럼 읽는 시점에 필요한 것은 실행될 곳이 없습니다.

<!--T:15 @70184466-->
== 빌드와 사이트가 어긋날 때 ==

<!--T:16 @a569137c-->
조용히 통과해 깨진 사이트를 만들던 불일치가 둘 있었습니다. 그중 하나는 빌드를 끝내고, 다른 하나는 알리기만 하며 베이크는 계속됩니다.

<!--T:17 @04586dc8-->
'''Scribunto 없는 모듈.''' <code>Module:</code> 파일이 있는데 <code>extensions</code>에 <code>Scribunto</code>가 없는 소스 트리도 빌드되며, 그 파일들이 무엇이 되는지를 알려줍니다. <code><nowiki>{{#invoke:}}</nowiki></code>는 문서에 자기 소스 텍스트로 남고, <code>.wikitext</code> 표시를 붙인 모듈은 문서로 게시됩니다. 여러분의 Lua가 세상에 읽히도록 내보내지는 것입니다. 빌드는 대신 결정하지 않고 본 것을 말하는데, <code>Module:</code> 파일이라는 판단은 이름에서 읽어낸 짐작이고 그 파일은 들어오는 중일 수도, 나가는 중일 수도, 다른 용도로 두고 있는 것일 수도 있기 때문입니다.

<!--T:18 @6f56833c-->
'''엔진 없는 Scribunto.''' Scribunto를 나열한 사이트는 그것을 실행할 Lua 엔진이 없는 곳에서 거부되며, 그곳이 [[$1|단독 실행 바이너리]]입니다. 그것이 빌드된 PHP에는 <code>luasandbox</code>가 없고, Scribunto의 다른 엔진은 외부 <code>lua</code> 프로그램을 실행하는데 단일 실행 파일은 그것을 담을 방법이 없습니다. 이쪽은 알리는 데 그치지 않고 거부되는데, 사이트가 Lua를 분명하게 요구했고 이 빌드는 그것을 줄 수 없기 때문입니다.

<!--T:19 @660d337a-->
그래서 Lua 모듈이 있는 사이트는 이미지로 빌드하는 사이트입니다. 바이너리가 필요하다면 논리를 [$1 위키텍스트 틀]과 [$2 ParserFunctions]에 두십시오. 둘은 모든 제품이 렌더링합니다.

<!--T:20 @20a389e4-->
이 문서 사이트도 모듈을 하나 쓰며, 그것이 위의 두 답을 정직하게 유지합니다. 이 사이트는 이미지로 빌드되고, 바이너리로는 빌드할 수 없습니다.
1 change: 1 addition & 0 deletions docs/MediaWiki:Sidebar-lua-modules.wikitext
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Lua modules
1 change: 1 addition & 0 deletions docs/MediaWiki:Sidebar-lua-modules/ko.wikitext
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Lua 모듈
1 change: 1 addition & 0 deletions docs/MediaWiki:Sidebar.wikitext
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
** Special:MyLanguage/Images|sidebar-images
** Special:MyLanguage/Skins|sidebar-skins
** Special:MyLanguage/Extensions|sidebar-extensions
** Special:MyLanguage/Lua modules|sidebar-lua-modules
** Special:MyLanguage/JavaScript|sidebar-javascript
** Special:MyLanguage/Searching|sidebar-searching
** Special:MyLanguage/Translating|sidebar-translating
Expand Down
22 changes: 22 additions & 0 deletions docs/Module:Example
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-- The one Lua module this documentation site has, and it is here to be read rather than to do work:
-- Special:MyLanguage/Lua modules shows this source and invokes it on the same page, so the example a
-- reader copies is the code that ran, and the smoke test asserts the answer it produced.
--
-- It answers with a page name and no prose, because a module's return value is not a translation unit
-- and would reach a reader of any language in whatever language it was written in. The sentence around
-- the invocation carries the words, and is translated like every other sentence on that page.
--
-- What it returns also has to be the same on every bake, since a module is run once at build time and
-- its answer is baked into the page. A title satisfies that; a clock or a request would not, and the
-- reproducibility check would catch it.

local p = {}

--- The title of the page being rendered.
-- @param frame the invocation, unused: the question is about the page, not the arguments
-- @return the page's title, as wikitext
function p.thisPage( frame )
return '<code>' .. mw.title.getCurrentTitle().text .. '</code>'
end

return p
Loading
Loading