"""
This script rebuilds "src/netedit/templates.h" the files
representing the templates.
It does this by parsing the data from the sumo data dir.
"""
from __future__ import print_function
from __future__ import absolute_import
import sys
import os
import re
import subprocess
import io
from os.path import dirname, join
from glob import glob
TOOLS = [
"detector/edgeDataFromFlow.py",
"detector/flowFromEdgeData.py",
"detector/mapDetectors.py",
"district/filterDistricts.py",
"district/gridDistricts.py",
"district/stationDistricts.py",
"drt/drtOrtools.py",
"import/citybrain/citybrain_flow.py",
"import/citybrain/citybrain_infostep.py",
"import/citybrain/citybrain_road.py",
"import/dxf/dxf2jupedsim.py",
"import/gtfs/gtfs2fcd.py",
"import/gtfs/gtfs2pt.py",
"import/vissim/vissim_parseRoutes.py",
"import/visum/visum_convertEdgeTypes.py",
"net/abstractRail.py",
"net/createRoundaboutConnections.py",
"net/net2geojson.py",
"net/net2jpsgeometry.py",
"net/net2kml.py",
"net/net2poly.py",
"net/netcheck.py",
"net/netdiff.py",
"net/netmatch.py",
"net/network_statistics.py",
"net/reduceLanes.py",
"net/split_at_stops.py",
"route/addStopDelay.py",
"route/addStops2Routes.py",
"route/addTAZ.py",
"route/checkStopOrder.py",
"route/implausibleRoutes.py",
"route/route2OD.py",
"route/route2poly.py",
"route/route2sel.py",
"route/routecheck.py",
"route/routecompare.py",
"route/routeStats.py",
"route/scaleTimeLine.py",
"route/sort_routes.py",
"route/splitRandom.py",
"route/splitRouteFiles.py",
"route/tracegenerator.py",
"route/tracemapper.py",
"output/aggregateBatteryOutput.py",
"output/analyze_pedestrian_jam.py",
"output/analyze_teleports.py",
"output/attributeStats.py",
"output/attributeDiff.py",
"output/attributeCompare.py",
"output/computeCoordination.py",
"output/computePassengerCounts.py",
"output/computeStoppingPlaceUsage.py",
"output/countLaneChanges.py",
"output/edgeDataDiff.py",
"output/fcdDiff.py",
"output/generateTLSE2Detectors.py",
"output/parkingSearchTraffic.py",
"output/scheduleStats.py",
"output/stopOrder.py",
"output/tripinfoByType.py",
"output/vehLanes.py",
"output/vehrouteCountValidation.py",
"output/vehrouteDiff.py",
"output/walkFactor.py",
"shapes/circlePolygon.py",
"tls/createTlsCsv.py",
"tls/tls_csvSignalGroups.py",
"turn-defs/generateTurnRatios.py",
"turn-defs/turnCount2EdgeCount.py",
"turn-defs/turnFile2EdgeRelations.py",
"visualization/plot_csv_bars.py",
"visualization/plot_csv_pie.py",
"visualization/plot_csv_timeline.py",
"visualization/plot_net_dump.py",
"visualization/plot_net_selection.py",
"visualization/plot_net_speeds.py",
"visualization/plot_net_trafficLights.py",
"visualization/plot_summary.py",
"visualization/plotXMLAttributes.py",
"xml/csv2xml.py",
"xml/xml2csv.py",
"xml/changeAttribute.py",
"xml/filterElements.py",
"countEdgeUsage.py",
"createVehTypeDistribution.py",
"edgesInDistricts.py",
"fcdReplay.py",
"findAllRoutes.py",
"generateBidiDistricts.py",
"generateContinuousRerouters.py",
"generateParkingAreaRerouters.py",
"generateParkingAreas.py",
"generateRailSignalConstraints.py",
"generateRerouters.py",
"osmGet.py",
"plot_trajectories.py",
"ptlines2flows.py",
"randomTrips.py",
"routeSampler.py",
"runSeeds.py",
"stateReplay.py",
"tileGet.py",
"tlsCoordinator.py",
"tlsCycleAdaptation.py",
"jtcrouter.py",
"distributeChargingStations.py",
"traceExporter.py",
"createScreenshotSequence.py",
"averageTripStatistics.py",
"generateLandmarks.py",
"assign/duaIterateMix.py",
"assign/duaIterate_analysis.py",
"assign/duaIterate_reroutingAnalysis.py",
"assign/one-shot.py",
"assign/costFunctionChecker.py",
"assign/duaIterate.py",
"detector/aggregateFlows.py",
"detector/filterFlows.py",
"detector/flowFromRoutes.py",
"detector/flowrouter.py",
"detector/routeUsage.py",
"detector/validate.py",
"detector/plotFlows.py",
"drt/drtOnline.py",
"import/matsim/matsim_importPlans.py",
"import/osm/osmTaxiStop.py",
"import/vissim/convert_detectors2SUMO.py",
"import/vissim/convert_vissimXML_flows_statRoutes.py",
"import/vissim/tls_vissimXML2SUMOnet_update.py",
"import/vissim/vissim2poly.py",
"import/vissim/vissim_parseBusStops.py",
"import/visum/visum_convertRoutes.py",
"import/visum/visum_convertTurnPercentages.py",
"import/visum/visum_parseZaehlstelle.py",
"import/opendrive/signal_POIs_from_xodr.py",
"output/generateMeanDataDefinitions.py",
"output/edgeDepartDelay.py",
"output/vehroute2amitranOD.py",
"output/tripinfoByTAZ.py",
"output/tripinfoDiff.py",
"route/route_departOffset.py",
"route/cutTrips.py",
"route/driveways2poly.py",
"route/addParkingAreaStops2Trips.py",
"route/analyzePersonPlans.py",
"route/addParkingAreaStops2Routes.py",
"route/cutRoutes.py",
"route/route2alts.py",
"route/route_1htoDay.py",
"route/geoTrip2POI.py",
"visualization/macrOutput.py",
"visualization/plotWKT.py",
"xml/protobuf2xml.py",
"xml/xml2protobuf.py",
"district/aggregateAndSplitMatrices.py",
"district/countConnectionsInDistricts.py",
"district/districtMapper.py",
"emissions/hbefa2sumo.py",
"net/buildFullGraph.py",
"net/generateStationEdges.py",
"net/patchVClasses.py",
"shapes/poly2edgedata.py",
"tls/buildTransitions.py",
"tls/tls_csv2SUMO.py",
"trigger/csv2vss.py",
"trigger/meandata2vss.py",
]
PATH_MAPPING = {
"import/dxf": "import",
"import/osm": "import",
"import/matsim": "import",
"import/opendrive": "import",
}
SOURCE_DEPS = [
"microsim/MSFrame.cpp", "microsim/devices/*.cpp",
"utils/common/RandHelper.cpp", "utils/common/SystemFrame.cpp",
"utils/geom/GeoConvHelper.cpp",
]
def buildTemplateToolHeader(templateHeaderFile):
print(
u"#pragma once\n"
"#include <string>\n"
"#include <vector>\n"
"\n"
"// @brief template tool\n"
"struct TemplateTool {\n"
"\n"
" // @brief constructor\n"
" TemplateTool(const std::string name_, const std::string pythonPath_,\n"
" const std::string subfolder_, const std::string templateStr_) :\n"
" name(name_),\n"
" pythonPath(pythonPath_),\n"
" subfolder(subfolder_),\n"
" templateStr(templateStr_) {\n"
" }\n"
"\n"
" // @brief tool name\n"
" const std::string name;\n"
"\n"
" // @brief python path\n"
" const std::string pythonPath;\n"
"\n"
" // @brief subfolder path\n"
" const std::string subfolder;\n"
"\n"
" // @brief tool template\n"
" const std::string templateStr;\n"
"};\n",
file=templateHeaderFile)
def formatBinTemplate(templateStr):
"""
@brief parse binary of a bin template (sumo, netconvert, etc.)
"""
templateStr = templateStr.replace("\\r", '')
templateStr = templateStr.replace('"', '\\"')
return templateStr.replace("\n", '"\n "')
def formatToolTemplate(templateStr):
"""
@brief format python tool template
"""
if templateStr == '' or templateStr[0] != "<":
return '""'
templateStr = re.sub("(?<=value)(.*)(?=netedit)", "", templateStr)
templateStr = templateStr.replace('netedit', '="')
templateStr = templateStr.replace('"', '\\"')
return templateStr.replace("<", '"<').replace("\n", '"\n')
def generateTemplate(app, appBin):
"""
@brief generate template for the given app
"""
print("Obtaining " + app + " template")
env = dict(os.environ)
env["LSAN_OPTIONS"] = "suppressions=%s/../../build_config/clang_memleak_suppressions.txt" % dirname(__file__)
env["UBSAN_OPTIONS"] = "suppressions=%s/../../build_config/clang_ubsan_suppressions.txt" % dirname(__file__)
try:
template = formatBinTemplate(subprocess.check_output(
[appBin, "--save-template", "stdout"], env=env, universal_newlines=True))
except subprocess.CalledProcessError as e:
sys.stderr.write("Error when generating template for " + app + ": '%s'" % e)
template = ""
return u'const std::string %sTemplate = "%s";\n' % (app, template)
def _collectOutput(procs, toolPaths, failed, verbose, testFailure):
result = u""
for p, toolPath in zip(procs, toolPaths):
toolName = os.path.basename(toolPath)[:-3]
d = os.path.dirname(toolPath)
result += 'TemplateTool("%s", "tools/%s", "%s",\n' % (toolName, toolPath, PATH_MAPPING.get(d, d))
stdout, stderr = p.communicate()
if p.returncode:
failed.append(toolPath if testFailure else toolName)
if verbose:
print("Cannot generate tool template for %s: '%s'." % (toolName, stderr), file=sys.stderr)
result += '""'
else:
result += formatToolTemplate(stdout)
result += '),\n'
return result
def generateToolTemplates(toolDir, toolPaths, verbose, testFailure=False):
"""
@brief generate tool template
"""
print("Obtaining tool templates.")
procs = []
result = u""
failed = []
paths = []
env = dict(os.environ)
if "SUMO_HOME" not in env:
env["SUMO_HOME"] = join(dirname(__file__), '..', '..')
for toolPath in toolPaths:
toolName = os.path.basename(toolPath)[:-3]
if verbose:
print("Obtaining '" + toolName + "' tool template.")
procs.append(subprocess.Popen([sys.executable, join(toolDir, toolPath), "--save-template", "stdout"], env=env,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True))
paths.append(toolPath)
if len(procs) == 32:
result += _collectOutput(procs, paths, failed, verbose, testFailure)
procs = []
paths = []
result += _collectOutput(procs, paths, failed, verbose, testFailure)
if testFailure:
return failed
if failed:
print("Could not generate tool templates for %s." % (", ".join(failed)), file=sys.stderr)
return result
def checkMod(toolDir, reference):
mtime = os.path.getmtime(reference)
for root, _, files in os.walk(toolDir):
for f in files:
if f[-3:] == ".py" and os.path.getmtime(join(root, f)) > mtime:
return True
srcDir = join(dirname(toolDir), 'src')
for p in SOURCE_DEPS:
for f in glob(join(srcDir, p)):
if os.path.getmtime(f) > mtime:
return True
return False
def main():
if len(sys.argv) != 3:
sys.exit("Arguments: <pathToSumo> <pathToNetgenerate>")
toolDir = join(dirname(__file__), '..')
if not os.path.exists("templates.h") or checkMod(toolDir, "templates.h"):
with io.open("templates.h", 'w', encoding='utf8') as templateHeaderFile:
buildTemplateToolHeader(templateHeaderFile)
is_debug = sys.argv[1].endswith("D") or sys.argv[1].endswith("D.exe")
print(u"const std::vector<TemplateTool> templateTools {\n", file=templateHeaderFile)
print(generateToolTemplates(toolDir, TOOLS, is_debug), file=templateHeaderFile)
print(u"};\n", file=templateHeaderFile)
print(generateTemplate("sumo", sys.argv[1]), file=templateHeaderFile)
print(generateTemplate("netgenerate", sys.argv[2]), file=templateHeaderFile)
if __name__ == "__main__":
main()