use clap::{crate_version, App, Arg};
mod auth;
mod config;
mod handlers;
mod submit;
pub const NAME_QUL: &str = "dev";
pub const NAME_ORG: &str = "thud";
pub const NAME_BIN: &str = "caffeine";
pub const AUTH_FILE_NAME: &str = "auth.yml";
pub const AUTH_HELP_MSG: &str = "To generate an API key & secret, go to \
https://codeforces.com/settings/api";
pub const CONF_FILE_NAME: &str = "config.yml";
pub const PROGRAM_TYPE_ID_HELP: &str = "43 GNU GCC C11 5.1.0
52 Clang++17 Diagnostics
42 GNU G++11 5.1.0
50 GNU G++14 6.4.0
54 GNU G++17 7.3.0
2 Microsoft Visual C++ 2010
59 Microsoft Visual C++ 2017
61 GNU G++17 9.2.0 (64 bit, msys 2)
65 C# 8, .NET Core 3.1
9 C# Mono 6.8
28 D DMD32 v2.091.0
32 Go 1.15.6
12 Haskell GHC 8.10.1
60 Java 11.0.6
36 Java 1.8.0_241
48 Kotlin 1.4.0
19 OCaml 4.02.1
3 Delphi 7
4 Free Pascal 3.0.2
51 PascalABC.NET 3.4.2
13 Perl 5.20.1
6 PHP 7.2.13
7 Python 2.7.18
31 Python 3.9.1
40 PyPy 2.7 (7.3.0)
41 PyPy 3.7 (7.3.0)
67 Ruby 3.0.0
49 Rust 1.49.0
20 Scala 2.12.8
34 JavaScript V8 4.8.0
55 Node.js 12.6.3";
fn main() {
let app = App::new("caffeine")
.version(crate_version!())
.about("A CLI tool for accessing codeforces resources")
.author("thud <thud.dev>")
.version_short("v")
.args(&[
Arg::with_name("raw")
.help("Boolean Flag, return raw JSON")
.short("r")
.long("raw")
.display_order(1000)
.global(true),
Arg::with_name("key")
.help("String value, manually provide API key (not \
recommended)")
.requires("secret")
.short("k")
.long("key")
.takes_value(true)
.display_order(1000)
.global(true),
Arg::with_name("secret")
.help("String value, manually provide API secret (not \
recommended)")
.requires("key")
.short("s")
.long("secret")
.takes_value(true)
.display_order(1000)
.global(true),
])
.subcommand(
App::new("blogentry")
.about("Get information about a blog entry")
.subcommand(
App::new("comments")
.about("Returns a list of comments on a specified blog entry")
.args(&[
Arg::with_name("BLOGENTRYID")
.help("blogEntryId of specified blog entry")
.index(1)
.required(true)
])
)
.subcommand(
App::new("view")
.about("Returns specified blog entry")
.args(&[
Arg::with_name("BLOGENTRYID")
.help("blogEntryId of specified blog entry (eg. 82347)")
.index(1)
.required(true)
])
)
)
.subcommand(
App::new("contest")
.about("Get information about one or more contests")
.subcommand(
App::new("hacks")
.about("Returns list of hacks in the specified contests")
.args(&[
Arg::with_name("CONTESTID")
.help("contestId of specified contest (eg. 1466)")
.index(1)
.required(true)
])
)
.subcommand(
App::new("list")
.about("Returns information about all available contests")
.args(&[
Arg::with_name("gym")
.help("If true, gym contests are returned")
.long("gym")
.short("g")
])
)
.subcommand(
App::new("ratingchanges")
.about("Returns rating changes after a contest")
.args(&[
Arg::with_name("CONTESTID")
.help("contestId of specified contest (eg. 1466)")
.index(1)
.required(true)
])
)
.subcommand(
App::new("standings")
.about("Returns the description of the contest and the \
requested part of the standings")
.args(&[
Arg::with_name("CONTESTID")
.help("contestId of specified contest (eg. 1466)")
.index(1)
.required(true),
Arg::with_name("from")
.help("1-based index of the standings row to start the \
ranklist")
.long("from")
.short("f")
.takes_value(true),
Arg::with_name("count")
.help("Number of standing rows to return")
.long("count")
.short("n")
.takes_value(true),
Arg::with_name("handles")
.help("List of handles")
.long("handles")
.short("H")
.takes_value(true)
.multiple(true)
.use_delimiter(true),
Arg::with_name("room")
.help("If specified, show only participants in given room")
.long("room")
.short("R")
.takes_value(true),
Arg::with_name("showunofficial")
.help("If set, all participants (virtual, out of \
competition) are shown")
.long("showunofficial")
.short("u"),
Arg::with_name("dontfetchtestcases")
.help("If set, don't fetch testcases for each problem (raw \
never fetches)")
.long("dontfetchtestcases")
.short("F"),
])
)
.subcommand(
App::new("status")
.about("Returns submissions for specified contest")
.args(&[
Arg::with_name("CONTESTID")
.help("contestId of specified contest (eg. 1466)")
.index(1)
.required(true),
Arg::with_name("handle")
.help("Codeforces user handle")
.long("handle")
.short("H")
.takes_value(true),
Arg::with_name("from")
.help("1-based index of the first submission to return")
.long("from")
.short("f")
.takes_value(true),
Arg::with_name("count")
.help("Number of returned submissions")
.short("n")
.takes_value(true),
])
)
.subcommand(
App::new("testcases")
.about("Returns testcases for every problem (delimited) in \
specified contest")
.args(&[
Arg::with_name("CONTESTID")
.help("contestId of specified contest (eg. 1466)")
.index(1)
.required(true),
Arg::with_name("wait")
.help("Flag or Number value indicating whether to wait for \
contest to start. (default value = 10 seconds)")
.long("wait")
.short("w")
.default_value("10")
.takes_value(true)
.required(true),
Arg::with_name("timeout")
.help("Program timeout value (default 1000 seconds). Only \
used if wait enabled.")
.long("timeout")
.short("t")
.takes_value(true)
.default_value("1000")
.required(true),
])
)
)
.subcommand(
App::new("problemset")
.about("Get information about one or more problems")
.subcommand(
App::new("problems")
.about("Returns all problems from problemset")
.args(&[
Arg::with_name("tags")
.help("List of tags for a problemset")
.long("tags")
.short("t")
.takes_value(true)
.multiple(true)
.use_delimiter(true),
Arg::with_name("problemsetname")
.help("Custom problemset's short name, like `acmsguru`")
.long("problemsetname")
.short("N")
.takes_value(true),
Arg::with_name("dontfetchtestcases") .help("If set, don't fetch testcases for each problem (raw \
never fetches)")
.long("dontfetchtestcases")
.short("F"),
])
)
.subcommand(
App::new("recentstatus")
.about("Returns recent submissions")
.args(&[
Arg::with_name("count")
.long("count")
.short("n")
.takes_value(true)
.required(true),
Arg::with_name("problemsetname")
.long("problemsetname")
.short("N")
.takes_value(true),
])
)
)
.subcommand(
App::new("recentactions")
.about("Returns recent actions")
.args(&[
Arg::with_name("maxcount")
.long("maxcount")
.short("n")
.takes_value(true)
.required(true),
])
)
.subcommand(
App::new("user")
.about("Get information about a user")
.subcommand(
App::new("blogentries")
.about("Returns a list of user's blog entries")
.args(&[
Arg::with_name("HANDLE")
.help("Codeforces user handle (set the default user \
with `caffeine config`) ")
.index(1),
]),
)
.subcommand(
App::new("friends")
.about("Return's friends of the currently logged in user (api \
keys required)")
.args(&[
Arg::with_name("onlyonline")
.help("Only return online friends")
.long("onlyonline")
.short("o"),
])
)
.subcommand(
App::new("info")
.about("Returns information about one or more users")
.args(&[
Arg::with_name("HANDLES")
.help("list of handles to get info for (set the default \
user with `caffeine config`)")
.index(1)
.multiple(true)
.use_delimiter(true),
])
)
.subcommand(
App::new("ratedlist")
.about("Returns the list of users who have participated in \
>=1 rated contests")
.args(&[
Arg::with_name("activeonly")
.help("only show users who participated in contests \
recently (last month)")
.long("activeonly")
.short("a"),
])
)
.subcommand(
App::new("rating")
.about("Returns the rating history of a specified user")
.args(&[
Arg::with_name("HANDLE")
.help("Codeforces user handle (set the default \
user with `caffeine config`)")
.index(1)
])
)
.subcommand(
App::new("status")
.about("Returns submissions of a specified user")
.args(&[
Arg::with_name("HANDLE")
.help("Codeforces user handle (set the default \
user with `caffeine config`)")
.index(1)
.takes_value(true),
Arg::with_name("from")
.help("1-based index of the first submission to return \
(recent first)")
.long("from")
.short("f")
.takes_value(true),
Arg::with_name("count")
.help("Number of returned submissions")
.long("count")
.short("n")
.takes_value(true),
])
)
)
.subcommand(
App::new("submit")
.about("Submit code to a specified problem")
.args(&[
Arg::with_name("handle")
.help("Handle or email to login with (not recommended)")
.long("handle")
.short("H")
.takes_value(true),
Arg::with_name("password")
.help("Handle or email to login with (not recommended)")
.long("password")
.short("p")
.takes_value(true),
Arg::with_name("CONTESTID")
.help("contestId of requested problem")
.index(1)
.required(true)
.takes_value(true),
Arg::with_name("PROBLEMID")
.help("problemId of requested problem (eg A)")
.index(2)
.required(true)
.takes_value(true),
Arg::with_name("programtypeid")
.help("programTypeId of solution to be submitted (eg 54 = \
C++17)")
.long("programtypeid")
.short("l")
.takes_value(true),
Arg::with_name("mirror")
.help("Number (0-3) indicating the mirror which should be used \
(0 = codeforces.com, 1 = m1.codeforces.com ...)")
.long("mirror")
.short("m")
.takes_value(true),
Arg::with_name("FILENAME")
.help("String value, filename of solution to be submitted \
(alternatively use piped stdin)")
.index(3)
.takes_value(true),
])
)
.subcommand(
App::new("login")
.about("Save api keys and login details (recommended over cli \
flags)")
.args(&[
Arg::with_name("handle")
.help("String value, provide login handle/email as cli \
argument (not recommended)")
.long("handle")
.short("H")
.requires("password")
.takes_value(true),
Arg::with_name("password")
.help("String value, provide login password as cli argument \
(not recommended)")
.long("password")
.short("p")
.requires("handle")
.takes_value(true),
])
)
.subcommand(
App::new("config")
.about("change configuration (eg. default programming language)")
.args(&[
Arg::with_name("defaultuser")
.help("String value, provide default user handle for \
commands like `user status` as cli argument")
.long("defaultuser")
.short("u")
.takes_value(true),
Arg::with_name("defaultprogramtypeid")
.help("Number, set default programTypeId language for \
submitting code (eg. 54 = C++17) as cli argument")
.long("lang")
.short("l")
.takes_value(true),
])
);
let matches = app.get_matches();
match matches.subcommand() {
("blogentry", Some(subcommand)) => {
handlers::blogentry_command(subcommand);
}
("contest", Some(subcommand)) => {
handlers::contest_command(subcommand);
}
("problemset", Some(subcommand)) => {
handlers::problemset_command(subcommand);
}
("recentactions", Some(args)) => {
handlers::recentactions_command(args);
}
("user", Some(subcommand)) => {
handlers::user_command(subcommand);
}
("submit", Some(args)) => {
handlers::submit_command(args);
}
("login", Some(args)) => {
handlers::login_command(args);
}
("config", Some(args)) => {
handlers::config_command(args);
}
_ => {
handlers::exit_with_usage(&matches);
}
}
}