THRIFT-3221 Create a tool to audit network compatibility between two
.thrift files
Client: Compiler (general)
Patch: Sanjay Poojary <sanjay.poojary@ni.com>, Ben Craig
<bencraig@apache.org>, and Zach Hindes <zach.hindes@ni.com>
This closes #541
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
index 97d523e..a337cc6 100644
--- a/compiler/cpp/src/main.cc
+++ b/compiler/cpp/src/main.cc
@@ -51,6 +51,7 @@
#include "parse/t_program.h"
#include "parse/t_scope.h"
#include "generate/t_generator.h"
+#include "audit/t_audit.h"
#include "version.h"
@@ -169,6 +170,17 @@
bool gen_recurse = false;
/**
+ * Flags to control thrift audit
+ */
+bool g_audit = false;
+
+/**
+ * Flag to control return status
+ */
+bool g_return_failure = false;
+bool g_audit_fatal = true;
+
+/**
* Win32 doesn't have realpath, so use fallback implementation in that case,
* otherwise this just calls through to realpath
*/
@@ -711,6 +723,13 @@
fprintf(stderr, " Keys and values are options passed to the generator.\n");
fprintf(stderr, " Many options will not require values.\n");
fprintf(stderr, "\n");
+ fprintf(stderr, "Options related to audit operation\n");
+ fprintf(stderr, " --audit OldFile Old Thrift file to be audited with 'file'\n");
+ fprintf(stderr, " -Iold dir Add a directory to the list of directories\n");
+ fprintf(stderr, " searched for include directives for old thrift file\n");
+ fprintf(stderr, " -Inew dir Add a directory to the list of directories\n");
+ fprintf(stderr, " searched for include directives for new thrift file\n");
+ fprintf(stderr, "\n");
fprintf(stderr, "Available generators (and options):\n");
t_generator_registry::gen_map_t gen_map = t_generator_registry::get_generator_map();
@@ -1029,6 +1048,30 @@
}
}
+void audit(t_program* new_program, t_program* old_program, string new_thrift_include_path, string old_thrift_include_path)
+{
+ vector<string> temp_incl_searchpath = g_incl_searchpath;
+ if(!old_thrift_include_path.empty()) {
+ g_incl_searchpath.push_back(old_thrift_include_path);
+ }
+
+ parse(old_program, NULL);
+
+ g_incl_searchpath = temp_incl_searchpath;
+ if(!new_thrift_include_path.empty()) {
+ g_incl_searchpath.push_back(new_thrift_include_path);
+ }
+
+ parse(new_program, NULL);
+
+ compare_namespace(new_program, old_program);
+ compare_services(new_program->get_services(), old_program->get_services());
+ compare_enums(new_program->get_enums(), old_program->get_enums());
+ compare_structs(new_program->get_structs(), old_program->get_structs());
+ compare_structs(new_program->get_xceptions(), old_program->get_xceptions());
+ compare_consts(new_program->get_consts(), old_program->get_consts());
+}
+
/**
* Parse it up.. then spit it back out, in pretty much every language. Alright
* not that many languages, but the cool ones that we care about.
@@ -1049,6 +1092,9 @@
}
vector<string> generator_strings;
+ string old_thrift_include_path;
+ string new_thrift_include_path;
+ string old_input_file;
// Set the current path to a dummy value to make warning messages clearer.
g_curpath = "arguments";
@@ -1118,6 +1164,35 @@
#endif
if (!check_is_directory(out_path.c_str()))
return -1;
+ } else if (strcmp(arg, "-audit") == 0) {
+ g_audit = true;
+ arg = argv[++i];
+ if (arg == NULL) {
+ fprintf(stderr, "Missing old thrift file name for audit operation\n");
+ usage();
+ }
+ char old_thrift_file_rp[THRIFT_PATH_MAX];
+
+ if (saferealpath(arg, old_thrift_file_rp) == NULL) {
+ failure("Could not open input file with realpath: %s", arg);
+ }
+ old_input_file = string(old_thrift_file_rp);
+ } else if(strcmp(arg, "-audit-nofatal") == 0){
+ g_audit_fatal = false;
+ } else if (strcmp(arg, "-Iold") == 0) {
+ arg = argv[++i];
+ if (arg == NULL) {
+ fprintf(stderr, "Missing Include directory for old thrift file\n");
+ usage();
+ }
+ old_thrift_include_path = string(arg);
+ } else if (strcmp(arg, "-Inew") == 0) {
+ arg = argv[++i];
+ if(arg == NULL) {
+ fprintf(stderr, "Missing Include directory for new thrift file\n");
+ usage();
+ }
+ new_thrift_include_path = string(arg);
} else {
fprintf(stderr, "Unrecognized option: %s\n", arg);
usage();
@@ -1139,41 +1214,6 @@
exit(0);
}
- // You gotta generate something!
- if (generator_strings.empty()) {
- fprintf(stderr, "No output language(s) specified\n");
- usage();
- }
-
- // Real-pathify it
- char rp[THRIFT_PATH_MAX];
- if (argv[i] == NULL) {
- fprintf(stderr, "Missing file name\n");
- usage();
- }
- if (saferealpath(argv[i], rp) == NULL) {
- failure("Could not open input file with realpath: %s", argv[i]);
- }
- string input_file(rp);
-
- // Instance of the global parse tree
- t_program* program = new t_program(input_file);
- if (out_path.size()) {
- program->set_out_path(out_path, out_path_is_absolute);
- }
-
- // Compute the cpp include prefix.
- // infer this from the filename passed in
- string input_filename = argv[i];
- string include_prefix;
-
- string::size_type last_slash = string::npos;
- if ((last_slash = input_filename.rfind("/")) != string::npos) {
- include_prefix = input_filename.substr(0, last_slash);
- }
-
- program->set_include_prefix(include_prefix);
-
// Initialize global types
g_type_void = new t_base_type("void", t_base_type::TYPE_VOID);
g_type_string = new t_base_type("string", t_base_type::TYPE_STRING);
@@ -1188,24 +1228,87 @@
g_type_i64 = new t_base_type("i64", t_base_type::TYPE_I64);
g_type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE);
- // Parse it!
- parse(program, NULL);
+ if(g_audit)
+ {
+ // Audit operation
- // The current path is not really relevant when we are doing generation.
- // Reset the variable to make warning messages clearer.
- g_curpath = "generation";
- // Reset yylineno for the heck of it. Use 1 instead of 0 because
- // That is what shows up during argument parsing.
- yylineno = 1;
+ if (old_input_file.empty()) {
+ fprintf(stderr, "Missing file name of old thrift file for audit\n");
+ usage();
+ }
- // Generate it!
- generate(program, generator_strings);
+ char new_thrift_file_rp[THRIFT_PATH_MAX];
+ if (argv[i] == NULL) {
+ fprintf(stderr, "Missing file name of new thrift file for audit\n");
+ usage();
+ }
+ if (saferealpath(argv[i], new_thrift_file_rp) == NULL) {
+ failure("Could not open input file with realpath: %s", argv[i]);
+ }
+ string new_input_file(new_thrift_file_rp);
+
+ t_program new_program(new_input_file);
+ t_program old_program(old_input_file);
+
+ audit(&new_program, &old_program, new_thrift_include_path, old_thrift_include_path);
+
+ } else {
+ // Generate options
+
+ // You gotta generate something!
+ if (generator_strings.empty()) {
+ fprintf(stderr, "No output language(s) specified\n");
+ usage();
+ }
+
+ // Real-pathify it
+ char rp[THRIFT_PATH_MAX];
+ if (argv[i] == NULL) {
+ fprintf(stderr, "Missing file name\n");
+ usage();
+ }
+ if (saferealpath(argv[i], rp) == NULL) {
+ failure("Could not open input file with realpath: %s", argv[i]);
+ }
+ string input_file(rp);
+
+ // Instance of the global parse tree
+ t_program* program = new t_program(input_file);
+ if (out_path.size()) {
+ program->set_out_path(out_path, out_path_is_absolute);
+ }
+
+ // Compute the cpp include prefix.
+ // infer this from the filename passed in
+ string input_filename = argv[i];
+ string include_prefix;
+
+ string::size_type last_slash = string::npos;
+ if ((last_slash = input_filename.rfind("/")) != string::npos) {
+ include_prefix = input_filename.substr(0, last_slash);
+ }
+
+ program->set_include_prefix(include_prefix);
+
+ // Parse it!
+ parse(program, NULL);
+
+ // The current path is not really relevant when we are doing generation.
+ // Reset the variable to make warning messages clearer.
+ g_curpath = "generation";
+ // Reset yylineno for the heck of it. Use 1 instead of 0 because
+ // That is what shows up during argument parsing.
+ yylineno = 1;
+
+ // Generate it!
+ generate(program, generator_strings);
+ delete program;
+ }
// Clean up. Who am I kidding... this program probably orphans heap memory
// all over the place, but who cares because it is about to exit and it is
// all referenced and used by this wacky parse tree up until now anyways.
- delete program;
delete g_type_void;
delete g_type_string;
delete g_type_bool;
@@ -1216,5 +1319,9 @@
delete g_type_double;
// Finished
+ if (g_return_failure && g_audit_fatal) {
+ exit(2);
+ }
+ // Finished
return 0;
}