<commit_before>/* ************************************************************************

   qooxdoo - the new era of web development

   http://qooxdoo.org

   Copyright:
     2017 <NAME>

   License:
     MIT: https://opensource.org/licenses/MIT
     See the LICENSE file in the project's top-level directory for details.

   Authors:
     * <NAME> (<EMAIL>, @cboulanger)

************************************************************************ */

/*global qxcli*/

require("../Contrib");

require("qooxdoo");
const download = require('download');
const fs = qx.tool.compiler.utils.Promisify.fs;
const path = require('upath');
const process = require('process');
const jsonlint = require("jsonlint");

/**
 * Installs a contrib libraries
 */
qx.Class.define("qx.tool.cli.commands.contrib.Install", {
  extend: qx.tool.cli.commands.Contrib,

  statics: {
    getYargsCommand: function() {
      return {
        command: 'install [repository]',
        describe: 'installs the latest compatible release of a contrib library (as per Manifest.json). Use "-r <release tag>" to install a particular release.',
        builder: {
          "release" : {
            alias: 'r',
            describe: 'use a specific release tag instead of the tag of the latest compatible release',
            nargs: 1,
            requiresArg: true,
            type: "string" 
          },
          "verbose": {
            alias: 'v',
            describe: 'Verbose logging'
          },
          'quiet': {
            alias: 'q',
            describe: 'No output'
          }
        },
        handler: function(argv) {
          return new qx.tool.cli.commands.contrib.Install(argv)
            .process()
            .catch((e) => {
              console.error(e.stack || e.message);
              process.exit(1);
            });
        }
      };
    }
  },

  members: {

    /**
     * Lists contrib libraries compatible with the current project
     */
    process: async function() {
  
      let argv = this.argv;
      let repos_cache = this.getCache().repos;

      if ( repos_cache.list.length == 0 ){
        throw new qx.tool.cli.Utils.UserError("You need to execute 'qx contrib update' first.");
      }

      if (!argv.repository) {
        this.__loadFromContrib();
        return;
      }
   
      let qooxdoo_version = await this.getUserQxVersion();
      if(argv.verbose) console.log(`>>> qooxdoo version:  ${qooxdoo_version}`);
     
      // has a repository name been given?
      if (!argv.repository) {
        throw new qx.tool.cli.Utils.UserError("No repo name given");
      }
      let repo_name = argv.repository;
      if( ! this.getCache().repos.data[repo_name] ){
        throw new qx.tool.cli.Utils.UserError(`'${repo_name}' does not exist or is not a contrib library.`);
      }
      // get compatible tag name unless a release name has been given
      let tag_name = argv.release;
      if ( ! tag_name ){
        if ( this.getCache().compat[qooxdoo_version] === undefined ){
          throw new qx.tool.cli.Utils.UserError("You need to execute 'qx contrib list' first.");
        }      
        tag_name = this.getCache().compat[qooxdoo_version][repo_name];
        if ( ! tag_name ){
          throw new qx.tool.cli.Utils.UserError(`'${repo_name}' has no stable release compatible with qooxdoo version ${qooxdoo_version}.`);
        }           
      }

      let { release_data, download_path } = await this.__download(repo_name, tag_name);

      // read libraries array from contrib.json
      let data = await this.getContribData();

      // iterate over contained libraries
      let library_elem = null;
      for( let { info, path:filename } of release_data.manifests ) {
        // does the repository name already exist?
        let index = data.libraries.findIndex((elem)=>{
          return elem.repo_name == repo_name 
            && elem.library_name == info.name;
        });
        library_elem = {
          library_name : info.name,
          library_version : info.version,
          repo_name : repo_name,
          repo_tag : tag_name,
          path : path.relative(process.cwd(), path.join(download_path, path.dirname(filename)))
        };
        if( index >= 0 ){
          data.libraries[index]=library_elem;
          if (! argv.quiet) console.info(`Updating already existing config.json entry '${info.name}'.`);
        } else {
          data.libraries.push(library_elem);
        }
      }
      await fs.writeFileAsync(this.getContribFileName(), JSON.stringify(data, null, 2), "utf-8");
      await this.installApplication(repo_name);
      if (argv.verbose) 
        console.info(">>> Done.");
      return 
    },
    
    installApplication: async function(repoName) {
      let contribJson = await this.getContribData();
      let libraryJson = contribJson.libraries.find(data => data.repo_name == repoName);
      if (!libraryJson)
        throw new Error("Repo for " + repoName + " is not installed as a contrib");
      
      let manifest = await qx.tool.compiler.utils.Json.loadJsonAsync(path.join(libraryJson.path, "Manifest.json"), "utf8");
      if (!manifest.provides || !manifest.provides.application) {
        if (this.argv.verbose) 
          console.info(">>> No applications to install.");
        return;
      }
      
      let compileJson = await qx.tool.compiler.utils.Json.loadJsonAsync("compile.json");
      let manifestApp = manifest.provides.application;
      let app = compileJson.applications.find(app => {
        if (manifestApp.name && app.name)
          return manifestApp.name == app.name;
        return manifestApp["class"] == app["class"];
      });
      if (!app) {
        compileJson.applications.push(manifestApp);
        app = manifestApp;
      } else {
        for (let key in manifestApp)
          app[key] = manifestApp[key];
      }
      if (this.argv.verbose) 
        console.info(">>> Installed application " + (app.name||app["class"]));
      
      return await qx.tool.compiler.utils.Json.saveJsonAsync("compile.json", compileJson);
    },

    __loadFromContrib: async function() {<commit_msg>fix another typo<commit_after>/* ************************************************************************

   qooxdoo - the new era of web development

   http://qooxdoo.org

   Copyright:
     2017 <NAME>

   License:
     MIT: https://opensource.org/licenses/MIT
     See the LICENSE file in the project's top-level directory for details.

   Authors:
     * <NAME> (<EMAIL>, @cboulanger)

************************************************************************ */

/*global qxcli*/

require("../Contrib");

require("qooxdoo");
const download = require('download');
const fs = qx.tool.compiler.utils.Promisify.fs;
const path = require('upath');
const process = require('process');
const jsonlint = require("jsonlint");

/**
 * Installs a contrib libraries
 */
qx.Class.define("qx.tool.cli.commands.contrib.Install", {
  extend: qx.tool.cli.commands.Contrib,

  statics: {
    getYargsCommand: function() {
      return {
        command: 'install [repository]',
        describe: 'installs the latest compatible release of a contrib library (as per Manifest.json). Use "-r <release tag>" to install a particular release.',
        builder: {
          "release" : {
            alias: 'r',
            describe: 'use a specific release tag instead of the tag of the latest compatible release',
            nargs: 1,
            requiresArg: true,
            type: "string" 
          },
          "verbose": {
            alias: 'v',
            describe: 'Verbose logging'
          },
          'quiet': {
            alias: 'q',
            describe: 'No output'
          }
        },
        handler: function(argv) {
          return new qx.tool.cli.commands.contrib.Install(argv)
            .process()
            .catch((e) => {
              console.error(e.stack || e.message);
              process.exit(1);
            });
        }
      };
    }
  },

  members: {

    /**
     * Lists contrib libraries compatible with the current project
     */
    process: async function() {
  
      let argv = this.argv;
      let repos_cache = this.getCache().repos;

      if ( repos_cache.list.length == 0 ){
        throw new qx.tool.cli.Utils.UserError("You need to execute 'qx contrib update' first.");
      }

      if (!argv.repository) {
        this.__loadFromContrib();
        return;
      }
   
      let qooxdoo_version = await this.getUserQxVersion();
      if(argv.verbose) console.log(`>>> qooxdoo version:  ${qooxdoo_version}`);
     
      // has a repository name been given?
      if (!argv.repository) {
        throw new qx.tool.cli.Utils.UserError("No repo name given");
      }
      let repo_name = argv.repository;
      if( ! this.getCache().repos.data[repo_name] ){
        throw new qx.tool.cli.Utils.UserError(`'${repo_name}' does not exist or is not a contrib library.`);
      }
      // get compatible tag name unless a release name has been given
      let tag_name = argv.release;
      if ( ! tag_name ){
        if ( this.getCache().compat[qooxdoo_version] === undefined ){
          throw new qx.tool.cli.Utils.UserError("You need to execute 'qx contrib list' first.");
        }      
        tag_name = this.getCache().compat[qooxdoo_version][repo_name];
        if ( ! tag_name ){
          throw new qx.tool.cli.Utils.UserError(`'${repo_name}' has no stable release compatible with qooxdoo version ${qooxdoo_version}.`);
        }           
      }

      let { release_data, download_path } = await this.__download(repo_name, tag_name);

      // read libraries array from contrib.json
      let data = await this.getContribData();

      // iterate over contained libraries
      let library_elem = null;
      for( let { info, path:filename } of release_data.manifests ) {
        // does the repository name already exist?
        let index = data.libraries.findIndex((elem)=>{
          return elem.repo_name == repo_name 
            && elem.library_name == info.name;
        });
        library_elem = {
          library_name : info.name,
          library_version : info.version,
          repo_name : repo_name,
          repo_tag : tag_name,
          path : path.relative(process.cwd(), path.join(download_path, path.dirname(filename)))
        };
        if( index >= 0 ){
          data.libraries[index]=library_elem;
          if (! argv.quiet) console.info(`Updating already existing config.json entry '${info.name}'.`);
        } else {
          data.libraries.push(library_elem);
        }
      }
      await fs.writeFileAsync(this.getContribFileName(), JSON.stringify(data, null, 2), "utf-8");
      await this.installApplication(repo_name);
      if (argv.verbose) 
        console.info(">>> Done.");
      return 
    },
    
    installApplication: async function(repoName) {
      let contribJson = await this.getContribData();
      let libraryJson = contribJson.libraries.find(data => data.repo_name == repoName);
      if (!libraryJson)
        throw new Error("Repo for " + repoName + " is not installed as a contrib");
      
      let manifest = await qx.tool.compiler.utils.Json.loadJsonAsync(path.join(libraryJson.path, "Manifest.json"), "utf8");
      if (!manifest.provides || !manifest.provides.application) {
        if (this.argv.verbose) 
          console.info(">>> No application to install.");
        return;
      }
      
      let compileJson = await qx.tool.compiler.utils.Json.loadJsonAsync("compile.json");
      let manifestApp = manifest.provides.application;
      let app = compileJson.applications.find(app => {
        if (manifestApp.name && app.name)
          return manifestApp.name == app.name;
        return manifestApp["class"] == app["class"];
      });
      if (!app) {
        compileJson.applications.push(manifestApp);
        app = manifestApp;
      } else {
        for (let key in manifestApp)
          app[key] = manifestApp[key];
      }
      if (this.argv.verbose) 
        console.info(">>> Installed application " + (app.name||app["class"]));
      
      return await qx.tool.compiler.utils.Json.saveJsonAsync("compile.json", compileJson);
    },

    __loadFromContrib: async function() {
{'fraction_non_alphanumeric': 0.14773098269670257, 'fraction_numerical': 0.0017956252040483187, 'mean_word_length': 2.308938698352687, 'pattern_counts': {'":': 2, '<': 11, '<?xml version=': 0, '>': 45, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1550378', 'n_tokens_mistral': 3552, 'n_tokens_neox': 3451, 'n_words': 844}