cookutils view lighttpd/index.cgi @ rev 1126

Using single database for the cooker badges - speed up the listings, show counts
author Aleksej Bobylev <al.bobylev@gmail.com>
date Wed Jan 02 18:06:34 2019 +0200 (2019-01-02)
parents 8cf248ef571e
children 4f2ea8b43594
line source
1 #!/bin/sh
2 #
3 # SliTaz Cooker CGI + Lighttpd web interface.
4 #
6 # Make request URI relative to the script name
7 base="$(dirname "$SCRIPT_NAME")"; [ "$base" == '/' ] && base=''
8 REQUEST_URI=$(echo "$REQUEST_URI" | sed "s|^$base/*|/|; s|\?.*||")
10 # Split the URI request to /pkg/cmd/arg
11 export pkg=$(echo "$REQUEST_URI" | cut -d/ -f2)
12 export cmd=$(echo "$REQUEST_URI" | cut -d/ -f3)
13 export arg=$(echo "$REQUEST_URI" | sed 's|^/[^/]*/[^/]*/||')
16 . /usr/lib/slitaz/httphelper.sh
18 case $QUERY_STRING in
19 *debug*)
20 debug='yes'
21 QUERY_STRING="$(echo "$QUERY_STRING" | sed 's|debug||; s|^&||; s|&&|\&|; s|&$||')"
22 ;;
23 esac
25 [ -f "/etc/slitaz/cook.conf" ] && . /etc/slitaz/cook.conf
26 [ -f "./cook.conf" ] && . ./cook.conf
27 wok="$WOK"
28 title=${title:-SliTaz Cooker}
29 # Cooker DB files.
30 activity="$CACHE/activity"
31 commits="$CACHE/commits"
32 cooklist="$CACHE/cooklist"
33 cookorder="$CACHE/cookorder"
34 command="$CACHE/command"; touch $command
35 blocked="$CACHE/blocked"
36 broken="$CACHE/broken"
37 badges="$CACHE/badges"
38 cooknotes="$CACHE/cooknotes"
39 cooktime="$CACHE/cooktime"
40 wokrev="$CACHE/wokrev"
41 webstat="$CACHE/webstat" # note, file should be previously created with write permissions for www
42 splitdb="$CACHE/split.db"
43 maintdb="$CACHE/maint.db"
44 repologydb="$CACHE/repology.db" # note, file should be previously created with write permissions for www
46 # Path to markdown to html convertor
47 cmark_opts='--smart -e table -e strikethrough -e autolink -e tagfilter'
48 if [ -n "$(which cmark 2>/dev/null)" ]; then
49 md2html="$(which cmark) $cmark_opts"
50 elif [ -x "./cmark" ]; then
51 md2html="./cmark $cmark_opts"
52 elif [ -n "$(which sundown 2>/dev/null)" ]; then
53 md2html=$(which sundown)
54 elif [ -x "./sundown" ]; then
55 md2html="./sundown"
56 fi
61 # Search form redirection
62 if [ -n "$(GET search)" ]; then
63 echo -e "HTTP/1.1 301 Moved Permanently\nLocation: $base/$(GET q)\n\n"
64 exit 0
65 fi
68 # Show the running command and its progression
70 running_command() {
71 state="$(cat $command)"
72 local pct=''
73 if [ -n "$state" ];then
74 echo -n "$state</td></tr><tr><td>Completion</td>"
75 set -- $(grep "^$state" $cooktime)
76 [ -n "$1" -a $2 -ne 0 ] && pct=$((($(date +%s)-$3)*100/$2))
77 [ -n "$pct" ] && max="max='100'"
78 echo -n "<td><progress id='gauge' $max value='$pct' title='Click to stop updating' onclick='stopUpdating()'>"
79 echo -n "</progress> <span id='pct'>${pct:-?}%</span>"
80 [ "$2" -gt 60 ] &&
81 echo -n "</td></tr><tr><td>Estimated end time</td><td>$(date +%H:%M -ud @$(($2+$3)))"
82 else
83 echo 'not running'
84 fi
85 }
88 # HTML page header
90 page_header() {
91 local theme t='' css pretitle='' command
92 theme=$(COOKIE theme)
93 [ "$theme" == 'default' ] && theme=''
94 [ -n "$theme" ] && theme="-$theme"
95 css="cooker$theme.css"
97 if [ -n "$pkg" ]; then
98 case "$pkg" in
99 ~) if [ -z "$cmd" ]; then pretitle="Tag cloud - "; else pretitle="Tag \"$cmd\" - "; fi;;
100 =) if [ -z "$cmd" ]; then pretitle="Badges - "; else pretitle="Badge \"$cmd\" - "; fi;;
101 *) pretitle="$pkg - ";;
102 esac
103 else
104 command="$(cat $command)"
105 [ -n "$command" ] && pretitle="$command - "
106 fi
107 [ -z "$favicon" ] && favicon='/slitaz-cooker.png'
109 echo -e 'Content-Type: text/html; charset=UTF-8\n'
111 cat <<EOT
112 <!DOCTYPE html>
113 <html lang="en">
114 <head>
115 <title>$pretitle$title</title>
116 <link rel="stylesheet" href="/$css">
117 <link rel="icon" type="image/png" href="$favicon">
118 <link rel="search" href="$base/os.xml" title="$title" type="application/opensearchdescription+xml">
119 <!-- mobile -->
120 <meta name="viewport" content="width=device-width, initial-scale=1.0">
121 <meta name="theme-color" content="#222">
122 <!-- rss -->
123 <link rel="alternate" type="application/rss+xml" title="$title Feed" href="?rss">
124 <script>
125 // Get part of the main page
126 function getPart(part) {
127 var partRequest = new XMLHttpRequest();
128 partRequest.onreadystatechange = function() {
129 if (this.readyState == 4 && this.status == 200) {
130 response = this.responseText;
131 var partElement = document.getElementById(part);
132 if (response !== null) partElement.innerHTML = response;
133 }
134 };
135 partRequest.open('GET', '?part=' + part, true);
136 partRequest.responseType = '';
137 partRequest.send();
138 }
139 </script>
140 </head>
141 <body>
142 <div id="container">
143 <header>
144 <h1><a href="$base/">$title</a></h1>
145 <div class="network">
146 <a class="out" href="http://www.slitaz.org/">Home</a>
147 <a class="out" href="http://bugs.slitaz.org/">Bugs</a>
148 <a class="out" href="http://hg.slitaz.org/wok-next/">Hg</a>
149 <a class="out" href="http://roadmap.slitaz.org/">Roadmap</a>
150 <a class="out" href="http://pizza.slitaz.me/">Pizza</a>
151 <a class="out" href="http://tank.slitaz.org/">Tank</a>
152 |
153 <a class="in" href="/cross/">Cross</a>
154 <a class="in" href="/i486.cgi">i486</a>
155 <a class="in" href="$base/cookiso.cgi">ISO</a>
156 <select onChange="window.location.href=this.value" style="display: none">
157 <option value=".">Go to…</option>
158 <option value="http://www.slitaz.org/">Home</option>
159 <option value="http://bugs.slitaz.org/">Bug tracker</option>
160 <option value="http://hg.slitaz.org/wok/">Hg wok</option>
161 <option value="http://roadmap.slitaz.org/">Roadmap</option>
162 <option value="http://pizza.slitaz.me/">Pizza</option>
163 <option value="http://tank.slitaz.org/">Tank</option>
164 <option disabled>---------</option>
165 <option value="cross/">Cross</option>
166 <option value="i486.cgi">i486</option>
167 <option value="cookiso.cgi">ISO</option>
168 </select>
169 </div>
170 </header>
172 <main>
173 EOT
175 [ -n "$debug" ] && echo "<pre><code class='language-ini'>$(env | sort)</code></pre>"
176 }
179 # HTML page footer
181 page_footer() {
182 date_now=$(date +%s)
183 sec_now=$(date +%S); sec_now=${sec_now#0} # remove one leading zero
184 wait_sec=$(( 60 - $sec_now ))
185 cat <<-EOT
186 </main>
188 <footer>
189 <a href="http://www.slitaz.org/">SliTaz Website</a>
190 <a href="http://tank.slitaz.org/graphs.php">Server status</a>
191 <a href="$base/doc/cookutils/cookutils.html">Documentation</a>
192 <a href="$base/?theme">Theme</a>
193 </footer>
194 </div>
195 <script src="/cooker.js"></script>
196 <script>refreshDate(${wait_sec}000, ${date_now}000)</script>
197 </body>
198 </html>
199 EOT
200 }
203 show_note() {
204 echo "<div class='bigicon-$1'>$2</div>"
205 }
208 not_found() {
209 local file="${1#$PKGS/}"; file="${file#$LOGS/}"; file="${file#$WOK/}"
210 echo "HTTP/1.1 404 Not Found"
211 page_header
212 echo "<h2>Not Found</h2>"
213 case $2 in
214 pkg)
215 show_note e "The requested package “$(basename "$(dirname "$file")")” was not found." ;;
216 *)
217 show_note e "The requested file “$file” was not found." ;;
218 esac
219 page_footer
220 }
223 manage_modified() {
224 local file="$1" option="$2" nul day mon year time hh mm ss date_s
225 if [ ! -f "$file" ]; then
226 if [ "$option" == 'silently-absent' ]; then
227 echo "HTTP/1.1 404 Not Found"
228 return
229 else
230 not_found "$file" "$2"
231 exit
232 fi
233 fi
234 [ "$option" == 'no-last-modified' ] && return
235 if [ -n "$HTTP_IF_MODIFIED_SINCE" ]; then
236 echo "$HTTP_IF_MODIFIED_SINCE" | \
237 while read nul day mon year time nul; do
238 case $mon in
239 Jan) mon='01';; Feb) mon='02';; Mar) mon='03';; Apr) mon='04';;
240 May) mon='05';; Jun) mon='06';; Jul) mon='07';; Aug) mon='08';;
241 Sep) mon='09';; Oct) mon='10';; Nov) mon='11';; Dec) mon='12';;
242 esac
243 hh=$(echo $time | cut -d: -f1)
244 mm=$(echo $time | cut -d: -f2)
245 ss=$(echo $time | cut -d: -f3)
246 date_s=$(date -ud "$year$mon$day$hh$mm.$ss" +%s)
247 # if [ "$date_s" -ge "$(date -ur "$file" +%s)" ]; then
248 # echo -e 'HTTP/1.1 304 Not Modified\n'
249 # exit
250 # fi
251 # TODO: improve caching control
252 done
253 fi
254 echo "Last-Modified: $(date -Rur "$file" | sed 's|UTC|GMT|')"
255 echo "Cache-Control: public, max-age=3600"
256 }
259 # Proxy to the Repology
260 # Problems:
261 # 1. Function "latest packaged version" widely used here and it has no JSON API, but only SVG badge.
262 # 2. So, all version comparisons can be only visual and not automated.
263 # 3. When the thousands of badges present on the web page, many of them are broken (maybe server
264 # drops requests), while our server displays status icons well.
265 # 4. Default badges are wide and not customizable.
266 # Solution:
267 # 1. Make local cache. Update it on demand, but no more than once a day (Repology caches info
268 # on a hourly basis). Use cached values when they are not expired.
269 # 2. Extract and save version(s) from the SVG badges. Values can be compared in the scripts as well
270 # as custom badges that may also be provided.
272 repology_get() {
273 local found versions day=$(date +%j) # %j is the number of the day in the year
274 found=$(awk -F$'\t' -vpkg="$1" -vday="$day" '{
275 if ($1 == pkg && $2 == day) { print $3; exit; }
276 }' $repologydb)
277 if [ -n "$found" ]; then
278 echo "$found"
279 else
280 # set HOST_WGET in cook.conf
281 versions=$($HOST_WGET -q -T 20 -O- https://repology.org/badge/latest-versions/$1.svg \
282 | sed '/<text /!d; /fill/d; /latest/d; s|.*>\(.*\)<.*|\1|; s|, | |g') # space separated list
283 if [ -n "$versions" ]; then
284 sed -i "/^$1 /d" $repologydb
285 echo -e "$1\t$day\t$versions" >> $repologydb
286 echo $versions
287 fi
288 fi
289 }
292 # Query '?pct=<package>': update percentage
294 if [ -n "$(GET pct)" ]; then
295 pkg="$(GET pct)"
296 state="$(cat $command)"
297 if [ "$state" == "cook:$pkg" ]; then
298 set -- $(grep "^$state" $cooktime)
299 [ -n "$1" ] && pct=$(( ($(date +%s) - $3) * 100 / $2 ))
300 echo "${pct:-?}"
301 else
302 echo 'reload'
303 fi
304 exit 0
305 fi
308 # Query '?poke': poke cooker
310 if [ -n "$(GET poke)" ]; then
311 touch $CACHE/cooker-request
312 echo -e "Location: ${HTTP_REFERER:-${REQUEST_URI%\?*}}\n"
313 exit
314 fi
317 # Query '?recook=<package>': query to recook package
319 if [ -n "$(GET recook)" ]; then
320 pkg="$(GET recook)"
321 case "$HTTP_USER_AGENT" in
322 *SliTaz*)
323 grep -qs "^$pkg$" $CACHE/recook-packages ||
324 echo "$pkg" >> $CACHE/recook-packages
325 esac
326 echo -e "Location: ${HTTP_REFERER:-${REQUEST_URI%\?*}}\n"
327 exit
328 fi
331 # Query '/i/<log>/<pkg>': show indicator icon
332 # Can't use ?query - not able to change '+' to '%2B' in the sed rules (see log handler)
334 if [ "$pkg" == 'i' ]; then
335 echo -en "Content-Type: image/svg+xml\n\n<svg xmlns='http://www.w3.org/2000/svg' height='12' width='8'><path d='"
336 if [ $LOGS/$cmd -nt $PKGS/$arg.tazpkg ]; then
337 echo "m1 2-1 1v8l1 1h6l1-1v-8l-1-1z' fill='#090'/></svg>"
338 else
339 echo "m0 3v8l1 1h6l1-1v-8l-1-1h-6zm3 0h2v5h-2zm0 6h2v2h-2z' fill='#d00'/></svg>"
340 fi
341 exit
342 fi
345 # Query '/s/<pkg>': show status indicator icon
346 # Can't use ?query - not able to change '+' to '%2B' in the sed rules (see log handler)
348 if [ "$pkg" == 's' ]; then
349 # argument <pkg> is in $cmd variable
350 echo -en "Content-Type: image/svg+xml\n\n<svg xmlns='http://www.w3.org/2000/svg' height='12' width='8'><path d='"
351 # packages.info updates with each new package, so we'll find actual info here
352 if grep -q "^$cmd"$'\t' $PKGS/packages-$ARCH.info; then
353 echo "m1 2-1 1v8l1 1h6l1-1v-8l-1-1z' fill='#090'/></svg>"
354 else
355 echo "m0 3v8l1 1h6l1-1v-8l-1-1h-6zm3 0h2v5h-2zm0 6h2v2h-2z' fill='#d00'/></svg>"
356 fi
357 exit
358 fi
361 # Query '?theme[=<theme>]': change UI theme
363 if [ -n "$(GET theme)" ]; then
364 theme="$(GET theme)"
365 ref="$(echo "$HTTP_REFERER" | sed 's|:|%3A|g; s|/|%2F|g; s|\?|%3F|g; s|\+|%2B|g;')"
366 case $theme in
367 theme)
368 current=$(COOKIE theme)
369 page_header
370 cat <<-EOT
371 <section>
372 <h2>Change theme</h2>
373 <p>Current theme: “${current:-default}”. Select other:</p>
374 <ul>$(
375 for i in default emerald sky goldenrod midnight like2016 terminal; do
376 [ "$i" == "${current:-default}" ] || echo "<li><a href=\"$base/?theme=$i&amp;ref=$ref\">$i</a></li>"
377 done
378 )</ul>
379 </section>
380 EOT
381 page_footer
382 exit 0
383 ;;
384 default|emerald|sky|goldenrod|midnight|like2016|terminal)
385 ref="$(GET ref)"
386 [ -n "$ref" ] || ref="$base/"
387 # Expires in a year
388 expires=$(date -uRd @$(($(date +%s)+31536000)) | sed 's|UTC|GMT|')
389 echo -e "HTTP/1.1 302 Found\nLocation: $ref\nCache-Control: no-cache\nSet-Cookie: theme=$theme; expires=$expires\n\n"
390 exit 0
391 ;;
392 esac
393 fi
396 #case "$QUERY_STRING" in
397 # stuff*)
398 # file="$wok/$(GET stuff)"
399 # manage_modified "$file"
400 # ;;
401 #
402 # pkg=*|receipt=*|description=*|files=*|log=*|man=*|doc=*|info=*)
403 # type=${QUERY_STRING%%=*}
404 # pkg=$(GET $type)
405 # case "$type" in
406 # description)
407 # manage_modified "$wok/$pkg/receipt" 'no-last-modified'
408 # manage_modified "$wok/$pkg/description.txt" 'silently-absent'
409 # ;;
410 # log)
411 # manage_modified "$wok/${pkg%%.log*}/receipt" 'no-last-modified'
412 # manage_modified "$LOGS/$pkg"
413 # ;;
414 # *)
415 # manage_modified "$wok/$pkg/receipt" pkg
416 # ;;
417 # esac
418 # ;;
419 #esac
422 # RSS feed generator
423 # URI: ?rss[&limit={1..100}]
425 if [ -n "$(GET rss)" ]; then
426 limit=$(GET limit); limit="${limit:-12}"; [ "$limit" -gt 100 ] && limit='100'
427 pubdate=$(date -Rur$(ls -t $FEEDS/*.xml | head -n1) | sed 's|UTC|GMT|')
428 cooker_url="http://$HTTP_HOST$base/"
429 cat <<-EOT
430 Content-Type: application/rss+xml
432 <?xml version="1.0" encoding="utf-8" ?>
433 <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
434 <channel>
435 <title>$title</title>
436 <description>The SliTaz packages cooker feed</description>
437 <link>$cooker_url</link>
438 <lastBuildDate>$pubdate</lastBuildDate>
439 <pubDate>$pubdate</pubDate>
440 <atom:link href="$cooker_url?rss" rel="self" type="application/rss+xml" />
441 EOT
442 for rss in $(ls -t $FEEDS/*.xml | head -n$limit); do
443 sed -e "/\?pkg=/s|http[^=]*=|$cooker_url|;" \
444 -e "s|\([0-9]\)</pubDate>|\1 GMT</pubDate>|" $rss
445 done
446 cat <<-EOT
447 </channel>
448 </rss>
449 EOT
450 exit 0
451 fi
454 ### OpenSearch ###
456 # Query '/os.xml': get OpenSearch Description
458 if [ "$pkg" == 'os.xml' ]; then
459 cat <<-EOT
460 Content-Type: application/xml; charset=UTF-8
462 <?xml version="1.0" encoding="UTF-8"?>
463 <OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
464 <ShortName>$title</ShortName>
465 <Description>SliTaz packages search</Description>
466 <Image width="16" height="16" type="image/png">http://$HTTP_HOST/images/logo.png</Image>
467 <Url type="text/html" method="GET" template="http://$HTTP_HOST$base/{searchTerms}"/>
468 <Url type="application/x-suggestions+json" method="GET" template="http://$HTTP_HOST$base/">
469 <Param name="oss" value="{searchTerms}"/>
470 </Url>
471 <SearchForm>http://$HTTP_HOST$base/</SearchForm>
472 <InputEncoding>UTF-8</InputEncoding>
473 </OpenSearchDescription>
474 EOT
475 exit 0
476 fi
478 # Query '?oss[=<term>]': OpenSearch suggestions
480 if [ -n "$(GET oss)" ]; then
481 term="$(GET oss | tr -cd '[:alnum:]+-')"
482 echo -e 'Content-Type: application/x-suggestions+json; charset=UTF-8\n'
483 cd $wok
484 ls | fgrep "$term" | head -n10 | awk -vterm="$term" '
485 BEGIN{printf("[\"%s\",[", term)}
486 {printf("%s\"%s\"", NR != 1 ? "," : "", $0)}
487 END {printf("]]")}
488 '
489 exit 0
490 fi
495 #
496 # Functions
497 #
500 # Unpack to stdout
502 docat() {
503 case "$1" in
504 *gz) zcat ;;
505 *bz2) bzcat ;;
506 *xz) xzcat ;;
507 *) cat
508 esac < $1
509 }
512 # Tiny texinfo converter
514 info2html() {
515 sed \
516 -e 's|&|\&amp;|g; s|<|\&lt;|g; s|>|\&gt;|g;' \
517 -e "s|\`\([^']*\)'|<b>\1</b>|g" \
518 -e 's|"\([A-Za-z0-9]\)|“\1|g; s|"|”|g' \
519 -e 's|^\* \(.*\)::|* <a href="#\1">\1</a> |' \
520 -e 's|\*note \(.*\)::|<a href="#\1">\1</a>|' \
521 -e '/^File: / s|(dir)|Top|g' \
522 -e '/^File: / s|Next: \([^,]*\)|<a class="button icon next" href="#\1">Next: \1</a>|' \
523 -e '/^File: / s|Prev: \([^,]*\)|<a class="button icon prev" href="#\1">Prev: \1</a>|' \
524 -e '/^File: / s|Up: \([^,]*\)|<a class="button icon up" href="#\1">Up: \1</a>|' \
525 -e '/^File: / s|^.* Node: \([^,]*\), *\(.*\)$|<pre id="\1">\2|' \
526 -e '/^<pre id=/ s|^\([^>]*>\)\(<a[^>]*>Next: [^,]*\), *\(<a[^>]*>Prev: [^,]*\), *\(<a[^>]*>Up: .*\)|\1<div class="buttonbar">\3 \4 \2</div>|' \
527 -e '/^<pre id=/ s|^\([^>]*>\)*\(<a[^>]*>Prev: [^,]*\), *\(<a[^>]*>Up: .*\)|\1<div class="buttonbar">\2 \3 <a class="button icon next" href="#">Next</a></div>|' \
528 -e '/^Tag Table:$/,/^End Tag Table$/d' \
529 -e '/INFO-DIR/,/^END-INFO-DIR/d' \
530 -e "s|https*://[^>),'\"\`’ ]*|<a href=\"&\">&</a>|g" \
531 -e "s|ftp://[^>),\"\` ]*|<a href=\"&\">&</a>|g" \
532 -e 's|^\* Menu:|<b>Menu:</b>|' \
533 -e "s|^|</pre>|"
534 }
537 # Put some colors into log and DB files.
539 syntax_highlighter() {
540 case $1 in
541 log)
542 # If variables not defined - define them with some rare values
543 : ${_src=#_#_#}
544 : ${_install=#_#_#}
545 : ${_fs=#_#_#}
546 : ${_stuff=#_#_#}
547 # Use one-letter html tags to save some bytes :)
548 # <b>is error (red)</b> <u>is warning (orange)</u> <i>is informative (green)</i>
549 sed \
550 -e 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g' \
551 -e 's#OK$#<i>OK</i>#' \
552 -e 's#\([Dd]one\)$#<i>\1</i>#' \
553 -e 's#Success$#<i>Success</i>#' \
554 -e 's#\([^a-z]\)ok$#\1<i>ok</i>#' \
555 -e 's#\([^a-z]\)yes$#\1<i>yes</i>#' \
556 -e 's#: \(YES.*\)#: <i>\1</i>#' \
557 -e 's#\([^a-z]\)ON$#\1<i>ON</i>#' \
558 -e 's#\(enabled\)$#<i>\1</i>#' \
559 -e 's#\([^a-z]\)no$#\1<u>no</u>#' \
560 -e 's#: \(NO.*\)#: <u>\1</u>#' \
561 -e 's#\([^a-z]\)none$#\1<u>none</u>#' \
562 -e 's#\([^a-z]\)false$#\1<u>false</u>#' \
563 -e 's#\([^a-z]\)OFF$#\1<u>OFF</u>#' \
564 -e 's#\(disabled\)$#<u>\1</u>#' \
565 -e 's#\(^checking .*\.\.\. \)\(.*\)$#\1<i>\2</i>#' \
566 \
567 -e 's#\( \[Y[nm/]\?\] n\)$# <u>\1</u>#' \
568 -e 's#\( \[N[ym/]\?\] y\)$# <i>\1</i>#' \
569 -e 's# y$# <i>y</i>#' \
570 -e 's# n$# <u>n</u>#' \
571 -e 's#(NEW) *$#<b>(NEW)</b>#' \
572 \
573 -e 's#.*(pkg/local).*#<i>\0</i>#' \
574 -e 's#.*(web/cache).*#<u>\0</u>#' \
575 \
576 -e 's#\([^a-zA-Z]\)\([Ee]rror\)$#\1<b>\2</b>#' \
577 -e 's#ERROR:#<b>ERROR:</b>#g' \
578 \
579 -e 's#^.*multiple definition of.*#<b>\0</b>#' \
580 -e 's#^.*[Ff][Aa][Ii][Ll][Ee][Dd].*#<b>\0</b>#' \
581 -e 's#^.*[^A-Za-z:/-][Ff]atal.*#<b>\0</b>#' \
582 -e '/non-fatal/ s|</*b>||g' \
583 -e 's#^.*[Nn]ot found.*#<b>\0</b>#' \
584 -e 's#^.*[Nn]o such file.*#<b>\0</b>#' \
585 -e 's#^.*No package .* found.*#<b>\0</b>#' \
586 -e 's#^.*Unable to find.*#<b>\0</b>#' \
587 -e 's#[^a-zA-Z-][Ii]nvalid.*#<b>\0</b>#' \
588 -e 's#Segmentation fault#<b>\1</b>#' \
589 -e 's#\([Nn][Oo][Tt] found\.*\)$#<b>\1</b>#' \
590 -e 's#\(found\.*\)$#<i>\1</i>#' \
591 \
592 -e 's#^.*WARNING:.*#<u>\0</u>#' \
593 -e 's#^.*warning:.*#<u>\0</u>#' \
594 -e 's#^.* [Ee]rror:* .*#<b>\0</b>#' \
595 -e 's#^.*terminated.*#<b>\0</b>#' \
596 -e 's#\(missing\)#<b>\1</b>#g' \
597 -e 's#^.*[Cc]annot find.*#<b>\0</b>#' \
598 -e 's#^.*unrecognized option.*#<u>\0</u>#' \
599 -e 's#^.*does not.*#<u>\0</u>#' \
600 -e 's#^.*[Ii]gnoring.*#<u>\0</u>#' \
601 -e 's#^.*note:.*#<u>\0</u>#' \
602 \
603 -e 's#^.* will not .*#<u>\0</u>#' \
604 -e 's!^Hunk .* succeeded at .*!<u>\0</u>!' \
605 -e 's#^.* Warning: .*#<u>\0</u>#' \
606 \
607 -e "s#^Executing:\([^']*\).#<em>\0</em>#" \
608 -e "s#^Making.*#<em>\0</em>#" \
609 -e "s#^Scanning dependencies of target .*#<em>\0</em>#" \
610 -e "s#^====\([^']*\).#<span class='span-line'>\0</span>#g" \
611 -e "s#^[a-zA-Z0-9]\([^']*\) :: #<span class='span-sky'>\0</span>#g" \
612 -e "s#[fh]tt*ps*://[^ '\"]*#<a href='\0'>\0</a>#g" \
613 -e 's|^Switching to the .*|<span class="switch">‣‣‣ \0</span>|' \
614 \
615 -e 's|^<u>\(.*libtool: warning: relinking.*\)</u>|\1|' \
616 -e 's|^<u>\(.*libtool: warning: .* has not been installed in .*\)</u>|\1|' \
617 -e 's|^<u>\(.*checking for a sed.*\)</u>|\1|' \
618 -e 's|^<u><b>\(.*inlining failed.*\)</b></u>|<u>\1</u>|' \
619 \
620 -e "s|$_src|<var>\${src}</var>|g;
621 s|$_install|<var>\${install}</var>|g;
622 s|$_fs|<var>\${fs}</var>|g;
623 s|$_stuff|<var>\${stuff}</var>|g" \
624 \
625 -e "s|\[\([01]\)m\[3\([1-7]\)m|<span class='c\2\1'>|g;
626 s|\[\([01]\);3\([1-7]\)m|<span class='c\2\1'>|g;
627 s|\[3\([1-7]\)m|<span class='c\10'>|g;
628 s|\[\([01]\);0m|<span class='c0\1'>|g;
629 s|\[0m|</span>|g;
630 s|\[m|</span>|g;
631 s|\[0;10m|</span>|g;
632 s|\[K||g;" \
633 \
634 -e "s|\[9\([1-6]\)m|<span class='c\10'>|;
635 s|\[39m|</span>|;
636 #s|\[1m|<span class='c01'>|g;
637 s|\[1m|<span style='font-weight:bold'>|g; s|(B|</span>|g;
638 s|\[m||g;" \
639 \
640 -e "s!^|\(+.*\)!|<span class='c20'>\1</span>!;
641 s!^|\(-.*\)!|<span class='c10'>\1</span>!;
642 s!^|\(@@.*@@\)\$!|<span class='c30'>\1</span>!;" \
643 \
644 -e "s|^Successfully installed [^ ][^ ]*$|<i>\0</i>|;
645 s|^Successfully installed .*$|<b>\0</b>|;
646 s|^\(Requirement already satisfied: .*\) in|<i>\1</i> in|;
647 s|^Collecting .* (from .*$|<b>\0</b>|;
648 s|^ Could not find.*|<b>\0</b>|;
649 s|^No matching distribution found for.*|<b>\0</b>|;"
651 ;;
653 files)
654 # Highlight the Busybox's `ls` output
655 awk '{
656 part1 = substr($0, 0, 16);
657 part2 = substr($0, 17, 9);
658 part3 = substr($0, 26, 9);
659 part4 = substr($0, 35);
660 if (part2 != "root ") part2 = "<span class=\"c11\">" part2 "</span>";
661 if (part3 != "root ") part3 = "<span class=\"c11\">" part3 "</span>";
662 print part1 part2 part3 part4;
663 }' | \
664 sed "s|\[0m/|/\[0m|g;
665 s|\[\([01]\);3\([1-7]\)m|<a class='c\2\1'>|g;
666 s|\[\([01]\);0m|<a class='c0\1'>|g;
667 s|\[0m|</a>|g;
668 s|^\(lrwxrwxrwx\)|<span class='c61'>\1</span>|;
669 s|^\(-rwxr-xr-x\)|<span class='c21'>\1</span>|;
670 s|^\(-rw-r--r--\)|<span class='c31'>\1</span>|;
671 s|^\(drwxr-xr-x\)|<span class='c41'>\1</span>|;
672 s|^\(-rwsr-xr-x\)|<span class='c51'>\1</span>|;
673 s|^\([lrwxs-][lrwxs-]*\)|<span class='c11'>\1</span>|;
674 "
675 ;;
676 esac
677 }
680 show_code() {
681 echo -n "<pre><code class=\"language-$1\">"
682 sed 's|&|\&amp;|g; s|<|\&lt;|g; s|>|\&gt;|g'
683 echo '</code></pre>'
684 }
687 datalist() {
688 cut -d$'\t' -f2 $splitdb | tr ' ' '\n' | sort -u | awk '
689 BEGIN{printf("<datalist id=\"packages\">")}
690 {printf("<option>%s",$1)}
691 END {printf("</datalist>")}
692 '
693 }
696 mklog() {
697 awk '
698 BEGIN { printf("<pre class=\"log dog\">\n") }
699 { print }
700 END { print "</pre>" }'
701 }
704 summary() {
705 log="$1"
706 pkg="$(basename ${log%%.log*})"
708 if [ -f "$log" ]; then
709 if grep -q "cook:$pkg$" $command; then
710 show_note i "The Cooker is currently building $pkg" \
711 | sed 's|>|&<progress id="gauge" class="meter-small" max="100" value="0"></progress> |'
712 echo "<script>updatePkg = '${pkg//+/%2B}';</script>"
713 elif fgrep -q "Summary for:" $log; then
714 sed '/^Summary for:/,$!d' $log | awk '
715 BEGIN { print "<section>" }
716 function row(line) {
717 split(line, s, " : ");
718 printf("\t<tr><td>%s</td><td>%s</td></tr>\n", s[1], s[2]);
719 }
720 function row2(line, rowNum) {
721 split(line, s, " : ");
722 if (rowNum == 1) {
723 print "<thead>";
724 printf("\t<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n", s[1], s[2], s[3], s[4], s[5]);
725 print "</thead><tbody>";
726 }
727 else
728 printf("\t<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", s[1], s[2], s[3], s[4], s[5]);
729 }
730 {
731 if (NR==1) { printf("<h3>%s</h3>\n<table>\n", $0); next }
732 if ($0 ~ "===") { seen++; if (seen == 1) next; else exit; }
733 if ($0 ~ "---") {
734 seen2++;
735 if (seen2 == 1) print "</table>\n\n<table class=\"pkgslist\">"
736 next
737 }
738 if (seen2) row2($0, seen2); else row($0);
739 }
740 END { print "</tbody></table></section>" }
741 '
742 elif fgrep -q "Debug information" $log; then
743 # second line of log is "Cook: <package> <version>"
744 echo -e "<section>\n<h3>Debug information for $(sed '2!d; s|.*: ||' $log)</h3>"
745 sed -e '/^Debug information/,$!d; /^===/d; /^$/d' $log | sed -n '1!p' | \
746 if [ -n "$2" ]; then
747 syntax_highlighter log | sed 's|\([^0-9 ]\)\([0-9][0-9]*\):|\1<a href="#l\2">\2</a>:|'
748 else
749 sed 's|^[0-9][0-9]*:||' | syntax_highlighter log
750 fi | mklog
751 echo '</section>'
752 fi
753 else
754 [ -n "$pkg" -a -d "$wok/$pkg" ] && show_note e "No log for $pkg"
755 fi
756 }
759 active() {
760 [ "$cmd" == "$1" -o "$cmd" == "${2:-$1}" ] && echo -n ' active'
761 }
764 pkg_info() {
765 local log active bpkg short_desc=''
766 log="$LOGS/$pkg.log"
768 echo -n "<div id=\"hdr\"><a href=\"$base/${requested_pkg:-$pkg}\">"
769 if [ -e $wok/$pkg/.icon.png ]; then
770 echo -n "<img src=\"$base/$pkg/browse/.icon.png\" alt=\"$pkg icon\"/>"
771 else
772 echo -n "<img src=\"/tazpkg.png\" alt=\"package icon\"/>"
773 fi
774 echo -n "</a>"
775 echo -n "<h2><a href=\"$base/${requested_pkg:-$pkg}\">${requested_pkg:-$pkg}</a>"
776 # Get short description for existing packages
777 [ -f $PKGS/packages-$ARCH.info ] &&
778 short_desc="$(awk -F$'\t' -vp="${requested_pkg:-$pkg}" '{if ($1 == p) { printf("%s", $4); exit; }}' $PKGS/packages-$ARCH.info)"
779 # If package does not exist (not created yet or broken), get short description
780 # (but only for "main" package) from receipt
781 [ -n "$short_desc" ] || short_desc="$(. $wok/$pkg/receipt; echo "$SHORT_DESC")"
782 echo "<br/>$short_desc</h2></div>"
783 echo '<div id="info">'
784 echo "<a class='button icon receipt$(active receipt stuff)' href='$base/$pkg/receipt'>receipt &amp; stuff</a>"
786 # In the receipts $EXTRAVERSION is defined using $kvers, get it here [copy from 'cook' set_paths()]
787 if [ -f "$wok/linux/receipt" ]; then
788 kvers=$(. $wok/linux/receipt; echo $VERSION)
789 kbasevers=$(echo $kvers | cut -d. -f1,2)
790 elif [ -f "$INSTALLED/linux-api-headers/receipt" ]; then
791 kvers=$(. $INSTALLED/linux-api-headers/receipt; echo $VERSION)
792 kbasevers=$(echo $kvers | cut -d. -f1,2)
793 fi
795 unset WEB_SITE WANTED
796 . $wok/$pkg/receipt
798 [ -n "$WEB_SITE" ] &&
799 echo "<a class='button icon website' href='$WEB_SITE' target='_blank' rel='noopener noreferrer'>web site</a>"
801 [ -f "$wok/$pkg/taz/$PACKAGE-$VERSION$EXTRAVERSION/receipt" ] &&
802 echo "<a class='button icon files$(active files)' href='$base/$pkg/files'>files</a>"
804 [ -n "$(ls $wok/$pkg/description*.txt)" ] &&
805 echo "<a class='button icon desc$(active description)' href='$base/$pkg/description'>description</a>"
807 [ -n "$TARBALL" -a -s "$SRC/$TARBALL" -o -d "$wok/$pkg/taz" ] &&
808 echo "<a class='button icon download' href='$base/$pkg/download'>downloads</a>"
810 echo "<a class='button icon browse' href='$base/$pkg/browse/'>browse</a>"
812 [ -x ./man2html.bin -a -d "$wok/$pkg/install/usr/share/man" ] &&
813 echo "<a class='button icon doc$(active man)' href='$base/$pkg/man/'>man</a>"
815 [ -d "$wok/$pkg/install/usr/share/doc" -o -d "$wok/$pkg/install/usr/share/gtk-doc" ] &&
816 echo "<a class='button icon doc$(active doc)' href='$base/$pkg/doc/'>doc</a>"
818 [ -d "$wok/$pkg/install/usr/share/info" ] &&
819 echo "<a class='button icon doc$(active info)' href='$base/$pkg/info/#Top'>info</a>"
821 if [ -n "$LFS" ]; then
822 printf "<a class='button icon lfs' href='%s' target='_blank' rel='noopener noreferrer'>" "$LFS"
823 [ "${LFS/blfs/}" != "$LFS" ] && printf "B"
824 printf "LFS</a>\n"
825 fi
827 ls $log* >/dev/null 2>&1 &&
828 echo "<a class='button icon log$(active log)' href='$base/$pkg/log/'>logs</a>"
830 echo '</div>'
831 }
834 mktable() {
835 sed 's# : #|#' | awk -vc="$1" '
836 BEGIN { printf("<table class=\"%s\">\n", c); FS="|" }
837 { printf("<tr><td>%s</td>", $1);
838 if (NF == 2) printf("<td>%s</td>", $2);
839 printf("</tr>\n", $2) }
840 END { print "</table>" }'
841 }
844 section() {
845 local i=$(basename "$1")
846 echo -e '\n\n<section>'
847 [ $(wc -l < $1) -gt $2 ] && echo "<a class='button icon more r' href='?$i'>${3#*|}</a>"
848 echo "<h2>${3%|*}</h2>"
849 mktable "$i"
850 echo '</section>'
851 }
854 show_desc() {
855 echo "<section><h3>Description of “$1”</h3>"
856 if [ -n "$md2html" ]; then
857 $md2html $2
858 else
859 show_code markdown < $2
860 fi
861 echo "</section>"
862 }
865 # Return all the names of packages bundled in this receipt
867 all_names() {
868 # Get package names from $SPLIT variable
869 local split=$(echo $SPLIT \
870 | awk '
871 BEGIN { RS = " "; FS = ":"; }
872 { print $1; }' \
873 | tr '\n' ' ')
874 local split_space=" $split "
875 if ! head -n1 $WOK/$pkg/receipt | fgrep -q 'v2'; then
876 # For receipts v1: $SPLIT may present in the $WANTED package,
877 # but split packages have their own receipts
878 echo $PACKAGE
879 elif [ "${split_space/ $PACKAGE /}" != "$split_space" ]; then
880 # $PACKAGE included somewhere in $SPLIT (probably in the end).
881 # We should build packages in the order defined in the $SPLIT.
882 echo $split
883 else
884 # We'll build the $PACKAGE, then all defined in the $SPLIT.
885 echo $PACKAGE $split
886 fi
887 }
890 toolchain_version() {
891 echo "<tr><td><a href='$base/$1'>$1</a></td>"
892 awk -F$'\t' -vpkg="$1" '
893 BEGIN { version = description = "---"; }
894 {
895 if ($1 == pkg) { version = $2; description = $4; }
896 }
897 END { printf("<td>%s</td><td>%s</td></tr>", version, description); }
898 ' $PKGS/packages-$ARCH.info
899 }
902 files_header() {
903 echo '<section><h3>Available downloads:</h3>'
904 echo '<table><thead><tr><th>File</th><th>Size</th><th>Description</th></tr></thead><tbody>'
905 }
908 # Update statistics used in web interface.
909 # There is no need to recalculate the statistics every time the page is displayed.
910 # Note, $webstat file must be owned by www, otherwise this function will not be able to do the job.
912 update_webstat() {
913 # for receipts:
914 rtotal=$(ls $WOK/*/arch.$ARCH | wc -l)
915 rcooked=$(ls -d $WOK/*/taz | wc -l)
916 runbuilt=$(($rtotal - $rcooked))
917 rblocked=$(wc -l < $blocked)
918 rbroken=$(wc -l < $broken)
920 # for packages:
921 ptotal=$(cut -d$'\t' -f2 $CACHE/split.db | tr ' ' '\n' | sort -u | wc -l)
922 pcooked=$(wc -l < $PKGS/packages-$ARCH.info)
923 punbuilt=$(($ptotal - $pcooked))
924 pblocked=$(
925 while read i; do
926 sed "/^$i\t/!d" $CACHE/split.db
927 done < $blocked | cut -d$'\t' -f2 | tr ' ' '\n' | wc -l)
928 pbroken=$(
929 while read i; do
930 sed "/^$i\t/!d" $CACHE/split.db
931 done < $broken | cut -d$'\t' -f2 | tr ' ' '\n' | wc -l)
933 cat > $webstat <<-EOT
934 rtotal="$rtotal"; rcooked="$rcooked"; runbuilt="$runbuilt"; rblocked="$rblocked"; rbroken="$rbroken"
935 ptotal="$ptotal"; pcooked="$pcooked"; punbuilt="$punbuilt"; pblocked="$pblocked"; pbroken="$pbroken"
936 EOT
937 }
940 # Show badges for specified package
942 show_badges() {
943 local t p s # title problem solution
944 unset t p s
945 counts=$(mktemp)
947 case $layout in
948 table)
949 echo "<section><h2>Badges</h2><table class=\"badges\"><thead><tr><th></th><th>Problem</th><th>Solution</th></tr></thead><tbody>"
950 ;;
951 list)
952 echo "<section><h2>Badges list</h2><p>Click on badge to get list of packages</p><table class=\"badges\"><thead><tr><th></th><th>Problem</th><th>Count</th></tr></thead><tbody>"
953 for i in bdbroken broken any noany libtool nolibtool own ownover perm permover symlink ss fadd frem fdup old orphan patch win no-badge; do
954 case $i in
955 no-badge) num=$(awk -F$'\t' '{if (! $2) print 1}' $badges | wc -l);;
956 *) num=$(awk -F$'\t' -vi=" $i " '{if (index(" " $2 " ", i)) print 1}' $badges | wc -l);;
957 esac
958 echo "$i $num" >>$counts
959 done
960 ;;
961 esac
963 for badge in $@; do
964 case $badge in
965 bdbroken)
966 t="Broken bdeps"
967 p="This package cannot be built because its creation depends on broken packages"
968 s="Fix broken build dependencies"
969 ;;
970 broken)
971 t="Broken package"
972 p="Package is broken"
973 s="Fix package build: analyze <a href=\"$base/$PACKAGE/log/\">logs</a>, upgrade the version, search for patches"
974 ;;
975 any)
976 t="“Any” arch"
977 p="This package contains only architecture-less <a href=\"$base/$PACKAGE/files\">files</a>, it does not make sense to make it several times in each build environment"
978 s="Add the line <code>HOST_ARCH=\"any\"</code> to <a href=\"$base/$PACKAGE/receipt\">receipt</a>"
979 ;;
980 noany)
981 t="No “any” arch"
982 p="This package contains architecture dependent <a href=\"$base/$PACKAGE/files\">files</a>"
983 s="Remove the line <code>HOST_ARCH=\"any\"</code> from <a href=\"$base/$PACKAGE/receipt\">receipt</a>"
984 ;;
985 libtool)
986 t="Libtool isn't fixed"
987 p="This package uses <code>libtool</code> that likes to add unnecessary dependencies to programs and libraries"
988 s="Add the <code>fix libtool</code> command to the <a href=\"$base/$PACKAGE/receipt\">receipt</a> between the <code>configure</code> and <code>make</code> commands invocation"
989 ;;
990 nolibtool)
991 t="Libtool is absent"
992 p="This package does not use <code>libtool</code>, nothing to fix"
993 s="Remove the command <code>fix libtool</code> from <a href=\"$base/$PACKAGE/receipt\">receipt</a>"
994 ;;
995 own)
996 t="Ownership problems"
997 p="Some files of this package have <a href=\"$base/$PACKAGE/files\">ownership problems</a>"
998 s="Correct the ownership or add problem files to the “<a href=\"$base/$PACKAGE/stuff/overrides\">overrides</a>” list if you believe it is OK"
999 ;;
1000 ownover)
1001 t="Ownership overridden"
1002 p="This package contains files with <a href=\"$base/$PACKAGE/files\">ownership problems</a> that have been overridden"
1003 s="<abbr title=\"For your information\">FYI</abbr> only, you may want to revise <a href=\"$base/$PACKAGE/stuff/overrides\">the list</a>"
1004 ;;
1005 perm)
1006 t="Permissions problems"
1007 p="Some files of this package have <a href=\"$base/$PACKAGE/files\">unusual permissions</a>"
1008 s="Correct the permissions or add problem files to the “<a href=\"$base/$PACKAGE/stuff/overrides\">overrides</a>” list if you believe it is OK"
1009 ;;
1010 permover)
1011 t="Permissions overridden"
1012 p="This package contains files with <a href=\"$base/$PACKAGE/files\">unusual permissions</a> that have been recorded"
1013 s="<abbr title=\"For your information\">FYI</abbr> only, you may want to revise <a href=\"$base/$PACKAGE/stuff/overrides\">the list</a>"
1014 ;;
1015 symlink)
1016 t="Broken symlink"
1017 p="This package contains one or more <a href=\"$base/$PACKAGE/files\">broken symlinks</a>"
1018 s="Fix the symlinks destination; you may use <code>fix symlinks</code> when symlinks have absolute path"
1019 ;;
1020 ss)
1021 t="Site script"
1022 p="This autotools-based building system uses site script; most of the paths (like <var>prefix</var>, <var>sysconfdir</var> and <var>mandir</var>) are defined there with correct default values"
1023 s="You may remove your paths from <code>configure</code> invocation"
1024 ;;
1025 fadd)
1026 t="Files have been added"
1027 p="Some files absent in <var>\$install</var> was <a href=\"$base/$PACKAGE/files#outoftree\">directly added</a> to <var>\$fs</var>"
1028 s="Rework your <code>compile_rules()</code> to add all the required files to <var>\$install</var> there"
1029 ;;
1030 frem)
1031 t="Files have been removed"
1032 p="Some files existing in <var>\$install</var> <a href=\"$base/$PACKAGE/files#orphans\">not belonging to any package</a>"
1033 s="Revise <code>genpkg_rules()</code> or add files to “<a href=\"$base/$PACKAGE/stuff/overrides\">overrides</a>” list"
1034 ;;
1035 fdup)
1036 t="Files are duplicated"
1037 p="Some files existing in <var>\$install</var> was added to <a href=\"$base/$PACKAGE/files#repeats\">more than one</a> package"
1038 s="Check your copy rules in <code>genpkg_rules()</code>"
1039 ;;
1040 old)
1041 t="Oldie"
1042 p="According to Repology, this package may be <a href=\"https://repology.org/metapackage/${REPOLOGY:-$pkg}\" target=\"_blank\" rel=\"noopener noreferrer\">outdated</a>"
1043 s="Update the package"
1044 ;;
1045 win)
1046 t="Winner"
1047 p="This package has no problems"
1048 s="Well done, keep it up!"
1049 ;;
1050 orphan)
1051 t="Orphaned package"
1052 p="It seems that no other package depends on this one"
1053 s="See if anyone needs it"
1054 ;;
1055 patch)
1056 t="Patch"
1057 p="Patch has been applied"
1058 s="<abbr title=\"For your information\">FYI</abbr> only, you may want to revise <a href=\"$base/$PACKAGE/stuff/patches/series\">the list of patches</a>"
1059 ;;
1060 no-badge)
1061 t="No badge"
1062 p="Packages without badges"
1063 s=""
1064 ;;
1065 equal)
1066 t="Not changed"
1067 p="Package hasn't changed after rebuilding"
1068 s="<abbr title=\"For your information\">FYI</abbr> only"
1069 ;;
1070 esac
1071 case $layout in
1072 table)
1073 echo "<tr><td><span class=\"badge $badge\" title=\"$t\"/></td><td>$p</td><td>$s</td></tr>"
1074 ;;
1075 list)
1076 p=$(echo $p | sed 's|<a [^>]*>\([^<]*\)</a>|\1|g')
1077 s=$(echo $s | sed 's|<a [^>]*>\([^<]*\)</a>|\1|g|')
1078 c=$(awk -vbadge="$badge" '{if ($1 == badge) { print $2; exit }}' $counts)
1079 echo "<tr><td><a href=\"$badge\" class=\"button badge $badge\" title=\"$t\"></a></td><td>$p</td><td>$c</td></tr>"
1080 ;;
1081 *)
1082 echo -n "<span class=\"badge $badge\" title=\"$t\"/>"
1083 ;;
1084 esac
1085 done
1087 case $layout in
1088 table|list)
1089 echo "</tbody></table></section>"
1090 ;;
1091 esac
1093 rm $counts
1097 # Generate part of the main page
1099 part() {
1100 echo -n "<div id='$1'>"
1102 case $1 in
1103 summary)
1104 echo '<h2>Summary</h2>'
1106 mktable <<EOT
1107 Cooker state : $(running_command)
1108 Wok revision : <a href='$WOK_URL' target='_blank' rel='noopener noreferrer'>$(cat $wokrev)</a>
1109 Commits to cook : $(wc -l < $commits)
1110 Current cooklist : $(wc -l < $cooklist)
1111 Architecture : $ARCH, <a href="$toolchain">toolchain</a>
1112 Server date : <span id='date'>$(date -u '+%F %R %Z')</span>
1113 EOT
1115 # If command is "cook:*", update gauge and percentage periodically.
1116 # If different package is cooking, reload the page (with new settings)
1117 cmd="$(cat $command)"
1118 case "$cmd" in
1119 cook:*)
1120 pkg=${cmd#*:}
1121 echo "<script>updatePkg = '${pkg//+/%2B}';</script>"
1122 ;;
1123 esac
1124 ;;
1125 webstat)
1126 # Do we need to update the statistics?
1127 if [ -n "$nojs" -a "$activity" -nt "$webstat" ]; then update_webstat; fi
1128 . $webstat
1130 pct=0; [ "$rtotal" -gt 0 ] && pct=$(( ($rcooked * 100) / $rtotal ))
1132 cat <<-EOT
1133 <div class="meter"><progress max="100" value="$pct">${pct}%</progress><span>${pct}%</span></div>
1135 <table class="webstat">
1136 <thead>
1137 <tr>
1138 <th> </th>
1139 <th>Total </th>
1140 <th>Cooked </th>
1141 <th>Unbuilt </th>
1142 <th>Blocked </th>
1143 <th>Broken </th>
1144 </tr>
1145 </thead>
1146 <tbody>
1147 <tr>
1148 <td>Receipts</td>
1149 <td>$rtotal</td>
1150 <td>$rcooked</td>
1151 <td>$runbuilt</td>
1152 <td>$rblocked</td>
1153 <td>$rbroken</td>
1154 </tr>
1155 <tr>
1156 <td>Packages</td>
1157 <td>$ptotal</td>
1158 <td>$pcooked</td>
1159 <td>$punbuilt</td>
1160 <td>$pblocked</td>
1161 <td>$pbroken</td>
1162 </tr>
1163 </tbody>
1164 </table>
1165 EOT
1166 if [ -z "$nojs" ]; then echo "<script>getPart('$1')</script>"; fi
1167 ;;
1168 activity)
1169 tac $activity | head -n12 | sed 's|cooker.cgi?pkg=||;
1170 s|\[ Done|<span class="r c20">Done|;
1171 s|\[ Failed|<span class="r c10">Failed|;
1172 s|\[ -Failed|<span class="r c10"><del>Failed</del>|;
1173 s| \]|</span>|;
1174 s|%2B|\+|g' \
1175 | while read line; do
1176 case "$line" in
1177 *data-badges=*)
1178 badges="$(echo "$line" | sed "s|.*data-badges='\([^']*\)'.*|\1|")"
1179 echo "$line" | sed "s|</a>|</a> $(show_badges "$badges")|"
1180 ;;
1181 *)
1182 echo "$line"
1183 ;;
1184 esac
1185 done | section $activity 12 "Activity|More activity" \
1186 ;;
1187 cooknotes)
1188 [ -s "$cooknotes" ] && tac $cooknotes | head -n12 | \
1189 section $cooknotes 12 "Cooknotes|More notes"
1190 ;;
1191 commits)
1192 [ -s "$commits" ] && head -n20 $commits | \
1193 section $commits 20 "Commits|More commits"
1194 ;;
1195 cooklist)
1196 [ -s "$cooklist" ] && head -n 20 $cooklist | \
1197 section $cooklist 20 "Cooklist|Full cooklist"
1198 ;;
1199 broken)
1200 [ -s "$broken" ] && head -n20 $broken | sed "s|^[^']*|<a href='\0'>\0</a>|g" | \
1201 section $broken 20 "Broken|All broken packages"
1202 ;;
1203 blocked)
1204 [ -s "$blocked" ] && sed "s|^[^']*|<a href='\0'>\0</a>|g" $blocked | \
1205 section $blocked 12 "Blocked|All blocked packages"
1206 ;;
1207 pkgs)
1208 cd $PKGS
1209 # About BusyBox's `ls`
1210 # On the Tank server: BusyBox v1.18.4 (2012-03-14 03:32:25 CET) multi-call binary.
1211 # It supported the option `-e`, output with `-let` options like this:
1212 # -rw-r--r-- 1 user group 100000 Fri Nov 3 10:00:00 2017 filename
1213 # 1 2 3 4 5 6 7 8 9 10 11
1214 # Newer BusyBox v1.27.2 doesn't support option `-e` and has no configs to
1215 # configure it or return the option back. It supported the long option
1216 # `--full-time` instead, but output is different:
1217 # -rw-r--r-- 1 user group 100000 2017-11-03 10:00:00 +0200 filename
1218 # 1 2 3 4 5 6 7 8 9
1219 if ls -let >/dev/null 2>&1; then
1220 ls -let *.tazpkg \
1221 | awk '
1222 (NR<=20){
1223 sub(/:[0-9][0-9]$/, "", $9);
1224 mon = index(" JanFebMarAprMayJunJulAugSepOctNovDec", $7) / 3;
1225 printf("%d-%02d-%02d %s : <a href=\"get/%s\">%s</a>\n", $10, mon, $8, $9, $11, $11);
1226 }' \
1227 | section $activity 1000 "Latest cook"
1228 else
1229 ls -lt --full-time *.tazpkg \
1230 | awk '
1231 (NR<=20){
1232 sub(/:[0-9][0-9]$/, "", $7);
1233 printf("%s %s : <a href=\"get/%s\">%s</a>\n", $6, $7, $9, $9);
1234 }' \
1235 | section $activity 1000 "Latest cook"
1236 fi
1237 ;;
1238 esac
1239 echo "</div>"
1243 # Query '?part=<part>': get part of the main page
1245 if [ -n "$(GET part)" ]; then
1246 part="$(GET part)"
1247 case $part in
1248 summary|webstat|activity|cooknotes|commits|cooklist|broken|blocked|pkgs)
1249 nojs='yes'
1250 part $part
1251 ;;
1252 esac
1253 exit 0
1254 fi
1260 # Load requested page
1263 if [ -z "$pkg" ]; then
1265 page_header
1266 if [ -n "$QUERY_STRING" ]; then
1268 [ "$QUERY_STRING" != 'commits.log' ] &&
1269 for list in activity cooknotes cooklist commits; do
1270 [ -n "$(GET $list)" ] || continue
1271 case $list in
1272 cooklist) nb="- Packages: $(wc -l < $cooklist)";;
1273 commits) nb="- Packages: $(wc -l < $commits)";;
1274 esac
1275 echo '<section id="content2">'
1276 echo "<h2>DB: $list $nb</h2>"
1278 tac $CACHE/$list | sed 's|cooker.cgi?pkg=||; s|%2B|+|g;
1279 s|\[ Done|<span class="r c20">Done|;
1280 s|\[ Failed|<span class="r c10">Failed|;
1281 s|\[ -Failed|<span class="r c10"><del>Failed</del>|;
1282 s| \]|</span>|;
1283 s|%2B|\+|g' \
1284 | while read line; do
1285 case "$line" in
1286 *data-badges=*)
1287 badges="$(echo "$line" | sed "s|.*data-badges='\([^']*\)'.*|\1|")"
1288 echo "$line" | sed "s|</a>|</a> $(show_badges "$badges")|"
1289 ;;
1290 *)
1291 echo "$line"
1292 ;;
1293 esac
1294 done \
1295 | mktable $list
1297 echo '</section>'
1298 done
1300 if [ -n "$(GET broken)" ]; then
1301 echo '<section id="content2">'
1302 echo "<h2>DB: broken - Packages: $(wc -l < $broken)</h2>"
1303 sort $CACHE/broken | sed "s|^[^']*|<a href='$base/\0'>\0</a>|g" | mktable
1304 echo '</section>'
1305 fi
1307 case "$QUERY_STRING" in
1308 *.log)
1309 log=$LOGS/$QUERY_STRING
1310 name=$(basename $log)
1311 if [ -f "$log" ]; then
1312 echo "<h2>Log for: ${name%.log}</h2>"
1313 if fgrep -q "Summary" $log; then
1314 echo '<pre class="log">'
1315 grep -A 20 'Summary' $log | syntax_highlighter log
1316 echo '</pre>'
1317 fi
1318 echo '<pre class="log">'
1319 syntax_highlighter log < $log
1320 echo '</pre>'
1321 if [ "$QUERY_STRING" == 'pkgdb.log' ]; then
1322 # Display button only for SliTaz web browser
1323 case "$HTTP_USER_AGENT" in
1324 *SliTaz*)
1325 if [ -f $CACHE/cooker-request -a -n "$HTTP_REFERER" ]; then
1326 if grep -qs '^pkgdb$' $CACHE/recook-packages; then
1327 show_note i "The package database has been requested for re-creation"
1328 else
1329 echo "<a class='button' href='$base/?recook=pkgdb'>Re-create the DB</a>"
1330 fi
1331 fi
1332 ;;
1333 esac
1334 fi
1335 else
1336 show_note e "No log file: $log"
1337 fi
1338 ;;
1339 toolchain)
1340 cat <<-EOT
1341 <div id="content2">
1342 <section>
1343 <h2>SliTaz GNU/Linux toolchain</h2>
1345 <table>
1346 <tr>
1347 <td>Build date</td>
1348 <td colspan="2">$(sed -n '/^Cook date/s|[^:]*: \(.*\)|\1|p' $LOGS/slitaz-toolchain.log)</td>
1349 </tr>
1350 <tr>
1351 <td>Build duration</td>
1352 <td colspan="2">$(sed -n '/^Cook time/s|[^:]*: \(.*\)|\1|p' $LOGS/slitaz-toolchain.log)</td>
1353 </tr>
1354 <tr>
1355 <td>Architecture</td>
1356 <td colspan="2">$ARCH</td>
1357 </tr>
1358 <tr>
1359 <td>Host system</td>
1360 <td colspan="2">$BUILD_SYSTEM</td>
1361 </tr>
1362 <tr>
1363 <td>Target system</td>
1364 <td colspan="2">$HOST_SYSTEM</td>
1365 </tr>
1366 <tr>
1367 <th>Package</th>
1368 <th>Version</th>
1369 <th>Description</th>
1370 </tr>
1371 $(toolchain_version slitaz-toolchain)
1372 $(toolchain_version binutils)
1373 $(toolchain_version linux-api-headers)
1374 $(toolchain_version gcc)
1375 $(toolchain_version glibc)
1376 </table>
1378 <div id="info">
1379 <a class="button icon doc" target="_blank" rel="noopener noreferrer" href="http://doc.slitaz.org/en:cookbook:toolchain">Toolchain documentation</a>
1380 </div>
1382 </section>
1383 </div>
1384 EOT
1385 ;;
1386 maintainer*)
1387 maintainer=$(GET maintainer); maintainer=${maintainer/maintainer/}
1388 regexp=$(GET regexp); regexp=${regexp/regexp/}
1389 [ -n "$regexp" ] && maintainer=''
1390 cat <<-EOT
1391 <section>
1392 <h2>For maintainers</h2>
1393 <p>Here you can <a href="=/">explore the badges</a>.</p>
1394 <p>Or see some <a href="?maintainer&amp;stats">repository statistics</a>.</p>
1395 <p>Or check packages version either for specified maintainer or using regular expressions:</p>
1396 <form>
1397 <select name="maintainer">
1398 <option value=''>--- select maintainer ---
1399 EOT
1400 cut -d$'\t' -f1 $maintdb | sort -u \
1401 | awk -vm=$maintainer '{
1402 selected=$0==m?"selected":""
1403 printf("<option %s value=\"%s\">%s\n", selected, $0, $0)
1404 }'
1405 cat <<-EOT
1406 </select>
1407 or
1408 <input type="text" name="regexp" value="$regexp"/>
1409 <button type="submit">Go</button>
1410 </form>
1411 EOT
1412 if [ -n "$maintainer" -o -n "$regexp" ]; then
1413 tmp_status=$(mktemp)
1414 cat <<-EOT
1415 <table class="maint">
1416 <thead><tr><th>Package</th><th>Version</th><th>Repology</th></tr></thead>
1417 EOT
1419 if [ -n "$maintainer" ]; then
1420 awk -vm=$maintainer '{if ($1 == m) print $2}' $maintdb
1421 fi
1422 if [ -n "$regexp" ]; then
1423 cd $wok; ls | grep "$regexp"
1424 fi
1425 } | while read pkg; do
1426 unset VERSION; REPOLOGY=$pkg
1427 . $wok/$pkg/receipt
1428 ver=$(awk -F$'\t' -vpkg="$pkg" '{if ($1 == pkg) {print $2; exit}}' $PKGS/packages-$ARCH.info)
1429 if [ "$REPOLOGY" == '-' ]; then
1430 unset repo_info1 repo_info2
1431 echo '-' >>$tmp_status
1432 else
1433 repo_ver=$(repology_get $REPOLOGY)
1434 if [ "$repo_ver" == '-' ]; then
1435 echo '-' >>$tmp_status
1436 icon='more'
1437 else
1438 if echo " $repo_ver " | fgrep -q " ${ver:-$VERSION} "; then
1439 icon='actual'
1440 else
1441 icon='update'
1442 fi
1443 echo $icon >>$tmp_status
1444 fi
1445 repo_info1="<a class='icon $icon' href='https://repology.org/metapackage/$REPOLOGY' target='_blank'"
1446 repo_info2="rel='noopener noreferrer' title='latest packaged version(s)'>${repo_ver// /, }</a>"
1447 fi
1448 cat <<-EOT
1449 <tr>
1450 <td><img src="$base/s/$pkg" alt="$pkg"> <a href="$pkg">$pkg</a></td>
1451 <td>${ver:-$VERSION}</td>
1452 <td>$repo_info1 $repo_info2</td>
1453 </tr>
1454 EOT
1455 done
1457 pkg_total=$( wc -l < $tmp_status)
1458 pkg_actual=$( fgrep actual $tmp_status | wc -l)
1459 pkg_outdated=$(fgrep update $tmp_status | wc -l)
1460 pkg_unknown=$( fgrep '-' $tmp_status | wc -l)
1462 pct_actual=$(( $pkg_actual * 100 / $pkg_total ))
1463 pct_outdated=$(( $pkg_outdated * 100 / $pkg_total ))
1464 pct_unknown=$(( $pkg_unknown * 100 / $pkg_total ))
1466 [ "$pkg_actual" -eq 0 ] && pkg_actual=''
1467 [ "$pkg_outdated" -eq 0 ] && pkg_outdated=''
1468 [ "$pkg_unknown" -eq 0 ] && pkg_unknown=''
1470 cat <<-EOT
1471 </table>
1473 <div class="meter" style="width:100%;text-align:center"><div
1474 style="display:inline-block;background-color:#090;width:$pct_actual%">$pkg_actual</div><div
1475 style="display:inline-block;background-color:#f90;width:$pct_outdated%">$pkg_outdated</div><div
1476 style="display:inline-block;background-color:#ccc;width:$pct_unknown%">$pkg_unknown</div></div>
1477 EOT
1478 rm $tmp_status
1479 fi
1480 cat <<-EOT
1481 </section>
1482 EOT
1483 ;;
1484 esac
1485 page_footer
1486 exit 0
1487 fi
1490 # We may have a toolchain.cgi script for cross cooker's
1491 if [ -f "toolchain.cgi" ]; then
1492 toolchain="toolchain.cgi"
1493 else
1494 toolchain="?toolchain"
1495 fi
1497 # Main page with summary. Count only packages included in ARCH,
1498 # use 'cooker arch-db' to manually create arch.$ARCH files.
1500 cat <<-EOT
1501 <div id="content2">
1503 <section>
1504 <form method="get" action="" class="search r">
1505 <input type="hidden" name="search" value="pkg"/>
1506 <button type="submit" title="Search">Search</button>
1507 <input type="search" name="q" placeholder="Package" list="packages" autocorrect="off" autocapitalize="off"/>
1508 </form>
1509 EOT
1511 unset nojs
1512 part summary
1513 part webstat
1515 cat <<-EOT
1516 <p>
1517 Service logs:
1518 <a href="?cookorder.log">cookorder</a> ·
1519 <a href="?commits.log">commits</a> ·
1520 <a href="?pkgdb.log">pkgdb</a>
1521 </p>
1522 EOT
1524 if [ -e "$CACHE/cooker-request" -a ! -s $command ]; then
1525 if [ "$activity" -nt "$CACHE/cooker-request" ]; then
1526 echo '<a class="button icon bell r" href="?poke">Wake up</a>'
1527 else
1528 show_note i 'Cooker will be launched in the next 5 minutes.'
1529 fi
1530 fi
1532 cat <<-EOT
1533 <a class="button icon maintainers" href="?maintainer">For maintainers</a>
1534 <a class="button icon tag" href="~/">Tags</a>
1535 </section>
1536 EOT
1538 part activity
1539 part cooknotes
1540 part commits
1541 part cooklist
1542 part broken
1543 part blocked
1544 part pkgs
1546 echo '</div>'
1547 datalist
1548 page_footer
1549 exit 0
1550 fi
1553 # show tag
1555 if [ "$pkg" == '~' ]; then
1556 page_header
1557 echo '<div id="content2"><section>'
1559 if [ -n "$cmd" ]; then
1560 tag="$cmd"
1561 cat <<-EOT
1562 <h2>Tag “$tag”</h2>
1564 <table>
1565 <thead><tr><th>Name</th><th>Description</th><th>Category</th></tr></thead>
1566 <tbody>
1567 EOT
1568 sort $PKGS/packages-$ARCH.info \
1569 | awk -F$'\t' -vtag=" $tag " -vbase="$base/" '{
1570 if (index(" " $6 " ", tag)) {
1571 url = base $1 "/";
1572 gsub("+", "%2B", url);
1573 printf("<tr><td><img src=\"%ss/%s\" alt=\"%s\"> ", base, $1, $1);
1574 printf("<a href=\"%s\">%s</a></td><td>%s</td><td>%s</td></tr>\n", url, $1, $4, $3);
1576 }'
1577 echo '</tbody></table>'
1578 else
1579 # Fast and nice tag cloud
1580 echo '<h2>Tag cloud</h2><p class="tags">'
1581 # Some magic in tag sizes :-) It's because of non-linear distribution
1582 # of tags. Currently 1x198 (each of 198 tags marks one package);
1583 # 2x79 (each of 79 other tags marks two packages); 3x28 (and so on);
1584 # 4x23; 5x14; 6x5; 7x9; 8x11; 9x4; 10x3; 11x5; 12x6; 13x3; 14x1; 15x1;
1585 # 16x2; 18x1; 20x3; 22x3; 23, 24, 27, 33, 39, 42, 45, 57, 59, 65, 90x1.
1586 awk -F$'\t' -vbase="$base/~/" '
1588 split($6, tags, " ");
1589 for (i in tags) { tag[tags[i]]++; if (tag[tags[i]] > max) max = tag[tags[i]]; }
1591 END {
1592 for (i in tag) {
1593 j = tag[i];
1594 size = (j == 1) ? 0 : (j == 2) ? 1 : (j < 5) ? 2 : (j < 9) ? 3 : (j < 18) ? 4 : 5;
1595 printf("<a href=\"%s\" class=\"tag%s\">%s<sup>%s</sup></a>\n", base i, size, i, tag[i]);
1598 ' $PKGS/packages-$ARCH.info | sort -f # sort alphabetically case insensitive
1599 fi
1600 echo '</p></section></div>'
1601 page_footer
1602 exit 0
1603 fi
1606 # show badges
1608 if [ "$pkg" == '=' ]; then
1609 page_header
1610 echo '<div id="content2">'
1612 if [ -n "$cmd" ]; then
1613 badge="$cmd"
1614 case "$badge" in
1615 no-badge)
1616 cat <<-EOT
1617 <section>
1618 <h2 class="badge $badge"> Packages without badges</h2>
1620 <table>
1621 <thead><tr><th>Name</th><th>Description</th><th>Category</th></tr></thead>
1622 <tbody>
1623 EOT
1625 awk -F$'\t' '{if (! $2) print $1}' $badges \
1626 | while read pkg; do
1627 awk -F$'\t' -vpkg="$pkg" -vbase="$base/" '{
1628 if ($1 == pkg) {
1629 url = base $1 "/";
1630 gsub("+", "%2B", url);
1631 printf("<tr><td><img src=\"%ss/%s\" alt=\"%s\"> ", base, $1, $1);
1632 printf("<a href=\"%s\">%s</a></td><td>%s</td><td>%s</td></tr>\n", url, $1, $4, $3);
1634 }' $PKGS/packages-$ARCH.info
1635 done
1636 ;;
1637 *)
1638 cat <<-EOT
1639 <section>
1640 <h2 class="badge $badge"> Badge “$badge”</h2>
1642 <table>
1643 <thead><tr><th>Name</th><th>Description</th><th>Category</th></tr></thead>
1644 <tbody>
1645 EOT
1647 awk -F$'\t' -vbadge=" $badge " '{if (index(" " $2 " ", badge)) print $1}' $badges \
1648 | while read pkg; do
1649 if grep -q "^$pkg " $PKGS/packages-$ARCH.info; then
1650 awk -F$'\t' -vpkg="$pkg" -vbase="$base/" '{
1651 if ($1 == pkg) {
1652 url = base $1 "/";
1653 gsub("+", "%2B", url);
1654 printf("<tr><td><img src=\"%ss/%s\" alt=\"%s\"> ", base, $1, $1);
1655 printf("<a href=\"%s\">%s</a></td><td>%s</td><td>%s</td></tr>\n", url, $1, $4, $3);
1657 }' $PKGS/packages-$ARCH.info
1658 else
1659 # broken packages absent in packages-<arch>.info; use receipt (slower)
1661 . $WOK/$pkg/receipt
1662 echo -n "<tr><td><img src=\"$base/s/$pkg\" alt=\"$pkg\"> "
1663 echo -n "<a href=\"$base/$pkg/\">$pkg</a></td>"
1664 echo "<td>$SHORT_DESC</td><td>$CATEGORY</td></tr>"
1666 fi
1667 done
1668 ;;
1669 esac
1670 echo '</tbody></table></section>'
1671 else
1672 layout='list' show_badges bdbroken broken any noany libtool nolibtool own ownover perm permover symlink ss fadd frem fdup old orphan patch win no-badge
1673 fi
1674 echo '</div>'
1675 page_footer
1676 exit 0
1677 fi
1680 case "$cmd" in
1681 '')
1682 page_header
1684 requested_pkg="$pkg"
1685 # Package info.
1686 if [ ! -f "$wok/$pkg/receipt" ]; then
1687 # Let's look at the cases when the package was not found
1689 # Maybe query is the exact name of split package? -> proceed to main package
1690 mainpkg=$(awk -F$'\t' -vpkg=" $pkg " '{
1691 if (index(" " $2 " ", pkg)) {print $1; exit}
1692 }' $splitdb)
1694 # No, so let's find any matches among packages names (both main and split)
1695 if [ -z "$mainpkg" ]; then
1696 pkgs=$(cut -d$'\t' -f2 $splitdb | tr ' ' '\n' | fgrep "$pkg")
1697 # Nothing matched
1698 if [ -z "$pkgs" ]; then
1699 echo "<h2>Not Found</h2>"
1700 show_note e "The requested package <b>$pkg</b> was not found on this server."
1701 page_footer; exit 0
1702 fi
1703 # Search results page
1704 echo "<section><h2>Package names matching “$pkg”</h2>"
1705 echo "<table><thead><tr><th>Name</th><th>Description</th><th>Category</th></tr></thead><tbody>"
1706 query="$pkg"
1707 for pkg in $pkgs; do
1708 # Find main package
1709 mainpkg=$(awk -F$'\t' -vpkg=" $pkg " '{
1710 if (index(" " $2 " ", pkg)) {print $1; exit}
1711 }' $splitdb)
1712 unset SHORT_DESC CATEGORY; . $wok/$mainpkg/receipt
1714 unset SHORT_DESC CATEGORY
1715 [ -e "$wok/$mainpkg/taz/$PACKAGE-$VERSION/receipt" ] &&
1716 . $wok/$mainpkg/taz/$PACKAGE-$VERSION/receipt
1718 echo -n "<tr><td><a href="$base/$pkg">${pkg//$query/<mark>$query</mark>}</a>"
1719 [ "$pkg" == "$mainpkg" ] || echo -n " (${mainpkg//$query/<mark>$query</mark>})"
1720 echo -n "</td><td>$SHORT_DESC</td><td>$CATEGORY</td></tr>"
1721 done
1722 echo '</tbody></table></section>'
1723 page_footer; exit 0
1724 fi
1725 pkg="$mainpkg"
1726 fi
1728 log=$LOGS/$pkg.log
1729 pkg_info
1731 # Check for a log file and display summary if it exists.
1732 summary "$log"
1735 # Show Cooker badges
1736 pkg_badges=$(awk -F$'\t' -vpkg="$pkg" '{if ($1 == pkg) { print $2; exit } }' $badges)
1737 if [ -n "$pkg_badges" ]; then
1738 layout='table' show_badges $pkg_badges
1739 fi
1742 # Repology badge
1743 [ "$REPOLOGY" == '-' ] || cat <<-EOT
1744 <section>
1745 <h3>Repology</h3>
1746 <a href="https://repology.org/metapackage/${REPOLOGY:-$pkg}" target='_blank'
1747 rel='noopener noreferrer' title="latest packaged version(s) by Repology">
1748 <img src="https://repology.org/badge/latest-versions/${REPOLOGY:-$pkg}.svg" alt="latest packaged version(s)">
1749 <img src="https://repology.org/badge/tiny-repos/${REPOLOGY:-$pkg}.svg" alt="Packaging status">
1750 </a>
1751 </section>
1752 EOT
1755 # Show tag list
1756 taglist=$(
1757 for i in $pkg $(awk -F$'\t' -vp="$pkg" '{if ($1 == p) print $2}' $splitdb); do
1758 [ -s "$PKGS/packages-$ARCH.info" ] &&
1759 awk -F$'\t' -vpkg="$i" '{
1760 if ($1 == pkg) { print $6; exit; }
1761 }' "$PKGS/packages-$ARCH.info"
1762 done \
1763 | tr ' ' '\n' \
1764 | sort -u
1766 if [ -n "$taglist" ]; then
1767 echo -n '<section><h3>Tags</h3><p>'
1768 lasttag=$(echo "$taglist" | tail -n1)
1769 for tag in $taglist; do
1770 echo -n "<a href=\"$base/~/${tag//+/%2B}\">$tag</a>"
1771 [ "$tag" != "$lasttag" ] && echo -n " · "
1772 done
1773 echo '</p></section>'
1774 fi
1777 # Informational table with dependencies
1778 pkg="$requested_pkg"
1779 inf="$(mktemp -d)"
1781 # 1/3: Build dependencies (from receipt and pkgdb)
1782 for i in $WANTED $BUILD_DEPENDS $(awk -F$'\t' -vp=" $pkg " '{if (index(" " $2 " ", p) && (" " $1 " " != p)) print $1}' $splitdb); do
1783 echo "$i" >> $inf/a
1784 done
1786 # 2/3: Runtime dependencies (from pkgdb)
1788 [ -s "$PKGS/packages-$ARCH.info" ] &&
1789 awk -F$'\t' -vp="$pkg" '{
1790 if ($1 == p) print $8
1791 }' "$PKGS/packages-$ARCH.info"
1792 } | tr ' ' '\n' | sort -u > $inf/b
1794 # 3/3: Required by (from pkgdb)
1796 for i in $pkg $(awk -F$'\t' -vp="$pkg" '{if ($1 == p) print $2}' $splitdb); do
1797 [ -s "$PKGS/packages-$ARCH.info" ] &&
1798 awk -F$'\t' -vp=" $i " '{
1799 if (index(" " $8 " ", p)) print $1
1800 }' "$PKGS/packages-$ARCH.info"
1802 [ -s "$PKGS/bdeps.txt" ] &&
1803 awk -F$'\t' -vp=" $i " '{
1804 if (index(" " $2 " ", p)) print $1
1805 }' $PKGS/bdeps.txt
1806 done
1807 } | sort -u > $inf/c
1809 cat <<-EOT
1810 <section>
1811 <h3>Related packages</h3>
1812 <table class="third">
1813 <thead>
1814 <tr>
1815 <th>Build dependencies</th>
1816 <th>Runtime dependencies</th>
1817 <th>Required by</th>
1818 </tr>
1819 </thead>
1820 <tbody>
1821 EOT
1823 awk -vinf="$inf" -vbase="$base" '
1824 function linki(i) {
1825 if (i) return sprintf("<img src=\"%s/s/%s\" alt=\"%s\"> <a href=\"%s/%s\">%s</a>", base, i, i, base, i, i);
1827 BEGIN{
1828 do {
1829 a = b = c = "";
1830 getline a < inf "/a";
1831 getline b < inf "/b";
1832 getline c < inf "/c";
1833 printf("<tr><td>%s </td><td>%s </td><td>%s </td></tr>", linki(a), linki(b), linki(c));
1834 } while ( a b c )
1835 }'
1836 cat <<-EOT
1837 </tbody>
1838 </table>
1839 </section>
1840 EOT
1841 # Clean
1842 rm -r $inf
1847 # Display <Recook> button only for SliTaz web browser
1848 case "$HTTP_USER_AGENT" in
1849 *SliTaz*)
1850 if [ -f $CACHE/cooker-request -a -n "$HTTP_REFERER" ]; then
1851 if grep -qs "^$pkg$" $CACHE/recook-packages; then
1852 show_note i "The package “$pkg” has been requested for recook"
1853 else
1854 echo "<a class='button' href='$base/?recook=${pkg//+/%2B}'>Recook $pkg</a>"
1855 fi
1856 fi
1857 ;;
1858 esac
1859 ;;
1861 receipt)
1862 page_header
1863 pkg_info
1864 echo "<a class='button receipt' href='$base/$pkg/receipt'>receipt</a>"
1865 ( cd $wok/$pkg; find stuff -type f 2>/dev/null ) | sort | \
1866 awk -vb="$base/$pkg" '{printf("<a class=\"button\" href=\"%s/%s\">%s</a>\n", b, $0, $0)}'
1868 show_code bash < $wok/$pkg/receipt | sed 's|<pre>|<pre class="line-numbers">|'
1869 ;;
1871 stuff)
1872 page_header
1873 pkg_info
1874 file="$pkg/stuff/$arg"
1875 echo "<a class='button' href='$base/$pkg/receipt'>receipt</a>"
1876 ( cd $wok/$pkg; find stuff -type f 2>/dev/null ) | sort | \
1877 awk -vb="$base/$pkg" -va="stuff/$arg" '{
1878 printf("<a class=\"button%s\" href=\"%s/%s\">%s</a>\n", a==$0 ? " receipt" : "", b, $0, $0)
1879 }'
1881 if [ -f "$wok/$file" ]; then
1882 case $file in
1883 *.desktop|*.theme) class="ini" ;;
1884 *.patch|*.diff|*.u) class="diff" ;;
1885 */patches/series) class="bash";;
1886 *.sh) class="bash" ;;
1887 *.conf*|*.ini)
1888 class="bash"
1889 [ -n "$(cut -c1 < $wok/$file | fgrep '[')" ] && class="ini"
1890 ;;
1891 *.pl) class="perl" ;;
1892 *.c|*.h|*.awk) class="clike" ;;
1893 *.svg) class="svg" ;;
1894 *Makefile*) class="makefile" ;;
1895 *.po|*.pot) class="bash" ;;
1896 *.css) class="css" ;;
1897 *.htm|*.html) class="html" ;;
1898 *.js) class="js" ;;
1899 *.txt) class="asciidoc" ;;
1900 *)
1901 case $(head -n1 $wok/$file) in
1902 *!/bin/sh*|*!/bin/bash*) class="bash" ;;
1903 esac
1904 if [ -z "$class" -a "$(head -n1 $wok/$file | cut -b1)" == '#' ]; then
1905 class="bash"
1906 fi
1907 if [ -z "$class" ]; then
1908 # Follow Busybox restrictions. Search for non-printable chars
1909 if [ $(tr -d '[:alnum:][:punct:][:blank:][:cntrl:]' < "$wok/$file" | wc -c) -gt 0 ]; then
1910 raw="true"
1911 fi
1912 fi
1913 ;;
1914 esac
1916 # Display image
1917 case $file in
1918 *.png|*.svg|*.jpg|*.jpeg|*.ico)
1919 echo "<img src='$base/$pkg/browse/stuff/$arg' style='display: block; max-width: 100%; margin: auto' alt=''/>"
1920 ;;
1921 esac
1923 # Display colored listing for all text-based documents (also for *.svg)
1924 case $file in
1925 *.png|*.jpg|*.jpeg|*.ico) ;;
1926 *)
1927 if [ -z "$raw" ]; then
1928 cat $wok/$file | show_code $class
1929 fi
1930 ;;
1931 esac
1933 # Display hex dump for binary files
1934 if [ -n "$raw" ]; then
1935 hexdump -C $wok/$file | show_code #| sed 's|^\([0-9a-f][0-9a-f]*\)|<span class="c2">\1</span>|'
1936 fi
1937 else
1938 show_note e "File “$file” absent!"
1939 fi
1940 ;;
1942 files)
1943 page_header
1944 pkg_info
1946 # find main package
1947 wanted=$(. $wok/$pkg/receipt; echo $WANTED)
1948 main=${wanted:-$pkg}
1949 devpkg=''; [ -d "$wok/$main-dev" ] && devpkg="$main-dev"
1951 splitsets=$(echo $SPLIT" " \
1952 | awk '
1953 BEGIN { RS = " "; FS = ":"; }
1954 { print $2; }' \
1955 | sort -u \
1956 | tr '\n' ' ' \
1957 | sed 's|^ *||; s| *$||')
1959 splitpkgs=$(echo $SPLIT" " \
1960 | awk '
1961 BEGIN { RS = " "; FS = ":"; }
1962 { print $1; }' \
1963 | tr '\n' ' ' \
1964 | sed 's|^ *||; s| *$||')
1966 # we need the version
1967 if [ -f "$WOK/linux/receipt" ]; then
1968 kvers=$(. $WOK/linux/receipt; echo $VERSION)
1969 kbasevers=$(echo $kvers | cut -d. -f1,2)
1970 elif [ -f "$INSTALLED/linux-api-headers/receipt" ]; then
1971 kvers=$(. $INSTALLED/linux-api-headers/receipt; echo $VERSION)
1972 kbasevers=$(echo $kvers | cut -d. -f1,2)
1973 fi
1974 ver=$(. $wok/$main/receipt; echo $VERSION$EXTRAVERSION)
1976 echo "<section><h3>Quick jump:</h3>"
1979 for part in head body; do
1981 for set in '' $splitsets; do
1982 pkgsofset=$(echo $SPLIT" " \
1983 | awk -vset="$set" -vmain="$main" -vdev="$devpkg" '
1984 BEGIN {
1985 RS = " "; FS = ":";
1986 if (!set) print main;
1987 if (!set && dev) print dev;
1990 if ($2 == set) print $1;
1991 }' \
1992 | sort -u)
1994 set_description=''
1995 [ -n "$splitsets" ] &&
1996 case "$set" in
1997 '')
1998 set_description=' (default set)'
1999 set_title='Default set'
2000 ;;
2001 *)
2002 set_description=" (set “$set”)"
2003 set_title="Set “$set”"
2004 ;;
2005 esac
2007 install="$wok/$main/install"
2008 [ -n "$set" ] && install="$install-$set"
2010 case $part in
2011 head)
2012 [ -n "$splitsets" ] &&
2013 case "$set" in
2014 '') echo "<ul><li>Default set:";;
2015 *) echo "<li>Set “$set”:";;
2016 esac
2017 echo -e '\t<ul>'
2018 echo "$pkgsofset" | sed 'p' | xargs printf "\t\t<li><a href='#%s'>%s</a></li>\n"
2019 cat <<-EOT
2020 <li id='li-repeats$set' style='display:none'>
2021 <a href='#repeats$set'>repeatedly packaged files</a></li>
2022 <li id='li-empty$set' style='display:none'>
2023 <a href='#empty$set'>unpackaged empty folders</a></li>
2024 <li id='li-outoftree$set' style='display:none'>
2025 <a href='#outoftree$set'>out-of-tree files</a></li>
2026 <li id='li-orphans$set' style='display:none'>
2027 <a href='#orphans$set'>unpackaged files</a>
2028 <span id='orphansTypes$set'></span></li>
2029 EOT
2030 echo -e '\t</ul>'
2031 [ -n "$splitsets" ] && echo "</li>"
2032 ;;
2033 body)
2034 all_files=$(mktemp)
2035 cd $install; find ! -type d | sed 's|\.||' > $all_files
2037 # ------------------------------------------------------
2038 # Packages content
2039 # ------------------------------------------------------
2040 packaged=$(mktemp)
2041 for p in $pkgsofset; do
2042 namever="$(awk -F$'\t' -vp="$p" '{
2043 if ($1==p) {printf("%s-%s\n", $1, $2); exit}
2044 }' $PKGS/packages-$ARCH.info)"
2045 if [ -d "$wok/$p/taz/$p-$ver" ]; then
2046 indir=$p
2047 elif [ -d "$wok/$main/taz/$p-$ver" ]; then
2048 indir=$main
2049 fi
2050 dir="$wok/$indir/taz/$p-$ver/fs"
2052 size=$(du -hs $dir | awk '{ sub(/\.0/, ""); print $1 }')
2054 echo
2055 echo "<section id='$p'>"
2056 echo " <h3>Contents of package “$namever” (${size:-empty}):</h3>"
2057 echo ' <pre class="files">'
2058 if [ -s "$wok/$indir/taz/$p-$ver/files.list" ]; then
2059 echo -en '<span class="underline">permissions·lnk·user ·group · size·date &amp; time ·name\n</span>'
2060 cd $dir
2061 find . -print0 \
2062 | sort -z \
2063 | xargs -0 ls -ldp --color=always \
2064 | syntax_highlighter files \
2065 | sed "s|\([^>]*\)>\.\([^<]*\)\(<.*\)$|\1 href='$base/$indir/browse/taz/$p-$ver/fs\2'>\2\3|;" \
2066 | awk 'BEGIN { FS="\""; }
2067 { gsub("+", "%2B", $2); print; }'
2068 else
2069 echo 'No files'
2070 fi
2071 echo '</pre>'
2072 echo '</section>'
2074 cat $wok/$indir/taz/$p-$ver/files.list >> $packaged
2075 done
2076 # ------------------------------------------------------
2077 # /Packages content
2078 # ------------------------------------------------------
2080 # ------------------------------------------------------
2081 # Repeatedly packaged files
2082 # ------------------------------------------------------
2083 repeats=$(mktemp)
2084 sort $packaged | uniq -d > $repeats
2085 if [ -s "$repeats" ]; then
2086 cat <<-EOT
2088 <script>document.getElementById('li-repeats$set').style.display = 'list-item'</script>
2089 <section id='repeats$set'>
2090 <h3>Repeatedly packaged files$set_description:</h3>
2091 EOT
2092 cd $install
2094 IFS=$'\n'
2095 echo -n ' <pre class="files">'
2096 echo -en '<span class="underline">permissions·lnk·user ·group · size·date &amp; time ·name\n</span>'
2097 while read i; do
2098 find .$i -exec ls -ldp --color=always '{}' \; \
2099 | syntax_highlighter files \
2100 | sed 's|>\./|>/|'
2101 done < $repeats
2102 cat <<-EOT
2103 </pre>
2104 </section>
2105 EOT
2106 unset IFS
2107 fi
2108 rm $repeats
2109 # ------------------------------------------------------
2110 # /Repeatedly packaged files
2111 # ------------------------------------------------------
2113 # ------------------------------------------------------
2114 # Unpackaged empty folders
2115 # ------------------------------------------------------
2116 emptydirs=$(mktemp)
2117 cd $install
2118 IFS=$'\n'
2119 find -type d \
2120 | sed 's|\.||' \
2121 | while read d; do
2122 [ -z "$(ls "$install$d")" ] || continue
2123 # empty dir determined by empty `ls`
2124 echo $d
2125 done \
2126 | while read d; do
2127 notfound='yes'
2128 for p in $(cd $wok/$main/taz; ls); do
2129 if [ -d "$wok/$main/taz/$p/fs$d" ]; then
2130 notfound=''
2131 break
2132 fi
2133 done
2134 [ -n "$notfound" ] &&
2135 ls -ldp --color=always .$d \
2136 | syntax_highlighter files \
2137 | sed 's|>\./|>/|'
2138 done > $emptydirs
2139 unset IFS
2140 if [ -s "$emptydirs" ]; then
2141 cat <<-EOT
2143 <script>document.getElementById('li-empty$set').style.display = 'list-item'</script>
2144 <section id='empty$set'>
2145 <h3>Unpackaged empty folders$set_description:</h3>
2146 EOT
2147 echo -n ' <pre class="files">'
2148 echo -en '<span class="underline">permissions·lnk·user ·group · size·date &amp; time ·name\n</span>'
2149 cat $emptydirs
2150 cat <<-EOT
2151 </pre>
2152 </section>
2153 EOT
2154 fi
2155 rm $emptydirs
2156 # ------------------------------------------------------
2157 # /Unpackaged empty folders
2158 # ------------------------------------------------------
2160 # ------------------------------------------------------
2161 # Out-of-tree files
2162 # ------------------------------------------------------
2163 outoftree=$(mktemp)
2164 awk -F$'\n' -vall="$all_files" '
2166 if (FILENAME == all) files_all[$1] = "1";
2167 else files_pkg[$1] = "1";
2169 END {
2170 for (i in files_pkg) {
2171 if (! files_all[i]) print i;
2174 ' "$all_files" "$packaged" > $outoftree
2176 if [ -d "$install" -a -s "$outoftree" ]; then
2177 echo
2178 echo "<script>document.getElementById('li-outoftree$set').style.display = 'list-item'</script>"
2179 echo "<section id='outoftree$set'>"
2180 echo " <h3>Out-of-tree files$set_description:</h3>"
2181 echo -n ' <pre class="files">'
2182 echo -en '<span class="underline">permissions·lnk·user ·group · size·date &amp; time ·name\n</span>'
2183 IFS=$'\n'
2184 while read outoftree_line; do
2185 # Find the package out-of-tree file belongs to
2186 for i in $pkgsofset; do
2187 if grep -q "^$outoftree_line$" $wok/$main/taz/$i-$ver/files.list; then
2188 cd $wok/$main/taz/$i-$ver/fs
2189 ls -ldp --color=always ".$outoftree_line" \
2190 | syntax_highlighter files \
2191 | sed "s|\([^>]*\)>\.\([^<]*\)\(<.*\)$|\1 href='$base/$main/browse/taz/$i-$ver/fs\2'>\2\3|;" \
2192 | awk 'BEGIN { FS="\""; }
2193 { gsub("+", "%2B", $2); print; }'
2194 fi
2195 done
2196 done < $outoftree
2197 unset IFS
2198 echo '</pre>'
2199 echo '</section>'
2200 fi
2201 rm $outoftree
2202 # ------------------------------------------------------
2203 # /Out-of-tree files
2204 # ------------------------------------------------------
2206 # ------------------------------------------------------
2207 # Unpackaged files
2208 # ------------------------------------------------------
2209 orphans=$(mktemp)
2210 awk -F$'\n' -vall="$all_files" '
2212 if (FILENAME == all) files_all[$1] = "1";
2213 else files_pkg[$1] = "1";
2215 END {
2216 for (i in files_all) {
2217 if (! files_pkg[i]) print i;
2220 ' "$all_files" "$packaged" | sort > $orphans
2221 if [ -d "$install" -a -s "$orphans" ]; then
2222 echo
2223 echo "<script>document.getElementById('li-orphans$set').style.display = 'list-item'</script>"
2224 echo "<section id='orphans$set'>"
2225 echo " <h3>Unpackaged files$set_description:</h3>"
2226 table=$(mktemp)
2227 awk '
2228 function tag(text, color) {
2229 printf("<span class=\"c%s1\">%s</span> ", color, text);
2230 printf("%s\n", $0);
2232 /\/perllocal\.pod$/ || /\/\.packlist$/ ||
2233 /\/share\/bash-completion\// || /\/etc\/bash_completion\.d\// ||
2234 /\/lib\/systemd\// || /\.pyc$/ || /\.pyo$/ ||
2235 /\/fonts\.scale$/ || /\/fonts\.dir$/ || /\.la$/ ||
2236 /\/cache\/.*\.gem$/ {
2237 tag("---", 0); next }
2238 /\.pod$/ { tag("pod", 5); next }
2239 /\/share\/man\// { tag("man", 5); next }
2240 /\/share\/doc\// || /\/share\/gtk-doc\// || /\/share\/info\// ||
2241 /\/share\/devhelp\// { tag("doc", 5); next }
2242 /\/share\/icons\// { tag("ico", 2); next }
2243 /\/share\/locale\// { tag("loc", 4); next }
2244 /\.h$/ || /\.a$/ || /\.pc$/ || /\/bin\/.*-config$/ ||
2245 /\/Makefile.*$/ { tag("dev", 3); next }
2246 /\/share\/help\// || /\/share\/appdata\// ||
2247 /\/share\/metainfo\// || /\/share\/application-registry\// ||
2248 /\/share\/mime-info\// || /\/share\/gnome\/help\// || /\/share\/omf\// {
2249 tag("gnm", 6); next }
2250 { tag("???", 1) }
2251 ' "$orphans" > $table
2253 # Summary table
2254 orphans_types='()'
2255 for i in head body; do
2256 case $i in
2257 head) echo -n '<table class="summary"><tr>';;
2258 body) echo -n '<th> </th></tr><tr>';;
2259 esac
2260 for j in '???1' dev3 loc4 ico2 doc5 man5 pod5 gnm6 '---0'; do
2261 tag=${j:0:3}; class="c${j:3:1}0"; [ "$class" == 'c00' ] && class='c01'
2262 case $i in
2263 head) echo -n "<th class='$class'>$tag</th>";;
2264 body)
2265 tagscount="$(grep ">$tag<" $table | wc -l)"
2266 printf '<td>%s</td>' "$tagscount"
2267 [ "$tagscount" -gt 0 ] && orphans_types="${orphans_types/)/ $tag)}"
2268 ;;
2269 esac
2270 done
2271 done
2272 echo '<td> </td></tr></table>'
2273 orphans_types="${orphans_types/( /(}"
2274 [ "$orphans_types" != '()' ] &&
2275 echo "<script>document.getElementById('orphansTypes$set').innerText = '${orphans_types// /, }';</script>"
2277 suffix=''; [ -n "$set" ] && suffix="-$set"
2278 echo -n ' <pre class="files">'
2279 echo -en '<span class="underline">tag·permissions·lnk·user ·group · size·date &amp; time ·name\n</span>'
2280 IFS=$'\n'
2281 while read orphan_line; do
2282 echo -n "${orphan_line/span> */span>} "
2283 cd $install
2284 ls -ldp --color=always ".${orphan_line#*</span> }" \
2285 | syntax_highlighter files \
2286 | sed "s|\([^>]*\)>\.\([^<]*\)\(<.*\)$|\1 href='$base/$main/browse/install$suffix\2'>\2\3|;" \
2287 | awk 'BEGIN { FS="\""; }
2288 { gsub("+", "%2B", $2); print; }'
2289 done < $table
2290 unset IFS
2291 echo '</pre>'
2292 echo '</section>'
2293 rm $table
2294 fi
2295 rm $orphans
2296 # ------------------------------------------------------
2297 # /Unpackaged files
2298 # ------------------------------------------------------
2300 rm $all_files $packaged
2301 ;;
2302 esac
2303 done # /set
2305 case "$part" in
2306 head)
2307 [ -n "$splitsets" ] && echo "</ul>"
2308 echo "</section>"
2309 ;;
2310 esac
2311 done # /part
2313 ;;
2315 description)
2316 page_header
2317 pkg_info
2318 descs="$(ls $WOK/$pkg/description*.txt)"
2319 if [ -n "$descs" ]; then
2320 echo '<div id="content2">'
2321 [ -f "$WOK/$pkg/description.txt" ] && show_desc "$pkg" "$WOK/$pkg/description.txt"
2322 for i in $descs; do
2323 case $i in
2324 */description.txt) continue ;;
2325 *) package=$(echo $i | cut -d. -f2) ;;
2326 esac
2327 show_desc "$package" "$i"
2328 done
2329 echo '</div>'
2330 else
2331 show_note w "No description of $pkg"
2332 fi
2333 ;;
2335 log)
2336 page_header
2337 pkg_info
2338 [ -z "$arg" ] && arg=$(stat -c %Y $LOGS/$pkg.log)
2340 echo '<div class="btnList">'
2341 acc='l' # access key for the latest log is 'L'
2342 while read log; do
2343 # for all $pkg.log, $pkg.log.0 .. $pkg.log.9, $pkg-pack.log (if any)
2344 timestamp=$(stat -c %Y $log)
2345 class=''
2346 if [ "$arg" == "$timestamp" ]; then
2347 class=' log'
2348 logfile="$log"
2349 fi
2350 case $log in *-pack.log) acc='p';; esac # access key for the packing log is 'P'
2351 echo -n "<a class='button$class' data-acc='$acc' accesskey='$acc' href='$base/$pkg/log/$timestamp'>"
2352 echo "$(stat -c %y $log | cut -d: -f1,2)</a>"
2353 case $acc in
2354 l) acc=0;;
2355 *) acc=$((acc+1));;
2356 esac
2357 done <<EOT
2358 $(find $LOGS -name "$pkg.log*" | sort)
2359 $(find $LOGS -name "$pkg-pack.log")
2360 EOT
2361 echo '</div>'
2363 if [ -z "$logfile" ]; then
2364 show_note e "Requested log is absent"
2365 page_footer
2366 exit 0
2367 fi
2369 # Define cook variables for syntax highlighter
2370 if [ -s "$WOK/$pkg/receipt" ]; then
2371 . "$WOK/$pkg/receipt"
2372 _wok='/home/slitaz/wok'
2373 _src="$_wok/$pkg/source/$PACKAGE-$VERSION"
2374 _install="$_wok/$pkg/install"
2375 _fs="$_wok/$pkg/taz/$PACKAGE-$VERSION/fs"
2376 _stuff="$_wok/$pkg/stuff"
2377 fi
2379 # if [ ! -f "gzlog/$pkg.$arg" ]; then
2380 # {
2381 # summary "$logfile" links
2383 # syntax_highlighter log < $logfile | awk '
2384 # BEGIN { print "<pre class=\"log\">"; }
2385 # { printf("<a name=\"l%d\" href=\"#l%d\">%5d</a> %s\n", NR, NR, NR, $0); }
2386 # END { print "</pre>"; }
2387 # '
2389 # page_footer
2390 # } | gzip > gzlog/$pkg.$arg
2391 # fi
2393 blog=$(basename $logfile)
2394 summary "$logfile" links
2396 # disable next `sed` for the 'like2016' theme
2397 theme=$(COOKIE theme); theme=${theme:-default}; [ "$theme" != 'like2016' ] && theme=''
2398 cat $logfile | syntax_highlighter log | \
2399 sed -e "/(pkg\/local$theme):/ s|: \([^<]*\)|<img src='$base/i/$blog/\1' alt=''> \1|" | \
2400 awk '
2401 BEGIN { print "<pre class=\"log\">"; }
2402 { printf("<span id=\"l%d\">%s</span><a href=\"#l%d\"></a>\n", NR, $0, NR); }
2403 END { print "</pre>"; }
2405 ;;
2408 man|doc|info)
2409 page_header
2410 pkg_info
2411 echo '<div style="max-height: 6.4em; overflow: auto; padding: 0 4px">'
2413 dir="wok/$pkg/install/usr/share/$cmd/"; dir2=''
2414 if [ "$cmd" == 'doc' ]; then
2415 dir2="wok/$pkg/install/usr/share/gtk-doc/"
2416 subdirs="$(ls -p $dir | sed '/\/$/!d')"
2417 [ $(echo "$subdirs" | wc -l) -eq 1 ] && dir="$dir$subdirs"
2418 if [ -z "$arg" ]; then
2419 try=$(for i in $dir $dir2; do find $i -name 'index.htm*'; done | sed q)
2420 [ -n "$try" ] && arg="$try"
2421 fi
2422 fi
2424 while read i; do
2425 [ -s "$i" ] || continue
2426 case "$i" in
2427 *.jp*g|*.png|*.gif|*.svg|*.css) continue
2428 esac
2429 i=${i#$dir}; i=${i#$dir2}
2430 [ -n "$arg" ] || arg="$i"
2431 class=''; [ "$arg" == "$i" ] && class=" doc"
2432 case "$cmd" in
2433 man)
2434 case $i in
2435 man*) lang='';;
2436 *) lang="${i%%/*}: ";;
2437 esac
2438 man=$(basename $i .gz)
2439 echo "<a class='button$class' href='$base/$pkg/man/$i'>$lang${man%.*} (${man##*.})</a>"
2440 ;;
2441 doc)
2442 echo "<a class='button$class' href='$base/$pkg/doc/$i'>$i</a>"
2443 ;;
2444 info)
2445 info=$(basename $i)
2446 echo "<a class='button$class' href='$base/$pkg/info/$i#Top'>${info/.info/}</a>"
2447 ;;
2448 esac
2449 done <<EOT
2450 $(for i in $dir $dir2; do find $i -type f; done | sort)
2451 EOT
2452 echo '</div>'
2454 [ -f "$arg" ] || arg="$dir/$arg"
2455 if [ -f "$arg" ]; then
2456 tmp="$(mktemp)"
2457 docat "$arg" > $tmp
2458 [ -s "$tmp" ] &&
2459 case "$cmd" in
2460 info)
2461 echo '<div id="content2" class="texinfo"><pre class="first">'
2462 info2html < "$tmp"
2463 echo '</pre></div>'
2464 ;;
2465 doc)
2466 case "$arg" in
2467 *.sgml|*.devhelp2) class='xml';;
2468 *.py) class='python';; # pycurl package
2469 *.css) class='css';;
2470 *.sh) class='bash';;
2471 *.rb|*/Rakefile*|*/Gemfile*) class='ruby';;
2472 *.rdoc) class='asciidoc';;
2473 *)
2474 first=$(head -n1 "$tmp")
2475 if [ "${first:0:1}" == '#' ]; then
2476 class='bash' # first line begins with '#'
2477 else
2478 class='asciidoc'
2479 fi;;
2480 esac
2481 case "$arg" in
2482 *.htm*)
2483 case $arg in
2484 wok/*) page="${arg#wok/}"; page="$base/$pkg/browse/${page#*/}";;
2485 *) page="$base/$pkg/browse/install/usr/share/$cmd/$arg";;
2486 esac
2487 # make the iframe height so long to contain its contents without scrollbar
2488 echo "<iframe id='idoc' src='$page' width='100%' onload='resizeIframe(this)'></iframe>"
2489 ;;
2490 *.pdf)
2491 case $arg in
2492 wok/*) page="${arg#wok/}"; page="$base/$pkg/browse/${page#*/}";;
2493 *) page="$base/$pkg/browse/install/usr/share/$cmd/$arg";;
2494 esac
2495 cat <<-EOT
2496 <object id="idoc" data="$page" width="100%" height="100%" type="application/pdf" style="min-height: 600px">
2497 $(show_note w "Missing PDF plugin.<br/>Get the file <a href="$page">$(basename "$page")</a>.")
2498 </object>
2499 EOT
2500 ;;
2501 *.md|*.markdown)
2502 echo '<section class="markdown">'
2503 case "$md2html" in
2504 *sundown)
2505 $md2html "$tmp" | sed 's|class="|class="language-|g'
2506 ;;
2507 *)
2508 $md2html "$tmp"
2509 ;;
2510 esac
2511 echo '</section>'
2512 ;;
2513 *)
2514 show_code $class < "$tmp"
2515 ;;
2516 esac
2517 ;;
2518 man)
2519 #export TEXTDOMAIN='man2html'
2520 echo "<div id='content2' class='manpage'>"
2522 html=$(./man2html.bin "$tmp" | sed -e '1,/<header>/d' -e '/<footer>/,$d' \
2523 -e 's|<a href="file:///[^>]*>\([^<]*\)</a>|\1|g' \
2524 -e 's|<a href="?[1-9]\+[^>]*>\([^<]*\)</a>|\1|g')
2526 if [ -n "$(echo "$html" | fgrep 'The requested file /tmp/tmp.')" ]; then
2527 # Process the pre-formatted man-cat page
2528 # (for example see sudo package without groff in build dependencies)
2529 sed -i '
2530 s|M-bM-^@M-^S|—|g;
2531 s|M-bM-^@M-^\\|<b>|g;
2532 s|M-bM-^@M-^]|</b>|g
2533 s|M-bM-^@M-^X|<u>|g;
2534 s|M-bM-^@M-^Y|</u>|g;
2535 s|M-BM-||g;
2536 s|++oo|•|g;
2537 s|&|\&amp;|g; s|<|\&lt;|g; s|>|\&gt;|g;
2538 ' "$tmp"
2539 for i in a b c d e f g h i j k l m n o p q r s t u v w x y z \
2540 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
2541 0 1 2 3 4 5 6 7 8 9 _ - '\\+' '\.' /; do
2542 sed -i "s|$i$i|<b>$i</b>|g; s|_$i|<u>$i</u>|g" "$tmp"
2543 done
2544 echo '<pre class="catman">'
2545 sed 's|</b><b>||g; s|</u><u>||g; s|</u><b>_</b><u>|_|g; s|</b> <b>| |g;' "$tmp"
2546 echo '</pre>'
2547 else
2548 echo "$html"
2549 fi
2550 echo "</div>"
2551 ;;
2552 esac
2553 rm -f $tmp
2554 else
2555 show_note e "File “$arg” does not exist!"
2556 fi
2557 ;;
2559 download)
2560 page_header
2561 pkg_info
2562 show=0
2564 . $wok/$pkg/receipt
2566 if [ -n "$TARBALL" -a -s "$SRC/$TARBALL" ]; then
2567 files_header
2568 echo "<tr><td><a href='$base/src/$TARBALL' class='icon tarball'>$TARBALL</a></td>"
2569 ls -lh "$SRC/$TARBALL" | awk '{printf("<td>%sB</td>", $5)}'
2570 echo "<td>Sources for building the package “$pkg”</td></tr>"
2571 show=1
2572 fi
2574 tmp_table=$(mktemp)
2575 save_ARCH="$ARCH"
2577 for ARCH in i486 x86_64; do
2578 . $wok/$pkg/receipt
2579 for i in $(all_names | tr ' ' '\n'); do
2580 awk -F$'\t' -vpkg="$i" -vbase="$base" -vPKGS="$PKGS" '{
2581 if ($1 == pkg) {
2582 class = ($11 == "0") ? "any" : ($11 == "6") ? "64" : "32";
2583 arch = ($11 == "0") ? "any" : ($11 == "6") ? "x86_64" : "i486";
2584 file = $1 "-" $2 "-" arch ".tazpkg";
2585 desc = $4;
2586 "ls -lh " PKGS "/" file | getline lsout; split(lsout, ls, " ");
2587 size = (ls[5]) ? ls[5] "B" : "---";
2588 printf("<tr><td><a href=\"%s/get/%s\" ", base, file);
2589 printf("class=\"icon pkg%s\">%s</a></td>", class, file);
2590 printf("<td>%s</td><td>%s</td></tr>\n", size, desc);
2592 }' $PKGS/packages-$ARCH.info
2593 done
2594 done \
2595 | sort -u \
2596 > $tmp_table
2598 if [ -s "$tmp_table" ]; then
2599 [ "$show" -eq 0 ] && files_header
2600 cat $tmp_table
2601 show=1
2602 fi
2604 if [ "$show" -eq 1 ]; then
2605 echo '</tbody></table></section>'
2606 else
2607 show_note w "Sorry, there's nothing to download…"
2608 fi
2610 ARCH="$save_ARCH"
2611 rm $tmp_table
2612 ;;
2614 esac
2617 page_footer
2618 exit 0