Commit 0163b931 authored by carlosperate's avatar carlosperate

Update static docs build script for better error management.

parent d4a299f6
......@@ -90,4 +90,5 @@ cef_debug.log
/ardublockly_run.bat
# The documentation is built with the GitHub wiki data
/Documentation
package/ardublocklydocs/site
......@@ -7,9 +7,9 @@ __Downloading the packaged Ardublockly__: The binaries will be hosted in GitHub
## Building Ardublockly from source
These scripts are currently built and tested using Python 2.7.
These scripts have tested using Python 2.7.
While it is possible to maintain compatibility with other Python versions (the ArdublocklyServer Python package used in the developer installation has been tested on Python 2.7 and 3.4), due to the multiple individual perks of the python libraries used here, it has been decided to target a single build environment.
While it is possible to maintain compatibility with other Python versions (the ArdublocklyServer Python package used in the developer installation has been tested on Python 2.7 and 3.4), due to the multiple individual perks of the python libraries used here, a single build environment will be targeted.
If you are using Python virtual environments on Windows this [collection of Python extensions binaries][2] is highly recommended.
......@@ -28,23 +28,36 @@ CEF Python provides python bindings for the Chromium Embedded Framework. This is
#### py2exe
py2exe is a Distutils extension to build Python scripts into Windows executable programs.
There is a plan to migrate from py2exe to Pyinstaller, but for now this is the main library used to create the Windows build.
You can download py2exe from their [official website][6].
#### MkDocs
MkDocs is a static page generator specifically designed for documentation using Markdown.
The project documentation is written and hosted in the [Arudblockly repository GitHub Wiki][7]. The build script for the documentation pulls its markdown files and converts them into an HTML static site for offline access.
More information about this procedure can be found in [this article][8].
## Build steps
Download and initialise this project repository:
```
git clone https://github.com/carlosperate/ardublockly.git
cd ardublockly
git submodule init
git submodule update
cd closure-library
git pull origin master
```
Now navigate to the `package` folder in the project directory:
```
cd ../package
cd package
```
To first build the offline documentation execute the `build_docs.py` file. This will add a folder named `documentation` into the project root directory:
```
python build_docs.py
```
To build Ardublockly all you have to do is execute the `build_windows.py` file:
......@@ -54,7 +67,7 @@ python build_windows.py
This will remove any previous build directory (`/win` directory in project root), rebuild, and create the `ardublockly_run.bat` file into the project root.
To run Ardublockly then just execute the `ardublockly_run.bat` file.
To run Ardublockly on Windows execute the `ardublockly_run.bat` file.
[1]: https://github.com/carlosperate/ardublockly/releases/
......@@ -63,3 +76,5 @@ To run Ardublockly then just execute the `ardublockly_run.bat` file.
[4]: http://www.wxpython.org/download.php
[5]: https://code.google.com/p/cefpython/
[6]: http://www.py2exe.org/
[7]: https://github.com/carlosperate/ardublockly/wiki
[8]: http://www.embeddedlog.com/static-docs-from-github-wiki.html
#!/usr/bin/env python2
# -*- coding: utf-8 -*- #
#
# Builds the GitHub Wiki documentation into static HTML.
# Builds the GitHub Wiki documentation into a static HTML site.
#
# Copyright (c) 2015 carlosperate https://github.com/carlosperate/
#
......@@ -22,20 +22,21 @@
# Edits the MkDocs configuration file to include all the markdown files
# Creates an index.html file to have root redirected to a specific page
# Builds the static site using MkDocs
# REMOVES the root Documentation folder
# Copies the generate content into the root Documentation folder
#
from __future__ import unicode_literals, absolute_import
import os
import sys
import fileinput
import shutil
import subprocess
from shutil import move
from tempfile import mkstemp
# mkdocs used only in the command line, imported just to ensure it's installed
try:
import mkdocs
except ImportError:
print("You need to have mkdocs installed!")
print("You need to have mkdocs installed !")
sys.exit(1)
......@@ -53,22 +54,49 @@ DEFAULT_INDEX = 'Home'
def pull_wiki_repo():
""" Pulls latest changes from wiki repo. """
"""
Pulls latest changes from the wiki repo.
:return: Boolean indicating if the operation was successful.
"""
# Ensure the submodule is initialised
pipe = subprocess.PIPE
git_process = subprocess.Popen(
["git", "submodule", "update"], stdout=pipe, stderr=pipe)
std_op, std_err_op = git_process.communicate()
if std_err_op:
print("ERROR: Could not update git submodule !\n%s" + std_err_op)
return False
# Set working directory to the wiki repository
wiki_folder = os.path.join(MKDOCS_DIR, WIKI_NAME)
os.chdir(wiki_folder)
if os.path.isdir(wiki_folder):
os.chdir(wiki_folder)
else:
print("ERROR: Wiki repo directory is not correct: %s" % wiki_folder)
return False
# Ensure the subfolder selected in the correct repo
PIPE = subprocess.PIPE
git_process = subprocess.Popen(["git", "config", "--get", "remote.origin.url"],
stdout=PIPE, stderr=PIPE)
# Ensure the subfolder selected is the correct repository
git_process = subprocess.Popen(
["git", "config", "--get", "remote.origin.url"],
stdout=pipe, stderr=pipe)
std_op, std_err_op = git_process.communicate()
if std_err_op:
print("ERROR: Could not get the remote information from the wiki "
"repository !\n%s" + std_err_op)
return False
if not GITHUB_WIKI_REPO_SHORT in std_op:
print("Wiki repository:\n\t%s\nnot found in url:\n\t%s" %
(GITHUB_WIKI_REPO_SHORT, std_op))
else:
subprocess.call(["git", "submodule", "update"])
subprocess.call(["git", "pull", "origin", "master"])
print(("ERROR: Wiki repository:\n\t%s\n" % GITHUB_WIKI_REPO_SHORT) +
"not found in directory %s url:\n\t%s\n" % (wiki_folder, std_op))
return False
# Git Fetch prints progress in stderr, so cannot check for erros that way
print("\nPull from Wiki repository...")
subprocess.call(["git", "pull", "origin", "master"])
print("")
return True
def edit_mkdocs_config():
......@@ -77,16 +105,27 @@ def edit_mkdocs_config():
files as part of the documentation.
These files are created by default with the '.md' extension and it is
assumed no other file extensions are to be linked.
:return: Boolean indicating the success of the operation.
"""
path_list = []
for file in os.listdir(os.path.join(MKDOCS_DIR, WIKI_NAME)):
if file.endswith(".md"):
path_list.append("- ['%s', '%s']" % (file, file[:-3].replace("-", " ")))
path_list.append("- ['%s', '%s']" %
(file, file[:-3].replace("-", " ")))
if not path_list:
print(("ERROR: No markdown files found in %s ! " % MKDOCS_DIR) +
"Check if repository has been set up correctly.")
return False
pages_str = "pages:\n" + "\n".join(path_list) + "\n"
print pages_str
# Replace the pages data, strategically located at the end of the file
mkdocs_yml = os.path.join(MKDOCS_DIR, "mkdocs.yml")
if not os.path.exists(mkdocs_yml):
print("ERROR: The MkDocs config file %s does not exist !" % mkdocs_yml)
return False
# Copy config file until the pages line, strategically located at the end
temp_file_handler, temp_abs_path = mkstemp()
with open(temp_abs_path, 'w') as temp_file:
with open(mkdocs_yml) as original_file:
......@@ -94,55 +133,142 @@ def edit_mkdocs_config():
if not "pages:" in line:
temp_file.write(line)
else:
print("Replacing 'pages' property found in mkdocs.yml ...")
break
else:
print("Did not find the 'pages' property in mkdocs.yml.\n" +
"Attaching the property at the end of the file.")
temp_file.write(pages_str)
print(pages_str)
# Remove original file and move the new temp to replace it
os.close(temp_file_handler)
os.remove(mkdocs_yml)
move(temp_abs_path, mkdocs_yml)
try:
os.remove(mkdocs_yml)
except IOError:
print("ERROR: Could not delete original config file %s !" % mkdocs_yml)
return False
try:
shutil.move(temp_abs_path, mkdocs_yml)
except shutil.Error:
print("ERROR: Could move new config file to %s !" % mkdocs_yml)
return False
return True
def create_index():
""" Creates an HTML index page to redirect to an MkDocs generated page. """
"""
Creates an HTML index page to redirect to an MkDocs generated page.
:return: Boolean indicating the success of the operation.
"""
html_code = \
"<!DOCTYPE HTML>\n" +\
"<html>\n" +\
"\t<head>\n" +\
"\t\t<meta charset=\"UTF-8\">\n" +\
"\t\t<meta http-equiv=\"refresh\" content=\"1;url=%s/index.html\">\n"\
% DEFAULT_INDEX +\
"\t\t<script type=\"text/javascript\">\n" +\
"<!DOCTYPE HTML>\n " \
"<html>\n" \
"\t<head>\n" \
"\t\t<meta charset=\"UTF-8\">\n" \
"\t\t<meta http-equiv=\"refresh\" content=\"1;url=%s/index.html\">\n" \
% DEFAULT_INDEX + \
"\t\t<script type=\"text/javascript\">\n" \
"\t\t\twindow.location.href = \"%s/index.html\"\n" % DEFAULT_INDEX +\
"\t\t</script>\n" +\
"\t</head>\n" +\
"\t<body>\n" +\
"\t\tIf you are not redirected automatically to the " +\
"\t\t</script>\n" \
"\t</head>\n" \
"\t<body>\n" \
"\t\tIf you are not redirected automatically to the " \
"%s page, follow this <a href=\"%s/index.html\">link</a>\n"\
% (DEFAULT_INDEX, DEFAULT_INDEX) +\
"\t</body>\n" +\
% (DEFAULT_INDEX, DEFAULT_INDEX) + \
"\t</body>\n" \
"</html>\n"
generated_site_dir = os.path.join(MKDOCS_DIR, "site", "index.html")
index_file = open(generated_site_dir, "w")
index_file.write(html_code)
index_file.close()
print("Creating the index.html file...\n")
generated_site_dir = os.path.join(MKDOCS_DIR, "site")
if not os.path.exists(generated_site_dir):
try:
os.makedirs(generated_site_dir)
except IOError:
print("ERROR: Could not create site folder in %s !\n" %
generated_site_dir)
return False
try:
index_file = open(os.path.join(generated_site_dir, "index.html"), "w")
index_file.write(html_code)
index_file.close()
return True
except IOError:
print("ERROR: Could not create index.html file in %s !\n" %
generated_site_dir)
return False
def build_mkdocs():
""" Invokes MkDocs to build the static documentation. """
os.chdir(MKDOCS_DIR)
subprocess.call(["mkdocs", "build"])
"""
Invokes MkDocs to build the static documentation and moves the folder
into the project root folder.
:return: Boolean indicating the success of the operation.
"""
# Setting the working directory
if os.path.isdir(MKDOCS_DIR):
os.chdir(MKDOCS_DIR)
else:
print("ERROR: MkDocs directory is not correct: %s" % MKDOCS_DIR)
return False
# Building the MkDocs project
pipe = subprocess.PIPE
mkdocs_process = subprocess.Popen(
["mkdocs", "build"], stdout=pipe, stderr=pipe)
std_op, std_err_op = mkdocs_process.communicate()
if std_err_op:
print("ERROR: Could not build MkDocs !\n%s" %
std_err_op)
return False
else:
print(std_op)
# Remove root Documentation folder and copy the new site files into it
generated_site_dir = os.path.join(MKDOCS_DIR, "site")
root_documentation_dir = os.path.join(
os.path.dirname(THIS_FILE_DIR), "documentation")
print("Copy folder %s into %s ...\n" %
(generated_site_dir, root_documentation_dir))
if os.path.exists(root_documentation_dir):
try:
shutil.rmtree(root_documentation_dir)
except shutil.Error:
print("ERROR: Could not remove root documentation folder !")
return False
try:
shutil.move(generated_site_dir, root_documentation_dir)
except shutil.Error:
print("ERROR: Could move new documentation files from " +
"%s to %s !" % (generated_site_dir, root_documentation_dir))
return False
return True
def build_docs():
""" Builds the documentation HTML pages from the wiki repository. """
pull_wiki_repo()
edit_mkdocs_config()
""" Builds the documentation HTML pages from the Wiki repository. """
success = pull_wiki_repo()
if success is False:
sys.exit(1)
success = edit_mkdocs_config()
if success is False:
sys.exit(1)
# Create index.html before the MkDocs site is created in case the project
# already contains an index file.
create_index()
build_mkdocs()
success = create_index()
if success is False:
sys.exit(1)
success = build_mkdocs()
if success is False:
sys.exit(1)
print("Build process finished!")
if __name__ == "__main__":
......
#!/usr/bin/env python2
# -*- coding: utf-8 -*- #
#
# Builds the Ardublockly application for the Windows operating system.
#
# Copyright (c) 2015 carlosperate https://github.com/carlosperate/
#
# Licensed 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.
#
import os
import sys
import shutil
......
cefpython3==31.2
py2exe==0.6.9
wxPython==3.0.2.0
wxPython-common==3.0.2.0
mkdocs==0.12.1
cefpython3=>31.2
py2exe=>0.6.9
wxPython=>3.0.2.0
wxPython-common=>3.0.2.0
mkdocs=>0.12.1
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment