Skip to content

Commit 11bf399

Browse files
committed
REDM: Add web metadata validation and update
1 parent a7aeb2f commit 11bf399

1 file changed

Lines changed: 127 additions & 23 deletions

File tree

tools/rexm/rexm.c

Lines changed: 127 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,9 @@ typedef enum {
9999
VALID_NOT_IN_JS = 1 << 9, // Not listed in examples.js
100100
VALID_INCONSISTENT_INFO = 1 << 10, // Inconsistent info between collection and example header (stars, author...)
101101
VALID_MISSING_WEB_OUTPUT = 1 << 11, // Missing .html/.data/.wasm/.js
102-
VALID_INVALID_CATEGORY = 1 << 12, // Not a recognized category
103-
VALID_UNKNOWN_ERROR = 1 << 13 // Unknown failure case (fallback)
102+
VALID_MISSING_WEB_METADATA = 1 << 12, // Missing .html example metadata
103+
VALID_INVALID_CATEGORY = 1 << 13, // Not a recognized category
104+
VALID_UNKNOWN_ERROR = 1 << 14 // Unknown failure case (fallback)
104105
} rlExampleValidationStatus;
105106

106107
// Example management operations
@@ -174,7 +175,10 @@ static int AddVSProjectToSolution(const char *projFile, const char *slnFile, con
174175

175176
// Generate unique UUID v4 string
176177
// Output format: {9A2F48CC-0DA8-47C0-884E-02E37F9BE6C1}
177-
const char *GenerateUUIDv4(void);
178+
static const char *GenerateUUIDv4(void);
179+
180+
// Update generated Web example .html file metadata
181+
static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath);
178182

179183
//------------------------------------------------------------------------------------
180184
// Program main entry point
@@ -570,6 +574,10 @@ int main(int argc, char *argv[])
570574
system(TextFormat("make -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exCategory, exName));
571575
//system(TextFormat("%s/build_example_web.bat %s/%s", exBasePath, exCategory, exName));
572576

577+
// Update generated .html metadata
578+
UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
579+
TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
580+
573581
// Copy results to web side
574582
FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
575583
TextFormat("%s/%s/%s.html", exWebPath, exCategory, exName));
@@ -648,6 +656,10 @@ int main(int argc, char *argv[])
648656
system(TextFormat("%s/make -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRecategory, exRename));
649657
//system(TextFormat("%s/build_example_web.bat %s/%s", exBasePath, exRecategory, exRename));
650658

659+
// Update generated .html metadata
660+
UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
661+
TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
662+
651663
// Copy results to web side
652664
FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exRecategory, exRename),
653665
TextFormat("%s/%s/%s.html", exWebPath, exRecategory, exRename));
@@ -774,10 +786,10 @@ int main(int argc, char *argv[])
774786
char *exListUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
775787
bool listUpdated = false;
776788

777-
int exListLen = strlen(exList);
789+
int exListLen = (int)strlen(exList);
778790
strcpy(exListUpdated, exList);
779791

780-
for (int i = 0; i < list.count; i++)
792+
for (unsigned int i = 0; i < list.count; i++)
781793
{
782794
if ((strcmp("examples_template", GetFileNameWithoutExt(list.paths[i])) != 0) && // HACK: Skip "examples_template"
783795
(TextFindIndex(exList, GetFileNameWithoutExt(list.paths[i])) == -1))
@@ -908,6 +920,23 @@ int main(int argc, char *argv[])
908920
exInfo->status |= VALID_MISSING_WEB_OUTPUT;
909921
}
910922

923+
// Validate: raylib.com/examples/<category>/<category>_example_name.html -> Metadata
924+
if (FileExists(TextFormat("%s/%s/%s.html", exWebPath, exInfo->category, exInfo->name)))
925+
{
926+
char *exHtmlText = LoadFileText(TextFormat("%s/%s/%s.html", exWebPath, exInfo->category, exInfo->name));
927+
928+
if ((TextFindIndex(exHtmlText, "raylib web game") > -1) || // title
929+
(TextFindIndex(exHtmlText, "New raylib web videogame, developed using raylib videogames library") > -1) || // description
930+
(TextFindIndex(exHtmlText, "https://www.raylib.com/common/raylib_logo.png") > -1) || // image
931+
(TextFindIndex(exHtmlText, "https://www.raylib.com/games.html") > -1) || // url
932+
(TextFindIndex(exHtmlText, "https://github.com/raysan5/raylib") > -1)) // source code button
933+
{
934+
exInfo->status |= VALID_MISSING_WEB_METADATA;
935+
}
936+
937+
UnloadFileText(exHtmlText);
938+
}
939+
911940
// NOTE: Additional validation elements
912941
// Validate: Example naming conventions: <category>/<category>_example_name, valid category
913942
if ((TextFindIndex(exInfo->name, exInfo->category) == -1) ||
@@ -986,9 +1015,14 @@ int main(int argc, char *argv[])
9861015
// Review: Add/Remove: raylib.com/examples/<category>/<category>_example_name.js
9871016
// Solves: VALID_MISSING_WEB_OUTPUT
9881017
if ((strcmp(exInfo->category, "others") != 0) && // Skipping "others" category
989-
exInfo->status & VALID_MISSING_WEB_OUTPUT)
1018+
((exInfo->status & VALID_MISSING_WEB_OUTPUT) || (exInfo->status & VALID_MISSING_WEB_METADATA)))
9901019
{
991-
system(TextFormat("%s/build_example_web.bat %s/%s", exBasePath, exInfo->category, exInfo->name));
1020+
system(TextFormat("%s/make -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
1021+
//system(TextFormat("%s/build_example_web.bat %s/%s", exBasePath, exInfo->category, exInfo->name));
1022+
1023+
// Update generated .html metadata
1024+
UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
1025+
TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
9921026

9931027
// Copy results to web side
9941028
FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exInfo->category, exInfo->name),
@@ -1033,14 +1067,15 @@ int main(int argc, char *argv[])
10331067
[RDME] VALID_NOT_IN_README // Not listed in README.md
10341068
[JS] VALID_NOT_IN_JS // Not listed in examples.js
10351069
[WOUT] VALID_MISSING_WEB_OUTPUT // Missing .html/.data/.wasm/.js
1070+
[WMETA] VALID_MISSING_WEB_METADATA // Missing .html example metadata
10361071
[INFO] VALID_INCONSISTENT_INFO // Inconsistent info between collection and example header (stars, author...)
10371072
[CAT] VALID_INVALID_CATEGORY // Not a recognized category
10381073
1039-
| [EXAMPLE NAME] | [C] |[CAT]|[INFO]|[PNG]|[WPNG]|[RES]|[MK] |[MKWEB]|[VCX]|[SOL]|[RDME]|[JS] |[WOUT]|
1040-
|:-----------------------------|:---:|:---:|:----:|:---:|:----:|:---:|:---:|:-----:|:---:|:---:|:----:|:---:|:----:|
1041-
| core_basic_window | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
1042-
| shapes_colors_palette | ✘ | ✔ | ✘ | ✔ | ✘ | ✔ | ✔ | ✘ | ✔ | ✔ | ✔ | ✔ | ✔ |
1043-
| text_format_text | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✔ | ✘ | ✔ | ✔ | ✔ |
1074+
| [EXAMPLE NAME] | [C] |[CAT]|[INFO]|[PNG]|[WPNG]|[RES]|[MK] |[MKWEB]|[VCX]|[SOL]|[RDME]|[JS] |[WOUT]|[WMETA]|
1075+
|:-----------------------------|:---:|:---:|:----:|:---:|:----:|:---:|:---:|:-----:|:---:|:---:|:----:|:---:|:----:|:-----:|
1076+
| core_basic_window | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
1077+
| shapes_colors_palette | ✘ | ✔ | ✘ | ✔ | ✘ | ✔ | ✔ | ✘ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
1078+
| text_format_text | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✔ | ✘ | ✔ | ✔ | ✔ | ✔ |
10441079
*/
10451080

10461081
char *report = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
@@ -1061,14 +1096,15 @@ int main(int argc, char *argv[])
10611096
repIndex += sprintf(report + repIndex, " - [SOL] : Project not included in solution file\n");
10621097
repIndex += sprintf(report + repIndex, " - [RDME] : Not listed in README.md\n");
10631098
repIndex += sprintf(report + repIndex, " - [JS] : Not listed in Web (examples.js)\n");
1064-
repIndex += sprintf(report + repIndex, " - [WOUT] : Missing Web build (.html/.data/.wasm/.js)\n```\n");
1099+
repIndex += sprintf(report + repIndex, " - [WOUT] : Missing Web build (.html/.data/.wasm/.js)\n");
1100+
repIndex += sprintf(report + repIndex, " - [WMETA] : Missing Web .html example metadata\n```\n");
10651101

1066-
repIndex += sprintf(report + repIndex, "| **EXAMPLE NAME** | [C] | [CAT]| [INFO]|[PNG]|[WPNG]| [RES]| [MK] |[MKWEB]| [VCX]| [SOL]|[RDME]|[JS] | [WOUT]|\n");
1067-
repIndex += sprintf(report + repIndex, "|:---------------------------------|:---:|:----:|:-----:|:---:|:----:|:----:|:----:|:-----:|:----:|:----:|:----:|:---:|:-----:|\n");
1102+
repIndex += sprintf(report + repIndex, "| **EXAMPLE NAME** | [C] | [CAT]| [INFO]|[PNG]|[WPNG]| [RES]| [MK] |[MKWEB]| [VCX]| [SOL]|[RDME]|[JS] | [WOUT]|[WMETA]|\n");
1103+
repIndex += sprintf(report + repIndex, "|:---------------------------------|:---:|:----:|:-----:|:---:|:----:|:----:|:----:|:-----:|:----:|:----:|:----:|:---:|:-----:|:-----:|\n");
10681104

10691105
for (int i = 0; i < exCollectionCount; i++)
10701106
{
1071-
repIndex += sprintf(report + repIndex, "| %-32s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s |\n",
1107+
repIndex += sprintf(report + repIndex, "| %-32s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s |\n",
10721108
exCollection[i].name,
10731109
(exCollection[i].status & VALID_MISSING_C)? "❌" : "✔",
10741110
(exCollection[i].status & VALID_INVALID_CATEGORY)? "❌" : "✔",
@@ -1082,7 +1118,8 @@ int main(int argc, char *argv[])
10821118
(exCollection[i].status & VALID_NOT_IN_VCXSOL)? "❌" : "✔",
10831119
(exCollection[i].status & VALID_NOT_IN_README)? "❌" : "✔",
10841120
(exCollection[i].status & VALID_NOT_IN_JS)? "❌" : "✔",
1085-
(exCollection[i].status & VALID_MISSING_WEB_OUTPUT)? "❌" : "✔");
1121+
(exCollection[i].status & VALID_MISSING_WEB_OUTPUT)? "❌" : "✔",
1122+
(exCollection[i].status & VALID_MISSING_WEB_METADATA)? "❌" : "✔");
10861123
}
10871124

10881125
SaveFileText(TextFormat("%s/../tools/rexm/%s", exBasePath, "examples_report.md"), report);
@@ -1109,16 +1146,17 @@ int main(int argc, char *argv[])
11091146
repIndex += sprintf(reportIssues + repIndex, " - [SOL] : Project not included in solution file\n");
11101147
repIndex += sprintf(reportIssues + repIndex, " - [RDME] : Not listed in README.md\n");
11111148
repIndex += sprintf(reportIssues + repIndex, " - [JS] : Not listed in Web (examples.js)\n");
1112-
repIndex += sprintf(reportIssues + repIndex, " - [WOUT] : Missing Web build (.html/.data/.wasm/.js)\n```\n");
1149+
repIndex += sprintf(reportIssues + repIndex, " - [WOUT] : Missing Web build (.html/.data/.wasm/.js)\n");
1150+
repIndex += sprintf(reportIssues + repIndex, " - [WMETA] : Missing Web .html example metadata\n```\n");
11131151

1114-
repIndex += sprintf(reportIssues + repIndex, "| **EXAMPLE NAME** | [C] | [CAT]| [INFO]|[PNG]|[WPNG]| [RES]| [MK] |[MKWEB]| [VCX]| [SOL]|[RDME]|[JS] | [WOUT]|\n");
1115-
repIndex += sprintf(reportIssues + repIndex, "|:---------------------------------|:---:|:----:|:-----:|:---:|:----:|:----:|:----:|:-----:|:----:|:----:|:----:|:---:|:-----:|\n");
1152+
repIndex += sprintf(reportIssues + repIndex, "| **EXAMPLE NAME** | [C] | [CAT]| [INFO]|[PNG]|[WPNG]| [RES]| [MK] |[MKWEB]| [VCX]| [SOL]|[RDME]|[JS] | [WOUT]|[WMETA]|\n");
1153+
repIndex += sprintf(reportIssues + repIndex, "|:---------------------------------|:---:|:----:|:-----:|:---:|:----:|:----:|:----:|:-----:|:----:|:----:|:----:|:---:|:-----:|:-----:|\n");
11161154

11171155
for (int i = 0; i < exCollectionCount; i++)
11181156
{
11191157
if (exCollection[i].status > 0)
11201158
{
1121-
repIndex += sprintf(reportIssues + repIndex, "| %-32s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s |\n",
1159+
repIndex += sprintf(reportIssues + repIndex, "| %-32s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s |\n",
11221160
exCollection[i].name,
11231161
(exCollection[i].status & VALID_MISSING_C)? "❌" : "✔",
11241162
(exCollection[i].status & VALID_INVALID_CATEGORY)? "❌" : "✔",
@@ -1132,7 +1170,8 @@ int main(int argc, char *argv[])
11321170
(exCollection[i].status & VALID_NOT_IN_VCXSOL)? "❌" : "✔",
11331171
(exCollection[i].status & VALID_NOT_IN_README)? "❌" : "✔",
11341172
(exCollection[i].status & VALID_NOT_IN_JS)? "❌" : "✔",
1135-
(exCollection[i].status & VALID_MISSING_WEB_OUTPUT)? "❌" : "✔");
1173+
(exCollection[i].status & VALID_MISSING_WEB_OUTPUT)? "❌" : "✔",
1174+
(exCollection[i].status & VALID_MISSING_WEB_METADATA)? "❌" : "✔");
11361175
}
11371176
}
11381177

@@ -2097,7 +2136,7 @@ static int AddVSProjectToSolution(const char *projFile, const char *slnFile, con
20972136

20982137
// Generate unique UUID v4 string
20992138
// Output format: {9A2F48CC-0DA8-47C0-884E-02E37F9BE6C1}
2100-
const char *GenerateUUIDv4(void)
2139+
static const char *GenerateUUIDv4(void)
21012140
{
21022141
static char uuid[38] = { 0 };
21032142
memset(uuid, 0, 38);
@@ -2120,3 +2159,68 @@ const char *GenerateUUIDv4(void)
21202159

21212160
return uuid;
21222161
}
2162+
2163+
// Update generated Web example .html file metadata
2164+
static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath)
2165+
{
2166+
if (FileExists(exHtmlPath) && IsFileExtension(exHtmlPath, ".html"))
2167+
{
2168+
char *fileText = LoadFileText(exHtmlPath);
2169+
char *fileTextUpdated[6] = { 0 }; // Pointers to multiple updated text versions
2170+
2171+
char *exText = NULL; // Example code file, required to get description
2172+
char **lines = NULL; // Pointers to example code lines
2173+
int lineCount = 0; // Example code line count
2174+
int lineLength = 0; // Description line length
2175+
2176+
char exName[64] = { 0 }; // Example name: fileName without extension
2177+
char exCategory[16] = { 0 }; // Example category: core, shapes, text, textures, models, audio, shaders
2178+
char exDescription[256] = { 0 }; // Example description: example text line #3
2179+
char exTitle[64] = { 0 }; // Example title: fileName without extension, replacing underscores by spaces
2180+
2181+
memset(exName, 0, 64);
2182+
memset(exTitle, 0, 64);
2183+
memset(exDescription, 0, 256);
2184+
memset(exCategory, 0, 16);
2185+
lineLength = 0;
2186+
2187+
// Get example name: replace underscore by spaces
2188+
strcpy(exName, GetFileNameWithoutExt(exHtmlPath));
2189+
strcpy(exTitle, exName);
2190+
for (int i = 0; (i < 256) && (exTitle[i] != '\0'); i++) { if (exTitle[i] == '_') exTitle[i] = ' '; }
2191+
2192+
// Get example category from exName: copy until first underscore
2193+
for (int i = 0; (exName[i] != '_'); i++) exCategory[i] = exName[i];
2194+
2195+
// Get example description: copy line #3 from example file
2196+
exText = LoadFileText(exFilePath);
2197+
lines = LoadTextLines(exText, &lineCount);
2198+
for (int i = 0; (lines[2][i] != '\n') && (lines[2][i] != '\r'); i++) lineLength++;
2199+
strncpy(exDescription, lines[2] + 4, lineLength - 4);
2200+
UnloadFileText(exText);
2201+
2202+
// Update example.html required text
2203+
fileTextUpdated[0] = TextReplace(fileText, "raylib web game", exTitle);
2204+
fileTextUpdated[1] = TextReplace(fileTextUpdated[0], "New raylib web videogame, developed using raylib videogames library", exDescription);
2205+
fileTextUpdated[2] = TextReplace(fileTextUpdated[1], "https://www.raylib.com/common/raylib_logo.png",
2206+
TextFormat("https://raw.githubusercontent.com/raysan5/raylib/master/examples/%s/%s.png", exCategory, exName));
2207+
fileTextUpdated[3] = TextReplace(fileTextUpdated[2], "https://www.raylib.com/games.html",
2208+
TextFormat("https://www.raylib.com/examples/%s/%s.html", exCategory, exName));
2209+
fileTextUpdated[4] = TextReplace(fileTextUpdated[3], "raylib - example", TextFormat("raylib - %s", exName)); // og:site_name
2210+
fileTextUpdated[5] = TextReplace(fileTextUpdated[4], "https://github.com/raysan5/raylib",
2211+
TextFormat("https://github.com/raysan5/raylib/blob/master/examples/%s/%s.c", exCategory, exName));
2212+
2213+
SaveFileText(exHtmlPath, fileTextUpdated[5]);
2214+
2215+
//LOG("INFO: [%s] Updated successfully\n",files.paths[i]);
2216+
//LOG(" - Name / Title: %s / %s\n", exName, exTitle);
2217+
//LOG(" - Description: %s\n", exDescription);
2218+
//LOG(" - URL: %s\n", TextFormat("https://www.raylib.com/examples/%s/%s.html", exCategory, exName));
2219+
//LOG(" - URL Source: %s\n", TextFormat("https://github.com/raysan5/raylib/blob/master/examples/%s/%s.c", exCategory, exName));
2220+
2221+
for (int i = 0; i < 6; i++) { MemFree(fileTextUpdated[i]); fileTextUpdated[i] = NULL; }
2222+
2223+
UnloadTextLines(lines);
2224+
UnloadFileText(fileText);
2225+
}
2226+
}

0 commit comments

Comments
 (0)