562 |
mateuszvis |
1 |
<?php /*
|
|
|
2 |
|
|
|
3 |
SvarDOS repo index builder
|
|
|
4 |
Copyright (C) Mateusz Viste 2012-2022
|
|
|
5 |
|
734 |
bttr |
6 |
buildidx computes an index json file for the SvarDOS repository.
|
673 |
mateusz.vi |
7 |
it must be executed pointing to a directory that stores packages (*.svp)
|
562 |
mateuszvis |
8 |
files. buildidx will generate the index file and save it into the package
|
|
|
9 |
repository.
|
|
|
10 |
|
|
|
11 |
requires php-zip
|
|
|
12 |
|
730 |
mateusz.vi |
13 |
16 feb 2022: added warning about overlong version strings
|
719 |
mateusz.vi |
14 |
15 feb 2022: index is generated as json, contains all filenames and alt versions
|
673 |
mateusz.vi |
15 |
14 feb 2022: packages are expected to have the *.svp extension
|
650 |
mateusz.vi |
16 |
12 feb 2022: skip source packages from being processed (*.src.zip)
|
562 |
mateuszvis |
17 |
20 jan 2022: rewritten the code from ANSI C to PHP for easier maintenance
|
|
|
18 |
13 feb 2021: 'title' LSM field is no longer looked after
|
|
|
19 |
11 feb 2021: lsm headers are no longer checked, so it is compatible with the simpler lsm format used by SvarDOS
|
|
|
20 |
13 jan 2021: removed the identification line, changed CRC32 to bsum, not creating the listing.txt file and stopped compressing index
|
|
|
21 |
23 apr 2017: uncompressed index is no longer created, added CRC32 of zib (bin only) files, if present
|
|
|
22 |
28 aug 2016: listing.txt is always written inside the repo dir (instead of inside current dir)
|
|
|
23 |
27 aug 2016: accepting full paths to repos (starting with /...)
|
|
|
24 |
07 dec 2013: rewritten buildidx in ANSI C89
|
|
|
25 |
19 aug 2013: add a compressed version of the index file to repos (index.gz)
|
|
|
26 |
22 jul 2013: creating a listing.txt file with list of packages
|
|
|
27 |
18 jul 2013: writing the number of packaged into the first line of the lst file
|
|
|
28 |
11 jul 2013: added a switch to 7za to make it case insensitive when extracting lsm files
|
|
|
29 |
10 jul 2013: changed unzip calls to 7za (to handle cases when appinfo is compressed with lzma)
|
|
|
30 |
04 feb 2013: added CRC32 support
|
|
|
31 |
22 sep 2012: forked 1st version from FDUPDATE builder
|
|
|
32 |
*/
|
|
|
33 |
|
730 |
mateusz.vi |
34 |
$PVER = "20220216";
|
562 |
mateuszvis |
35 |
|
|
|
36 |
|
|
|
37 |
// computes the BSD sum of a file and returns it
|
|
|
38 |
function file2bsum($fname) {
|
|
|
39 |
$result = 0;
|
|
|
40 |
|
|
|
41 |
$fd = fopen($fname, 'rb');
|
|
|
42 |
if ($fd === false) return(0);
|
|
|
43 |
|
|
|
44 |
while (!feof($fd)) {
|
|
|
45 |
|
|
|
46 |
$buff = fread($fd, 1024 * 1024);
|
|
|
47 |
|
563 |
mateuszvis |
48 |
$slen = strlen($buff);
|
|
|
49 |
for ($i = 0; $i < $slen; $i++) {
|
562 |
mateuszvis |
50 |
// rotr
|
|
|
51 |
$result = ($result >> 1) | ($result << 15);
|
|
|
52 |
// add and truncate to 16 bits
|
563 |
mateuszvis |
53 |
$result += ord($buff[$i]);
|
562 |
mateuszvis |
54 |
$result &= 0xffff;
|
|
|
55 |
}
|
|
|
56 |
}
|
|
|
57 |
|
|
|
58 |
fclose($fd);
|
|
|
59 |
return($result);
|
|
|
60 |
}
|
|
|
61 |
|
|
|
62 |
|
|
|
63 |
// reads file fil from zip archive z and returns its content, or false on error
|
|
|
64 |
function read_file_from_zip($z, $fil) {
|
|
|
65 |
$zip = new ZipArchive;
|
|
|
66 |
if ($zip->open($z, ZipArchive::RDONLY) !== true) {
|
|
|
67 |
echo "ERROR: failed to open zip file '{$z}'\n";
|
|
|
68 |
return(false);
|
|
|
69 |
}
|
|
|
70 |
|
|
|
71 |
// load the appinfo/pkgname.lsm file
|
|
|
72 |
$res = $zip->getFromName($fil, 8192, ZipArchive::FL_NOCASE);
|
|
|
73 |
|
|
|
74 |
$zip->close();
|
|
|
75 |
return($res);
|
|
|
76 |
}
|
|
|
77 |
|
|
|
78 |
|
731 |
mateusz.vi |
79 |
function read_list_of_files_in_zip($z) {
|
|
|
80 |
$zip = new ZipArchive;
|
|
|
81 |
if ($zip->open($z, ZipArchive::RDONLY) !== true) {
|
|
|
82 |
echo "ERROR: failed to open zip file '{$z}'\n";
|
|
|
83 |
return(false);
|
|
|
84 |
}
|
|
|
85 |
|
|
|
86 |
$res = array();
|
|
|
87 |
for ($i = 0; $i < $zip->numFiles; $i++) $res[] = $zip->getNameIndex($i);
|
|
|
88 |
|
|
|
89 |
$zip->close();
|
|
|
90 |
return($res);
|
|
|
91 |
}
|
|
|
92 |
|
|
|
93 |
|
562 |
mateuszvis |
94 |
// reads a LSM string and returns it in the form of an array
|
|
|
95 |
function parse_lsm($s) {
|
|
|
96 |
$res = array();
|
|
|
97 |
for ($l = strtok($s, "\n"); $l !== false; $l = strtok("\n")) {
|
|
|
98 |
// the line is "token: value", let's find the colon
|
|
|
99 |
$colpos = strpos($l, ':');
|
|
|
100 |
if (($colpos === false) || ($colpos === 0)) continue;
|
|
|
101 |
$tok = strtolower(trim(substr($l, 0, $colpos)));
|
|
|
102 |
$val = trim(substr($l, $colpos + 1));
|
|
|
103 |
$res[$tok] = $val;
|
|
|
104 |
}
|
|
|
105 |
return($res);
|
|
|
106 |
}
|
|
|
107 |
|
|
|
108 |
|
731 |
mateusz.vi |
109 |
// on PHP 8+ there is str_starts_with(), but not on PHP 7 so I use this
|
|
|
110 |
function str_head_is($haystack, $needle) {
|
|
|
111 |
return strpos($haystack, $needle) === 0;
|
|
|
112 |
}
|
|
|
113 |
|
|
|
114 |
|
562 |
mateuszvis |
115 |
// ***************** MAIN ROUTINE *********************************************
|
|
|
116 |
|
719 |
mateusz.vi |
117 |
//echo "SvarDOS repository index generator ver {$PVER}\n";
|
562 |
mateuszvis |
118 |
|
|
|
119 |
if (($_SERVER['argc'] != 2) || ($_SERVER['argv'][1][0] == '-')) {
|
|
|
120 |
echo "usage: php buildidx.php repodir\n";
|
|
|
121 |
exit(1);
|
|
|
122 |
}
|
|
|
123 |
|
|
|
124 |
$repodir = $_SERVER['argv'][1];
|
|
|
125 |
|
|
|
126 |
$pkgfiles = scandir($repodir);
|
|
|
127 |
$pkgcount = 0;
|
|
|
128 |
|
719 |
mateusz.vi |
129 |
// do a list of all svp packages with their available versions and descriptions
|
562 |
mateuszvis |
130 |
|
719 |
mateusz.vi |
131 |
$pkgdb = array();
|
|
|
132 |
foreach ($pkgfiles as $fname) {
|
|
|
133 |
if (!preg_match('/.svp$/i', $fname)) continue; // skip non-svp files
|
562 |
mateuszvis |
134 |
|
719 |
mateusz.vi |
135 |
$path_parts = pathinfo($fname);
|
|
|
136 |
$pkgnam = explode('-', $path_parts['filename'])[0];
|
|
|
137 |
$pkgfullpath = realpath($repodir . '/' . $fname);
|
562 |
mateuszvis |
138 |
|
719 |
mateusz.vi |
139 |
$lsm = read_file_from_zip($pkgfullpath, "appinfo/{$pkgnam}.lsm");
|
562 |
mateuszvis |
140 |
if ($lsm == false) {
|
719 |
mateusz.vi |
141 |
echo "ERROR: pkg {$fname} does not contain an LSM file at the expected location\n";
|
|
|
142 |
continue;
|
562 |
mateuszvis |
143 |
}
|
|
|
144 |
$lsmarray = parse_lsm($lsm);
|
|
|
145 |
if (empty($lsmarray['version'])) {
|
719 |
mateusz.vi |
146 |
echo "ERROR: lsm file in {$fname} does not contain a version\n";
|
|
|
147 |
continue;
|
562 |
mateuszvis |
148 |
}
|
730 |
mateusz.vi |
149 |
if (strlen($lsmarray['version']) > 16) {
|
|
|
150 |
echo "WARNING: version string in lsm file of {$fname} is too long (16 chars max)\n";
|
|
|
151 |
continue;
|
|
|
152 |
}
|
562 |
mateuszvis |
153 |
if (empty($lsmarray['description'])) {
|
719 |
mateusz.vi |
154 |
echo "ERROR: lsm file in {$fname} does not contain a description\n";
|
|
|
155 |
continue;
|
562 |
mateuszvis |
156 |
}
|
|
|
157 |
|
731 |
mateusz.vi |
158 |
// validate the files present in the archive
|
|
|
159 |
$listoffiles = read_list_of_files_in_zip($pkgfullpath);
|
|
|
160 |
foreach ($listoffiles as $f) {
|
|
|
161 |
$f = strtolower($f);
|
|
|
162 |
// LSM file is ok
|
|
|
163 |
if ($f === "appinfo/{$pkgnam}.lsm") continue;
|
|
|
164 |
if ($f === "appinfo/") continue;
|
|
|
165 |
// well-known dirs are okay
|
|
|
166 |
if (str_head_is($f, 'bin/')) continue;
|
|
|
167 |
if (str_head_is($f, "doc/{$pkgnam}/")) continue;
|
|
|
168 |
if ($f === 'doc/') continue;
|
|
|
169 |
if (str_head_is($f, "nls/{$pkgnam}.")) continue;
|
|
|
170 |
if ($f === 'nls/') continue;
|
|
|
171 |
if (str_head_is($f, "progs/{$pkgnam}/")) continue;
|
|
|
172 |
if ($f === 'progs/') continue;
|
|
|
173 |
if (str_head_is($f, "devel/{$pkgnam}/")) continue;
|
|
|
174 |
if ($f === 'devel/') continue;
|
|
|
175 |
if (str_head_is($f, "games/{$pkgnam}/")) continue;
|
|
|
176 |
if ($f === 'games/') continue;
|
|
|
177 |
if (str_head_is($f, "drivers/{$pkgnam}/")) continue;
|
|
|
178 |
if ($f === 'drivers/') continue;
|
|
|
179 |
echo "WARNING: pkg {$fname} contains a file in an illegal location: {$f}\n";
|
|
|
180 |
}
|
|
|
181 |
|
719 |
mateusz.vi |
182 |
$meta['fname'] = $fname;
|
|
|
183 |
$meta['desc'] = $lsmarray['description'];
|
|
|
184 |
|
|
|
185 |
$pkgdb[$pkgnam][$lsmarray['version']] = $meta;
|
|
|
186 |
}
|
|
|
187 |
|
|
|
188 |
$db = array();
|
|
|
189 |
|
|
|
190 |
// iterate over each svp package
|
|
|
191 |
foreach ($pkgdb as $pkg => $versions) {
|
|
|
192 |
|
|
|
193 |
// sort filenames by version, highest first
|
|
|
194 |
uksort($versions, "version_compare");
|
|
|
195 |
$versions = array_reverse($versions, true);
|
|
|
196 |
|
|
|
197 |
foreach ($versions as $ver => $meta) {
|
|
|
198 |
$fname = $meta['fname'];
|
|
|
199 |
$desc = $meta['desc'];
|
|
|
200 |
|
|
|
201 |
$bsum = file2bsum(realpath($repodir . '/' . $fname));
|
|
|
202 |
|
|
|
203 |
$meta2['ver'] = strval($ver);
|
|
|
204 |
$meta2['bsum'] = $bsum;
|
|
|
205 |
|
|
|
206 |
if (empty($db[$pkg]['desc'])) $db[$pkg]['desc'] = $desc;
|
|
|
207 |
$db[$pkg]['versions'][$fname] = $meta2;
|
|
|
208 |
}
|
|
|
209 |
|
562 |
mateuszvis |
210 |
$pkgcount++;
|
|
|
211 |
|
|
|
212 |
}
|
|
|
213 |
|
719 |
mateusz.vi |
214 |
if ($pkgcount < 100) echo "WARNING: an unexpectedly low number of packages has been found in the repo ({$pkgcount})\n";
|
562 |
mateuszvis |
215 |
|
719 |
mateusz.vi |
216 |
file_put_contents($repodir . '/_index.json', json_encode($db));
|
562 |
mateuszvis |
217 |
|
|
|
218 |
exit(0);
|
|
|
219 |
|
|
|
220 |
?>
|