forked from privly/privly-applications
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build.py
191 lines (169 loc) · 6.91 KB
/
build.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# This python script builds Privly applications so they
# can share a common user interface and (eventually)
# support localization. If you are building
# a new application, you will probably want to copy
# an existing application folder, e.g. PlainPost,
# to a new directory and work there. When you are
# wanting to ship the application, we will work to
# integrate it with this build system.
#
# This build script looks for applications to build
# by looking at all the subfolders for manifest.json
# files. These files are expected to have the following format
#
# [
# {
# "release_status": "alpha", // Required values: redirect, experimental, deprecated, alpha, beta, release
# "platforms": ["chrome"], // Optional values: web, chrome, firefox
# "subtemplate_path": "Pages/ChromeFirstRun.html.subtemplate", // Required path to the subtemplate
# "outfile_path": "Pages/ChromeFirstRun.html", // Required path the othe output file
# "subtemplate_dict": {"name": "FirstRun", "action": "nav"} // Template dictionary values
# },
# {...}
# ]
#
# Prerequisites for running this script include
# html5lib, BeautifulSoup and Jinja2. You can install
# them both with:
#
# `pip install -r requirements.txt`
#
# This assumes you have python-pip installed:
# `sudo apt-get install python-pip`
#
# Alternatively, these can be installed using `easy_install`:
#
# `sudo easy_install html5lib beautifulsoup4 jinja2`
#
# This assumes you have python-setuptools:
# `sudo apt-get install python-setuptools`
#
# This script uses the jinja2 templating system. For
# information on Jinja2, see:
# http://jinja.pocoo.org/docs/
#
# We prefer readability over minified apps. BeautifulSoup
# properly formats the HTML so it is nested and readable.
# http://www.crummy.com/software/BeautifulSoup/bs4/doc/#installing-beautiful-soup
#
# You can run the script from the privly-applications directory:
# `python build.py`
from jinja2 import Environment, FileSystemLoader
from bs4 import BeautifulSoup as bs
import os
import json
import re
import argparse # Parsing arguments
def make_readable(html):
"""
Make the rendered HTML formatting readable
@param {string} html The HTML that we need to make readable.
"""
soup = bs(html, "html5lib")
prettyHTML = soup.prettify().encode("utf8")
# Beautiful soup breaks textarea formatting
# since it adds extra whitespace. If you use "pre"
# tags, you should be warry of the same problem
return re.sub(r'[\ \n]{2,}</textarea>',
"</textarea>",
prettyHTML)
def render(outfile_path, subtemplate_path, subtemplate_dict):
"""
Render the templates to html.
@param {string} outfile The relative path to the file which we are rendering
to.
@param {string} subtemplate_path The relative path to the file of the subtemplate
to be rendered.
@param {dictionary} subtemplate_dict The variables required by the subtemplate.
"""
f = open(outfile_path, 'w')
subtemplate = env.get_template(subtemplate_path)
html = subtemplate.render(subtemplate_dict)
prettyHTML = make_readable(html)
f.write(prettyHTML)
f.close()
def is_build_target(template):
"""
Determines whether the build target is currently active.
@param {dictionary} template The dictionary of the object to build.
"""
is_targeted_platform = "platforms" not in template or\
args.platform in template["platforms"]
is_targeted_release_type = release_titles.index(args.release) <=\
release_titles.index(template["release_status"])
return is_targeted_platform and is_targeted_release_type
def get_link_creation_apps():
"""
Gets a list of the apps that will be included in the top navigation
for generating new links
"""
creation_apps = []
for dirname, dirnames, filenames in os.walk('.'):
if "manifest.json" in filenames:
f = open(dirname + "/manifest.json", 'r')
template_list = json.load(f)
f.close()
for template in template_list:
if is_build_target(template):
if "nav" in template.keys() and template["nav"] == "new":
creation_apps.append(template["subtemplate_dict"]["name"])
# Hack to maintain current app order
creation_apps.sort()
return creation_apps
release_titles = ["redirect", "experimental", "deprecated", "alpha", "beta", "release"]
if __name__ == "__main__":
# Change the current working directory to the directory of the build script
abspath = os.path.abspath(__file__)
dname = os.path.dirname(abspath)
os.chdir(dname)
# Parse Arguments
# Specify the potential build targets
platforms = ['web', 'chrome', 'firefox']
parser = argparse.ArgumentParser(description='Declare platform build target.')
parser.add_argument('-p', '--platform', metavar='p', type=str,
help='The platform you are building for',
required=False,
default='web',
choices=platforms)
parser.add_argument('-r', '--release', metavar='r', type=str,
help="""Which apps to include in the navigation:
experimental, deprecated, alpha, beta, release
building 'experimental' will build all apps,
whereas 'release' will only build apps marked
for release""",
required=False,
default='deprecated',
choices=release_titles)
args = parser.parse_args()
# Templates are all referenced relative to the current
# working directory
env = Environment(loader=FileSystemLoader('.'))
# Listing of other apps so they can be added to the common nav
packages = {"new": get_link_creation_apps()}
print("################################################")
print("Targeting the *{0}* platform".format(args.platform))
print("To build for another platform, add the option --platform=NAME_HERE")
print("Current platform options include {0}".format(platforms))
print("################################################")
# Build the templates.
print("Building...")
# Find all the manifest files
for dirname, dirnames, filenames in os.walk('.'):
if "manifest.json" in filenames:
f = open(dirname + "/manifest.json", 'r')
template_list = json.load(f)
f.close()
for template in template_list:
# Don't build the app if a platform is specified and it is not the
# currently targeted platform
if not is_build_target(template):
continue
template["subtemplate_dict"].update({"args": args, "packages": packages})
print("{0}'s {1} action to {2}".format(
template["subtemplate_dict"]["name"],
template["subtemplate_dict"]["action"],
template["outfile_path"]))
render(template["outfile_path"], template["subtemplate_path"],
template["subtemplate_dict"])
print("################################################")
print("Build complete. You can now view the generated applications in their folders.")