← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands-website/encyclopedia into lp:widelands-website

 

GunChleoc has proposed merging lp:~widelands-dev/widelands-website/encyclopedia into lp:widelands-website.

Commit message:
Update the encyclopedia from JSON files.

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #350465 in Widelands Website: "online_help returns false information"
  https://bugs.launchpad.net/widelands-website/+bug/350465

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands-website/encyclopedia/+merge/287410

Update the encyclopedia from JSON files.

This will also call the new executable first to make sure that the JSON files have been written. Also checks that the files are valid JSON.

Also deletes the models in the database before regenerating, so we will get rid of the old duplicates.

There shouldn't be any other functionality changes.

Related Widelands branch:

https://code.launchpad.net/~widelands-dev/widelands/map_object_info

-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands-website/encyclopedia into lp:widelands-website.
=== modified file 'templates/wlhelp/index.html'
--- templates/wlhelp/index.html	2015-05-23 16:12:31 +0000
+++ templates/wlhelp/index.html	2016-02-28 18:22:18 +0000
@@ -10,8 +10,6 @@
 {% block content %}
 <h1>Encyclopedia</h1>
 <div class="blogEntry">
-<p><span style="font-weight: bold;"> !!! The encyclopedia currently contains some errors. !!!</span><br />Please use the in-game help for correct and up to date information.</p>
-
 Encyclopedia &#187; Index
 <br /><br />
 <p>This is a list of all tribes in Widelands:</p>

=== modified file 'templates/wlhelp/inlines/display_buildings.html'
--- templates/wlhelp/inlines/display_buildings.html	2012-05-19 19:55:15 +0000
+++ templates/wlhelp/inlines/display_buildings.html	2016-02-28 18:22:18 +0000
@@ -10,7 +10,7 @@
 	<tr class="{% cycle "odd" "even" %}">
 		<td>
 			<a href="{% url wlhelp_building_details b.tribe.name b.name %}" title="{{ b.displayname }}" id="{{ b.name }}">
-				{{ b.displayname|title }}
+				{{ b.displayname }}
 				<br />
 				<img alt="{{b.displayname}}" src="{{ b.image_url }}" />
 			</a>

=== modified file 'widelandslib/make_flow_diagram.py'
--- widelandslib/make_flow_diagram.py	2011-07-06 23:31:10 +0000
+++ widelandslib/make_flow_diagram.py	2016-02-28 18:22:18 +0000
@@ -4,7 +4,6 @@
 import pydot as d
 
 from widelandslib.tribe import *
-#from pudb import set_trace; set_trace()
 
 from os import makedirs, path
 import subprocess
@@ -15,12 +14,12 @@
 ##############################
 # To Do Make_Flow_Diagram.py #
 ##############################
-# i'd like to add things like: forester resores trunk or: gamekeeper restores meat
+# i'd like to add things like: forester resores log or: gamekeeper restores meat
 #
 # also, a building called construction site where alle the building material can point at would be nice
 #
 # how to tell the viewer, how many and wich ressources turn to others via buildings,
-# e.g. 6 trunks to 1 coal with the atlanteans, maybe on the edges?
+# e.g. 6 logs to 1 coal with the atlanteans, maybe on the edges?
 
 #############################
 # Work around bugs in pydot #
@@ -123,7 +122,7 @@
 
 
     if isinstance(b, (ProductionSite,)):
-        # for worker,c in b.workers: 
+        # for worker,c in b.workers:
         #     g.add_edge(Edge(worker, name, color="orange"))
 
         for output in b.outputs:
@@ -169,7 +168,14 @@
 def make_graph(tribe_name):
     global tdir
     tdir = mkdtemp(prefix="widelands-help")
-    t = Tribe(tribe_name)
+
+    base_directory = path.normpath(WIDELANDS_SVN_DIR + "/data")
+    json_directory = path.normpath(base_directory + "/map_object_info")
+
+    tribeinfo_file = open(path.normpath(json_directory + "/tribe_" + tribe_name + ".json"), "r")
+    tribeinfo = json.load(tribeinfo_file)
+
+    t = Tribe(tribeinfo, json_directory)
 
     g = CleanedDot(concentrate="false", style="filled", bgcolor="white",
                 overlap="false", splines="true", rankdir="LR")
@@ -186,7 +192,7 @@
 
     g.write_pdf(path.join(tdir, "%s.pdf" % tribe_name))
 
-    g.set_size("6")
+    g.set_size("32")
     g.write_gif(path.join(tdir, "%s.gif" % tribe_name))
 
     rtdir, tdir = tdir, ""
@@ -235,8 +241,8 @@
     g = CleanedDot(concentrate="false", bgcolor="transparent",
                 overlap="false", splines="true", rankdir="LR")
 
-    buildings = [bld for bld in t.buildings.values() if 
-            isinstance(bld, ProductionSite) and 
+    buildings = [bld for bld in t.buildings.values() if
+            isinstance(bld, ProductionSite) and
               (w.name in bld.workers or w.name in bld.recruits)]
 
     for bld in buildings:
@@ -260,6 +266,7 @@
 
     try: makedirs(path.join(tdir, "help/%s/workers/%s/" % (t.name, w.name)))
     except OSError: pass
+    dot_path = path.join(tdir, "help/%s/workers/%s/source.dot" % (t.name, w.name))
     g.write(path.join(tdir, "help/%s/workers/%s/source.dot" % (t.name, w.name)))
 
 def make_ware_graph(t, ware_name):
@@ -280,9 +287,9 @@
     g.write(path.join(tdir, "help/%s/wares/%s/source.dot" % (t.name, ware_name)))
 
 def process_dotfile(directory):
-    subprocess.Popen(("dot -Tpng -o %s/image.png -Tcmapx -o %s/map.map %s/source.dot" % (directory, directory, directory)).split(" ")).wait()
+    subprocess.Popen(("dot -Tpng -o %s/menu.png -Tcmapx -o %s/map.map %s/source.dot" % (directory, directory, directory)).split(" ")).wait()
     #with open(directory,"w") as html:
-    #    html.write(r"""<IMG SRC="image.png" border="0px" usemap="#G"/>""" + open(path.join(directory, "map.map")).read())
+    #    html.write(r"""<IMG SRC="menu.png" border="0px" usemap="#G"/>""" + open(path.join(directory, "map.map")).read())
 
 def make_all_subgraphs(t):
     global tdir
@@ -291,6 +298,13 @@
         t = Tribe(t)
     print "making all subgraphs for tribe", t.name, "in", tdir
 
+    print "  making wares"
+
+    for w in t.wares:
+        print "    " + w
+        make_ware_graph(t, w)
+        process_dotfile(path.join(tdir, "help/%s/wares/%s/" % (t.name, w)))
+
     print "  making workers"
 
     for w in t.workers:
@@ -298,13 +312,6 @@
         make_worker_graph(t, w)
         process_dotfile(path.join(tdir, "help/%s/workers/%s/" % (t.name, w)))
 
-    print "  making wares"
-
-    for w in t.wares:
-        print "    " + w
-        make_ware_graph(t, w)
-        process_dotfile(path.join(tdir, "help/%s/wares/%s/" % (t.name, w)))
-
     print "  making buildings"
 
     for b in t.buildings:

=== modified file 'widelandslib/tribe.py'
--- widelandslib/tribe.py	2012-05-18 23:41:26 +0000
+++ widelandslib/tribe.py	2016-02-28 18:22:18 +0000
@@ -1,13 +1,8 @@
 #!/usr/bin/env python
 # encoding: utf-8
 
-from conf import WidelandsConfigParser
-from ConfigParser import NoSectionError, NoOptionError
-import conf
-from itertools import chain
 import os.path as p
-import re
-from string import replace
+import json
 try:
     from settings import WIDELANDS_SVN_DIR
     basedir = WIDELANDS_SVN_DIR
@@ -15,18 +10,15 @@
     basedir = p.join(p.dirname(__file__), p.pardir, p.pardir)
 
 class BaseDescr(object):
-    def __init__(self, tribe, name, descname, tdir):
+    def __init__(self, tribe, name, descname, json):
         self.tribe = tribe
-        self._tdir = tdir
-        self._conf_file = p.join(tdir, name, "conf")
-        self._conf = WidelandsConfigParser(p.join(tdir,name,"conf"))
-
+        self._json = json
         self.name = name
         self.descname = descname
 
     @property
     def image(self):
-        return p.abspath(p.join(self._tdir,self.name,"menu.png"))
+        return p.abspath(p.join(WIDELANDS_SVN_DIR, "data", self._json['icon']))
 
 class Ware(BaseDescr):
     def __str__(self):
@@ -34,19 +26,11 @@
 
 class Worker(BaseDescr):
     @property
-    def outputs(self):
-        rv = set(sorted(
-            i.strip() for i in re.findall(r'\d+=\s*createitem\s*(\w+)',
-                open(self._conf_file).read())
-        ))
-        return rv
-
-    @property
     def becomes(self):
-        try:
-            return self._conf.get("global", "becomes")
-        except NoOptionError:
-            return None
+		 if 'becomes' in self._json:
+			return self._json['becomes']['name']
+		 else:
+			return None
 
     def __str__(self):
         return "Worker(%s)" % self.name
@@ -54,125 +38,131 @@
 class Building(BaseDescr):
     @property
     def enhanced_building(self):
-        return self._conf.getboolean("global", "enhanced_building", False)
+		 if 'enhanced' in self._json:
+			return True
+		 else:
+			return False
 
     @property
     def base_building(self):
-        if not self.enhanced_building:
-            return None
-        bases = [b for b in self.tribe.buildings.values() if b.enhancement == self.name]
-        if len(bases) == 0 and self.enhanced_building:
-            raise Exception("Building %s has no bases in tribe %s" % (self.name, self.tribe.name))
-        if len(bases) > 1:
-            raise Exception("Building %s seems to have more than one base in tribe %s." % (self.name, self.tribe.name))
-        return bases[0]
+       if not self.enhanced_building:
+           return None
+       bases = [b for b in self.tribe.buildings.values() if b.enhancement == self.name]
+       if len(bases) == 0 and self.enhanced_building:
+           raise Exception("Building %s has no bases in tribe %s" % (self.name, self.tribe.name))
+       if len(bases) > 1:
+           raise Exception("Building %s seems to have more than one base in tribe %s." % (self.name, self.tribe.name))
+       return bases[0]
 
     @property
     def enhancement(self):
-        rv = self._conf.getstring("global", "enhancement", "none")
-        return rv if rv != "none" else None
-
-    @property
-    def image(self):
-        glob_pat = self._conf.getstring("idle", "pics")
-        return p.abspath(p.join(self._tdir,self.name,replace(glob_pat,'?','0')))
+		 if 'enhancement' in self._json:
+			return self._json['enhancement']
+		 else:
+			return None
 
     @property
     def buildcost(self):
-        try:
-            return dict(self._conf.items("buildcost"))
-        except NoSectionError:
-            return {}
+		 result = dict()
+		 if 'buildcost' in self._json:
+			for buildcost in self._json['buildcost']:
+			  result[buildcost['name']] = buildcost['amount']
+		 return result
 
     @property
     def size(self):
-        return self._conf.getstring("global", "size")
+        return self._json['size']
 
 class ProductionSite(Building):
     btype = "productionsite"
     @property
     def outputs(self):
-        self_produced = set(sorted(
-            i.strip() for i in re.findall(r'produce\s*=\s*(\w+)',
-                open(self._conf_file).read())
-        ))
-        if not len(self_produced):
-            rv = reduce(lambda a,b: a | b, [ self.tribe.workers[w].outputs
-                    for w in self.workers ], set())
-            return rv
-        return self_produced
+		 result = set()
+		 if 'produced_wares' in self._json:
+			for warename in self._json['produced_wares']:
+			  result.add(warename)
+		 return result
 
     @property
     def inputs(self):
-        try:
-            return dict( (k, v) for k,v in self._conf.items("inputs") )
-        except conf.NoSectionError:
-            return dict()
+		 result = dict()
+		 if 'stored_wares' in self._json:
+			for ware in self._json['stored_wares']:
+			  result[ware['name']] = ware['amount']
+		 return result
 
     @property
     def workers(self):
-        return dict( (k, v) for k,v in self._conf.items("working positions") )
+		 result = dict()
+		 if 'workers' in self._json:
+			for worker in self._json['workers']:
+			  result[worker['name']] = worker['amount']
+		 return result
 
     @property
     def recruits(self):
-        recs = set([])
-        for prog,_ in self._conf.items("programs"):
-            recs |= set([name for type, name in self._conf.items(prog) if type == "recruit"])
-        return recs
+		 result = set()
+		 if 'produced_workers' in self._json:
+			for workername in self._json['produced_workers']:
+			  result.add(workername)
+		 return result
 
 class Warehouse(Building):
     btype = "warehouse"
     pass
 
 class TrainingSite(ProductionSite):
-    btype = "trainings site"
+    btype = "trainingsite"
     pass
 
 class MilitarySite(Building):
-    btype = "military site"
+    btype = "militarysite"
     @property
     def conquers(self):
-        return self._conf.get("global", "conquers")
+        return self._json['conquers']
 
     @property
     def max_soldiers(self):
-        return self._conf.get("global", "max_soldiers")
+        return self._json['max_soldiers']
 
     @property
     def heal_per_second(self):
-        return self._conf.getint("global", "heal_per_second")
+        return self._json['heal_per_second']
 
 
 class Tribe(object):
-    def __init__(self, name, bdir = basedir):
-        self.name = name
-
-        self._tdir = p.join(bdir, "tribes", name)
-
-        self._conf = WidelandsConfigParser(p.join(self._tdir, "conf"))
-
-        self.wares = dict( (k,Ware(self, k, v, self._tdir)) for k,v in
-            self._conf.items("ware types"))
-        self.workers = dict(chain(
-            ((k,Worker(self, k, v, self._tdir)) for k,v in
-                self._conf.items("worker types")),
-            ((k,Worker(self, k, v, self._tdir)) for k,v in
-                self._conf.items("carrier types")),
-        ))
-
-
-        self.buildings = dict(chain(
-            ((k,ProductionSite(self, k, v, self._tdir)) for k,v in \
-                self._conf.items("productionsite types")),
-            ((k,MilitarySite(self, k, v, self._tdir)) for k,v in \
-                self._conf.items("militarysite types")),
-            ((k,Warehouse(self, k, v, self._tdir)) for k,v in \
-                self._conf.items("warehouse types")),
-            ((k,TrainingSite(self, k, v, self._tdir)) for k,v in \
-                self._conf.items("trainingsite types")),
-        ))
+    def __init__(self, tribeinfo, json_directory):
+        self.name = tribeinfo['name']
+
+        wares_file = open(p.normpath(json_directory + "/" + self.name + "_wares.json"), "r")
+        waresinfo = json.load(wares_file)
+        self.wares = dict()
+        for ware in waresinfo['wares']:
+			  descname = ware['descname'].encode('ascii', 'xmlcharrefreplace')
+			  self.wares[ware['name']] = Ware(self, ware['name'], descname, ware)
+
+        workers_file = open(p.normpath(json_directory + "/" + self.name + "_workers.json"), "r")
+        workersinfo = json.load(workers_file)
+        self.workers = dict()
+        for worker in workersinfo['workers']:
+			  descname = worker['descname'].encode('ascii', 'xmlcharrefreplace')
+			  self.workers[worker['name']] = Worker(self, worker['name'], descname, worker)
+
+        buildings_file = open(p.normpath(json_directory + "/" + self.name + "_buildings.json"), "r")
+        buildingsinfo = json.load(buildings_file)
+        self.buildings = dict()
+        for building in buildingsinfo['buildings']:
+			  descname = building['descname'].encode('ascii', 'xmlcharrefreplace')
+			  if building['type'] == "productionsite":
+				  self.buildings[building['name']] = ProductionSite(self, building['name'], descname, building)
+			  elif building['type'] == "warehouse":
+				  self.buildings[building['name']] = Warehouse(self, building['name'], descname, building)
+			  elif building['type'] == "trainingsite":
+				  self.buildings[building['name']] = TrainingSite(self, building['name'], descname, building)
+			  elif building['type'] == "militarysite":
+				  self.buildings[building['name']] = MilitarySite(self, building['name'], descname, building)
+			  else:
+				  self.buildings[building['name']] = Building(self, building['name'], descname, building)
 
     def __str__(self):
         return "Tribe(%s)" % self.name
-
-

=== modified file 'wlhelp/management/commands/update_help.py'
--- wlhelp/management/commands/update_help.py	2012-05-19 19:55:15 +0000
+++ wlhelp/management/commands/update_help.py	2016-02-28 18:22:18 +0000
@@ -16,28 +16,19 @@
 
 from django.core.files import File
 from django.core.management.base import BaseCommand, CommandError
-from optparse import make_option
 
-from ConfigParser import ConfigParser, MissingSectionHeaderError
-from glob import glob
 import os
-from os import path
+from os import makedirs, path
 import shutil
-from cStringIO import StringIO
 import re
-from itertools import chain
+import json
+import subprocess
 
 from settings import MEDIA_ROOT, WIDELANDS_SVN_DIR, MEDIA_URL
 
 from widelandslib.tribe import *
 from widelandslib.make_flow_diagram import make_all_subgraphs
 
-def normalize_name( s ):
-    """
-    Strips _ from the name endings
-    """
-    return s.strip('_')
-
 class TribeParser(object):
     map_mouseover_pattern = re.compile(r'(?P<beginning>.*href="../../(?P<type>[^/]+)s/(?P<name>[^/]+)/".*")&lt;TABLE&gt;(?P<rest>.*)')
     def __init__(self, name):
@@ -45,32 +36,45 @@
         Parses the definitions for one tribe and generates the models
 
         name - name of the tribe
-        conf - path to the tribe/conf file
         """
-        self._tribe = Tribe(name)
+        self._delete_old_media_dir(name) # You can deactivate this line if you don't need to clean house.
+
+        base_directory = os.path.normpath(WIDELANDS_SVN_DIR + "/data")
+        json_directory = os.path.normpath(base_directory + "/map_object_info")
+
+        tribeinfo_file = open(os.path.normpath(json_directory + "/tribe_" + name + ".json"), "r")
+        tribeinfo = json.load(tribeinfo_file)
+
+        self._tribe = Tribe(tribeinfo, json_directory)
         # Generate the Tribe
         self._to = TribeModel.objects.get_or_create(name=name.lower())[0]
-        self._to.displayname = normalize_name(self._tribe._conf.getstring("tribe", "name"))
-        self._to.descr = normalize_name(self._tribe._conf.getstring("tribe", "descr"))
+        self._to.displayname = tribeinfo['descname']
+        self._to.descr = tribeinfo['tooltip']
         # copy icon
-        dn = "%s/wlhelp/img/%s/" % (MEDIA_ROOT,self._to.name)
+        dn = "%s/wlhelp/img/%s/" % (MEDIA_ROOT, tribeinfo['name'])
         try:
             os.makedirs(dn)
         except OSError, o:
             if o.errno != 17:
                 raise
         new_name = path.join(dn, "icon.png")
-        file = path.join(self._tribe._tdir,self._tribe._conf.getstring("tribe", "icon"))
+        file = os.path.normpath(base_directory + "/" + tribeinfo['icon'])
         shutil.copy(file, new_name )
         self._to.icon_url = path.normpath("%s/%s" % (MEDIA_URL, new_name[len(MEDIA_ROOT):]))
         self._to.save()
 
-    def parse( self ):
+    def parse( self, tribename, base_directory, json_directory ):
         """Put all data into the database"""
-        #self._delete_old_media_dir() why delete it? We can simply overwrite data
-        self._parse_workers()
-        self._parse_wares()
-        self._parse_buildings()
+        self._delete_old_data(tribename) # You can deactivate this line if you don't need to clean house.
+
+        wares_file = open(os.path.normpath(json_directory + "/" + tribename + "_wares.json"), "r")
+        self._parse_wares(base_directory, json.load(wares_file))
+
+        workers_file = open(os.path.normpath(json_directory + "/" + tribename + "_workers.json"), "r")
+        self._parse_workers(base_directory, json.load(workers_file))
+
+        buildings_file = open(os.path.normpath(json_directory + "/" + tribename + "_buildings.json"), "r")
+        self._parse_buildings(base_directory, json.load(buildings_file))
 
     def graph( self ):
         """Make all graphs"""
@@ -81,7 +85,7 @@
             for inst in obj.objects.all().filter(tribe=self._to):
                 try:
                     fpath = path.join(tdir,"help/%s/%s/%s/" % (self._tribe.name, cls, inst.name))
-                    url = self._copy_picture(path.join(fpath, "image.png"), inst.name, "graph.png")
+                    url = self._copy_picture(path.join(fpath, "menu.png"), inst.name, "graph.png")
                     inst.graph_url = url
                     inst.imagemap = open(path.join(fpath, "map.map")).read()
                     inst.imagemap = self.map_mouseover_pattern.sub(r"\1Show the \2 \3\4", inst.imagemap)
@@ -89,13 +93,30 @@
                 except Exception, e:
                     print "Exception while handling", cls, "of", self._tribe.name, ":", inst.name
                     print type(e), e, repr(e)
-        
+
         shutil.rmtree(tdir)
 
-    def _delete_old_media_dir(self):
-        sdir = os.path.join(MEDIA_ROOT, "wlhelp/img", self._to.name)
-        if os.path.exists(sdir):
-            shutil.rmtree(sdir)
+    def _delete_old_media_dir(self, tribename):
+		 """Clean house, e.g. when we have renamed a map object"""
+
+		 print("Deleting old media files...");
+		 sdir = os.path.join(MEDIA_ROOT, "wlhelp/img", tribename)
+		 if os.path.exists(sdir):
+			 shutil.rmtree(sdir)
+
+    def _delete_old_data(self, tribename):
+		 """Clean house, e.g. when we have renamed a map object"""
+
+		 t = TribeModel.objects.get(name=tribename)
+		 print("Deleting old wares...");
+		 for ware in WareModel.objects.filter(tribe=t):
+			ware.delete()
+		 print("Deleting old workers...");
+		 for worker in WorkerModel.objects.filter(tribe=t):
+			worker.delete()
+		 print("Deleting old buildings...");
+		 for building in BuildingModel.objects.filter(tribe=t):
+			building.delete()
 
     def _copy_picture( self, file, name, fname ):
         """
@@ -116,130 +137,148 @@
 
         return "%s/%s" % (MEDIA_URL, new_name[len(MEDIA_ROOT):])
 
-    def _parse_workers( self ):
+    def _parse_workers( self, base_directory, workersinfo ):
         """Put the workers into the database"""
         print "  parsing workers"
-        for worker in self._tribe.workers.values():
-            print "    " + worker.name
-            nn = self._copy_picture(worker.image, worker.name, "menu.png")
-
-            workero = WorkerModel.objects.get_or_create( tribe = self._to, name = worker.name )[0]
-            workero.displayname = normalize_name(worker.descname)
+
+        for worker in workersinfo['workers']:
+            print "    " + worker['name']
+            nn = self._copy_picture(os.path.normpath(base_directory + "/" + worker['icon']), worker['name'], "menu.png")
+
+            workero = WorkerModel.objects.get_or_create( tribe = self._to, name = worker['name'] )[0]
+            workero.displayname = worker['descname']
             workero.image_url = nn
 
-            # See if there is help available
-            if worker._conf.has_option("global","help"):
-                helpstr = normalize_name(worker._conf.get("global","help"))
-                workero.help = helpstr
+            # Help
+            workero.help = worker['helptext']
 
             # Check for experience
-            if worker._conf.has_option("global","experience"):
-                experience = normalize_name(worker._conf.get("global","experience"))
-                workero.exp = experience
+            if 'experience' in worker:
+                workero.exp = worker['experience']
 
             # See what the worker becomes
-            try:
-                enname = worker.becomes
-                workero.becomes = WorkerModel.objects.get_or_create(
-                        name=enname, tribe = self._to)[0]
-            except:
-                pass
+            if 'becomes' in worker:
+                try:
+                    enname = worker.becomes
+                    workero.becomes = WorkerModel.objects.get_or_create(
+                            name=worker['becomes']['name'], tribe = self._to)[0]
+                except:
+                    pass
 
             workero.save()
 
-    def _parse_wares( self ):
+    def _parse_wares( self, base_directory, waresinfo ):
         print "  parsing wares"
-        for ware in self._tribe.wares.values():
-            print "    " + ware.name
-            nn = self._copy_picture(ware.image, ware.name, "menu.png")
-
-            w = WareModel.objects.get_or_create( tribe = self._to, name = ware.name )[0]
-            w.displayname = normalize_name(ware.descname)
+
+        for ware in waresinfo['wares']:
+            print "    " + ware['name']
+            nn = self._copy_picture(os.path.normpath(base_directory + "/" + ware['icon']), ware['name'], "menu.png")
+
+            w = WareModel.objects.get_or_create( tribe = self._to, name = ware['name'] )[0]
+            w.displayname = ware['descname']
             w.image_url = nn
 
-
-            # See if there is help available
-            if ware._conf.has_option("global","help"):
-                helpstr = normalize_name(ware._conf.get("global","help"))
-                w.help = helpstr
+            # Help
+            w.help = ware['helptext']
 
             w.save()
 
-    def _parse_buildings( self ):
-        def objects_with_counts(objtype, set_):
-            counts = ' '.join(set_.values())
-            objects = [objtype.objects.get_or_create(name = w, tribe = self._to)[0] for w in set_.keys()]
-            return counts, objects
+    def _parse_buildings( self, base_directory, buildingsinfo ):
+        def objects_with_counts(objtype, json_):
+				element_set = {}
+				for element in json_:
+					element_set[element['name']] = str(element['amount'])
+				counts = ' '.join(element_set.values())
+				objects = [objtype.objects.get_or_create(name = w, tribe = self._to)[0] for w in element_set.keys()]
+				return counts, objects
 
-        enhancement_hier = []
+        enhancement_hierarchy = []
         print "  parsing buildings"
-        for building in self._tribe.buildings.values():
-            print "    " + building.name
-            b = BuildingModel.objects.get_or_create( tribe = self._to, name = building.name )[0]
-            b.displayname = normalize_name(building.descname)
-            b.type = building.btype
-
-            # Get the building size
-            size = building.size
-            res, = [ k for k,v in BuildingModel.SIZES if v == size ]
-
-            b.size = res
-
-            nn = self._copy_picture(building.image, building.name, "menu.png" )
-            b.image_url = nn
-
-            # Try to figure out buildcost
-            b.build_costs, b.build_wares = objects_with_counts(WareModel, building.buildcost)
-
-            # Try to figure out who works there
-            if isinstance(building, ProductionSite):
-                b.workers_count, b.workers_types = objects_with_counts(WorkerModel, building.workers)
-
-            # Try to figure out if this is an enhanced building
-            if building.enhancement:
-                enhancement_hier.append((b, building.enhancement))
-
-            if building._conf.has_option("global","help"):
-                b.help = normalize_name(building._conf.get("global","help"))
-            else:
-                try:
-                    b.help = [worker.help for worker in b.workers_types.all()][0]
-                except IndexError:
-                    print "could not find a help string for %s (%s) anywhere!" % (b.name, self._tribe.name)
-
-            # See if there is any inputs field around
-            if isinstance(building, ProductionSite):
-                b.store_count, b.store_wares = objects_with_counts(WareModel, building.inputs)
-
-                b.output_wares = [WareModel.objects.get_or_create(name = w, tribe = self._to)[0] for w in building.outputs]
-
-            try:
-                b.output_workers = [Worker.objects.get_or_create(name = w, tribe = self._to)[0] for w in building.recruits]
-            except AttributeError:
-                pass
-
-            b.save()
-
-        for b, tgt in enhancement_hier:
-            try:
-                b.enhancement = BuildingModel.objects.get(name = tgt, tribe = self._to)
-            except Exception, e:
-                raise
-            b.save()
+
+        for building in buildingsinfo['buildings']:
+				print "    " + building['name']
+				b = BuildingModel.objects.get_or_create( tribe = self._to, name = building['name'] )[0]
+				b.displayname = building['descname']
+				b.type = building['type']
+
+				# Get the building size
+				size = building['size']
+				res, = [ k for k,v in BuildingModel.SIZES if v == size ]
+				b.size = res
+
+				nn = self._copy_picture(os.path.normpath(base_directory + "/" + building['icon']), building['name'], "menu.png")
+				b.image_url = nn
+
+				# Buildcost if we have any
+				if 'buildcost' in building:
+					b.build_costs, b.build_wares = objects_with_counts(WareModel, building['buildcost'])
+
+				# Try to figure out who works there
+				if 'workers' in building:
+					b.workers_count, b.workers_types  = objects_with_counts(WorkerModel, building['workers'])
+
+				# Try to figure out if this is an enhanced building
+				if 'enhancement' in building:
+					enhancement_hierarchy.append((b, building['enhancement']))
+
+				b.help = building['helptext']
+
+				# Input wares
+				if 'stored_wares' in building:
+					b.store_count, b.store_wares = objects_with_counts(WareModel, building['stored_wares'])
+
+				# Output wares
+				if 'produced_wares' in building:
+					b.output_wares = [WareModel.objects.get_or_create(name = w, tribe = self._to)[0] for w in building['produced_wares']]
+
+				# Output workers
+				if 'produced_workers' in building:
+					b.output_workers = [WorkerModel.objects.get_or_create(name = w, tribe = self._to)[0] for w in building['produced_workers']]
+
+				b.save()
+
+        for b, tgt in enhancement_hierarchy:
+				try:
+					b.enhancement = BuildingModel.objects.get(name = tgt, tribe = self._to)
+				except Exception, e:
+					raise
+				b.save()
 
 class Command(BaseCommand):
     help =\
-    '''Reparses the conf files in a current checkout. '''
-
-    def handle(self, directory = WIDELANDS_SVN_DIR, **kwargs):
-
-        tribes = [d for d in glob("%s/tribes/*" % directory)
-                    if os.path.isdir(d)]
-
-        for t in tribes:
-            tribename = os.path.basename(t)
-            print "updating help for tribe ", tribename
-            p = TribeParser(tribename)
-
-            p.parse()
-            p.graph()
+    '''Regenerates and parses the json files in a current checkout. '''
+
+    def handle(self, directory = os.path.normpath(WIDELANDS_SVN_DIR + "/data"), **kwargs):
+
+        # First, we make sure that JSON files have been generated.
+        current_dir = os.path.dirname(os.path.realpath(__file__))
+        is_json_valid = False
+        os.chdir(WIDELANDS_SVN_DIR)
+        try:
+            subprocess.check_call(
+                [os.path.normpath(WIDELANDS_SVN_DIR + "/build/src/logic/wl_map_object_info")])
+        except:
+            print("Error: Unable to execute 'wl_map_object_info' for generating the JSON files.")
+
+        # Now we validate that they are indeed JSON files (syntax check only)
+        try:
+            subprocess.check_call(
+                [os.path.normpath(WIDELANDS_SVN_DIR + "/utils/validate_json.py")])
+            is_json_valid = True
+        except:
+            print("Error: JSON files are not valid.")
+
+        os.chdir(current_dir)
+
+        # We regenerate the encyclopedia only if the JSON files passed the syntax check
+        if is_json_valid:
+			  json_directory = os.path.normpath(directory + "/map_object_info")
+			  source_file = open(os.path.normpath(json_directory + "/tribes.json"), "r")
+			  tribesinfo = json.load(source_file)
+
+			  for t in tribesinfo['tribes']:
+			      tribename = t['name']
+			      print "updating help for tribe ", tribename
+			      p = TribeParser(tribename)
+			      p.parse(tribename, directory, json_directory)
+			      p.graph()

=== modified file 'wlhelp/management/commands/update_help_pdf.py'
--- wlhelp/management/commands/update_help_pdf.py	2012-05-19 19:55:15 +0000
+++ wlhelp/management/commands/update_help_pdf.py	2016-02-28 18:22:18 +0000
@@ -10,19 +10,20 @@
 from widelandslib.make_flow_diagram import make_graph
 from wlhelp.models import Tribe
 from glob import glob
+import json
 
 class Command(BaseCommand):
     help =\
     """Update the overview pdfs of all tribes in a current checkout"""
 
-    def handle(self, directory = WIDELANDS_SVN_DIR, **kwargs):
-        tribes = [d for d in glob("%s/tribes/*" % directory)
-                    if os.path.isdir(d)]
+    def handle(self, directory = os.path.normpath(WIDELANDS_SVN_DIR + "/data/map_object_info"), **kwargs):
+        source_file = open(os.path.normpath(directory + "/tribes.json"), "r")
+        tribesinfo = json.load(source_file)
 
         print "updating pdf files for all tribes"
 
-        for t in tribes:
-            tribename = os.path.basename(t)
+        for t in tribesinfo['tribes']:
+            tribename = t['name']
             print "  updating pdf file for tribe ", tribename
             gdir = make_graph(tribename)
             pdffile = path.join(gdir, tribename + ".pdf")

=== modified file 'wlhelp/models.py'
--- wlhelp/models.py	2012-05-19 19:55:15 +0000
+++ wlhelp/models.py	2016-02-28 18:22:18 +0000
@@ -73,6 +73,8 @@
         return self.all().filter(size="I")
     def port(self):
         return self.all().filter(size="P")
+    def headquarters(self):
+        return self.all().filter(size="H")
 
 
         # return self.build_wares.count()
@@ -86,16 +88,17 @@
             ('B', 'big'),
             ('I', 'mine'),
             ('P', 'port'),
+            ('H', 'headquarters'),
     )
     TYPES = (
             ('P', 'productionsite'),
             ('W', 'warehouse'),
-            ('M', 'military site'),
-            ('T', 'trainings site'),
+            ('M', 'militarysite'),
+            ('T', 'trainingsite')
     )
-    
+
     objects = BuildingManager()
-    
+
     if settings.USE_SPHINX:
         search          = SphinxSearch(
             weights = {

=== modified file 'wlhelp/views.py'
--- wlhelp/views.py	2013-06-14 19:23:53 +0000
+++ wlhelp/views.py	2016-02-28 18:22:18 +0000
@@ -4,7 +4,6 @@
 from .models import Worker, Ware, Building, Tribe
 
 from settings import WIDELANDS_SVN_DIR, MEDIA_ROOT
-import os
 
 def index( request ):
     tribes = Tribe.objects.all().order_by("displayname")
@@ -62,36 +61,33 @@
     # Request all the objects
     buildings = {}
 
-    buildings["headquarters"] = Building.objects.filter(tribe=t,name="headquarters").order_by("displayname")
-
-    all = Building.objects.filter(tribe=t).exclude(name="headquarters")
+    # All headquarters
+    buildings["headquarters"] = Building.objects.filter(size="H",tribe=t).order_by("displayname")
 
     # Now, all small buildings
-    small = all.filter(size="S",tribe=t).order_by("displayname")
+    small = Building.objects.filter(size="S",tribe=t).order_by("displayname")
     buildings["small"] = small.filter(enhanced_from=None)
     buildings["small_enhanced"] = small.exclude(enhanced_from=None)
 
     # Now, all medium buildings
-    medium = all.filter(size="M",tribe=t).order_by("displayname")
+    medium = Building.objects.filter(size="M",tribe=t).order_by("displayname")
     buildings["medium"] = medium.filter(enhanced_from=None)
     buildings["medium_enhanced"] = medium.exclude(enhanced_from=None)
 
     # Now, all big buildings
-    big = all.filter(size="B",tribe=t).order_by("displayname")
+    big = Building.objects.filter(size="B",tribe=t).order_by("displayname")
     buildings["big"] = big.filter(enhanced_from=None)
     buildings["big_enhanced"] = big.exclude(enhanced_from=None)
 
     # Now, all mines
-    mine = all.filter(size="I",tribe=t).order_by("displayname")
+    mine = Building.objects.filter(size="I",tribe=t).order_by("displayname")
     buildings["mine"] = mine.filter(enhanced_from=None)
     buildings["mine_enhanced"] = mine.exclude(enhanced_from=None)
 
     # Now, all ports
-    port = all.filter(size="P",tribe=t).order_by("displayname")
+    port = Building.objects.filter(size="P",tribe=t).order_by("displayname")
     buildings["port"] = port.filter(enhanced_from=None)
     buildings["port_enhanced"] = port.exclude(enhanced_from=None)
 
     return render_to_response('wlhelp/buildings.html', context_instance=RequestContext(request,
         { "buildings": buildings, "tribe": t }))
-
-


Follow ups