Prvni odevzdani
This commit is contained in:
parent
c7c3250d02
commit
826f74a5e9
63
README.md
63
README.md
@ -1,3 +1,66 @@
|
||||
# WebApp_builder
|
||||
|
||||
Skript pro sestavování webových aplikací pro ESP8266/ESP32. Používá se jako Git submodul u projektu.
|
||||
|
||||
## Návod k použití
|
||||
|
||||
Pro svoji práci používá soubor `project.json`, který obsahuje parametry pro sestavení. Povinná sekce je sekce `build`, která musí obsahovat následující:
|
||||
|
||||
* `approotdir` - cesta ke kořenovému adresáři projektu
|
||||
```json
|
||||
"approotdir":"./",
|
||||
```
|
||||
* `outputdir` - cesta k adresáři, do kterého je umístěna sestavená verze projektu bez použití komprese souborů (určena pro kontrolu a případné ladění na PC)
|
||||
```json
|
||||
"outputdir":"./dist/",
|
||||
```
|
||||
* `datadir` - cesta k adresáři, do kterého je generovaný výsledný obsah včetně případné komprese souborů
|
||||
```json
|
||||
"datadir":"../AZP_IoT_PIO/data/",
|
||||
```
|
||||
* `flist` - jméno souboru s obsahem webu pro případnou automatickou aktualizaci ze zařízení. Není-li uvedeno, seznam se negeneruje.
|
||||
```json
|
||||
"flist": "flist.txt",
|
||||
```
|
||||
* `combine` - seznam souborů, vzniklých kombinací (spojením) souborů jiných. Určeno pro minimalizaci současně stahovaných souborů.
|
||||
```json
|
||||
"combine": [
|
||||
{"name": "js/app.js",
|
||||
"items":[
|
||||
"js/l10n/l10n.js",
|
||||
"js/drooltip/package/js/build/drooltip.js",
|
||||
"js/MsgPop/js/msgPop.js",
|
||||
"js/sparkline/sparkline.js",
|
||||
"js/es6-promise.auto.min.js",
|
||||
"js/SweetAlert2/dist/sweetalert2.min.js",
|
||||
"js/menu.js",
|
||||
"js/app.js"
|
||||
]
|
||||
}
|
||||
],
|
||||
```
|
||||
* `copy` - seznam souborů a adresářů pro vytváření finální aplikace, obashuje také příznaky pro kompresi
|
||||
```json
|
||||
"copy": [
|
||||
{"src":"img/","dst":""},
|
||||
{"src":"lang/","dst":""},
|
||||
{"src":"html/favicon.png","dst":"favicon.png"},
|
||||
{"src":"html/index.htm","dst":"index.htm","compress": true,"istemplate":true,"flistforce":true},
|
||||
{"src":"html/setup.htm","dst":"setup.htm","compress": true,"istemplate":true,"flistforce":true},
|
||||
{"src":"html/update.htm","dst":"update.htm","istemplate":true},
|
||||
{"src":"devices/basic.json","dst":"basic.json","flistignore": true},
|
||||
{"src":"devices/acdc.json","dst":"acdc.json","flistignore": true},
|
||||
{"src":"devices/nmcu.json","dst":"nmcu.json","flistignore": true},
|
||||
{"src":"devices/creas.json","dst":"creas.json","flistignore": true},
|
||||
{"src":"js/microajax.js","dst":"","compress": true},
|
||||
{"synthetic":true, "src":"js/app.js","dst":"","compress": true},
|
||||
{"synthetic":true, "src":"css/app.css","dst":"","compress": true},
|
||||
{"src":"html/.htaccess","dst":".htaccess","flistignore":true}
|
||||
]
|
||||
```
|
||||
Doplňující parametry v sekci `copy` jsou:
|
||||
* `compress` - při kopírování do `datadir` se použije komprese gzip a jméno souboru se doplní o příponu `.gz`.
|
||||
* `istemplate` - při kopírování se použije textový template engine s nahrazováním - určeno pro uložení čísla verze
|
||||
* `flistforce` - v souboru se seznamem se použije klíčové slovo `force`, které vynutí násilný přepis souboru v cílovém zařízení
|
||||
* `flistignore` - soubor se neuloží do seznamu v souboru
|
||||
* `syntehtic` - příznak, že soubor pro přesun vznikl pomocí sekce `combine` a nemá se tedy hledat ve zdrojových adresářích
|
||||
|
248
generate.py
Normal file
248
generate.py
Normal file
@ -0,0 +1,248 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import gzip, shutil, os, errno, json, subprocess
|
||||
from distutils import dir_util
|
||||
from string import Template
|
||||
|
||||
__author__ = "Pavel Brychta"
|
||||
__copyright__ = "Copyright (c) 2019-2020, Pavel Brychta"
|
||||
__credits__ = ["Pavel Brychta"]
|
||||
__license__ = "Private"
|
||||
__version__ = "1.1.0"
|
||||
__maintainer__ = "Pavel Brychta"
|
||||
__email__ = "Pablo@xPablo.cz"
|
||||
__status__ = "Private Beta"
|
||||
|
||||
PROJECT_FILE = "project.json" # soubor s popisem sestaveni projektu
|
||||
|
||||
project = {}
|
||||
templatevars = {}
|
||||
flist = None
|
||||
flistcontent = ""
|
||||
version = ""
|
||||
|
||||
|
||||
# Vycisteni ciloveho adresare (bez jeho vymazu - jen vyprazdneni)
|
||||
def cleanup(path):
|
||||
for root, dirs, files in os.walk(path):
|
||||
for f in files:
|
||||
os.unlink(os.path.join(root, f))
|
||||
for d in dirs:
|
||||
shutil.rmtree(os.path.join(root, d), ignore_errors=True, onerror=None)
|
||||
|
||||
|
||||
# Vytvoreni pripadne chybejici cesty
|
||||
def maketree(filename):
|
||||
if not os.path.exists(os.path.dirname(filename)):
|
||||
try:
|
||||
os.makedirs(os.path.dirname(filename))
|
||||
except OSError as exc: # ochrana proti race condition
|
||||
if exc.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
|
||||
# Kopirovani adresaroveho stromu na cilove misto
|
||||
def copytree(src, dst):
|
||||
for item in os.listdir(src):
|
||||
s = os.path.normpath(os.path.join(src, item))
|
||||
d = os.path.normpath(os.path.join(dst, item))
|
||||
maketree(d)
|
||||
if os.path.isdir(s):
|
||||
print(s + ' (D)-> ' + d)
|
||||
copytree(s, d)
|
||||
else:
|
||||
print(s + ' (F)-> ' + d)
|
||||
shutil.copy2(s, d)
|
||||
|
||||
|
||||
# Kopirovani seznamu souboru
|
||||
def copyfiles(files, ffrom, where):
|
||||
|
||||
for entry in files:
|
||||
if "synthetic" not in entry:
|
||||
inf = entry["src"]
|
||||
outf = entry["dst"]
|
||||
if outf == '':
|
||||
outf = inf
|
||||
if os.path.isdir(ffrom + inf):
|
||||
copytree(ffrom + inf, where + outf)
|
||||
else:
|
||||
if "istemplate" in entry and entry["istemplate"]:
|
||||
with open(ffrom + inf, 'r') as infile:
|
||||
print(ffrom + inf + ' (T)-> ' + where + outf)
|
||||
maketree(where + outf)
|
||||
# https://stackoverflow.com/questions/4406102/light-weight-template-engine-for-python
|
||||
form = Template(infile.read()).substitute(templatevars)
|
||||
outfile = open(where + outf, 'w')
|
||||
outfile.write(form)
|
||||
outfile.close()
|
||||
else:
|
||||
with open(ffrom + inf, 'rb') as infile:
|
||||
print(ffrom + inf + ' (F)-> ' + where + outf)
|
||||
maketree(where + outf)
|
||||
outfile = open(where + outf, 'wb')
|
||||
outfile.write(infile.read())
|
||||
outfile.close()
|
||||
|
||||
|
||||
# Spojovani soubru
|
||||
def joinfilesindir(dir, outfile):
|
||||
for item in os.listdir(dir):
|
||||
fn = os.path.join(dir, item)
|
||||
if os.path.isfile(fn):
|
||||
with open(fn, 'rb') as infile:
|
||||
outfile.write(infile.read())
|
||||
else:
|
||||
if not fn.endswith("/"):
|
||||
fn += "/"
|
||||
joinfilesindir(fn, outfile)
|
||||
|
||||
|
||||
def joinfiles(srclist, srcPath, outfName):
|
||||
outfName = os.path.normpath(outfName)
|
||||
maketree(outfName)
|
||||
print(outfName + ' =')
|
||||
with open(outfName, 'wb') as outfile:
|
||||
for fname in srclist:
|
||||
fname = os.path.normpath(fname)
|
||||
print(' + ' + fname)
|
||||
if os.path.isfile(srcPath + fname):
|
||||
with open(srcPath + fname, 'rb') as infile:
|
||||
outfile.write(infile.read())
|
||||
else:
|
||||
joinfilesindir(srcPath + fname, outfile)
|
||||
outfile.close()
|
||||
|
||||
|
||||
def copycompresstree(src, dst, compress, dirbase):
|
||||
global flist
|
||||
global flistcontent
|
||||
|
||||
for item in os.listdir(src):
|
||||
s = os.path.normpath(os.path.join(src, item))
|
||||
d = os.path.normpath(os.path.join(dst, item))
|
||||
maketree(d)
|
||||
if os.path.isdir(s):
|
||||
d = os.path.normpath(os.path.join(dst, item))
|
||||
print(s + ' (D)-> ' + d)
|
||||
copycompresstree(s, d, compress, dirbase)
|
||||
else:
|
||||
dopack = 0
|
||||
rpath = os.path.relpath(dst, dirbase)
|
||||
if rpath == ".":
|
||||
rpath = ""
|
||||
else:
|
||||
rpath = "/" + rpath
|
||||
fignore = False
|
||||
fforce = False
|
||||
for entry in compress:
|
||||
target = os.path.normpath(entry["src"])
|
||||
if entry["dst"] != "":
|
||||
target = os.path.normpath(entry["dst"])
|
||||
if s.endswith(target):
|
||||
if "compress" in entry and entry["compress"]:
|
||||
dopack += 1
|
||||
if "flistignore" in entry:
|
||||
fignore = True
|
||||
if "flistforce" in entry:
|
||||
fforce = True
|
||||
if dopack != 0:
|
||||
d = os.path.normpath(os.path.join(dst, item + ".gz"))
|
||||
print(s + ' (C)-> ' + d)
|
||||
# packing & copying
|
||||
with open(s, 'rb') as infile:
|
||||
maketree(d)
|
||||
outfile = gzip.open(d, 'wb')
|
||||
outfile.writelines(infile)
|
||||
outfile.close()
|
||||
if flist is not None and not fignore:
|
||||
flc = item + ".gz"
|
||||
if fforce:
|
||||
flc += ",force"
|
||||
flistcontent += rpath + "/" + flc + "\r\n"
|
||||
else:
|
||||
d = os.path.normpath(os.path.join(dst, item))
|
||||
print(s + ' (F)-> ' + d)
|
||||
shutil.copy2(s, d)
|
||||
if flist is not None and not fignore:
|
||||
flc = item
|
||||
if fforce:
|
||||
flc += ",force"
|
||||
flistcontent += rpath + "/" + flc + "\r\n"
|
||||
|
||||
|
||||
# Ziskani verze repozitare z gitu
|
||||
def getgitversion():
|
||||
after = b"0"
|
||||
mod = b""
|
||||
try:
|
||||
tag = subprocess.check_output(["git", "describe", "--tags", "--always"]).strip()
|
||||
except:
|
||||
tag = b"0.0.0"
|
||||
if tag.find(b".") < 0:
|
||||
tag = b"0.0.0"
|
||||
if tag == b"0.0.0":
|
||||
after = subprocess.check_output(["git", "rev-list", "--all", "--count"]).strip()
|
||||
else:
|
||||
if tag.find(b"-") > 0:
|
||||
taginfo = tag.split(b'-')
|
||||
tag = taginfo[0]
|
||||
after = taginfo[1]
|
||||
else:
|
||||
after = subprocess.check_output(["git", "rev-list", tag + "..HEAD", "--count"]).strip()
|
||||
mod = subprocess.check_output(["git", "diff-index", "HEAD"]).strip()
|
||||
if after == b"0":
|
||||
revision = tag
|
||||
else:
|
||||
revision = tag + b'.' + after
|
||||
if mod != b"":
|
||||
revision = revision + b"m"
|
||||
return revision.decode("utf-8")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
version = getgitversion()
|
||||
templatevars['version'] = version
|
||||
print("Web version " + version)
|
||||
with open(PROJECT_FILE) as fd:
|
||||
project = json.load(fd)
|
||||
|
||||
if "build" in project:
|
||||
build = project["build"]
|
||||
|
||||
approotdir = build["approotdir"]
|
||||
outputdir = build["outputdir"]
|
||||
datadir = build["datadir"]
|
||||
if "flist" in build:
|
||||
flist = build["flist"]
|
||||
|
||||
# Vycistime vystupni adresare
|
||||
cleanup(outputdir)
|
||||
cleanup(datadir)
|
||||
|
||||
# Zacneme kombinaci soubou
|
||||
if "combine" in build:
|
||||
combine = build["combine"]
|
||||
for entry in combine:
|
||||
outname = entry["name"]
|
||||
items = entry["items"]
|
||||
joinfiles(items, approotdir, outputdir + outname)
|
||||
|
||||
# Pokracujeme kopirovanim souboru/adresaru
|
||||
if "copy" in build:
|
||||
copy = build["copy"]
|
||||
copyfiles(copy, approotdir, outputdir)
|
||||
|
||||
# .. a koncime prekopirovanim souboru do vystupniho adresare s prubeznou kompresi pozadovanych souboru a vytvareni flist.txt
|
||||
deploy = []
|
||||
if flist is not None:
|
||||
flistcontent = ":" + version + "\r\n"
|
||||
if "copy" in build:
|
||||
deploy = build["copy"]
|
||||
copycompresstree(outputdir, datadir, deploy, datadir)
|
||||
if flist is not None:
|
||||
with open(os.path.normpath(os.path.join(datadir, flist)), 'wb') as outfile:
|
||||
outfile.write(flistcontent.encode('utf-8'))
|
||||
outfile.close()
|
Loading…
Reference in New Issue
Block a user