This is an automated email from the ASF dual-hosted git repository.

dfoulks pushed a commit to branch dfoulks/pelican-gha
in repository https://gitbox.apache.org/repos/asf/petri.git

commit 2812e6a8972d0bb97b5e9658276406f76ca71021
Author: Drew <[email protected]>
AuthorDate: Fri May 17 12:00:42 2024 -0400

    Testing migration process on petri-site
---
 .github/workflows/build-pelican.yml |  44 +++++++
 pelicanconf.py                      |  49 ++++++++
 theme/plugins/gfm.py                | 237 ++++++++++++++++++++++++++++++++++++
 3 files changed, 330 insertions(+)

diff --git a/.github/workflows/build-pelican.yml 
b/.github/workflows/build-pelican.yml
new file mode 100644
index 0000000..ca20af8
--- /dev/null
+++ b/.github/workflows/build-pelican.yml
@@ -0,0 +1,44 @@
+name: Build a Pelican Website
+on:
+  push:
+    branches: [ "dfoulks/pelican_gha" ]
+    paths-ignore:
+      - 'output/**'
+  workflow_dispatch:
+env:
+  LIBCMARKDIR: 
/home/runner/work/infrastructure-website/infrastructure-website/cmark-gfm-0.28.3.gfm.12/lib
+jobs:
+  build-pelican:
+    runs-on: ubuntu-latest
+    continue-on-error: true
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          repository: ''
+          ref: 'dfoulks/pelican_gha'
+      - name: Install Pelican
+        run: pip3 install pelican markdown ghp-import bs4
+      # Optionally, if your website uses the gfm plugin uncomment the GFM block
+      #########################
+      # START BUILD GFM BLOCK #
+      #########################
+      - name: fetch libcmark-gfm.so buildscript
+        run: wget 
https://raw.githubusercontent.com/apache/infrastructure-pelican/master/bin/build-cmark.sh
+      - name: build libcmark-gfm.so
+        run: /bin/bash ./build-cmark.sh
+      #######################
+      # END BUILD GFM BLOCK #
+      #######################
+      - name: Generate website from markdown
+        run: python3 -m pelican content -o output
+        working-directory: 
'/home/runner/work/infrastructure-website/infrastructure-website'
+      - name: Open a PR against the staging branch
+        uses: peter-evans/[email protected]
+        with:
+          token: ${{ secrets.GITHUB_TOKEN }}
+          commit-message: GitHub Actions Generated Pelican Build
+          title: Generated Pelican Output
+          body: output generated
+          add-paths: |
+            output/
+          base: dfoulks/gha-site
diff --git a/pelicanconf.py b/pelicanconf.py
new file mode 100644
index 0000000..567b244
--- /dev/null
+++ b/pelicanconf.py
@@ -0,0 +1,49 @@
+
+# Basic information about the site.
+SITENAME = 'Apache Petri'
+SITEDESC = 'Assists external project communities interested in becoming an 
Apache project learn how The ASF works and its views on how to build a healthy 
community'
+SITEDOMAIN = 'petri.apache.org'
+SITEURL = 'https://petri.apache.org'
+SITELOGO = 'https://petri.apache.org/images/logo.png'
+SITEREPOSITORY = 'https://github.com/apache/petri/blob/master/content/'
+CURRENTYEAR = 2024
+TRADEMARKS = 'Apache, the Apache feather logo, and Petri are trademarks or 
registered trademarks'
+TIMEZONE = 'UTC'
+# Theme includes templates and possibly static files
+THEME = 'theme/apache'
+# Specify location of plugins, and which to use
+PLUGIN_PATHS = [ 'theme/plugins',  ]
+PLUGINS = [ 'toc2', 'gfm',  ]
+# All content is located at '.' (aka content/ )
+PAGE_PATHS = [ '.' ]
+STATIC_PATHS = [ '.',  ]
+# Where to place/link generated pages
+
+PATH_METADATA = '(?P<path_no_ext>.*)\\..*'
+
+PAGE_SAVE_AS = '{path_no_ext}.html'
+# Don't try to translate
+PAGE_TRANSLATION_ID = None
+# Disable unused Pelican features
+# N.B. These features are currently unsupported, see 
https://github.com/apache/infrastructure-pelican/issues/49
+FEED_ALL_ATOM = None
+INDEX_SAVE_AS = ''
+TAGS_SAVE_AS = ''
+CATEGORIES_SAVE_AS = ''
+AUTHORS_SAVE_AS = ''
+ARCHIVES_SAVE_AS = ''
+# Disable articles by pointing to a (should-be-absent) subdir
+ARTICLE_PATHS = [ 'blog' ]
+# needed to create blogs page
+ARTICLE_URL = 'blog/{slug}.html'
+ARTICLE_SAVE_AS = 'blog/{slug}.html'
+# Disable all processing of .html files
+READERS = { 'html': None, }
+
+
+
+
+
+
+
+
diff --git a/theme/plugins/gfm.py b/theme/plugins/gfm.py
new file mode 100644
index 0000000..597b831
--- /dev/null
+++ b/theme/plugins/gfm.py
@@ -0,0 +1,237 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+# gfm_reader.py -- GitHub-Flavored Markdown reader for Pelican
+#
+
+import sys
+import os.path
+import ctypes
+import re
+import platform
+
+import pelican.utils
+import pelican.plugins.signals
+import pelican.readers
+
+_LIBDIR = os.environ['LIBCMARKDIR']
+if platform.system() == 'Darwin':
+    _LIBEXT = '.dylib'
+else:
+    _LIBEXT = '.so'
+_LIBCMARK = f'libcmark-gfm{_LIBEXT}'
+try:
+    cmark = ctypes.CDLL(os.path.join(_LIBDIR, _LIBCMARK))
+except OSError as e:
+    raise ImportError('%s not found. See build-cmark.sh. Error:\n%s' % 
(_LIBCMARK, e))
+
+# Newer releases have different naming for this library. Try it first.
+try:
+    cmark_ext = ctypes.CDLL(os.path.join(_LIBDIR, 
f'libcmark-gfm-extensions{_LIBEXT}'))
+    ENSURE_REGISTERED = 'cmark_gfm_core_extensions_ensure_registered'
+except OSError:
+    # Try the older name for the library.
+    try:
+        cmark_ext = ctypes.CDLL(os.path.join(_LIBDIR, 
f'libcmark-gfmextensions{_LIBEXT}'))
+        ENSURE_REGISTERED = 'core_extensions_ensure_registered'
+    except OSError:
+        #print('LIBDIR:', _LIBDIR)
+        raise ImportError('GFM Extensions not found. See build-cmark.sh')
+#print(f'USING: {ENSURE_REGISTERED}')
+
+
+# Use ctypes to access the functions in libcmark-gfm
+F_cmark_parser_new = cmark.cmark_parser_new
+F_cmark_parser_new.restype = ctypes.c_void_p
+F_cmark_parser_new.argtypes = (ctypes.c_int,)
+
+F_cmark_parser_feed = cmark.cmark_parser_feed
+F_cmark_parser_feed.restype = None
+F_cmark_parser_feed.argtypes = (ctypes.c_void_p, ctypes.c_char_p, 
ctypes.c_size_t)
+
+F_cmark_parser_finish = cmark.cmark_parser_finish
+F_cmark_parser_finish.restype = ctypes.c_void_p
+F_cmark_parser_finish.argtypes = (ctypes.c_void_p,)
+
+F_cmark_parser_attach_syntax_extension = 
cmark.cmark_parser_attach_syntax_extension
+F_cmark_parser_attach_syntax_extension.restype = ctypes.c_int
+F_cmark_parser_attach_syntax_extension.argtypes = (ctypes.c_void_p, 
ctypes.c_void_p)
+
+F_cmark_parser_get_syntax_extensions = cmark.cmark_parser_get_syntax_extensions
+F_cmark_parser_get_syntax_extensions.restype = ctypes.c_void_p
+F_cmark_parser_get_syntax_extensions.argtypes = (ctypes.c_void_p,)
+
+F_cmark_parser_free = cmark.cmark_parser_free
+F_cmark_parser_free.restype = None
+F_cmark_parser_free.argtypes = (ctypes.c_void_p,)
+
+F_cmark_node_free = cmark.cmark_node_free
+F_cmark_node_free.restype = None
+F_cmark_node_free.argtypes = (ctypes.c_void_p,)
+
+F_cmark_find_syntax_extension = cmark.cmark_find_syntax_extension
+F_cmark_find_syntax_extension.restype = ctypes.c_void_p
+F_cmark_find_syntax_extension.argtypes = (ctypes.c_char_p,)
+
+F_cmark_render_html = cmark.cmark_render_html
+F_cmark_render_html.restype = ctypes.c_char_p
+F_cmark_render_html.argtypes = (ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p)
+
+
+# Set up the libcmark-gfm library and its extensions
+F_register = getattr(cmark_ext, ENSURE_REGISTERED)
+F_register.restype = None
+F_register.argtypes = ( )
+F_register()
+
+### technically, maybe install an atexit() to release the plugins
+
+# Options for the GFM rendering call
+### this could be moved into SETTINGS or somesuch, but meh. not needed now.
+OPTS = 0
+
+# The GFM extensions that we want to use
+EXTENSIONS = (
+    'autolink',
+    'table',
+    'strikethrough',
+    'tagfilter',
+)
+
+
+class GFMReader(pelican.readers.BaseReader):
+    enabled = True
+    """GFM-flavored Reader for the Pelican system.
+
+    Pelican looks for all subclasses of BaseReader, and automatically
+    registers them for the file extensions listed below. Thus, nothing
+    further is required by users of this Reader.
+    """
+
+    # NOTE: the builtin MarkdownReader must be disabled. Otherwise, it will be
+    #       non-deterministic which Reader will be used for these files.
+    file_extensions = ['md', 'markdown', 'mkd', 'mdown']
+
+    # Metadata is specified as a single, colon-separated line, such as:
+    #
+    # Title: this is the title
+    #
+    # Note: name starts in column 0, no whitespace before colon, will be
+    #       made lower-case, and value will be stripped
+    #
+    RE_METADATA = re.compile('^([A-za-z]+): (.*)$')
+
+    def read_source(self, source_path):
+        "Read metadata and content from the source."
+
+        # Prepare the "slug", which is the target file name. It will be the
+        # same as the source file, minus the leading 
".../content/(articles|pages)"
+        # and with the extension removed (Pelican will add .html)
+        relpath = os.path.relpath(source_path, self.settings['PATH'])
+        parts = relpath.split(os.sep)
+        parts[-1] = os.path.splitext(parts[-1])[0]  # split off ext, keep base
+        slug = os.sep.join(parts[1:])
+
+        metadata = {
+            'slug': slug,
+        }
+        # Fetch the source content, with a few appropriate tweaks
+        with pelican.utils.pelican_open(source_path) as text:
+
+            # Extract the metadata from the header of the text
+            lines = text.splitlines()
+            i = 0 # See 
https://github.com/apache/infrastructure-pelican/issues/70
+            for i in range(len(lines)):
+                line = lines[i]
+                match = GFMReader.RE_METADATA.match(line)
+                if match:
+                    name = match.group(1).strip().lower()
+                    if name != 'slug':
+                        value = match.group(2).strip()
+                        if name == 'date':
+                            value = pelican.utils.get_date(value)
+                    metadata[name] = value
+                    #if name != 'title':
+                    #  print 'META:', name, value
+                elif not line.strip():
+                    # blank line
+                    continue
+                else:
+                    # reached actual content
+                    break
+
+            # Redo the slug for articles.
+            # depending on pelicanconf.py this will change the output filename
+            if parts[0] == 'articles' and 'title' in metadata:
+                metadata['slug'] = pelican.utils.slugify(
+                    metadata['title'],
+                    self.settings.get('SLUG_SUBSTITUTIONS', ()))
+
+            # Reassemble content, minus the metadata
+            text = '\n'.join(lines[i:])
+
+            return text, metadata
+
+    def read(self, source_path):
+        "Read metadata and content then render into HTML."
+
+        # read metadata and markdown content
+        text, metadata = self.read_source(source_path)
+        assert text, 'Text must not be empty'
+        assert metadata, 'Metadata must not be empty'
+        # Render the markdown into HTML
+        if sys.version_info >= (3, 0):
+            text = text.encode('utf-8')
+            content = self.render(text).decode('utf-8')
+        else:
+            content = self.render(text)
+        assert content, 'Did not expect content to be empty'
+
+        return content, metadata
+
+    def render(self, text):
+        "Use cmark-gfm to render the Markdown into an HTML fragment."
+
+        parser = F_cmark_parser_new(OPTS)
+        assert parser, 'Failed to initialise parser'
+        for name in EXTENSIONS:
+            ext = F_cmark_find_syntax_extension(name.encode('utf-8'))
+            assert ext, 'Failed to find UTF-8 extension'
+            rv = F_cmark_parser_attach_syntax_extension(parser, ext)
+            assert rv, 'Failed to attach the UTF-8 extension'
+        exts = F_cmark_parser_get_syntax_extensions(parser)
+        F_cmark_parser_feed(parser, text, len(text))
+        doc = F_cmark_parser_finish(parser)
+        assert doc, 'Did not expect rendered output to be empty'
+
+        output = F_cmark_render_html(doc, OPTS, exts)
+
+        F_cmark_parser_free(parser)
+        F_cmark_node_free(doc)
+
+        return output
+
+
+def add_readers(readers):
+    readers.reader_classes['md'] = GFMReader
+
+
+def register():
+    pelican.plugins.signals.readers_init.connect(add_readers)

Reply via email to