Add check-rpc.py for Travis.

develop
Ben Lubar 2018-07-04 13:22:04 -05:00
parent 5db34339a5
commit 3b6a0738a0
No known key found for this signature in database
GPG Key ID: 018BAB45DB2D2B24
6 changed files with 165 additions and 0 deletions

@ -51,6 +51,7 @@ script:
- cd ..
- cp travis/dfhack_travis.init "$DF_FOLDER"/
- python travis/run-tests.py "$DF_FOLDER"
- python travis/check-rpc.py "$DF_FOLDER/dfhack-rpc.txt"
notifications:
email: false
irc:

@ -54,6 +54,7 @@ using namespace std;
#include "modules/Graphic.h"
#include "modules/Windows.h"
#include "RemoteServer.h"
#include "RemoteTools.h"
#include "LuaTools.h"
#include "DFHackVersion.h"
@ -632,6 +633,9 @@ string getBuiltinCommand(std::string cmd)
else if (cmd == "clear")
builtin = "cls";
else if (cmd == "devel/dump-rpc")
builtin = "devel/dump-rpc";
return builtin;
}
@ -1278,6 +1282,34 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
return CR_WRONG_USAGE;
}
}
else if (builtin == "devel/dump-rpc")
{
if (parts.size() == 1)
{
std::ofstream file(parts[0]);
CoreService core;
core.dumpMethods(file);
for (auto & it : *plug_mgr)
{
Plugin * plug = it.second;
if (!plug)
continue;
std::unique_ptr<RPCService> svc(plug->rpc_connect(con));
if (!svc)
continue;
file << "// Plugin: " << plug->getName() << endl;
svc->dumpMethods(file);
}
}
else
{
con << "Usage: devel/dump-rpc \"filename\"" << endl;
return CR_WRONG_USAGE;
}
}
else if (RunAlias(con, first, parts, res))
{
return res;

@ -109,6 +109,24 @@ void RPCService::finalize(ServerConnection *owner, std::vector<ServerFunctionBas
}
}
void RPCService::dumpMethods(std::ostream & out) const
{
for (auto fn : functions)
{
std::string in_name = fn->p_in_template->GetTypeName();
size_t last_dot = in_name.rfind('.');
if (last_dot != std::string::npos)
in_name = in_name.substr(last_dot + 1);
std::string out_name = fn->p_out_template->GetTypeName();
last_dot = out_name.rfind('.');
if (last_dot != std::string::npos)
out_name = out_name.substr(last_dot + 1);
out << "// RPC " << fn->name << " : " << in_name << " -> " << out_name << endl;
}
}
ServerConnection::ServerConnection(CActiveSocket *socket)
: socket(socket), stream(this)
{

@ -151,6 +151,7 @@ namespace DFHack
class DFHACK_EXPORT RPCService {
friend class ServerConnection;
friend class Plugin;
friend class Core;
std::vector<ServerFunctionBase*> functions;
std::map<std::string, ServerFunctionBase*> lookup;
@ -208,6 +209,8 @@ namespace DFHack
assert(!owner);
functions.push_back(new VoidServerMethod<Svc,In>(this, name, flags, fptr));
}
void dumpMethods(std::ostream & out) const;
};
class ServerConnection {

@ -0,0 +1,109 @@
import glob
import sys
actual = {'': {}}
with open(sys.argv[1]) as f:
plugin_name = ''
for line in f:
line = line.rstrip()
if line.startswith('// Plugin: '):
plugin_name = line.split(' ')[2]
if plugin_name not in actual:
actual[plugin_name] = {}
elif line.startswith('// RPC '):
parts = line.split(' ')
actual[plugin_name][parts[2]] = (parts[4], parts[6])
expected = {'': {}}
for p in glob.iglob('library/proto/*.proto'):
with open(p) as f:
for line in f:
line = line.rstrip()
if line.startswith('// RPC '):
parts = line.split(' ')
expected[''][parts[2]] = (parts[4], parts[6])
for p in glob.iglob('plugins/proto/*.proto'):
plugin_name = ''
with open(p) as f:
for line in f:
line = line.rstrip()
if line.startswith('// Plugin: '):
plugin_name = line.split(' ')[2]
if plugin_name not in expected:
expected[plugin_name] = {}
break
if plugin_name == '':
continue
with open(p) as f:
for line in f:
line = line.rstrip()
if line.startswith('// RPC '):
parts = line.split(' ')
expected[plugin_name][parts[2]] = (parts[4], parts[6])
error_count = 0
for plugin_name in actual:
methods = actual[plugin_name]
if plugin_name not in expected:
print('Missing documentation for plugin proto files: ' + plugin_name)
print('Add the following lines:')
print('// Plugin: ' + plugin_name)
error_count += 1
for m in methods:
io = methods[m]
print('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1])
error_count += 1
else:
missing = []
wrong = []
for m in methods:
io = methods[m]
if m in expected[plugin_name]:
if expected[plugin_name][m] != io:
wrong.add('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1])
else:
missing.add('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1])
if len(missing) > 0:
print('Incomplete documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Add the following lines:')
for m in missing:
print(m)
error_count += 1
if len(wrong) > 0:
print('Incorrect documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Replace the following comments:')
for m in wrong:
print(m)
error_count += 1
for plugin_name in expected:
methods = expected[plugin_name]
if plugin_name not in actual:
print('Incorrect documentation for plugin proto files: ' + plugin_name)
print('The following methods are documented, but the plugin does not provide any RPC methods:')
for m in methods:
io = methods[m]
print('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1])
error_count += 1
else:
missing = []
for m in methods:
io = methods[m]
if m not in actual[plugin_name]:
missing.add('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1])
if len(missing) > 0:
print('Incorrect documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Remove the following lines:')
for m in missing:
print(m)
error_count += 1
sys.exit(min(100, error_count))

@ -1,2 +1,4 @@
devel/dump-rpc dfhack-rpc.txt
:lua dfhack.internal.addScriptPath(os.getenv('TRAVIS_BUILD_DIR'))
test/main