Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
116 lines
2.8 KiB
Python
Executable file
116 lines
2.8 KiB
Python
Executable file
# Synchronizes the offline cache of an external app into a local directory
|
|
# structure. Run from the base directory of an app in gaia/external-apps.
|
|
# Builds a directory for each known origin in the offline cache.
|
|
|
|
import json
|
|
import os
|
|
import requests
|
|
|
|
|
|
def read_manifest():
|
|
file = open('manifest.webapp', 'r').read()
|
|
content = json.loads(file)
|
|
return content
|
|
|
|
|
|
def read_origin():
|
|
# Extract the origin from the origin file
|
|
return open('origin', 'r').readline().rstrip()
|
|
|
|
|
|
def parse_offline_manifest(s, origin):
|
|
lines = s.split('\n')
|
|
|
|
# Bail if this is an invalid appcache manifest.
|
|
if lines[0] != 'CACHE MANIFEST':
|
|
return None
|
|
|
|
sections = ['CACHE:', 'NETWORK:', 'FALLBACK:']
|
|
|
|
current_section = 'CACHE'
|
|
|
|
cache = []
|
|
|
|
for line in lines[1:]:
|
|
# ignore comments, empty lines, and wildcards
|
|
if line.startswith('#') or line.startswith('*') or not line.rstrip():
|
|
continue
|
|
if line in sections:
|
|
current_section = line[:len(line)-1]
|
|
continue
|
|
|
|
# Don't cache NETWORK entries.
|
|
if current_section == 'NETWORK':
|
|
continue
|
|
|
|
# if we're in FALLBACK, extract the fallback path.
|
|
if current_section == 'FALLBACK':
|
|
line = line.split(' ')[1]
|
|
|
|
# Ensure that all paths start with an origin.
|
|
if not line.startswith('http'):
|
|
if line.startswith('/'):
|
|
line = line[1:]
|
|
line = origin + line
|
|
|
|
cache.append(line)
|
|
|
|
return cache
|
|
|
|
|
|
def fetch_with_path(url):
|
|
# are we dealing with something URL-esque?
|
|
if not url.find('//') + 1:
|
|
return None
|
|
|
|
print 'fetching %s' % url
|
|
file = requests.get(url, verify=False)
|
|
if file.status_code != 200:
|
|
return None
|
|
|
|
# base our paths in the 'cache' directory.
|
|
path = 'cache/' + url.split('//')[1]
|
|
|
|
directory, fn = path.rsplit('/', 1)
|
|
# make the directory structure
|
|
if not os.path.exists(directory):
|
|
os.makedirs(directory)
|
|
|
|
# write our file
|
|
out_file = open(path, 'w')
|
|
out_file.write(file.content)
|
|
|
|
return file.content;
|
|
|
|
|
|
def main():
|
|
|
|
# Learn about the external app.
|
|
app_manifest = read_manifest()
|
|
origin = read_origin()
|
|
|
|
if 'appcache_path' not in app_manifest:
|
|
print 'no appcache found'
|
|
return
|
|
|
|
# Construct the appcache url and drop the first slash from appcache_path.
|
|
appcache_url = origin + app_manifest.get('appcache_path')[1:]
|
|
print 'fetching appcache at %s' % appcache_url
|
|
|
|
cache_manifest = fetch_with_path(appcache_url)
|
|
if not cache_manifest:
|
|
print 'failed to fetch appcache'
|
|
return
|
|
|
|
cache = parse_offline_manifest(cache_manifest, origin)
|
|
|
|
if not cache:
|
|
print 'bad offline cache'
|
|
return
|
|
|
|
# fetch each file, and store it in the right place
|
|
for entry in cache:
|
|
fetch_with_path(entry);
|
|
|
|
|
|
main()
|