void t_go_generator::generate_service_remote()

in compiler/cpp/src/thrift/generate/t_go_generator.cc [2266:2826]


void t_go_generator::generate_service_remote(t_service* tservice) {
  vector<t_function*> functions;
  std::unordered_map<std::string, std::string> func_to_service;

  // collect all functions including inherited functions
  t_service* parent = tservice;
  while (parent != nullptr) {
    vector<t_function*> p_functions = parent->get_functions();
    functions.insert(functions.end(), p_functions.begin(), p_functions.end());

    // We need to maintain a map of functions names to the name of their parent.
    // This is because functions may come from a parent service, and if we need
    // to create the arguments struct (e.g. `NewParentServiceNameFuncNameArgs()`)
    // we need to make sure to specify the correct service name.
    for (vector<t_function*>::iterator f_iter = p_functions.begin(); f_iter != p_functions.end(); ++f_iter) {
      auto it = func_to_service.find((*f_iter)->get_name());
      if (it == func_to_service.end()) {
        func_to_service.emplace((*f_iter)->get_name(), parent->get_name());
      }
    }

    parent = parent->get_extends();
  }

  // This file is not useful if there are no functions; don't generate it
  if (functions.size() == 0) {
    return;
  }

  string f_remote_dir = package_dir_ + "/" + underscore(service_name_) + "-remote";
  MKDIR(f_remote_dir.c_str());

  vector<t_function*>::iterator f_iter;
  string f_remote_name = f_remote_dir + "/"
                         + underscore(service_name_) + "-remote.go";
  ofstream_with_content_based_conditional_update f_remote;
  f_remote.open(f_remote_name.c_str());

  string unused_protection;

  std::vector<string> system_packages;
  system_packages.push_back("context");
  system_packages.push_back("flag");
  system_packages.push_back("fmt");
  system_packages.push_back("math");
  system_packages.push_back("net");
  system_packages.push_back("net/url");
  system_packages.push_back("os");
  system_packages.push_back("strconv");
  system_packages.push_back("strings");
  // For the thrift import, always do rename import to make sure it's called thrift.
  system_packages.push_back("thrift \"" + gen_thrift_import_ + "\"");

  f_remote << go_autogen_comment();
  f_remote << indent() << "package main" << '\n' << '\n';
  f_remote << indent() << "import (" << '\n';
  f_remote << render_system_packages(system_packages);
  f_remote << indent() << render_included_programs(unused_protection);
  f_remote << render_program_import(program_, unused_protection);
  f_remote << indent() << ")" << '\n';
  f_remote << indent() << '\n';
  f_remote << indent() << unused_protection; // filled in render_included_programs()
  f_remote << indent() << '\n';
  f_remote << indent() << "func Usage() {" << '\n';
  indent_up();
  f_remote << indent() << "fmt.Fprintln(os.Stderr, \"Usage of \", os.Args[0], \" "
                          "[-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:\")"
           << '\n';
  f_remote << indent() << "flag.PrintDefaults()" << '\n';
  f_remote << indent() << "fmt.Fprintln(os.Stderr, \"\\nFunctions:\")" << '\n';

  string package_name_aliased = package_identifiers_[get_real_go_module(program_)];

  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    f_remote << indent() << "fmt.Fprintln(os.Stderr, \"  " << (*f_iter)->get_returntype()->get_name() << " "
             << (*f_iter)->get_name() << "(";
    t_struct* arg_struct = (*f_iter)->get_arglist();
    const std::vector<t_field*>& args = arg_struct->get_members();
    std::vector<t_field*>::size_type num_args = args.size();
    bool first = true;

    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
      if (first) {
        first = false;
      } else {
        f_remote << ", ";
      }

      f_remote << args[i]->get_type()->get_name() << " " << args[i]->get_name();
    }

    f_remote << ")\")" << '\n';
  }

  f_remote << indent() << "fmt.Fprintln(os.Stderr)" << '\n';
  f_remote << indent() << "os.Exit(0)" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  f_remote << indent() << '\n';

  f_remote << indent() << "type httpHeaders map[string]string" << '\n';
  f_remote << indent() << '\n';
  f_remote << indent() << "func (h httpHeaders) String() string {" << '\n';
  indent_up();
  f_remote << indent() << "var m map[string]string = h" << '\n';
  f_remote << indent() << "return fmt.Sprintf(\"%s\", m)" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  f_remote << indent() << '\n';
  f_remote << indent() << "func (h httpHeaders) Set(value string) error {" << '\n';
  indent_up();
  f_remote << indent() << "parts := strings.Split(value, \": \")" << '\n';
  f_remote << indent() << "if len(parts) != 2 {" << '\n';
  indent_up();
  f_remote << indent() << "return fmt.Errorf(\"header should be of format 'Key: Value'\")" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  f_remote << indent() << "h[parts[0]] = parts[1]" << '\n';
  f_remote << indent() << "return nil" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  f_remote << indent() << '\n';

  f_remote << indent() << "func main() {" << '\n';
  indent_up();
  f_remote << indent() << "flag.Usage = Usage" << '\n';
  f_remote << indent() << "var host string" << '\n';
  f_remote << indent() << "var port int" << '\n';
  f_remote << indent() << "var protocol string" << '\n';
  f_remote << indent() << "var urlString string" << '\n';
  f_remote << indent() << "var framed bool" << '\n';
  f_remote << indent() << "var useHttp bool" << '\n';
  f_remote << indent() << "headers := make(httpHeaders)" << '\n';
  f_remote << indent() << "var parsedUrl *url.URL" << '\n';
  f_remote << indent() << "var trans thrift.TTransport" << '\n';
  f_remote << indent() << "_ = strconv.Atoi" << '\n';
  f_remote << indent() << "_ = math.Abs" << '\n';
  f_remote << indent() << "flag.Usage = Usage" << '\n';
  f_remote << indent() << "flag.StringVar(&host, \"h\", \"localhost\", \"Specify host and port\")"
           << '\n';
  f_remote << indent() << "flag.IntVar(&port, \"p\", 9090, \"Specify port\")" << '\n';
  f_remote << indent() << "flag.StringVar(&protocol, \"P\", \"binary\", \""
                          "Specify the protocol (binary, compact, simplejson, json)\")" << '\n';
  f_remote << indent() << "flag.StringVar(&urlString, \"u\", \"\", \"Specify the url\")" << '\n';
  f_remote << indent() << "flag.BoolVar(&framed, \"framed\", false, \"Use framed transport\")"
           << '\n';
  f_remote << indent() << "flag.BoolVar(&useHttp, \"http\", false, \"Use http\")" << '\n';
  f_remote << indent() << "flag.Var(headers, \"H\", \"Headers to set on the http(s) request (e.g. -H \\\"Key: Value\\\")\")" << '\n';
  f_remote << indent() << "flag.Parse()" << '\n';
  f_remote << indent() << '\n';
  f_remote << indent() << "if len(urlString) > 0 {" << '\n';
  indent_up();
  f_remote << indent() << "var err error" << '\n';
  f_remote << indent() << "parsedUrl, err = url.Parse(urlString)" << '\n';
  f_remote << indent() << "if err != nil {" << '\n';
  indent_up();
  f_remote << indent() << "fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << '\n';
  f_remote << indent() << "flag.Usage()" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  f_remote << indent() << "host = parsedUrl.Host" << '\n';
  f_remote << indent() << "useHttp = len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == \"http\" || parsedUrl.Scheme == \"https\""
           << '\n';
  indent_down();
  f_remote << indent() << "} else if useHttp {" << '\n';
  indent_up();
  f_remote << indent() << "_, err := url.Parse(fmt.Sprint(\"http://\", host, \":\", port))"
           << '\n';
  f_remote << indent() << "if err != nil {" << '\n';
  indent_up();
  f_remote << indent() << "fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << '\n';
  f_remote << indent() << "flag.Usage()" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  f_remote << indent() << '\n';
  f_remote << indent() << "cmd := flag.Arg(0)" << '\n';
  f_remote << indent() << "var err error" << '\n';
  f_remote << indent() << "var cfg *thrift.TConfiguration = nil" << '\n';
  f_remote << indent() << "if useHttp {" << '\n';
  indent_up();
  f_remote << indent() << "trans, err = thrift.NewTHttpClient(parsedUrl.String())" << '\n';
  f_remote << indent() << "if len(headers) > 0 {" << '\n';
  indent_up();
  f_remote << indent() << "httptrans := trans.(*thrift.THttpClient)" << '\n';
  f_remote << indent() << "for key, value := range headers {" << '\n';
  indent_up();
  f_remote << indent() << "httptrans.SetHeader(key, value)" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  indent_down();
  f_remote << indent() << "} else {" << '\n';
  indent_up();
  f_remote << indent() << "portStr := fmt.Sprint(port)" << '\n';
  f_remote << indent() << "if strings.Contains(host, \":\") {" << '\n';
  indent_up();
  f_remote << indent() << "host, portStr, err = net.SplitHostPort(host)" << '\n';
  f_remote << indent() << "if err != nil {" << '\n';
  indent_up();
  f_remote << indent() << "fmt.Fprintln(os.Stderr, \"error with host:\", err)"
           << '\n';
  f_remote << indent() << "os.Exit(1)" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  f_remote << indent() << "trans = thrift.NewTSocketConf(net.JoinHostPort(host, portStr), cfg)" << '\n';
  f_remote << indent() << "if err != nil {" << '\n';
  indent_up();
  f_remote << indent() << "fmt.Fprintln(os.Stderr, \"error resolving address:\", err)" << '\n';
  f_remote << indent() << "os.Exit(1)" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  f_remote << indent() << "if framed {" << '\n';
  indent_up();
  f_remote << indent() << "trans = thrift.NewTFramedTransportConf(trans, cfg)" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  f_remote << indent() << "if err != nil {" << '\n';
  indent_up();
  f_remote << indent() << "fmt.Fprintln(os.Stderr, \"Error creating transport\", err)" << '\n';
  f_remote << indent() << "os.Exit(1)" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  f_remote << indent() << "defer trans.Close()" << '\n';
  f_remote << indent() << "var protocolFactory thrift.TProtocolFactory" << '\n';
  f_remote << indent() << "switch protocol {" << '\n';
  f_remote << indent() << "case \"compact\":" << '\n';
  indent_up();
  f_remote << indent() << "protocolFactory = thrift.NewTCompactProtocolFactoryConf(cfg)" << '\n';
  indent_down();
  f_remote << indent() << "case \"simplejson\":" << '\n';
  indent_up();
  f_remote << indent() << "protocolFactory = thrift.NewTSimpleJSONProtocolFactoryConf(cfg)" << '\n';
  indent_down();
  f_remote << indent() << "case \"json\":" << '\n';
  indent_up();
  f_remote << indent() << "protocolFactory = thrift.NewTJSONProtocolFactory()" << '\n';
  indent_down();
  f_remote << indent() << "case \"binary\", \"\":" << '\n';
  indent_up();
  f_remote << indent() << "protocolFactory = thrift.NewTBinaryProtocolFactoryConf(cfg)" << '\n';
  indent_down();
  f_remote << indent() << "default:" << '\n';
  indent_up();
  f_remote << indent() << "fmt.Fprintln(os.Stderr, \"Invalid protocol specified: \", protocol)"
           << '\n';
  f_remote << indent() << "Usage()" << '\n';
  f_remote << indent() << "os.Exit(1)" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  f_remote << indent() << "iprot := protocolFactory.GetProtocol(trans)" << '\n';
  f_remote << indent() << "oprot := protocolFactory.GetProtocol(trans)" << '\n';
  f_remote << indent() << "client := " << package_name_aliased << ".New" << publicize(service_name_)
           << "Client(thrift.NewTStandardClient(iprot, oprot))" << '\n';
  f_remote << indent() << "if err := trans.Open(); err != nil {" << '\n';
  indent_up();
  f_remote << indent() << "fmt.Fprintln(os.Stderr, \"Error opening socket to \", "
                          "host, \":\", port, \" \", err)" << '\n';
  f_remote << indent() << "os.Exit(1)" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  f_remote << indent() << '\n';
  f_remote << indent() << "switch cmd {" << '\n';

  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    t_struct* arg_struct = (*f_iter)->get_arglist();
    const std::vector<t_field*>& args = arg_struct->get_members();
    std::vector<t_field*>::size_type num_args = args.size();
    string funcName((*f_iter)->get_name());
    string pubName(publicize(funcName));
    string argumentsName(publicize(funcName + "_args", true, func_to_service[funcName]));
    f_remote << indent() << "case \"" << escape_string(funcName) << "\":" << '\n';
    indent_up();
    f_remote << indent() << "if flag.NArg() - 1 != " << num_args << " {" << '\n';
    indent_up();
    f_remote << indent() << "fmt.Fprintln(os.Stderr, \"" << escape_string(pubName) << " requires "
             << num_args << " args\")" << '\n';
    f_remote << indent() << "flag.Usage()" << '\n';
    indent_down();
    f_remote << indent() << "}" << '\n';

    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
      std::vector<t_field*>::size_type flagArg = i + 1;
      t_type* the_type(args[i]->get_type());
      t_type* the_type2(get_true_type(the_type));

      if (the_type2->is_enum()) {
        f_remote << indent() << "tmp" << i << ", err := (strconv.Atoi(flag.Arg(" << flagArg << ")))"
                 << '\n';
        f_remote << indent() << "if err != nil {" << '\n';
        indent_up();
        f_remote << indent() << "Usage()" << '\n';
        f_remote << indent() << "return" << '\n';
        indent_down();
        f_remote << indent() << "}" << '\n';
        f_remote << indent() << "argvalue" << i << " := " << package_name_aliased << "."
                 << publicize(the_type->get_name()) << "(tmp" << i << ")" << '\n';
      } else if (the_type2->is_base_type()) {
        t_base_type::t_base e = ((t_base_type*)the_type2)->get_base();
        string err(tmp("err"));

        switch (e) {
        case t_base_type::TYPE_VOID:
          break;

        case t_base_type::TYPE_STRING:
          if (the_type2->is_binary()) {
            f_remote << indent() << "argvalue" << i << " := []byte(flag.Arg(" << flagArg << "))"
                     << '\n';
          } else {
            f_remote << indent() << "argvalue" << i << " := flag.Arg(" << flagArg << ")" << '\n';
          }
          break;

        case t_base_type::TYPE_BOOL:
          f_remote << indent() << "argvalue" << i << " := flag.Arg(" << flagArg << ") == \"true\""
                   << '\n';
          break;

        case t_base_type::TYPE_I8:
          f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg("
                   << flagArg << ")))" << '\n';
          f_remote << indent() << "if " << err << " != nil {" << '\n';
          indent_up();
          f_remote << indent() << "Usage()" << '\n';
          f_remote << indent() << "return" << '\n';
          indent_down();
          f_remote << indent() << "}" << '\n';
          f_remote << indent() << "argvalue" << i << " := int8(tmp" << i << ")" << '\n';
          break;

        case t_base_type::TYPE_I16:
          f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg("
                   << flagArg << ")))" << '\n';
          f_remote << indent() << "if " << err << " != nil {" << '\n';
          indent_up();
          f_remote << indent() << "Usage()" << '\n';
          f_remote << indent() << "return" << '\n';
          indent_down();
          f_remote << indent() << "}" << '\n';
          f_remote << indent() << "argvalue" << i << " := int16(tmp" << i << ")" << '\n';
          break;

        case t_base_type::TYPE_I32:
          f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg("
                   << flagArg << ")))" << '\n';
          f_remote << indent() << "if " << err << " != nil {" << '\n';
          indent_up();
          f_remote << indent() << "Usage()" << '\n';
          f_remote << indent() << "return" << '\n';
          indent_down();
          f_remote << indent() << "}" << '\n';
          f_remote << indent() << "argvalue" << i << " := int32(tmp" << i << ")" << '\n';
          break;

        case t_base_type::TYPE_I64:
          f_remote << indent() << "argvalue" << i << ", " << err
                   << " := (strconv.ParseInt(flag.Arg(" << flagArg << "), 10, 64))" << '\n';
          f_remote << indent() << "if " << err << " != nil {" << '\n';
          indent_up();
          f_remote << indent() << "Usage()" << '\n';
          f_remote << indent() << "return" << '\n';
          indent_down();
          f_remote << indent() << "}" << '\n';
          break;

        case t_base_type::TYPE_DOUBLE:
          f_remote << indent() << "argvalue" << i << ", " << err
                   << " := (strconv.ParseFloat(flag.Arg(" << flagArg << "), 64))" << '\n';
          f_remote << indent() << "if " << err << " != nil {" << '\n';
          indent_up();
          f_remote << indent() << "Usage()" << '\n';
          f_remote << indent() << "return" << '\n';
          indent_down();
          f_remote << indent() << "}" << '\n';
          break;

        case t_base_type::TYPE_UUID:
          f_remote << indent() << "argvalue" << i << ", " << err
                   << " := (thrift.ParseTuuid(flag.Arg(" << flagArg << ")))" << '\n';
          f_remote << indent() << "if " << err << " != nil {" << '\n';
          indent_up();
          f_remote << indent() << "Usage()" << '\n';
          f_remote << indent() << "return" << '\n';
          indent_down();
          f_remote << indent() << "}" << '\n';
          break;

        default:
          throw("Invalid base type in generate_service_remote");
        }

        // f_remote << publicize(args[i]->get_name()) << "(strconv.Atoi(flag.Arg(" << flagArg <<
        // ")))";
      } else if (the_type2->is_struct()) {
        string arg(tmp("arg"));
        string mbTrans(tmp("mbTrans"));
        string err1(tmp("err"));
        string factory(tmp("factory"));
        string jsProt(tmp("jsProt"));
        string err2(tmp("err"));
        std::string tstruct_name(publicize(the_type->get_name()));
        std::string tstruct_module( module_name(the_type));
        if(tstruct_module.empty()) {
          tstruct_module = package_name_aliased;
        }

        f_remote << indent() << arg << " := flag.Arg(" << flagArg << ")" << '\n';
        f_remote << indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))"
                 << '\n';
        f_remote << indent() << "defer " << mbTrans << ".Close()" << '\n';
        f_remote << indent() << "_, " << err1 << " := " << mbTrans << ".WriteString(" << arg << ")"
                 << '\n';
        f_remote << indent() << "if " << err1 << " != nil {" << '\n';
        indent_up();
        f_remote << indent() << "Usage()" << '\n';
        f_remote << indent() << "return" << '\n';
        indent_down();
        f_remote << indent() << "}" << '\n';
        f_remote << indent() << factory << " := thrift.NewTJSONProtocolFactory()" << '\n';
        f_remote << indent() << jsProt << " := " << factory << ".GetProtocol(" << mbTrans << ")"
                 << '\n';
        f_remote << indent() << "argvalue" << i << " := " << tstruct_module << ".New" << tstruct_name
                 << "()" << '\n';
        f_remote << indent() << err2 << " := argvalue" << i << "." << read_method_name_ << "(context.Background(), " << jsProt << ")" << '\n';
        f_remote << indent() << "if " << err2 << " != nil {" << '\n';
        indent_up();
        f_remote << indent() << "Usage()" << '\n';
        f_remote << indent() << "return" << '\n';
        indent_down();
        f_remote << indent() << "}" << '\n';
      } else if (the_type2->is_container() || the_type2->is_xception()) {
        string arg(tmp("arg"));
        string mbTrans(tmp("mbTrans"));
        string err1(tmp("err"));
        string factory(tmp("factory"));
        string jsProt(tmp("jsProt"));
        string err2(tmp("err"));
        std::string argName(publicize(args[i]->get_name()));
        f_remote << indent() << arg << " := flag.Arg(" << flagArg << ")" << '\n';
        f_remote << indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))"
                 << '\n';
        f_remote << indent() << "defer " << mbTrans << ".Close()" << '\n';
        f_remote << indent() << "_, " << err1 << " := " << mbTrans << ".WriteString(" << arg << ")"
                 << '\n';
        f_remote << indent() << "if " << err1 << " != nil {" << '\n';
        indent_up();
        f_remote << indent() << "Usage()" << '\n';
        f_remote << indent() << "return" << '\n';
        indent_down();
        f_remote << indent() << "}" << '\n';
        f_remote << indent() << factory << " := thrift.NewTJSONProtocolFactory()" << '\n';
        f_remote << indent() << jsProt << " := " << factory << ".GetProtocol(" << mbTrans << ")"
                 << '\n';
        f_remote << indent() << "containerStruct" << i << " := " << package_name_aliased << ".New"
                 << argumentsName << "()" << '\n';
        f_remote << indent() << err2 << " := containerStruct" << i << ".ReadField" << (i + 1) << "(context.Background(), "
                 << jsProt << ")" << '\n';
        f_remote << indent() << "if " << err2 << " != nil {" << '\n';
        indent_up();
        f_remote << indent() << "Usage()" << '\n';
        f_remote << indent() << "return" << '\n';
        indent_down();
        f_remote << indent() << "}" << '\n';
        f_remote << indent() << "argvalue" << i << " := containerStruct" << i << "." << argName
                 << '\n';
      } else {
        throw("Invalid argument type in generate_service_remote");
      }

      if (the_type->is_typedef()) {
        std::string typedef_module(module_name(the_type));
        if(typedef_module.empty()) {
          typedef_module = package_name_aliased;
        }
        f_remote << indent() << "value" << i << " := " << typedef_module << "."
                 << publicize(the_type->get_name()) << "(argvalue" << i << ")" << '\n';
      } else {
        f_remote << indent() << "value" << i << " := argvalue" << i << '\n';
      }
    }

    f_remote << indent() << "fmt.Print(client." << pubName << "(";
    bool argFirst = true;

    f_remote << "context.Background()";
    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
      if (argFirst) {
        argFirst = false;
        f_remote << ", ";
      } else {
        f_remote << ", ";
      }

      if (args[i]->get_type()->is_enum()) {
        f_remote << "value" << i;
      } else if (args[i]->get_type()->is_base_type()) {
        t_base_type::t_base e = ((t_base_type*)(args[i]->get_type()))->get_base();

        switch (e) {
        case t_base_type::TYPE_VOID:
          break;

        case t_base_type::TYPE_STRING:
        case t_base_type::TYPE_BOOL:
        case t_base_type::TYPE_I8:
        case t_base_type::TYPE_I16:
        case t_base_type::TYPE_I32:
        case t_base_type::TYPE_I64:
        case t_base_type::TYPE_DOUBLE:
        case t_base_type::TYPE_UUID:
          f_remote << "value" << i;
          break;

        default:
          throw("Invalid base type in generate_service_remote");
        }

        // f_remote << publicize(args[i]->get_name()) << "(strconv.Atoi(flag.Arg(" << flagArg <<
        // ")))";
      } else {
        f_remote << "value" << i;
      }
    }

    f_remote << "))" << '\n';
    f_remote << indent() << "fmt.Print(\"\\n\")" << '\n';
    f_remote << indent() << "break" << '\n';
    indent_down();
  }

  f_remote << indent() << "case \"\":" << '\n';
  indent_up();
  f_remote << indent() << "Usage()" << '\n';
  indent_down();
  f_remote << indent() << "default:" << '\n';
  indent_up();
  f_remote << indent() << "fmt.Fprintln(os.Stderr, \"Invalid function \", cmd)" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  indent_down();
  f_remote << indent() << "}" << '\n';
  // Close service file
  f_remote.close();
  format_go_output(f_remote_name);
#ifndef _MSC_VER
  // Make file executable, love that bitwise OR action
  chmod(f_remote_name.c_str(),
        S_IRUSR | S_IWUSR | S_IXUSR
#ifndef _WIN32
        | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
#endif
        );
#endif
}