Compare commits

..

5 Commits

Author SHA1 Message Date
abdelrahman d5578f009a Update stream utilities and fix peek logic
Release / release (push) Successful in 4s
2026-08-30 17:13:32 +01:00
abdelrahman b3830683f6 Print changelog contents to stdout
Release / release (push) Successful in 3s
2026-08-30 14:34:21 +01:00
abdelrahman 0060c51c12 Only extract changelog for new releases
Release / release (push) Successful in 3s
2026-08-30 14:31:11 +01:00
abdelrahman 23613d16b7 Update release workflow
Release / release (push) Successful in 4s
2026-08-30 14:20:47 +01:00
abdelrahman 8cd1d56b4a Save extracted changelog in workspace 2026-08-30 14:20:40 +01:00
12 changed files with 147 additions and 48 deletions
+19 -15
View File
@@ -35,9 +35,10 @@ jobs:
echo "version=$VERSION" >> $GITHUB_OUTPUT echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Extract version changelog - name: Extract version changelog
if: steps.tag.outputs.version
id: changelog id: changelog
run: | run: |
VERSION=$(cat VERSION | tr -d '[:space:]') # read version and trim whitespace VERSION="${{ steps.tag.outputs.version }}"
CHANGELOG_FILE=$(python3 scripts/get_changelog.py $VERSION) CHANGELOG_FILE=$(python3 scripts/get_changelog.py $VERSION)
if [[ $? != 0 ]]; then if [[ $? != 0 ]]; then
@@ -45,7 +46,8 @@ jobs:
exit 1 exit 1
fi fi
echo "changelog=$(cat $CHANGELOG_FILE)" >> $GITHUB_OUTPUT cat "$CHANGELOG_FILE"
echo "changelog_file=$CHANGELOG_FILE" >> $GITHUB_OUTPUT
- name: Build Artifacts - name: Build Artifacts
if: steps.tag.outputs.version if: steps.tag.outputs.version
@@ -59,18 +61,17 @@ jobs:
id: create_release id: create_release
run: | run: |
VERSION="${{ steps.tag.outputs.version }}" VERSION="${{ steps.tag.outputs.version }}"
CHANGELOG="${{ steps.changelog.outputs.changelog }}" CHANGELOG_FILE="${{ steps.changelog.outputs.changelog_file }}"
RESPONSE=$(curl -s -X POST \ RESPONSE=$(jq -n \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ --arg tag "v$VERSION" \
-H "Content-Type: application/json" \ --arg name "wapp-v$VERSION" \
"https://git.thewizardapprentice.com/api/v1/repos/${{ gitea.repository }}/releases" \ --rawfile body "$CHANGELOG_FILE" \
-d '{ '{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}' \
"tag_name": "v'"$VERSION"'", | curl -s -X POST \
"name": "wapp-v'"$VERSION"'", -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
"body": "'"$CHANGELOG"'", -H "Content-Type: application/json" \
"draft": false, --data-binary @- \
"prerelease": false "https://git.thewizardapprentice.com/api/v1/repos/${{ gitea.repository }}/releases")
}')
echo "$RESPONSE" echo "$RESPONSE"
RELEASE_ID=$(echo $RESPONSE | jq -r '.id') RELEASE_ID=$(echo $RESPONSE | jq -r '.id')
@@ -92,4 +93,7 @@ jobs:
- name: Cleanup - name: Cleanup
if: steps.tag.outputs.version if: steps.tag.outputs.version
run: rm -rf dist/* run: |
CHANGELOG_FILE="${{ steps.changelog.outputs.changelog_file }}"
rm -rf dist/*
rm -f "$CHANGELOG_FILE"
+10
View File
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [2.4.0] - 2026-08-30
### Added
- `wpStreamHasCount`, `wpStreamPeekWithOffset` and `wpStreamConsumeCount` utilities
### Fixed
- Logic for peeking at stream contents
## [2.3.0] - 2026-08-29 ## [2.3.0] - 2026-08-29
### Added ### Added
+1 -1
View File
@@ -1 +1 @@
2.3.0 2.4.0
+6 -7
View File
@@ -2,9 +2,9 @@ import os
import re import re
import argparse import argparse
from pathlib import Path from pathlib import Path
from tempfile import mkstemp
VERSION_HEADER = re.compile(r"\[\d+.\d+.\d+\]") VERSION_HEADER = re.compile(r"\[\d+.\d+.\d+\]")
SCRIPT_DIR = Path(__file__).absolute().parent.parent
def main(): def main():
@@ -19,8 +19,7 @@ def main():
def get_changelog(version: str) -> list[str]: def get_changelog(version: str) -> list[str]:
script_dir = Path(__file__).absolute().parent.parent changelog = SCRIPT_DIR / "CHANGELOG.md"
changelog = script_dir / "CHANGELOG.md"
with changelog.open("r") as infile: with changelog.open("r") as infile:
lines = infile.readlines() lines = infile.readlines()
@@ -47,10 +46,10 @@ def get_changelog(version: str) -> list[str]:
def save_changelog(version: str, lines: list[str]) -> str: def save_changelog(version: str, lines: list[str]) -> str:
fd, name = mkstemp(prefix=f"wapp-changelog-{version}-", text=True) version_changelog = SCRIPT_DIR / f"wapp-changelog-{version}.md"
os.write(fd, "".join(lines).encode("utf-8")) with version_changelog.open("w") as outfile:
os.close(fd) outfile.writelines(lines)
return name return str(version_changelog)
if __name__ == "__main__": if __name__ == "__main__":
+14 -11
View File
@@ -6,28 +6,31 @@
void _streamValidate(const WpStream *stream, u64 item_size); void _streamValidate(const WpStream *stream, u64 item_size);
b8 _streamAtEnd(const WpStream *stream, u64 item_size) { b8 wpStreamAtEnd(const WpStream *stream) {
_streamValidate(stream, item_size);
return stream->position >= stream->count; return stream->position >= stream->count;
} }
b8 _streamHasNext(const WpStream *stream, u64 item_size) { b8 _streamHasCount(const WpStream *stream, u64 count) {
_streamValidate(stream, item_size); return stream->position + count <= stream->count;
return stream->position + 1 < stream->count;
} }
void *_streamPeek(const WpStream *stream, u64 item_size) { void *_streamPeekWithOffset(const WpStream *stream, u64 offset, u64 item_size) {
if (_streamHasNext(stream, item_size)) { _streamValidate(stream, item_size);
u64 index = (stream->position + 1) * stream->item_size;
if (_streamHasCount(stream, offset + 1)) {
u64 index = (stream->position + offset) * stream->item_size;
return (void *)(&((u8 *)(stream->data))[index]); return (void *)(&((u8 *)(stream->data))[index]);
} }
return NULL; return NULL;
} }
void *_streamConsume(WpStream *stream, u64 item_size) { void *_streamConsumeCount(WpStream *stream, u64 count, u64 item_size) {
if (!_streamAtEnd(stream, item_size)) { _streamValidate(stream, item_size);
u64 index = stream->position++ * stream->item_size;
if (_streamHasCount(stream, count)) {
u64 index = stream->position * stream->item_size;
stream->position += count;
return (void *)(&((u8 *)(stream->data))[index]); return (void *)(&((u8 *)(stream->data))[index]);
} }
+13 -8
View File
@@ -58,15 +58,20 @@ typedef WpStream WpStr8Stream;
) )
#endif #endif
#define wpStreamAtEnd(TYPE, STREAM) _streamAtEnd(STREAM, sizeof(TYPE)) #define wpStreamHasNext(STREAM) _streamHasCount(STREAM, 1)
#define wpStreamHasNext(TYPE, STREAM) _streamHasNext(STREAM, sizeof(TYPE)) #define wpStreamHasCount(STREAM, COUNT) _streamHasCount(STREAM, COUNT)
#define wpStreamPeek(TYPE, STREAM) ((TYPE *)_streamPeek(STREAM, sizeof(TYPE))) #define wpStreamPeek(TYPE, STREAM) ((TYPE *)_streamPeekWithOffset(STREAM, 0, sizeof(TYPE)))
#define wpStreamConsume(TYPE, STREAM) ((TYPE *)_streamConsume(STREAM, sizeof(TYPE))) #define wpStreamPeekWithOffset(TYPE, STREAM, OFFSET) \
((TYPE *)_streamPeekWithOffset(STREAM, OFFSET, sizeof(TYPE)))
#define wpStreamConsume(TYPE, STREAM) ((TYPE *)_streamConsumeCount(STREAM, 1, sizeof(TYPE)))
#define wpStreamConsumeCount(TYPE, STREAM, COUNT) \
((TYPE *)_streamConsumeCount(STREAM, COUNT, sizeof(TYPE)))
b8 _streamAtEnd(const WpStream *stream, u64 item_size); b8 wpStreamAtEnd(const WpStream *stream);
b8 _streamHasNext(const WpStream *stream, u64 item_size);
void *_streamPeek(const WpStream *stream, u64 item_size); b8 _streamHasCount(const WpStream *stream, u64 count);
void *_streamConsume(WpStream *stream, u64 item_size); void *_streamPeekWithOffset(const WpStream *stream, u64 offset, u64 item_size);
void *_streamConsumeCount(WpStream *stream, u64 count, u64 item_size);
#ifdef WP_PLATFORM_CPP #ifdef WP_PLATFORM_CPP
END_C_LINKAGE END_C_LINKAGE
+8
View File
@@ -6,6 +6,10 @@
#include "../os/file/file.h" #include "../os/file/file.h"
#include "../base/strings/str8/str8.h" #include "../base/strings/str8/str8.h"
#ifdef WP_PLATFORM_CPP
BEGIN_C_LINKAGE
#endif // !WP_PLATFORM_CPP
typedef enum { typedef enum {
WP_LOG_LEVEL_FATAL, WP_LOG_LEVEL_FATAL,
WP_LOG_LEVEL_CRITICAL, WP_LOG_LEVEL_CRITICAL,
@@ -31,4 +35,8 @@ void wpLogError(const WpLogger *logger, WpStr8 msg);
void wpLogCritical(const WpLogger *logger, WpStr8 msg); void wpLogCritical(const WpLogger *logger, WpStr8 msg);
void wpLogFatal(const WpLogger *logger, WpStr8 msg); void wpLogFatal(const WpLogger *logger, WpStr8 msg);
#ifdef WP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WP_PLATFORM_CPP
#endif // !LOG_H #endif // !LOG_H
+35 -3
View File
@@ -1,6 +1,7 @@
// vim:fileencoding=utf-8:foldmethod=marker // vim:fileencoding=utf-8:foldmethod=marker
#include "test_stream.h" #include "test_stream.h"
#include <stdio.h>
#define COUNT 3 #define COUNT 3
@@ -12,7 +13,7 @@ WpTestFuncResult test_stream_at_end(void) {
for (u32 i = 0; i < COUNT; ++i) { for (u32 i = 0; i < COUNT; ++i) {
wpStreamConsume(c8, &stream); wpStreamConsume(c8, &stream);
result = result && (i == 2 ? wpStreamAtEnd(c8, &stream) : !wpStreamAtEnd(c8, &stream)); result = result && (i == 2 ? wpStreamAtEnd(&stream) : !wpStreamAtEnd(&stream));
} }
return wpTesterResult(result); return wpTesterResult(result);
@@ -25,15 +26,31 @@ WpTestFuncResult test_stream_peek(void) {
WpC8Stream stream = wpStream(c8, characters, COUNT); WpC8Stream stream = wpStream(c8, characters, COUNT);
c8 *c = NULL; c8 *c = NULL;
while (!wpStreamAtEnd(c8, &stream)) { for (u32 i = 0; i <= COUNT; ++i) {
c = wpStreamPeek(c8, &stream); c = wpStreamPeek(c8, &stream);
wpStreamConsume(c8, &stream); wpStreamConsume(c8, &stream);
result = result && (wpStreamAtEnd(c8, &stream) ? c == NULL : c != NULL); result = result && (i == 3 ? c == NULL : c != NULL);
} }
return wpTesterResult(result); return wpTesterResult(result);
} }
WpTestFuncResult test_stream_peek_with_offset(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
u64 offset = 2;
c8 *c = wpStreamPeekWithOffset(c8, &stream, offset);
result = result && *c == characters[offset];
c = wpStreamPeekWithOffset(c8, &stream, 5);
result = result && c == NULL;
return wpTesterResult(result);
}
WpTestFuncResult test_stream_consume(void) { WpTestFuncResult test_stream_consume(void) {
b8 result = true; b8 result = true;
@@ -48,3 +65,18 @@ WpTestFuncResult test_stream_consume(void) {
return wpTesterResult(result); return wpTesterResult(result);
} }
WpTestFuncResult test_stream_consume_count(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
c8 *c = wpStreamConsumeCount(c8, &stream, COUNT);
result = result && c != NULL && wpStreamAtEnd(&stream);
c = wpStreamConsumeCount(c8, &stream, COUNT);
result = result && c == NULL;
return wpTesterResult(result);
}
+35 -3
View File
@@ -1,6 +1,7 @@
// vim:fileencoding=utf-8:foldmethod=marker // vim:fileencoding=utf-8:foldmethod=marker
#include "test_stream.h" #include "test_stream.h"
#include <stdio.h>
#define COUNT 3 #define COUNT 3
@@ -12,7 +13,7 @@ WpTestFuncResult test_stream_at_end(void) {
for (u32 i = 0; i < COUNT; ++i) { for (u32 i = 0; i < COUNT; ++i) {
wpStreamConsume(c8, &stream); wpStreamConsume(c8, &stream);
result = result && (i == 2 ? wpStreamAtEnd(c8, &stream) : !wpStreamAtEnd(c8, &stream)); result = result && (i == 2 ? wpStreamAtEnd(&stream) : !wpStreamAtEnd(&stream));
} }
return wpTesterResult(result); return wpTesterResult(result);
@@ -25,15 +26,31 @@ WpTestFuncResult test_stream_peek(void) {
WpC8Stream stream = wpStream(c8, characters, COUNT); WpC8Stream stream = wpStream(c8, characters, COUNT);
c8 *c = NULL; c8 *c = NULL;
while (!wpStreamAtEnd(c8, &stream)) { for (u32 i = 0; i <= COUNT; ++i) {
c = wpStreamPeek(c8, &stream); c = wpStreamPeek(c8, &stream);
wpStreamConsume(c8, &stream); wpStreamConsume(c8, &stream);
result = result && (wpStreamAtEnd(c8, &stream) ? c == NULL : c != NULL); result = result && (i == 3 ? c == NULL : c != NULL);
} }
return wpTesterResult(result); return wpTesterResult(result);
} }
WpTestFuncResult test_stream_peek_with_offset(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
u64 offset = 2;
c8 *c = wpStreamPeekWithOffset(c8, &stream, offset);
result = result && *c == characters[offset];
c = wpStreamPeekWithOffset(c8, &stream, 5);
result = result && c == NULL;
return wpTesterResult(result);
}
WpTestFuncResult test_stream_consume(void) { WpTestFuncResult test_stream_consume(void) {
b8 result = true; b8 result = true;
@@ -48,3 +65,18 @@ WpTestFuncResult test_stream_consume(void) {
return wpTesterResult(result); return wpTesterResult(result);
} }
WpTestFuncResult test_stream_consume_count(void) {
b8 result = true;
c8 characters[COUNT] = {'a', 'b', 'c'};
WpC8Stream stream = wpStream(c8, characters, COUNT);
c8 *c = wpStreamConsumeCount(c8, &stream, COUNT);
result = result && c != NULL && wpStreamAtEnd(&stream);
c = wpStreamConsumeCount(c8, &stream, COUNT);
result = result && c == NULL;
return wpTesterResult(result);
}
+2
View File
@@ -7,6 +7,8 @@
WpTestFuncResult test_stream_at_end(void); WpTestFuncResult test_stream_at_end(void);
WpTestFuncResult test_stream_peek(void); WpTestFuncResult test_stream_peek(void);
WpTestFuncResult test_stream_peek_with_offset(void);
WpTestFuncResult test_stream_consume(void); WpTestFuncResult test_stream_consume(void);
WpTestFuncResult test_stream_consume_count(void);
#endif // !TEST_STREAM_H #endif // !TEST_STREAM_H
+2
View File
@@ -50,7 +50,9 @@ int main(void) {
test_queue_pop, test_queue_pop,
test_stream_at_end, test_stream_at_end,
test_stream_peek, test_stream_peek,
test_stream_peek_with_offset,
test_stream_consume, test_stream_consume,
test_stream_consume_count,
test_str8_lit, test_str8_lit,
test_str8_lit_ro, test_str8_lit_ro,
test_str8_buf, test_str8_buf,
+2
View File
@@ -50,7 +50,9 @@ int main(void) {
test_queue_pop, test_queue_pop,
test_stream_at_end, test_stream_at_end,
test_stream_peek, test_stream_peek,
test_stream_peek_with_offset,
test_stream_consume, test_stream_consume,
test_stream_consume_count,
test_str8_lit, test_str8_lit,
test_str8_lit_ro, test_str8_lit_ro,
test_str8_buf, test_str8_buf,