#!/usr/bin/env python
#encoding: utf8
"""
wmlunits -- tool to output information on all units in HTML
Run without arguments to see usage.
"""
# Makes things faster on 32-bit systems
try: import psyco; psyco.full()
except ImportError: pass
import sys, os, glob, shutil, urllib2, argparse, traceback
import subprocess, yaml
import multiprocessing, Queue
import wesnoth.wmlparser2 as wmlparser2
import unit_tree.helpers as helpers
import unit_tree.animations as animations
import unit_tree.html_output as html_output
import unit_tree.overview
import unit_tree.wiki_output as wiki_output
TIMEOUT = 15
def copy_images():
print("Recolorizing pictures.")
image_collector.copy_and_color_images(options.output)
shutil.copy2(os.path.join(image_collector.datadir,
"data/tools/unit_tree/style.css"), options.output)
shutil.copy2(os.path.join(image_collector.datadir,
"data/tools/unit_tree/menu.js"), options.output)
for grab in [
"http://www.wesnoth.org/mw/skins/glamdrol/headerbg.jpg",
"http://www.wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg",
"http://www.wesnoth.org/mw/skins/glamdrol/navbg.png"]:
local = os.path.join(options.output, grab[grab.rfind("/") + 1:])
if not os.path.exists(local):
print "Fetching", grab
url = urllib2.urlopen(grab)
file(local, "w").write(url.read())
def shell(com):
#print(com)
p = subprocess.Popen(com, stdout = subprocess.PIPE,
stderr = subprocess.PIPE, shell = True)
out, err = p.communicate()
#if out: sys.stdout.write(out)
#if err: sys.stdout.write(err)
return p.returncode
def shell_out(com):
p = subprocess.Popen(com,
stdout = subprocess.PIPE, stderr = subprocess.PIPE)
out, err = p.communicate()
return out
def bash(name):
return "'" + name.replace("'", "'\\''") + "'"
def move(f, t, name):
if os.path.exists(f + "/" + name + ".cfg"):
com = "mv " + f + "/" + bash(name + ".cfg") + " " + t + "/"
shell(com)
com = "mv " + f + "/" + bash(name) + " " + t + "/"
return shell(com)
_info = {}
def get_info(addon):
global _info
if addon in _info:
return _info[addon]
_info[addon] = None
try:
path = options.addons + "/" + addon + "/_info.cfg"
if os.path.exists(path):
parser = wmlparser2.Parser(options.wesnoth, options.config_dir,
options.data_dir, no_preprocess = False)
parser.parse_file(path)
_info[addon] = parser
else:
print("Cannot find " + path)
except wmlparser2.WMLError as e:
print(e)
return _info[addon]
_deps = {}
global_addons = set()
def get_dependencies(addon):
global _deps
global global_addons
if addon in _deps:
return _deps[addon]
_deps[addon] = []
try:
info = get_info(addon).get_all(tag = "info")[0]
row = info.get_text_val("dependencies")
if row:
deps1 = row.split(",")
else:
deps1 = []
for d in deps1:
if d in global_addons:
_deps[addon].append(d)
else:
print("Missing dependency for " + addon + ": " + d)
except Exception as e:
print(e)
return _deps[addon]
def set_dependencies(addon, depends_on):
_deps[addon] = depends_on
def get_all_dependencies(addon):
result = []
check = get_dependencies(addon)[:]
while check:
d = check.pop()
if d == addon: continue
if d in result: continue
result.append(d)
check += get_dependencies(d)
return result
def sorted_by_dependencies(addons):
sorted = []
unsorted = addons[:]
while unsorted:
n = 0
for addon in unsorted:
for d in get_dependencies(addon):
if d not in sorted:
break
else:
sorted.append(addon)
unsorted.remove(addon)
n += 1
continue
if n == 0:
print("Cannot sort dependencies for these addons: " + str(unsorted))
sorted += unsorted
break
return sorted
def search(batchlist, name):
for info in batchlist:
if info and info["name"] == name: return info
batchlist.append({})
batchlist[-1]["name"] = name
return batchlist[-1]
def list_contents():
class Empty: pass
local = Empty()
mainline_eras = set()
filename = options.list
def append(info, id, define, c = None, name = None, domain = None):
info.append({})
info[-1]["id"]= id
info[-1]["define"] = define
if c:
info[-1]["name"] = c.get_text_val("name")
else:
info[-1]["name"] = name
info[-1]["units"] = "?"
info[-1]["translations"] = {}
for isocode in languages:
translation = html_output.Translation(options.transdir, isocode)
def translate(string, domain):
return translation.translate(string, domain)
if c:
t = c.get_text_val("name", translation = translate)
else:
t = translate(name, domain)
if t != info[-1]["name"]:
info[-1]["translations"][isocode] = t
def get_dependency_eras(batchlist, addon):
dependency_eras = list(mainline_eras)
for d in get_all_dependencies(addon):
dinfo = search(batchlist, d)
for era in dinfo["eras"]:
dependency_eras.append(era["id"])
return dependency_eras
def list_eras(batchlist, addon):
eras = local.wesnoth.parser.get_all(tag = "era")
if addon != "mainline":
dependency_eras = get_dependency_eras(batchlist, addon)
eras = [x for x in eras if not x.get_text_val("id") in dependency_eras]
info = []
for era in eras:
eid = era.get_text_val("id")
if addon == "mainline":
mainline_eras.add(eid)
append(info, eid, "MULTIPLAYER", c = era)
return info
def list_campaigns(batchlist, addon):
campaigns = local.wesnoth.parser.get_all(tag = "campaign")
info = []
for campaign in campaigns:
cid = campaign.get_text_val("id")
d = campaign.get_text_val("define")
d2 = campaign.get_text_val("extra_defines")
if d2: d += "," + d2
d3 = campaign.get_text_val("difficulties")
if d3:
d += "," + d3.split(",")[0]
append(info, cid, d, c = campaign)
return info
def parse(wml, defines):
def f(options, wml, defines, q):
local.wesnoth = helpers.WesnothList(
options.wesnoth,
options.config_dir,
options.data_dir,
options.transdir)
#print("remote", local.wesnoth)
try:
local.wesnoth.parser.parse_text(wml, defines)
q.put(("ok", local.wesnoth))
except Exception as e:
q.put(("e", e))
q = multiprocessing.Queue()
p = multiprocessing.Process(target = f, args = (options, wml, defines, q))
p.start()
try:
s, local.wesnoth = q.get(timeout = TIMEOUT)
except Queue.Empty:
p.terminate()
raise
#print("local", s, local.wesnoth)
p.join()
if s == "e":
remote_exception = local.wesnoth
raise remote_exception
def get_version(addon):
parser = get_info(addon)
if parser:
for info in parser.get_all(tag = "info"):
return info.get_text_val("version") + "*" + info.get_text_val("uploads")
try: os.makedirs(options.output + "/mainline")
except OSError: pass
try:
batchlist = yaml.load(open(options.list))
except IOError:
batchlist = []
print("mainline")
info = search(batchlist, "mainline")
info["version"] = "mainline"
info["parsed"] = "false"
parse("{core}{multiplayer/eras.cfg}", "SKIP_CORE")
info["eras"] = list_eras(batchlist, "mainline")
# Fake mainline campaign to have an overview of the mainline units
info["campaigns"] = []
append(info["campaigns"], "mainline", "", name = "Units", domain = "wesnoth-help")
if not options.addons_only:
parse("{core}{campaigns}", "SKIP_CORE")
info["campaigns"] += list_campaigns(batchlist, "mainline")
addons = []
if options.addons:
addons = os.listdir(options.addons)
global global_addons
global_addons = set(addons)
# fill in the map for all dependencies
for addon in addons:
get_dependencies(addon)
# this ensures that info about eras in dependant addons is available
# already
addons = sorted_by_dependencies(addons)
for i, addon in enumerate(addons):
if not os.path.isdir(options.addons + "/" + addon): continue
sys.stdout.write("%4d/%4d " % (1 + i, len(addons)) + addon + " ... ")
sys.stdout.flush()
d = options.output + "/" + addon
logname = d + "/error.log"
try: os.makedirs(d)
except OSError: pass
version = get_version(addon)
move(options.addons, options.config_dir + "/data/add-ons", addon)
for d in get_dependencies(addon):
move(options.addons, options.config_dir + "/data/add-ons", d)
try:
info = search(batchlist, addon)
if info.get("version", "") == version and info.get("parsed", False) == True:
sys.stdout.write("up to date\n")
continue
info["parsed"] = False
info["dependencies"] = get_dependencies(addon)
parse("{core}{multiplayer}{~add-ons}", "MULTIPLAYER,SKIP_CORE")
info["eras"] = list_eras(batchlist, addon)
info["campaigns"] = list_campaigns(batchlist, addon)
info["version"] = version
sys.stdout.write("ok\n")
except wmlparser2.WMLError as e:
ef = open(logname, "w")
ef.write("
%s
\n" % (u.rid,)) f.write("