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"
|
"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": {
|
"anymatch": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
|
||||||
|
|
@ -1902,7 +1907,7 @@
|
||||||
"integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
|
"integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-directory": "0.3.1",
|
"is-directory": "0.3.1",
|
||||||
"js-yaml": "3.7.0",
|
"js-yaml": "3.10.0",
|
||||||
"minimist": "1.2.0",
|
"minimist": "1.2.0",
|
||||||
"object-assign": "4.1.1",
|
"object-assign": "4.1.1",
|
||||||
"os-homedir": "1.0.2",
|
"os-homedir": "1.0.2",
|
||||||
|
|
@ -2961,9 +2966,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"esprima": {
|
"esprima": {
|
||||||
"version": "2.7.3",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
|
||||||
"integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE="
|
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="
|
||||||
},
|
},
|
||||||
"esquery": {
|
"esquery": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
|
@ -4333,7 +4338,7 @@
|
||||||
"istanbul-lib-report": "1.1.1",
|
"istanbul-lib-report": "1.1.1",
|
||||||
"istanbul-lib-source-maps": "1.2.1",
|
"istanbul-lib-source-maps": "1.2.1",
|
||||||
"istanbul-reports": "1.1.2",
|
"istanbul-reports": "1.1.2",
|
||||||
"js-yaml": "3.7.0",
|
"js-yaml": "3.10.0",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"once": "1.4.0"
|
"once": "1.4.0"
|
||||||
}
|
}
|
||||||
|
|
@ -4690,12 +4695,12 @@
|
||||||
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
|
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
|
||||||
},
|
},
|
||||||
"js-yaml": {
|
"js-yaml": {
|
||||||
"version": "3.7.0",
|
"version": "3.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz",
|
||||||
"integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
|
"integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"argparse": "1.0.9",
|
"argparse": "1.0.9",
|
||||||
"esprima": "2.7.3"
|
"esprima": "4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jsbn": {
|
"jsbn": {
|
||||||
|
|
@ -5284,6 +5289,16 @@
|
||||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
|
||||||
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
|
"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": {
|
"natural-compare": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||||
|
|
@ -8212,6 +8227,22 @@
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"sax": "1.2.4",
|
"sax": "1.2.4",
|
||||||
"whet.extend": "0.9.9"
|
"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": {
|
"sw-precache": {
|
||||||
|
|
@ -8301,6 +8332,22 @@
|
||||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||||
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
|
"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": {
|
"throat": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/throat/-/throat-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/throat/-/throat-3.2.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"highlight.js": "^9.12.0",
|
"highlight.js": "^9.12.0",
|
||||||
|
"js-yaml": "^3.10.0",
|
||||||
|
"mz": "^2.7.0",
|
||||||
"react": "^15.6.1",
|
"react": "^15.6.1",
|
||||||
"react-dom": "^15.6.1",
|
"react-dom": "^15.6.1",
|
||||||
"react-fontawesome": "^1.6.1",
|
"react-fontawesome": "^1.6.1",
|
||||||
|
|
@ -15,7 +17,9 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"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",
|
"test": "react-scripts test --env=jsdom",
|
||||||
"eject": "react-scripts eject"
|
"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