Commit:    7971068c37a43fdd24f37542682729ab8bc6e7dd
Author:    Sara Golemon <[email protected]>         Wed, 17 Jun 2020 20:19:30 
+0000
Parents:   0df7236ff958b62aae073a66adc9fa25b8f3096a
Branches:  master

Link:       
http://git.php.net/?p=web/php.git;a=commitdiff;h=7971068c37a43fdd24f37542682729ab8bc6e7dd

Log:
Refactor createNewsEntry for non-interactive use

Add bin/createReleaseEntry script for common release announcements

Changed paths:
  M  bin/createNewsEntry
  A  bin/createReleaseEntry
  A  include/news_entry.inc

diff --git a/bin/createNewsEntry b/bin/createNewsEntry
index c83b18471..bf843cd08 100755
--- a/bin/createNewsEntry
+++ b/bin/createNewsEntry
@@ -2,20 +2,8 @@
 <?php
 PHP_SAPI == 'cli' or die("Please run this script using the cli sapi");
 
-// Script config
-const BASE = "https://www.php.net";;
-const PHPWEB = __DIR__ . '/../';
-const ARCHIVE_FILE_REL = 'archive/archive.xml';
-const ARCHIVE_FILE_ABS = PHPWEB . ARCHIVE_FILE_REL;
-const ARCHIVE_ENTRIES_REL = 'archive/entries/';
-const ARCHIVE_ENTRIES_ABS = PHPWEB . ARCHIVE_ENTRIES_REL;
-
-$categories = [
-       'frontpage'   => 'PHP.net frontpage news',
-       'releases'    => 'New PHP release',
-       'conferences' => 'Conference announcement',
-       'cfp'         => 'Call for Papers',
-];
+require(__DIR__ . '/../include/news_entry.inc');
+use phpweb\news\Entry;
 
 $imageRestriction = [
        'width' => 400,
@@ -23,119 +11,38 @@ $imageRestriction = [
 ];
 
 // Create an entry!
-if (!file_exists(ARCHIVE_FILE_ABS)) {
-       fwrite(STDERR, "Can't find " . ARCHIVE_FILE_REL . ", are you sure you 
are in phpweb/?\n");
+if (!file_exists(Entry::ARCHIVE_FILE_ABS)) {
+       fwrite(STDERR, "Can't find " . Entry::ARCHIVE_FILE_REL . ", are you 
sure you are in phpweb/?\n");
        exit(1);
 }
 
-$id = getNextId();
-createNewsEntry($id);
-updateArchiveXML($id, ARCHIVE_FILE_ABS);
-
-fwrite(STDOUT, "File saved.\nPlease git diff " . ARCHIVE_FILE_REL . " and 
sanity-check the changes before committing\n");
-fwrite(STDOUT, "NOTE: Remeber to git add " . ARCHIVE_ENTRIES_REL . $id . ".xml 
!!\n");
-
-// Implementation functions
-
-function getNextId(): string {
-       $filename = date("Y-m-d", $_SERVER["REQUEST_TIME"]);
-       $count = 0;
-       do {
-               ++$count;
-               $id = $filename . "-" . $count;
-               $basename  = "{$id}.xml";
-               fprintf(STDOUT, "Trying $basename\n");
-       } while (file_exists(ARCHIVE_ENTRIES_ABS . $basename));
-
-       return $id;
+if ($_SERVER['argc'] > 1) {
+       // getopt based non-interactive mode
+       $entry = parseOptions();
+} else {
+       // Classic interactive prompts
+       $entry = getEntry();
 }
 
-function createNewsEntry(string $id): void {
-       global $categories;
+$entry->save()->updateArchiveXML();
 
-       $entry = getEntry($id);
-
-       // Create the XML document.
-       $dom = new DOMDocument("1.0", "utf-8");
-       $dom->formatOutput = true;
-       $dom->preserveWhiteSpace = false;
-       $item = $dom->createElementNs("http://www.w3.org/2005/Atom";, "entry");
-
-       ce($dom, "title", $entry['title'], [], $item);
-       ce($dom, "id", $entry['archive'], array(), $item);
-       ce($dom, "published", date(DATE_ATOM), [], $item);
-       ce($dom, "updated", date(DATE_ATOM), [], $item);
-       ce($dom, "link", null, ['href' => "{$entry['href']}#id$id", "rel"  => 
"alternate", "type" => "text/html"], $item);
-       ce($dom, "link", null, ['href' => $entry['via'], 'rel'  => 'via', 
'type' => 'text/html'], $item);
-
-       if (isset($entry['conf-time'])) {
-               
$item->appendChild($dom->createElementNs("http://php.net/ns/news";, 
"finalTeaserDate", date("Y-m-d", $entry['conf-time'])));
-       }
-
-       foreach ($entry['categories'] as $cat) {
-               ce($dom, "category", null, ['term' => $cat, "label" => 
$categories[$cat]], $item);
-       }
+fwrite(STDOUT, "File saved.\nPlease git diff " . Entry::ARCHIVE_FILE_REL . " 
and sanity-check the changes before committing\n");
+fwrite(STDOUT, "NOTE: Remeber to git add " . Entry::ARCHIVE_ENTRIES_REL . 
$entry->getId() . ".xml !!\n");
 
-       if ($entry['image'] ?? false) {
-               $image = 
$item->appendChild($dom->createElementNs("http://php.net/ns/news";, "newsImage", 
$entry['image']['path']));
-               $image->setAttribute("link", $entry['image']['link']);
-               $image->setAttribute("title", $entry['image']['title']);
-       }
-
-       $content = ce($dom, "content", null, [], $item);
-
-       // Slurp content into our DOM.
-       $tdoc = new DOMDocument("1.0", "utf-8");
-       $tdoc->formatOutput = true;
-       if ($tdoc->loadXML("<div>{$entry['content']}    </div>")) {
-               $content->setAttribute("type", "xhtml");
-               $div = $content->appendChild($dom->createElement("div"));
-               $div->setAttribute("xmlns", "http://www.w3.org/1999/xhtml";);
-               foreach($tdoc->firstChild->childNodes as $node) {
-                       $div->appendChild($dom->importNode($node, true));
-               }
-       } else {
-               fwrite(STDERR, "There is something wrong with your xhtml, 
falling back to html");
-               $content->setAttribute("type", "html");
-               $content->nodeValue = $entry['content'];
-       }
-
-       $dom->appendChild($item);
-       $dom->save(ARCHIVE_ENTRIES_ABS . $id . ".xml");
-}
+// Implementation functions
 
-function ce(DOMDocument $d, string $name, $value, array $attrs = [], ?DOMNode 
$to = null) {
-       if ($value) {
-               $n = $d->createElement($name, $value);
-       } else {
-               $n = $d->createElement($name);
+function getEntry(): Entry {
+       $entry = new Entry;
+       $entry->setTitle(getTitle());
+       $entry->setCategories(selectCategories());
+       if ($entry->isConference()) {
+               $entry->setConfTime(getConfTime());
        }
-       foreach($attrs as $k => $v) {
-               $n->setAttribute($k, $v);
-       }
-       if ($to) {
-               return $to->appendChild($n);
-       }
-       return $n;
-}
 
-function getEntry(string $id): array {
-       $entry = [];
+       $image = getImage();
+       $entry->setImage($image['path'] ?? '', $image['title'] ?? '', 
$image['link'] ?? '');
 
-       $entry['title'] = getTitle();
-
-       $entry['categories'] = selectCategories();
-       if (array_intersect($entry['categories'], ['cfp', 'conferences'])) {
-               $entry['href'] = BASE . '/conferences/index.php';
-               $entry['conf-time'] = getConfTime();
-       } else {
-               $entry['href'] = BASE . '/index.php';
-       }
-
-       $entry['image'] = getImage();
-       $entry['content'] = getContent();
-       $entry['archive'] = BASE . "/archive/" . date('Y', 
$_SERVER['REQUEST_TIME']) . ".php#$id";
-       $entry['via'] = $entry['image']['link'] ?? $entry['archive'];
+       $entry->setContent(getContent());
 
        return $entry;
 }
@@ -150,12 +57,11 @@ function getTitle(): string {
 }
 
 function selectCategories(): array { for(;;) {
-       global $categories;
-       $ids = array_keys($categories);
+       $ids = array_keys(Entry::CATEGORIES);
 
        fwrite(STDOUT, "Categories:\n");
        foreach($ids as $n => $id) {
-               fprintf(STDOUT, "\t%d: %-11s\t [%s]\n", $n, $categories[$id], 
$id);
+               fprintf(STDOUT, "\t%d: %-11s\t [%s]\n", $n, 
Entry::CATEGORIES[$id], $id);
        }
        fwrite(STDOUT, "Please select appropriate categories, seperated with 
space: ");
 
@@ -166,8 +72,8 @@ function selectCategories(): array { for(;;) {
                },
                array_filter(
                        explode(" ", rtrim(fgets(STDIN))),
-                       function ($c) use ($categories) {
-                               return is_numeric($c) && ($c >= 0) && ($c < 
count($categories));
+                       function ($c) {
+                               return is_numeric($c) && ($c >= 0) && ($c < 
count(Entry::CATEGORIES));
                        })
        );
 
@@ -212,7 +118,7 @@ function getImage(): ?array {
                fwrite(STDOUT, "Enter the image name (note: the image has to 
exist in './images/news'): ");
                $path = basename(rtrim(fgets(STDIN)));
 
-               if (true === file_exists(PHPWEB . "/images/news/$path")) {
+               if (true === file_exists(Entry::PHPWEB . "/images/news/$path")) 
{
                        $isValidImage = true;
 
                        if (extension_loaded('gd')) {
@@ -267,3 +173,83 @@ function updateArchiveXML(string $id, string 
$archiveFile): void {
        $arch->documentElement->insertBefore($first, $second);
        $arch->save($archiveFile);
 }
+
+function parseOptions(): Entry {
+       $opts = getopt('h', [
+               'help',
+               'title:',
+               'category:',
+               'conf-time:',
+               'image-path:',
+               'image-title:',
+               'image-link:',
+               'content:',
+               'content-file:',
+       ]);
+       if (isset($opts['h']) || isset($opts['help'])) {
+               echo "Usage: {$_SERVER['argv'][0]} --title 'Name of event' 
--category cfp ( --content 'text' | --content-file '-') [...options]\n\n";
+               echo "  --title 'value'        The title of the entry 
(required)\n";
+               echo "  --category 'value'     'frontpage', 'release', 'cfp', 
or 'conference' (required; may repeat)\n";
+               echo "  --conf-time 'value'    When the event will be occurign 
(cfp and conference categories only)\n";
+               echo "  --content 'value'      Text content for the entry, may 
include XHTML\n";
+               echo "  --content-file 'value' Name of file to load content 
from, may not be specified with --content\n";
+               echo "  --image-path 'value'   Basename of image file in " . 
Entry::IMAGE_PATH_REL . "\n";
+               echo "  --image-title 'value'  Title for the image provided\n";
+               echo "  --image-link 'value'   URI to direct to when clicking 
the image\n";
+               exit(0);
+       }
+
+       $entry = new Entry;
+       if (!isset($opts['title'])) {
+               fwrite(STDERR, "--title required\n");
+               exit(1);
+       }
+       $entry->setTitle($opts['title']);
+
+       if (empty($opts['category'])) {
+               fwrite(STDERR, "--category required\n");
+               exit(1);
+       }
+       if (is_string($opts['category'])) {
+               $opts['category'] = [ $opts['category'] ];
+       }
+       foreach ($opts['category'] as $cat) {
+               $entry->addCategory($cat);
+       }
+       if ($entry->isConference()) {
+               if (empty($opts['conf-time'])) {
+                       fwrite(STDERR, "--conf-time required for 
conferences\n");
+                       exit(1);
+               }
+               $t = strtotime($opts['conf-time']);
+               if (!is_int($t)) {
+                       fwrite(STDERR, "Error parsing --conf-time\n");
+                       exit(1);
+               }
+               $entry->setConfTime($t);
+       } elseif (!empty($opts['conf-time'])) {
+               fwrite(STDERR, "--conf-time not allowed with non-conference 
events\n");
+               exit(1);
+       }
+
+       $entry->setImage($opts['image-path'] ?? '', $opts['image-title'] ?? '', 
$opts['image-link'] ?? '');
+
+       if (isset($opts['content'])) {
+               if (isset($opts['content-file'])) {
+                       fwrite(STDERR, "--content and --content-file may not be 
specified together\n");
+                       exit(1);
+               }
+               $entry->setContent($opts['content']);
+       } elseif (isset($opts['content-file'])) {
+               if ($opts['content-file'] === '-') {
+                       $entry->setContent(stream_get_contents(STDIN));
+               } else {
+                       
$entry->setContent(file_get_contents($opts['content-file']));
+               }
+       } else {
+               fwrite(STDERR, "--content or --content-file required\n");
+               exit(1);
+       }
+
+       return $entry;
+}
diff --git a/bin/createReleaseEntry b/bin/createReleaseEntry
new file mode 100755
index 000000000..732510486
--- /dev/null
+++ b/bin/createReleaseEntry
@@ -0,0 +1,48 @@
+#!/usr/bin/env php
+<?php
+PHP_SAPI == 'cli' or die("Please run this script using the cli sapi");
+
+require(__DIR__ . '/../include/news_entry.inc');
+use phpweb\news\Entry;
+
+if (!file_exists(Entry::ARCHIVE_FILE_ABS)) {
+       fwrite(STDERR, "Can't find " . Entry::ARCHIVE_FILE_REL . ", are you 
sure you are in phpweb/?\n");
+       exit(1);
+}
+
+$opts = getopt('v:',['security']);
+if (!isset($opts['v'])) {
+       echo "Usage: {$_SERVER['argv'][0]} -v 8.0.8 [ --security ]\n";
+       exit(0);
+}
+$version = $opts['v'];
+if (!preg_match('/^(\d+)\.(\d+)\.\d+?$/', $version, $matches)) {
+       fwrite(STDERR, "Unable to parse version identifier\n");
+       exit(1);
+}
+$major = $matches[1];
+$branch = "{$major}.{$matches[2]}";
+$security = isset($opts['security']) ? 'security' : 'bug fix';
+
+// Create content.
+$template = <<<EOD
+<p>The PHP development team announces the immediate availability of PHP 
$version. This is a $security release.</p>
+
+<p>All PHP $branch users are encouraged to upgrade to this version.</p>
+
+<p>For source downloads of PHP $version please visit our <a 
href="https://www.php.net/downloads.php";>downloads page</a>,
+Windows source and binaries can be found on <a 
href="https://windows.php.net/download/";>windows.php.net/download/</a>.
+The list of changes is recorded in the <a 
href="https://www.php.net/ChangeLog-{$major}.php#{$version}";>ChangeLog</a>.
+</p>
+EOD;
+
+$entry = (new Entry)
+       ->setTitle("PHP $version Released!")
+       ->setCategories(['releases','frontpage'])
+       ->setContent($template);
+
+$entry->save()->updateArchiveXML();
+
+fwrite(STDOUT, "File saved.\nPlease git diff " . Entry::ARCHIVE_FILE_REL . " 
and sanity-check the changes before committing\n");
+fwrite(STDOUT, "NOTE: Remeber to git add " . Entry::ARCHIVE_ENTRIES_REL . 
$entry->getId() . ".xml !!\n");
+
diff --git a/include/news_entry.inc b/include/news_entry.inc
new file mode 100755
index 000000000..db9c7bdc5
--- /dev/null
+++ b/include/news_entry.inc
@@ -0,0 +1,210 @@
+<?php
+
+namespace phpweb\news;
+
+class Entry {
+       const CATEGORIES = [
+               'frontpage'   => 'PHP.net frontpage news',
+               'releases'    => 'New PHP release',
+               'conferences' => 'Conference announcement',
+               'cfp'         => 'Call for Papers',
+       ];
+
+       const WEBROOT = "https://www.php.net";;
+       const PHPWEB = __DIR__ . '/../';
+       const ARCHIVE_FILE_REL = 'archive/archive.xml';
+       const ARCHIVE_FILE_ABS = self::PHPWEB . self::ARCHIVE_FILE_REL;
+       const ARCHIVE_ENTRIES_REL = 'archive/entries/';
+       const ARCHIVE_ENTRIES_ABS = self::PHPWEB . self::ARCHIVE_ENTRIES_REL;
+       const IMAGE_PATH_REL = 'images/news/';
+       const IMAGE_PATH_ABS = self::PHPWEB . self::IMAGE_PATH_REL;
+
+
+       protected $title = '';
+       public function getTitle(): string {
+               return $this->title;
+       }
+
+       public function setTitle(string $title): self {
+               $this->title = $title;
+               return $this;
+       }
+
+       protected $categories = [];
+       public function setCategories(array $cats): self {
+               foreach ($cats as $cat) {
+                       if (!isset(self::CATEGORIES[$cat])) {
+                               throw new \Exception("Unknown category: $cat");
+                       }
+               }
+               $this->categories = $cats;
+               return $this;
+       }
+       public function addCategory(string $cat): self {
+               if (!isset(self::CATEGORIES[$cat])) {
+                       throw new \Exception("Unknown category: $cat");
+               }
+               if (!in_array($cat, $this->categories)) {
+                       $this->categories[] = $cat;
+               }
+               return $this;
+       }
+       public function getCategories(): array {
+               return $this->categories;
+       }
+       public function isConference(): bool {
+               return (bool)array_intersect($this->categories, ['cfp', 
'conferences']);
+       }
+
+       protected $conf_time = 0;
+       public function setConfTime(int $time): self {
+               $this->conf_time = $time;
+               return $this;
+       }
+       public function getConfTime(): int {
+               return $this->conf_time;
+       }
+
+       protected $image = [];
+       public function setImage(string $path, string $title, ?string $link): 
self {
+               if (basename($path) !== $path) {
+                       throw new \Exception('path must be a simple file name 
under ' . self::IMAGE_PATH_REL);
+               }
+               if (!file_exists(self::IMAGE_PATH_ABS . $path)) {
+                       throw new \Exception('Image not found at web-php/' . 
self::IMAGE_PATH_REL . $path);
+               }
+               $this->image = [
+                       'path' => $path,
+                       'title' => $title,
+                       'link' => $link,
+               ];
+               return $this;
+       }
+       public function getImage(): array {
+               return $this->image;
+       }
+
+       protected $content = '';
+       public function setContent(string $content): self {
+               if (empty($content)) {
+                       throw new \Exception('Content must not be empty');
+               }
+               $this->content = $content;
+               return $this;
+       }
+       public function getContent(): string {
+               return $this->content;
+       }
+
+       protected $id = '';
+       private static function selectNextId(): string {
+               $filename = date("Y-m-d", $_SERVER["REQUEST_TIME"]);
+               $count = 0;
+               do {
+                       ++$count;
+                       $id = $filename . "-" . $count;
+                       $basename  = "{$id}.xml";
+               } while (file_exists(self::ARCHIVE_ENTRIES_ABS . $basename));
+
+               return $id;
+       }
+       public function getId(): string {
+               return $this->id;
+       }
+
+       public function save(): self {
+               if (empty($this->id)) {
+                       $this->id = self::selectNextId();
+               }
+
+               // Create the XML document.
+               $dom = new \DOMDocument("1.0", "utf-8");
+               $dom->formatOutput = true;
+               $dom->preserveWhiteSpace = false;
+               $item = $dom->createElementNs("http://www.w3.org/2005/Atom";, 
"entry");
+
+               $href = self::WEBROOT . ($this->isConference() ? 
'/conferences/index.php' : '/index.php');
+               $archive = self::WEBROOT . "/archive/" . date('Y', 
$_SERVER['REQUEST_TIME']) . ".php#{$this->id}";
+               $link = ($this->image['link'] ?? null) ?: $archive;
+
+               self::ce($dom, "title", $this->title, [], $item);
+               self::ce($dom, "id", $archive, [], $item);
+               self::ce($dom, "published", date(DATE_ATOM), [], $item);
+               self::ce($dom, "updated", date(DATE_ATOM), [], $item);
+               self::ce($dom, "link", null, ['href' => 
"{$href}#id{$this->id}", "rel"  => "alternate", "type" => "text/html"], $item);
+               self::ce($dom, "link", null, ['href' => $link, 'rel'  => 'via', 
'type' => 'text/html'], $item);
+
+               if (!empty($this->conf_time)) {
+                       
$item->appendChild($dom->createElementNs("http://php.net/ns/news";, 
"finalTeaserDate", date("Y-m-d", $this->conf_time)));
+               }
+
+               foreach ($this->categories as $cat) {
+                       self::ce($dom, "category", null, ['term' => $cat, 
"label" => self::CATEGORIES[$cat]], $item);
+               }
+
+               if ($this->image['path'] ?? '') {
+                       $image = 
$item->appendChild($dom->createElementNs("http://php.net/ns/news";, "newsImage", 
$this->image['path']));
+                       $image->setAttribute("link", $this->image['link']);
+                       $image->setAttribute("title", $this->image['title']);
+               }
+
+               $content = self::ce($dom, "content", null, [], $item);
+
+               // Slurp content into our DOM.
+               $tdoc = new \DOMDocument("1.0", "utf-8");
+               $tdoc->formatOutput = true;
+               if ($tdoc->loadXML("<div>{$this->content}    </div>")) {
+                       $content->setAttribute("type", "xhtml");
+                       $div = 
$content->appendChild($dom->createElement("div"));
+                       $div->setAttribute("xmlns", 
"http://www.w3.org/1999/xhtml";);
+                       foreach($tdoc->firstChild->childNodes as $node) {
+                               $div->appendChild($dom->importNode($node, 
true));
+                       }
+               } else {
+                       fwrite(STDERR, "There is something wrong with your 
xhtml, falling back to html");
+                       $content->setAttribute("type", "html");
+                       $content->nodeValue = $this->content;
+               }
+
+               $dom->appendChild($item);
+               $dom->save(self::ARCHIVE_ENTRIES_ABS . $this->id . ".xml");
+
+               return $this;
+       }
+
+       public function updateArchiveXML(): self {
+               if (empty($this->id)) {
+                       throw new \Exception('Entry must be saved before 
updating archive XML');
+               }
+
+               $arch = new \DOMDocument("1.0", "utf-8");
+               $arch->formatOutput = true;
+               $arch->preserveWhiteSpace = false;
+               $arch->load(self::ARCHIVE_FILE_ABS);
+
+               $first = 
$arch->createElementNs("http://www.w3.org/2001/XInclude";, "xi:include");
+               $first->setAttribute("href", "entries/{$this->id}.xml");
+
+               $second = 
$arch->getElementsByTagNameNs("http://www.w3.org/2001/XInclude";, 
"include")->item(0);
+               $arch->documentElement->insertBefore($first, $second);
+               $arch->save(self::ARCHIVE_FILE_ABS);
+
+               return $this;
+       }
+
+       private static function ce(\DOMDocument $d, string $name, $value, array 
$attrs = [], ?\DOMNode $to = null) {
+               if ($value) {
+                       $n = $d->createElement($name, $value);
+               } else {
+                       $n = $d->createElement($name);
+               }
+               foreach($attrs as $k => $v) {
+                       $n->setAttribute($k, $v);
+               }
+               if ($to) {
+                       return $to->appendChild($n);
+               }
+               return $n;
+       }
+}
+
-- 
PHP Webmaster List Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to