whole_func_string: async function() {
        var parsedArgs = await this.__parseImpl();
        var config = {};
        var contribConfig = {
          version: qx.tool.cli.ConfigSchemas.lockfile.version
        };
  
        if (parsedArgs.config) {
          config = await this.__loadJson(parsedArgs.config);
          let lockfile = qx.tool.cli.ConfigSchemas.lockfile.filename;
          try {
            var name = path.join(path.dirname(parsedArgs.config), lockfile);
            contribConfig = await this.__loadJson(name);
          } catch (ex) {
            // Nothing
          }
          // check semver-type compatibility (i.e. compatible as long as major version stays the same)
          let schemaVersion = semver.coerce(qx.tool.cli.ConfigSchemas.lockfile.version, true).raw;
          let fileVersion = contribConfig.version ? semver.coerce(contribConfig.version, true).raw : "1.0.0";
          if (semver.major(schemaVersion) > semver.major(fileVersion)) {
            if (this.argv.force) {
              let config = {
                verbose: this.argv.verbose,
                quite: this.argv.quiet,
                save: false
              };
              const installer = new qx.tool.cli.commands.contrib.Install(config);
              let filepath = installer.getContribFileName();
              let backup = filepath + ".old";
              await fs.copyFileAsync(filepath, backup);
              if (!this.argv.quiet) {
                console.info(`A backup of ${lockfile} has been saved to ${backup}, in case you need to revert to it.`);
              }
              await installer.deleteContribData();
              for (let lib of contribConfig.libraries) {
                if (!await installer.isInstalled(lib.uri, lib.repo_tag)) {
                  if (lib.repo_tag) {
                    await installer.install(lib.uri, lib.repo_tag);
                  } else if (lib.path && fs.existsSync(lib.path)) {
                    await installer.installFromLocaPath(lib.path, lib.uri);
                  }
                } else if (this.argv.verbose) {
                  console.info(`>>> ${lib.uri}@${lib.repo_tag} is already installed.`);
                }
              }
              contribConfig = await installer.getContribData();
            } else {
              throw new qx.tool.cli.Utils.UserError(
                `*** Warning ***\n` +
                `The schema of '${lockfile}' has changed. Execute 'qx clean && qx compile --force' to delete and regenerate it.\n` +
                `You might have to re-apply manual modifications to '${lockfile}'.`
              );
            }
          }
        }
        this._mergeArguments(parsedArgs, config, contribConfig);
        if (config.libraries) {
          for (const aPath of config.libraries) {
            if (typeof aPath === "object" && typeof aPath.path === "string") {
              throw new Error("Configuration for libraries has changed - it is now an array of strings, each of which is a path to the directory containing Manifest.json.  Please run 'qx upgrade'");
            }
            await this.__loadJs(path.join(aPath, "compile.js"), config);
          }
        }
        return config;
      }
func_code_string: async function() {
        var parsedArgs = await this.__parseImpl();
        var config = {};
        var contribConfig = {
          version: qx.tool.cli.ConfigSchemas.lockfile.version
        };
  
        if (parsedArgs.config) {
          config = await this.__loadJson(parsedArgs.config);
          let lockfile = qx.tool.cli.ConfigSchemas.lockfile.filename;
          try {
            var name = path.join(path.dirname(parsedArgs.config), lockfile);
            contribConfig = await this.__loadJson(name);
          } catch (ex) {
            // Nothing
          }
          // check semver-type compatibility (i.e. compatible as long as major version stays the same)
          let schemaVersion = semver.coerce(qx.tool.cli.ConfigSchemas.lockfile.version, true).raw;
          let fileVersion = contribConfig.version ? semver.coerce(contribConfig.version, true).raw : "1.0.0";
          if (semver.major(schemaVersion) > semver.major(fileVersion)) {
            if (this.argv.force) {
              let config = {
                verbose: this.argv.verbose,
                quite: this.argv.quiet,
                save: false
              };
              const installer = new qx.tool.cli.commands.contrib.Install(config);
              let filepath = installer.getContribFileName();
              let backup = filepath + ".old";
              await fs.copyFileAsync(filepath, backup);
              if (!this.argv.quiet) {
                console.info(`A backup of ${lockfile} has been saved to ${backup}, in case you need to revert to it.`);
              }
              await installer.deleteContribData();
              for (let lib of contribConfig.libraries) {
                if (!await installer.isInstalled(lib.uri, lib.repo_tag)) {
                  if (lib.repo_tag) {
                    await installer.install(lib.uri, lib.repo_tag);
                  } else if (lib.path && fs.existsSync(lib.path)) {
                    await installer.installFromLocaPath(lib.path, lib.uri);
                  }
                } else if (this.argv.verbose) {
                  console.info(`>>> ${lib.uri}@${lib.repo_tag} is already installed.`);
                }
              }
              contribConfig = await installer.getContribData();
            } else {
              throw new qx.tool.cli.Utils.UserError(
                `*** Warning ***\n` +
                `The schema of '${lockfile}' has changed. Execute 'qx clean && qx compile --force' to delete and regenerate it.\n` +
                `You might have to re-apply manual modifications to '${lockfile}'.`
              );
            }
          }
        }
        this._mergeArguments(parsedArgs, config, contribConfig);
        if (config.libraries) {
          for (const aPath of config.libraries) {
            if (typeof aPath === "object" && typeof aPath.path === "string") {
              throw new Error("Configuration for libraries has changed - it is now an array of strings, each of which is a path to the directory containing Manifest.json.  Please run 'qx upgrade'");
            }
            await this.__loadJs(path.join(aPath, "compile.js"), config);
          }
        }
        return config;
      }
func_documentation_string: Parses the command line and produces configuration data
  
  Loads a configuration file from a .js or .json file; if you provide a .js
  file the file MUST return a function.
  If there is also a .json, then it is loaded and parsed first.
  
  The Function returned from a .js file MUST accept two arguments, one for the
  data (which will be null if there is no .json) and the second is the callback
  to call when complete; the callback takes an error object and the output
  configuration data.
  
  Configuration files do not support processes, job executions, or even
  macros - if you want to add basic processing (eg for macros), use a .js file to
  manipulate the data.  If you want to customise the Maker that is produced, you
  need to use the API directly.