aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@users.noreply.github.com>2024-08-28 13:52:12 -0400
committerGitHub <noreply@github.com>2024-08-28 13:52:12 -0400
commitb625cf2045a73b9477abe3cc25f38bf34c8c483b (patch)
treeabc1f6dfaef579b2248f81d176c65aa789f18b9e
parentf22a121c6667e3139f8695ff1dbcc0b33039f330 (diff)
downloadstasis-b625cf2045a73b9477abe3cc25f38bf34c8c483b.tar.gz
Pandoc improvements (#37)
* Tweak pandoc command and add a style sheet * Only search for platform sub-string when valid * Add get_pandoc_version * Add version checking and set options accordingly * Add support for globals.sysconfdir * Add missing brace * Remove options that are created dynamically
-rw-r--r--CMakeLists.txt1
-rw-r--r--src/stasis_indexer.c134
-rw-r--r--stasis_pandoc.css232
3 files changed, 355 insertions, 12 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f358b22..abb700c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,5 +35,6 @@ endif()
set(SYSCONFDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/config.h @ONLY)
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/stasis_pandoc.css DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/stasis)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/stasis.ini DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/stasis)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/mission DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/stasis)
diff --git a/src/stasis_indexer.c b/src/stasis_indexer.c
index 4f57a86..25f0fa7 100644
--- a/src/stasis_indexer.c
+++ b/src/stasis_indexer.c
@@ -119,12 +119,7 @@ int indexer_load_metadata(struct Delivery *ctx, const char *filename) {
} else if (!strcmp(name, "codename")) {
ctx->meta.codename = strdup(value);
} else if (!strcmp(name, "platform")) {
- ctx->system.platform = calloc(DELIVERY_PLATFORM_MAX, sizeof(*ctx->system.platform));
- char **platform = split(value, " ", 0);
- ctx->system.platform[DELIVERY_PLATFORM] = platform[DELIVERY_PLATFORM];
- ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR] = platform[DELIVERY_PLATFORM_CONDA_SUBDIR];
- ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER] = platform[DELIVERY_PLATFORM_CONDA_INSTALLER];
- ctx->system.platform[DELIVERY_PLATFORM_RELEASE] = platform[DELIVERY_PLATFORM_RELEASE];
+ ctx->system.platform = split(value, " ", 0);
} else if (!strcmp(name, "arch")) {
ctx->system.arch = strdup(value);
} else if (!strcmp(name, "time")) {
@@ -229,6 +224,56 @@ struct Delivery **get_latest_deliveries(struct Delivery ctx[], size_t nelem) {
return result;
}
+int get_pandoc_version(size_t *result) {
+ *result = 0;
+ int state = 0;
+ char *version_str = shell_output("pandoc --version", &state);
+ if (state || !version_str) {
+ // an error occurred
+ return -1;
+ }
+
+ // Verify that we're looking at pandoc
+ if (strlen(version_str) > 7 && !strncmp(version_str, "pandoc ", 7)) {
+ // we have pandoc
+ char *v_begin = &version_str[7];
+ if (!v_begin) {
+ SYSERROR("unexpected pandoc output: %s", version_str);
+ return -1;
+ }
+ char *v_end = strchr(version_str, '\n');
+ if (v_end) {
+ *v_end = 0;
+ }
+
+ char **parts = split(v_begin, ".", 0);
+ if (!parts) {
+ SYSERROR("unable to split pandoc version string, '%s': %s", version_str, strerror(errno));
+ return -1;
+ }
+
+ size_t parts_total;
+ for (parts_total = 0; parts[parts_total] != NULL; parts_total++);
+
+ // generate the version as an integer
+ // note: pandoc version scheme never exceeds four elements (or bytes in this case)
+ for (size_t i = 0; i < 4; i++) {
+ unsigned char tmp = 0;
+ if (i < parts_total) {
+ // only process version elements we have. the rest will be zeros.
+ tmp = strtoul(parts[i], NULL, 10);
+ }
+ // pack version element into result
+ *result = (*result << 8) | tmp;
+ }
+ } else {
+ // invalid version string
+ return 1;
+ }
+
+ return 0;
+}
+
int indexer_make_website(struct Delivery *ctx) {
char cmd[PATH_MAX];
const char *pattern = "*.md";
@@ -238,6 +283,43 @@ int indexer_make_website(struct Delivery *ctx) {
return 0;
}
+ char *css_filename = calloc(PATH_MAX, sizeof(*css_filename));
+ if (!css_filename) {
+ SYSERROR("unable to allocate string for CSS file path: %s", strerror(errno));
+ return -1;
+ }
+
+ sprintf(css_filename, "%s/%s", globals.sysconfdir, "stasis_pandoc.css");
+ int have_css = access(css_filename, F_OK | R_OK) == 0;
+
+ char pandoc_versioned_args[255] = {0};
+ size_t pandoc_version = 0;
+
+ if (!get_pandoc_version(&pandoc_version)) {
+ // < 2.19
+ if (pandoc_version < 0x02130000) {
+ strcat(pandoc_versioned_args, "--self-contained ");
+ } else {
+ // >= 2.19
+ strcat(pandoc_versioned_args, "--embed-resources ");
+ }
+
+ // >= 1.15.0.4
+ if (pandoc_version >= 0x010f0004) {
+ strcat(pandoc_versioned_args, "--standalone ");
+ }
+
+ // >= 1.10.0.1
+ if (pandoc_version >= 0x010a0001) {
+ strcat(cmd, "-f markdown+autolink_bare_uris ");
+ }
+
+ // >= 3.1.10
+ if (pandoc_version >= 0x03010a00) {
+ strcat(cmd, "-f markdown+alerts ");
+ }
+ }
+
struct StrList *dirs = strlist_init();
strlist_append(&dirs, ctx->storage.delivery_dir);
strlist_append(&dirs, ctx->storage.results_dir);
@@ -269,7 +351,13 @@ int indexer_make_website(struct Delivery *ctx) {
// Converts a markdown file to html
strcpy(cmd, "pandoc ");
- strcat(cmd, "--standalone ");
+ strcat(cmd, pandoc_versioned_args);
+ if (have_css) {
+ strcat(cmd, "--css ");
+ strcat(cmd, css_filename);
+ }
+ strcat(cmd, " ");
+ strcat(cmd, "--metadata title=\"STASIS\" ");
strcat(cmd, "-o ");
strcat(cmd, fullpath_dest);
strcat(cmd, " ");
@@ -423,8 +511,11 @@ int indexer_readmes(struct Delivery ctx[], size_t nelem) {
char *arch = strlist_item(archs, a);
int have_combo = 0;
for (size_t i = 0; i < nelem; i++) {
- if (strstr(latest[i]->system.platform[DELIVERY_PLATFORM_RELEASE], platform) && strstr(latest[i]->system.arch, arch)) {
- have_combo = 1;
+ if (latest[i] && latest[i]->system.platform) {
+ if (strstr(latest[i]->system.platform[DELIVERY_PLATFORM_RELEASE], platform) &&
+ strstr(latest[i]->system.arch, arch)) {
+ have_combo = 1;
+ }
}
}
if (!have_combo) {
@@ -500,9 +591,12 @@ int indexer_junitxml_report(struct Delivery ctx[], size_t nelem) {
char *arch = strlist_item(archs, a);
int have_combo = 0;
for (size_t i = 0; i < nelem; i++) {
- if (strstr(latest[i]->system.platform[DELIVERY_PLATFORM_RELEASE], platform) && strstr(latest[i]->system.arch, arch)) {
- have_combo = 1;
- break;
+ if (latest[i] && latest[i]->system.platform) {
+ if (strstr(latest[i]->system.platform[DELIVERY_PLATFORM_RELEASE], platform) &&
+ strstr(latest[i]->system.arch, arch)) {
+ have_combo = 1;
+ break;
+ }
}
}
if (!have_combo) {
@@ -664,10 +758,26 @@ int main(int argc, char *argv[]) {
if (isempty(rootdirs[i]) || !strcmp(rootdirs[i], "/") || !strcmp(rootdirs[i], "\\")) {
SYSERROR("Unsafe directory: %s", rootdirs[i]);
exit(1);
+ } else if (access(rootdirs[i], F_OK)) {
+ SYSERROR("%s: %s", rootdirs[i], strerror(errno));
+ exit(1);
}
}
}
+ char stasis_sysconfdir_tmp[PATH_MAX];
+ if (getenv("STASIS_SYSCONFDIR")) {
+ strncpy(stasis_sysconfdir_tmp, getenv("STASIS_SYSCONFDIR"), sizeof(stasis_sysconfdir_tmp) - 1);
+ } else {
+ strncpy(stasis_sysconfdir_tmp, STASIS_SYSCONFDIR, sizeof(stasis_sysconfdir_tmp) - 1);
+ }
+
+ globals.sysconfdir = realpath(stasis_sysconfdir_tmp, NULL);
+ if (!globals.sysconfdir) {
+ msg(STASIS_MSG_ERROR | STASIS_MSG_L1, "Unable to resolve path to configuration directory: %s\n", stasis_sysconfdir_tmp);
+ exit(1);
+ }
+
char *workdir;
char workdir_template[PATH_MAX] = {0};
char *system_tmp = getenv("TMPDIR");
diff --git a/stasis_pandoc.css b/stasis_pandoc.css
new file mode 100644
index 0000000..456c3e9
--- /dev/null
+++ b/stasis_pandoc.css
@@ -0,0 +1,232 @@
+/* Modified pandoc defaults */
+
+html {
+ color: #1a1a1a;
+ background-color: #fdfdfd;
+}
+
+body {
+ margin: 0 auto;
+ max-width: 50%;
+ padding-left: 50px;
+ padding-right: 50px;
+ padding-top: 50px;
+ padding-bottom: 50px;
+ hyphens: auto;
+ overflow-wrap: break-word;
+ text-rendering: optimizeLegibility;
+ font-kerning: normal;
+}
+
+@media (max-width: 600px) {
+ body {
+ font-size: 0.9em;
+ padding: 12px;
+ }
+
+ h1 {
+ font-size: 1.8em;
+ }
+}
+
+@media print {
+ html {
+ background-color: white;
+ }
+
+ body {
+ background-color: transparent;
+ color: black;
+ font-size: 12pt;
+ }
+
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3;
+ }
+
+ h2,
+ h3,
+ h4 {
+ page-break-after: avoid;
+ }
+}
+
+p {
+ margin: 1em 0;
+}
+
+/* Use browser defaults
+a {
+color: #1a1a1a;
+}
+a:visited {
+color: #1a1a1a;
+}
+*/
+img {
+ max-width: 100%;
+}
+
+svg {
+ height: auto;
+ max-width: 100%;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ margin-top: 1.4em;
+}
+
+h5,
+h6 {
+ font-size: 1em;
+ font-style: italic;
+}
+
+h6 {
+ font-weight: normal;
+}
+
+ol,
+ul {
+ padding-left: 1.7em;
+ margin-top: 1em;
+}
+
+li>ol,
+li>ul {
+ margin-top: 0;
+}
+
+blockquote {
+ margin: 1em 0 1em 1.7em;
+ padding-left: 1em;
+ border-left: 2px solid #e6e6e6;
+ color: #606060;
+}
+
+code {
+ font-family: Menlo, Monaco, Consolas, 'Lucida Console', monospace;
+ font-size: 90%;
+ margin: 0;
+ hyphens: manual;
+}
+
+pre {
+ margin: 1em 0;
+ overflow: auto;
+}
+
+pre code {
+ padding: 0;
+ overflow: visible;
+ overflow-wrap: normal;
+}
+
+.sourceCode {
+ background-color: transparent;
+ overflow: visible;
+}
+
+hr {
+ background-color: #1a1a1a;
+ border: none;
+ height: 1px;
+ margin: 1em 0;
+}
+
+table {
+ margin: 1em 0;
+ border-collapse: collapse;
+ width: 100%;
+ overflow-x: auto;
+ display: block;
+ font-variant-numeric: lining-nums tabular-nums;
+}
+
+table caption {
+ margin-bottom: 0.75em;
+}
+
+tbody {
+ margin-top: 0.5em;
+ border-top: 1px solid #1a1a1a;
+ border-bottom: 1px solid #1a1a1a;
+}
+
+th {
+ border-top: 1px solid #1a1a1a;
+ padding: 0.25em 0.5em 0.25em 0.5em;
+}
+
+td {
+ padding: 0.125em 0.5em 0.25em 0.5em;
+}
+
+header {
+ margin-bottom: 4em;
+ text-align: center;
+}
+
+#TOC li {
+ list-style: none;
+}
+
+#TOC ul {
+ padding-left: 1.3em;
+}
+
+#TOC>ul {
+ padding-left: 0;
+}
+
+#TOC a:not(:hover) {
+ text-decoration: none;
+}
+
+code {
+ white-space: pre-wrap;
+}
+
+span.smallcaps {
+ font-variant: small-caps;
+}
+
+div.columns {
+ display: flex;
+ gap: min(4vw, 1.5em);
+}
+
+div.column {
+ flex: auto;
+ overflow-x: auto;
+}
+
+div.hanging-indent {
+ margin-left: 1.5em;
+ text-indent: -1.5em;
+}
+
+ul.task-list[class] {
+ list-style: none;
+}
+
+ul.task-list li input[type="checkbox"] {
+ font-size: inherit;
+ width: 0.8em;
+ margin: 0 0.8em 0.2em -1.6em;
+ vertical-align: middle;
+}
+
+.display.math {
+ display: block;
+ text-align: center;
+ margin: 0.5rem auto;
+} \ No newline at end of file