/** >HEADER Copyright (c) 2013 -- 2017 Rob Patro rob.patro@cs.stonybrook.edu This file is part of salmon. salmon is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. salmon is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with salmon. If not, see .
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // C++ string formatting library #include "spdlog/fmt/fmt.h" #include "GenomicFeature.hpp" #include "SalmonConfig.hpp" #include "VersionChecker.hpp" #include "SalmonIndex.hpp" int help(const std::vector& /*opts*/) { fmt::MemoryWriter helpMsg; helpMsg.write("salmon v{}\n\n", salmon::version); helpMsg.write( "Usage: salmon -h|--help or \n" " salmon -v|--version or \n" " salmon -c|--cite or \n" " salmon [--no-version-check] [-h | options]\n\n"); helpMsg.write("Commands:\n"); helpMsg.write(" index : create a salmon index\n"); helpMsg.write(" quant : quantify a sample\n"); helpMsg.write(" alevin : single cell analysis\n"); helpMsg.write(" swim : perform super-secret operation\n"); helpMsg.write(" quantmerge : merge multiple quantifications into a single file\n"); std::cout << helpMsg.str(); return 0; } int dualModeMessage() { auto helpmsg = R"( =============== salmon quant has two modes --- one quantifies expression using raw reads and the other makes use of already-aligned reads (in BAM/SAM format). Which algorithm is used depends on the arguments passed to salmon quant. If you provide salmon with alignments '-a [ --alignments ]' then the alignment-based algorithm will be used, otherwise the algorithm for quantifying from raw reads will be used. to view the help for salmon's selective-alignment-based mode, use the command salmon quant --help-reads To view the help for salmon's alignment-based mode, use the command salmon quant --help-alignment )"; std::cout << " salmon v" << salmon::version << helpmsg << "\n"; return 0; } typedef std::function& index)> SubCmdType; /** * Bonus! */ int salmonSwim(int /*argc*/, const char* /*argv*/[], std::unique_ptr& /*index*/) { std::cout << R"( _____ __ / ___/____ _/ /___ ___ ____ ____ \__ \/ __ `/ / __ `__ \/ __ \/ __ \ ___/ / /_/ / / / / / / / /_/ / / / / /____/\__,_/_/_/ /_/ /_/\____/_/ /_/ )"; return 0; } /** * Citation */ void printCite() { std::cout << R"( If you use salmon in your research, please cite the publication in any papers, pre-prints or reports. The proper citation information for salmon appears below. Reference: ========== Rob Patro, Geet Duggal, Michael I. Love, Rafael A. Irizarry, Carl Kingsford. Salmon provides fast and bias-aware quantification of transcript expression. Nature Methods. 2017;14(4):417-419. doi: 10.1038/nmeth.4197 bibtex: ======= @article{Patro2017Salmon, doi = {10.1038/nmeth.4197}, url = {https://doi.org/10.1038%2Fnmeth.4197}, year = {2017}, month = {mar}, publisher = {{Springer Nature}}, volume = {14}, number = {4}, pages = {417--419}, author = {Rob Patro and Geet Duggal and Michael I Love and Rafael A Irizarry and Carl Kingsford}, title = {Salmon provides fast and bias-aware quantification of transcript expression}, journal = {{Nature Methods}} } )"; } int salmonIndex(int argc, const char* argv[], std::unique_ptr& index); int salmonQuantify(int argc, const char* argv[], std::unique_ptr& index); int salmonAlignmentQuantify(int argc, const char* argv[], std::unique_ptr& index); int salmonAlignmentDualMode(int argc, const char* argv[], std::unique_ptr& index); // TODO : PF_INTEGRATION int salmonBarcoding(int argc, const char* argv[], std::unique_ptr& index); int salmonQuantMerge(int argc, const char* argv[], std::unique_ptr& index); bool verbose = false; int main(int argc, const char* argv[]) { using std::string; namespace po = boost::program_options; std::setlocale(LC_ALL, "en_US.UTF-8"); // With no arguments, print help if (argc == 1) { std::vector o; help(o); // argc, argv); std::exit(1); } try { // subcommand parsing code inspired by : // https://gist.github.com/randomphrase/10801888 po::options_description sfopts("Allowed Options"); sfopts.add_options()("version,v", "print version string")( "no-version-check", "don't check with the server to see if this is the latest version")( "cite,c", "show citation information")( "help,h", "produce help message")("command", po::value(), "command to run {index, quant, sf}")( "subargs", po::value>(), "Arguments for command"); po::options_description all("Allowed Options"); all.add(sfopts); po::positional_options_description pd; pd.add("command", 1).add("subargs", -1); po::variables_map vm; po::parsed_options parsed = po::command_line_parser(argc, argv) .options(all) .positional(pd) .allow_unregistered() .run(); po::store(parsed, vm); if (vm.count("version")) { std::cout << "salmon " << salmon::version << "\n"; std::exit(0); } if (vm.count("help") and !vm.count("command")) { std::vector o; help(o); std::exit(0); } if (vm.count("cite") and !vm.count("command")) { printCite(); std::exit(0); } const char* no_version_env_ptr = std::getenv("SALMON_NO_VERSION_CHECK"); std::string no_version_env = (no_version_env_ptr == nullptr) ? "" : std::string(no_version_env_ptr); std::transform(no_version_env.begin(), no_version_env.end(), no_version_env.begin(), [](unsigned char c){ return std::toupper(c); } // correct ); bool skip_version_check = vm.count("no-version-check") or (no_version_env == "1") or (no_version_env == "TRUE") or (no_version_env == "T"); if (!skip_version_check) { std::string versionMessage = getVersionMessage(); std::cerr << versionMessage; } // po::notify(vm); std::string cmd = vm["command"].as(); std::vector opts = po::collect_unrecognized(parsed.options, po::include_positional); opts.erase(opts.begin()); // if there was a help and a command, then add the help back since it was // parsed if (vm.count("help")) { opts.insert(opts.begin(), "--help"); } std::unordered_map cmds( {{"index", salmonIndex}, {"quant", salmonAlignmentDualMode}, {"quantmerge", salmonQuantMerge}, // TODO : PF_INTEGRATION {"alevin", salmonBarcoding}, {"swim", salmonSwim}}); /* //string cmd = vm["command"].as(); int subCommandArgc = argc - topLevelArgc + 1; char** argv2 = new char*[subCommandArgc]; argv2[0] = argv[0]; std::copy_n( &argv[topLevelArgc], argc-topLevelArgc, &argv2[1] ); */ std::unique_ptr preloadedIndex; int32_t nargc = opts.size() + 1; std::unique_ptr argv2(new const char*[nargc]); argv2[0] = argv[0]; for (int32_t i = 0; i < nargc - 1; ++i) { argv2[i + 1] = opts[i].c_str(); } const char** nargv = argv2.get(); while(true) { auto cmdMain = cmds.find(cmd); if (cmdMain == cmds.end()) { // help(subCommandArgc, argv2); return help(opts); } return cmdMain->second(nargc, nargv, preloadedIndex); } } catch (po::error& e) { std::cerr << "Program Option Error (main) : [" << e.what() << "].\n Exiting.\n"; std::exit(1); } catch (...) { std::cerr << argv[0] << " was invoked improperly.\n"; std::cerr << "For usage information, try " << argv[0] << " --help\nExiting.\n"; } return 0; } int salmonAlignmentDualMode(int argc, const char* argv[], std::unique_ptr& index) { // If the command is quant; determine whether // we're quantifying with raw sequences or alignments if (argc < 2) { return dualModeMessage(); } // detect mode-specific help request if (strncmp(argv[1], "--help-alignment", 16) == 0) { const char* helpArgv[] = {argv[0], "--help", nullptr}; return salmonAlignmentQuantify(2, helpArgv, index); } else if (strncmp(argv[1], "--help-reads", 12) == 0) { const char* helpArgv[] = {argv[0], "--help", nullptr}; return salmonQuantify(2, helpArgv, index); } // detect general help request if (strncmp(argv[1], "--help", 6) == 0 or strncmp(argv[1], "-h", 2) == 0) { return dualModeMessage(); } // otherwise, detect and dispatch the correct mode bool useSalmonAlign{false}; for (int i = 0; i < argc; ++i) { if (strncmp(argv[i], "-a", 2) == 0 or strncmp(argv[i], "-e", 2) == 0 or strncmp(argv[i], "--alignments", 12) == 0 or strncmp(argv[i], "--eqclasses", 11) == 0) { useSalmonAlign = true; break; } } if (useSalmonAlign) { return salmonAlignmentQuantify(argc, argv, index); } else { return salmonQuantify(argc, argv, index); } }