<commit_before>// System Objects
var path = require('path');
var http = require('http');
var path = require('path');
var url = require('url');

// Third Party Dependencies
var fs = require('fs-extra');
var tags = require('common-tags');
var tar = require('tar');
var toml = require('toml');
var Reader = require('fstream').Reader;

// Internal
var commands = require('../commands');
var lists = require('./lists/rust');
var log = require('../../log');
var Tessel = require('../tessel');

function bundle(_opts) {
  //TODO use _opts

  return rust.getBuildConfig()
  .catch(e => {
    console.error('Could not find all the components for cross-compiling Rust.')
    console.error(e.message);
    console.error('Please run "t2 sdk install" and try again.')
    console.error('NOTE: Cross-compilation is only supported on Rust stable builds.')
    process.exit(1);
  })
  .then(_config => config = _config)
  .then(() => rust.cargoMetadata())
  .then(metadata => {
    // Get first package.
    var pkg = metadata.packages.pop();
    var bins = pkg.targets.filter(target => target.kind.indexOf('bin') > -1);

    // Filter by --bin argument.
    var idx = process.argv.indexOf('--bin');
    var name = idx > -1 ? process.argv[idx + 1] : null;
    var validbins = bins;
    if (name != null) {
      validbins = validbins.filter(bin => bin.name == process.argv[idx + 1]);
    }

    // Throw if multiple bins exist.
    if (validbins.length == 0) {
      if (name) {
        console.error(`No binary target "${name}" exists for this Rust crate.\nMake sure you specify a valid binary using --bin. e.g.:`)
        bins.forEach(bin => {
          console.error('    t2 run Cargo.toml --bin', bin.name);
        })
      } else {
        console.error('No binary targets exist for this Rust crate.\nPlease add a binary and try again.')
      }
      process.exit(1);
    }
    if (validbins.length > 1) {
      console.error('Multiple binary targets exist for this Rust crate.\nPlease specify one by name with --bin. e.g.:')
      bins.forEach(bin => {
        console.error('    t2 run Cargo.toml --bin', bin.name);
      })
      process.exit(1);
    }

    var out = validbins[0];
    var dest = path.join(path.dirname(pkg.manifest_path), 'target/tessel2/release', out.name);

    config.name = out.name;
    config.path = dest;
  })
  .then(() => rust.buildTessel(config))
  .then(() => rust.bundleTessel(config))
  .then(tarball => {
    return {
      name: config.name,
      tarball: fs.readFileSync(tarball),
    };
  });
};


var exportables = {
  meta: {
    name: 'rust',
    extname: 'rs',
    binary: '.',
    entry: 'src/main.rs',
    configuration: 'Cargo.toml',
    checkConfiguration: (pushdir, basename, program) => {
      var cargoToml = toml.parse(fs.readFileSync(path.join(pushdir, 'Cargo.toml'), 'utf8'));

      if (cargoToml.package) {
        basename = pushdir;
        program = cargoToml.package.name;
      }

      return {
        basename,
        program
      };
    },
    shell: (options) => {
      return tags.stripIndent `
        #!/bin/sh
        exec /app/remote-script/${options.resolvedEntryPoint} ${options.subargs.join(' ')}
      `;
    },
  },
  lists: lists,
};

// The Rust prebundle step just updated the resolvedEntryPoint
// property with the Rust binary name
exportables.preBundle = function(opts) {
  return new Promise((resolve, reject) => {
    // Get details of the project
    var details = exportables.meta.checkConfiguration(opts.target);

    // If it was unable to fetch the details
    if (typeof details !== 'object') {
      // Abort the deploy
      return reject('Unable to parse Cargo.toml');
    } else {
      // Update the resolved entry point to the program name
      //TODO opts.resolvedEntryPoint = details.program;
      // Continue with the deploy
      resolve();
    }
  });
};

// This must implement a Promise that resolves with a Buffer
// that represents a DIRECTORY containing the compiled Rust
// executable.
exportables.tarBundle = function(opts) {
  return bundle(opts).then(data => {
    opts.resolvedEntryPoint = data.name;
    return opts.tarball;
  });
  // return exportables.remoteRustCompilation(opts);
};

/*
exportables.postRun = function(tessel, options) {
  return Promise.resolve();<commit_msg>Rust deployment now works properly.<commit_after>// System Objects
var path = require('path');
var http = require('http');
var path = require('path');
var url = require('url');

// Third Party Dependencies
var fs = require('fs-extra');
var tags = require('common-tags');
var tar = require('tar');
var toml = require('toml');
var Reader = require('fstream').Reader;

// Internal
var commands = require('../commands');
var lists = require('./lists/rust');
var log = require('../../log');
var Tessel = require('../tessel');
var sdk = require('../../sdk');

function bundle(_opts) {
  //TODO use _opts

  return sdk.getBuildConfig()
  .catch(e => {
    console.error('Could not find all the components for cross-compiling Rust.')
    console.error(e.message);
    console.error('Please run "t2 sdk install" and try again.')
    console.error('NOTE: Cross-compilation is only supported on Rust stable builds.')
    process.exit(1);
  })
  .then(_config => config = _config)
  .then(() => sdk.cargoMetadata())
  .then(metadata => {
    // Get first package.
    var pkg = metadata.packages.pop();
    var bins = pkg.targets.filter(target => target.kind.indexOf('bin') > -1);

    // Filter by --bin argument.
    var idx = process.argv.indexOf('--bin');
    var name = idx > -1 ? process.argv[idx + 1] : null;
    var validbins = bins;
    if (name != null) {
      validbins = validbins.filter(bin => bin.name == process.argv[idx + 1]);
    }

    // Throw if multiple bins exist.
    if (validbins.length == 0) {
      if (name) {
        console.error(`No binary target "${name}" exists for this Rust crate.\nMake sure you specify a valid binary using --bin. e.g.:`)
        bins.forEach(bin => {
          console.error('    t2 run Cargo.toml --bin', bin.name);
        })
      } else {
        console.error('No binary targets exist for this Rust crate.\nPlease add a binary and try again.')
      }
      process.exit(1);
    }
    if (validbins.length > 1) {
      console.error('Multiple binary targets exist for this Rust crate.\nPlease specify one by name with --bin. e.g.:')
      bins.forEach(bin => {
        console.error('    t2 run Cargo.toml --bin', bin.name);
      })
      process.exit(1);
    }

    var out = validbins[0];
    var dest = path.join(path.dirname(pkg.manifest_path), 'target/tessel2/release', out.name);

    config.name = out.name;
    config.path = dest;
  })
  .then(() => sdk.buildTessel(config))
  .then(() => sdk.bundleTessel(config))
  .then(tarball => {
    return {
      name: config.name,
      tarball: fs.readFileSync(tarball),
    };
  });
};


var exportables = {
  meta: {
    name: 'rust',
    extname: 'rs',
    binary: '.',
    entry: 'src/main.rs',
    configuration: 'Cargo.toml',
    checkConfiguration: (pushdir, basename, program) => {
      var cargoToml = toml.parse(fs.readFileSync(path.join(pushdir, 'Cargo.toml'), 'utf8'));

      if (cargoToml.package) {
        basename = pushdir;
        program = cargoToml.package.name;
      }

      return {
        basename,
        program
      };
    },
    shell: (options) => {
      return tags.stripIndent `
        #!/bin/sh
        exec /app/remote-script/${options.resolvedEntryPoint} ${options.subargs.join(' ')}
      `;
    },
  },
  lists: lists,
};

// The Rust prebundle step just updated the resolvedEntryPoint
// property with the Rust binary name
exportables.preBundle = function(opts) {
  return new Promise((resolve, reject) => {
    // Get details of the project
    var details = exportables.meta.checkConfiguration(opts.target);

    // If it was unable to fetch the details
    if (typeof details !== 'object') {
      // Abort the deploy
      return reject('Unable to parse Cargo.toml');
    } else {
      // Update the resolved entry point to the program name
      //TODO opts.resolvedEntryPoint = details.program;
      // Continue with the deploy
      resolve();
    }
  });
};

// This must implement a Promise that resolves with a Buffer
// that represents a DIRECTORY containing the compiled Rust
// executable.
exportables.tarBundle = function(opts) {
  return bundle(opts).then(data => {
    opts.resolvedEntryPoint = data.name;
    return data.tarball;
  });
  // return exportables.remoteRustCompilation(opts);
};

/*
exportables.postRun = function(tessel, options) {
  return Promise.resolve();
{'fraction_non_alphanumeric': 0.15035937862276838, 'fraction_numerical': 0.0034778576396939484, 'mean_word_length': 2.7249568221070812, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4599915', 'n_tokens_mistral': 2704, 'n_tokens_neox': 2609, 'n_words': 732}