Port the Python build script over to JS
`npm run build` now builds both the site.json file and the React app. Two new run scripts are available: * build_site - just build the site.json file * build_code - build the React app
This commit is contained in:
parent
55610cb0ba
commit
3eedb94180
5 changed files with 139 additions and 195 deletions
65
package-lock.json
generated
65
package-lock.json
generated
|
|
@ -165,6 +165,11 @@
|
|||
"color-convert": "1.9.0"
|
||||
}
|
||||
},
|
||||
"any-promise": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
||||
"integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
|
||||
},
|
||||
"anymatch": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
|
||||
|
|
@ -1902,7 +1907,7 @@
|
|||
"integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
|
||||
"requires": {
|
||||
"is-directory": "0.3.1",
|
||||
"js-yaml": "3.7.0",
|
||||
"js-yaml": "3.10.0",
|
||||
"minimist": "1.2.0",
|
||||
"object-assign": "4.1.1",
|
||||
"os-homedir": "1.0.2",
|
||||
|
|
@ -2961,9 +2966,9 @@
|
|||
}
|
||||
},
|
||||
"esprima": {
|
||||
"version": "2.7.3",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
|
||||
"integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE="
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
|
||||
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="
|
||||
},
|
||||
"esquery": {
|
||||
"version": "1.0.0",
|
||||
|
|
@ -4333,7 +4338,7 @@
|
|||
"istanbul-lib-report": "1.1.1",
|
||||
"istanbul-lib-source-maps": "1.2.1",
|
||||
"istanbul-reports": "1.1.2",
|
||||
"js-yaml": "3.7.0",
|
||||
"js-yaml": "3.10.0",
|
||||
"mkdirp": "0.5.1",
|
||||
"once": "1.4.0"
|
||||
}
|
||||
|
|
@ -4690,12 +4695,12 @@
|
|||
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
|
||||
"integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
|
||||
"version": "3.10.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz",
|
||||
"integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==",
|
||||
"requires": {
|
||||
"argparse": "1.0.9",
|
||||
"esprima": "2.7.3"
|
||||
"esprima": "4.0.0"
|
||||
}
|
||||
},
|
||||
"jsbn": {
|
||||
|
|
@ -5284,6 +5289,16 @@
|
|||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
|
||||
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
|
||||
},
|
||||
"mz": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
|
||||
"requires": {
|
||||
"any-promise": "1.3.0",
|
||||
"object-assign": "4.1.1",
|
||||
"thenify-all": "1.6.0"
|
||||
}
|
||||
},
|
||||
"natural-compare": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
|
|
@ -8212,6 +8227,22 @@
|
|||
"mkdirp": "0.5.1",
|
||||
"sax": "1.2.4",
|
||||
"whet.extend": "0.9.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"esprima": {
|
||||
"version": "2.7.3",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
|
||||
"integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE="
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
|
||||
"integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
|
||||
"requires": {
|
||||
"argparse": "1.0.9",
|
||||
"esprima": "2.7.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sw-precache": {
|
||||
|
|
@ -8301,6 +8332,22 @@
|
|||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
|
||||
},
|
||||
"thenify": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz",
|
||||
"integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=",
|
||||
"requires": {
|
||||
"any-promise": "1.3.0"
|
||||
}
|
||||
},
|
||||
"thenify-all": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
|
||||
"integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
|
||||
"requires": {
|
||||
"thenify": "3.3.0"
|
||||
}
|
||||
},
|
||||
"throat": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/throat/-/throat-3.2.0.tgz",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
"private": true,
|
||||
"dependencies": {
|
||||
"highlight.js": "^9.12.0",
|
||||
"js-yaml": "^3.10.0",
|
||||
"mz": "^2.7.0",
|
||||
"react": "^15.6.1",
|
||||
"react-dom": "^15.6.1",
|
||||
"react-fontawesome": "^1.6.1",
|
||||
|
|
@ -15,7 +17,9 @@
|
|||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"build_site": "scripts/build_site.js",
|
||||
"build_code": "react-scripts build",
|
||||
"build": "scripts/build_site.js && react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
77
scripts/build_site.js
Executable file
77
scripts/build_site.js
Executable file
|
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
const fs = require('mz/fs');
|
||||
const path = require('path');
|
||||
const yaml = require('js-yaml');
|
||||
|
||||
|
||||
async function build() {
|
||||
let site = {
|
||||
pages: [],
|
||||
posts: [],
|
||||
tags: [],
|
||||
};
|
||||
|
||||
site.pages = await fs.readdir('_pages')
|
||||
.then(files => (
|
||||
Promise.all(files.map(f => fs.readFile(path.join('_pages', f), 'utf8')))
|
||||
))
|
||||
.then(files => {
|
||||
return files.map(contents => {
|
||||
let [_, meta, body] = contents.split("---\n");
|
||||
let page = yaml.safeLoad(meta);
|
||||
|
||||
if (page.parent === undefined) {
|
||||
page.parent = null;
|
||||
}
|
||||
|
||||
page.body = body.trim();
|
||||
return page;
|
||||
})
|
||||
})
|
||||
.catch(err => console.log('Failure while fetching pages:', err));
|
||||
|
||||
[site.posts, site.tags] = await fs.readdir('_posts')
|
||||
.then(files => (
|
||||
Promise.all(files.map(f => fs.readFile(path.join('_posts', f), 'utf8')))
|
||||
))
|
||||
.then(files => {
|
||||
let tags = new Set();
|
||||
let posts = files.map(contents => {
|
||||
let parts = contents.split("---\n");
|
||||
let post = yaml.safeLoad(parts[0]);
|
||||
|
||||
if (parts.length === 2) {
|
||||
post.blurb = parts[1];
|
||||
post.body = post.blurb;
|
||||
} else if (parts.length === 3) {
|
||||
post.blurb = parts[1];
|
||||
post.body = parts.slice(1).join("\n");
|
||||
}
|
||||
|
||||
if (post.tags === undefined) {
|
||||
post.tags = [];
|
||||
}
|
||||
|
||||
post.tags.forEach(tag => {
|
||||
tags.add(tag);
|
||||
});
|
||||
|
||||
return post;
|
||||
})
|
||||
|
||||
return [posts, tags];
|
||||
})
|
||||
.catch(err => console.log('Failure while fetching posts:', err));
|
||||
|
||||
site.pages.sort((a, b) => a.title.localeCompare(b.title));
|
||||
// sort posts newest to oldest
|
||||
site.posts.sort((a, b) => (b.date - a.date));
|
||||
site.tags = Array.from(site.tags.values());
|
||||
|
||||
fs.writeFile('public/site.json', JSON.stringify(site))
|
||||
.catch(err => console.log('Unable to write site.json:', err));
|
||||
}
|
||||
|
||||
build();
|
||||
184
site.py
184
site.py
|
|
@ -1,184 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
CLI command to manage my site
|
||||
|
||||
Imports posts from Posty, builds YAML files into JSON blobs, etc.
|
||||
|
||||
This may be the start of Posty 2.0, who knows.
|
||||
"""
|
||||
|
||||
import click
|
||||
from dateutil import parser as date_parser
|
||||
import json
|
||||
import markdown
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
pass
|
||||
|
||||
|
||||
@cli.command()
|
||||
def init():
|
||||
"""
|
||||
Initialize a site in the current directory
|
||||
"""
|
||||
for directory in ('_media', '_pages', '_posts'):
|
||||
if not os.path.exists(directory):
|
||||
os.mkdir(directory)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option(
|
||||
'--path',
|
||||
help='Path to output JSON file',
|
||||
default='site.json',
|
||||
show_default=True
|
||||
)
|
||||
def build(path):
|
||||
"""
|
||||
Build posts and pages JSON files
|
||||
|
||||
Takes all of the YAML in _pages and _posts, combines them into JSON blobs
|
||||
and writes them out to disk.
|
||||
"""
|
||||
if not all([os.path.exists('_pages'), os.path.exists('_posts')]):
|
||||
raise click.UsageError('You must run `init` first!')
|
||||
|
||||
tags = set()
|
||||
blob = {
|
||||
'pages': [],
|
||||
'posts': [],
|
||||
'tags': [],
|
||||
}
|
||||
|
||||
pages = []
|
||||
for filename in os.listdir('_pages'):
|
||||
contents = open(os.path.join('_pages', filename)).read()
|
||||
_, meta_yaml, body = contents.split("---\n")
|
||||
page = yaml.load(meta_yaml)
|
||||
|
||||
# page['body'] = render(body.strip())
|
||||
page['body'] = body.strip()
|
||||
page.setdefault('parent')
|
||||
|
||||
pages.append(page)
|
||||
blob['pages'] = sorted(pages, key=lambda x: x['title'].lower())
|
||||
|
||||
posts = []
|
||||
for filename in os.listdir('_posts'):
|
||||
contents = open(os.path.join('_posts', filename)).read()
|
||||
parts = contents.split("---\n")
|
||||
|
||||
post = yaml.load(parts[0])
|
||||
post['date'] = post['date'].isoformat()
|
||||
post.setdefault('tags', [])
|
||||
|
||||
if len(parts[1:]) == 1:
|
||||
post['blurb'] = parts[1]
|
||||
post['body'] = parts[1]
|
||||
elif len(parts[1:]) == 2:
|
||||
post['blurb'] = parts[1]
|
||||
post['body'] = "\n".join(parts[1:])
|
||||
else:
|
||||
raise click.UsageError("Got too many YAML documents in {}".format(filename))
|
||||
|
||||
# post['blurb'] = render(post['blurb'].strip())
|
||||
# post['body'] = render(post['body'].strip())
|
||||
post['blurb'] = post['blurb'].strip()
|
||||
post['body'] = post['body'].strip()
|
||||
|
||||
for tag in post['tags']:
|
||||
tags.add(tag)
|
||||
|
||||
posts.append(post)
|
||||
blob['posts'] = sorted(posts, key=lambda x: x['date'], reverse=True)
|
||||
|
||||
blob['tags'] = list(tags)
|
||||
|
||||
with open(path, 'w') as f:
|
||||
f.write(json.dumps(blob))
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option(
|
||||
'--path',
|
||||
help='path to the Posty site',
|
||||
required=True
|
||||
)
|
||||
def posty_import(path):
|
||||
"""
|
||||
Import posts and pages from an existing Posty 1.x site
|
||||
|
||||
All YAML files are read in and in the case of posts, a blurb is generated
|
||||
if one doesn't already exist by singling out the first paragraph.
|
||||
"""
|
||||
if not all(os.path.exists('_pages'), os.path.exists('_posts')):
|
||||
raise click.UsageError('You must run `init` first!')
|
||||
|
||||
click.echo('Importing site at {} ...'.format(path))
|
||||
|
||||
# Simply copy pages over, nothing special to do
|
||||
for page in os.listdir(os.path.join(path, '_pages')):
|
||||
orig_path = os.path.join(path, '_pages', page)
|
||||
new_path = os.path.join('_pages', page)
|
||||
shutil.copy(orig_path, new_path)
|
||||
|
||||
old_posts_path = os.path.join(path, '_posts')
|
||||
for post in os.listdir(old_posts_path):
|
||||
old_post = open(os.path.join(old_posts_path, post)).read()
|
||||
click.echo(post)
|
||||
new_post = convert_from_posty(old_post)
|
||||
|
||||
with open(os.path.join('_posts', post), 'w') as f:
|
||||
f.write(new_post)
|
||||
|
||||
click.echo('Done!')
|
||||
|
||||
|
||||
# Utility functions
|
||||
def convert_from_posty(old_post):
|
||||
"""
|
||||
Converts an old Posty post (a string) into a new-style post with a blurb
|
||||
and everything. Returns a string containing the three YAML documents.
|
||||
"""
|
||||
old_post = old_post.replace("\r\n", "\n")
|
||||
docs = old_post.split("---\n")
|
||||
new_post = ''
|
||||
|
||||
# Convert the metadata
|
||||
meta = yaml.load(docs[1])
|
||||
meta.setdefault('tags', [])
|
||||
new_post += yaml.dump(meta)
|
||||
|
||||
# Create a blurb out of the first paragraph
|
||||
body = docs[2].strip().split("\n\n")
|
||||
blurb = body[0]
|
||||
rest_of_post = "\n\n".join(body[1:])
|
||||
|
||||
new_post += "---\n"
|
||||
new_post += blurb
|
||||
|
||||
# Drop in the rest of the post
|
||||
new_post += "\n---\n"
|
||||
new_post += rest_of_post
|
||||
|
||||
return new_post
|
||||
|
||||
|
||||
def render(thing):
|
||||
"""
|
||||
Renders a specific thing using Markdown
|
||||
"""
|
||||
return markdown.markdown(thing, extensions=[
|
||||
'markdown.extensions.fenced_code',
|
||||
])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli()
|
||||
Loading…
Add table
Add a link
Reference in a new issue