forked from enviodev/hyperindex
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclap_definitions.rs
More file actions
439 lines (369 loc) · 13.7 KB
/
Copy pathclap_definitions.rs
File metadata and controls
439 lines (369 loc) · 13.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
use crate::constants::project_paths::{DEFAULT_CONFIG_PATH, DEFAULT_GENERATED_PATH};
use crate::package_manager::PackageManager;
use clap::{Args, Parser, Subcommand};
use clap_markdown::MarkdownOptions;
use strum::{Display, EnumIter, EnumString};
use subenum::subenum;
use super::init_config::{self};
#[derive(Debug, Parser)]
#[clap(author, version, about)]
pub struct CommandLineArgs {
#[clap(subcommand)]
pub command: CommandType,
#[command(flatten)]
pub project_paths: ProjectPaths,
}
impl CommandLineArgs {
pub fn generate_markdown_help() -> String {
let options = MarkdownOptions::new()
.show_footer(false)
.title("Command-Line Help for `envio`".to_string());
clap_markdown::help_markdown_custom::<Self>(&options)
}
}
#[derive(Args, Debug, Clone)]
pub struct ProjectPaths {
///The directory of the project. Defaults to current dir ("./")
#[arg(global = true, short, long)]
pub directory: Option<String>,
///The directory for generated code output. We recommend configuring this using the `output` field in your config.yaml instead
#[arg(global = true, short, long, default_value_t=String::from(DEFAULT_GENERATED_PATH))]
pub output_directory: String,
///The file in the project containing config.
#[arg(global = true, long, default_value_t=String::from(DEFAULT_CONFIG_PATH))]
pub config: String,
}
#[derive(Debug, Subcommand)]
pub enum CommandType {
///Initialize an indexer with one of the initialization options
Init(InitArgs),
/// Development commands for starting, stopping, and restarting the indexer with automatic codegen for any changed files
Dev,
/// Stop the local environment - delete the database and stop all processes (including Docker) for the current directory
Stop,
///Generate indexing code from user-defined configuration & schema files
Codegen,
///Prints a summary of the benchmark data after running the indexer
///with envio start --bench flag or setting 'ENVIO_SAVE_BENCHMARK_DATA=true'
BenchmarkSummary,
///Prepare local environment for envio testing
// #[clap(hide = true)]
#[command(subcommand)]
Local(LocalCommandTypes),
///Start the indexer without any automatic codegen
Start(StartArgs),
#[clap(hide = true)]
#[command(subcommand)]
Script(Script),
}
#[derive(Debug, Subcommand)]
pub enum Script {
///Print missing networks from the API
PrintMissingNetworks,
///Print help into a markdown file
PrintCliHelpMd,
///Print help into a markdown file
#[command(subcommand)]
PrintConfigJsonSchema(JsonSchema),
}
#[derive(Debug, Subcommand)]
pub enum JsonSchema {
Evm,
Fuel,
Svm,
}
#[derive(Debug, Args)]
pub struct StartArgs {
///Clear your database and restart indexing from scratch
#[arg(short = 'r', long, action)]
pub restart: bool,
///Saves benchmark data to a file during indexing
#[arg(short = 'b', long, action)]
pub bench: bool,
}
#[derive(Debug, Subcommand)]
pub enum LocalCommandTypes {
/// Local Envio environment commands
#[command(subcommand)]
Docker(LocalDockerSubcommands),
/// Local Envio database commands
#[command(subcommand)]
DbMigrate(DbMigrateSubcommands),
}
#[derive(Subcommand, Debug, Clone)]
pub enum LocalDockerSubcommands {
///Create docker images required for local environment
Up,
///Delete existing docker images on local environment
Down,
}
#[derive(Subcommand, Debug)]
pub enum DbMigrateSubcommands {
///Migrate latest schema to database
Up,
///Drop database schema
Down,
///Setup database by dropping schema and then running migrations
Setup,
}
#[derive(Args, Debug, Clone)]
pub struct InitArgs {
///The name of your project
#[arg(global = true, short, long)]
pub name: Option<String>,
///Initialization option for creating an indexer
#[command(subcommand)]
pub init_commands: Option<InitFlow>,
///The language used to write handlers
#[arg(global = true, short = 'l', long = "language")]
#[clap(value_enum)]
pub language: Option<init_config::Language>,
///The hypersync API key to be initialized in your templates .env file
#[arg(global = true, long)]
pub api_token: Option<String>,
///The package manager to use (npm, yarn, pnpm, bun). Auto-detected from lockfiles if not specified.
#[arg(global = true, short = 'p', long = "package-manager")]
#[clap(value_enum)]
pub package_manager: Option<PackageManager>,
}
#[subenum(EvmInitFlowInteractive)]
#[derive(Subcommand, Debug, EnumIter, Display, EnumString, Clone)]
pub enum InitFlow {
///Initialize Evm indexer by importing config from a contract for a given chain
#[subenum(EvmInitFlowInteractive)]
#[strum(serialize = "Contract Import")]
ContractImport(evm::ContractImportArgs),
///Initialize Evm indexer from an example template
#[subenum(EvmInitFlowInteractive)]
Template(evm::TemplateArgs),
///Initialize Evm indexer by migrating config from an existing subgraph
#[clap(hide = true)] //hiding for now until this is more stable
#[strum(serialize = "Subgraph Migration (Experimental)")]
SubgraphMigration(evm::SubgraphMigrationArgs),
///Initialization option for creating Svm indexer
Svm {
#[command(subcommand)]
init_flow: Option<svm::InitFlow>,
},
///Initialization option for creating Fuel indexer
Fuel {
#[command(subcommand)]
init_flow: Option<fuel::InitFlow>,
},
}
pub mod evm {
use crate::{
config_parsing::chain_helpers::{Network, NetworkWithExplorer},
evm, init_config,
};
use anyhow::Context;
use clap::{Args, Subcommand};
use std::str::FromStr;
use strum::{Display, EnumIter, EnumString};
#[derive(Args, Debug, Default, Clone)]
pub struct ContractImportArgs {
///Choose to import a contract from a local abi or
///using get values from an explorer using a contract address
#[command(subcommand)]
pub local_or_explorer: Option<LocalOrExplorerImport>,
///Contract address to generate the config from
#[arg(global = true, short, long)]
pub contract_address: Option<evm::address::Address>,
///If selected, prompt will not ask for additional contracts/addresses/chains
#[arg(long, action)]
pub single_contract: bool,
///If selected, prompt will not ask to confirm selection of events on a contract
#[arg(long, action)]
pub all_events: bool,
}
#[derive(Args, Debug, Default, Clone)]
pub struct TemplateArgs {
///Name of the template to be used in initialization
#[arg(short, long)]
#[clap(value_enum)]
pub template: Option<init_config::evm::Template>,
}
type SubgraphMigrationID = String;
#[derive(Args, Debug, Default, Clone)]
pub struct SubgraphMigrationArgs {
///Subgraph ID to start a migration from
#[arg(short, long)]
pub subgraph_id: Option<SubgraphMigrationID>,
}
#[derive(Subcommand, Debug, EnumIter, EnumString, Display, Clone)]
pub enum LocalOrExplorerImport {
///Initialize by pulling the contract ABI from a block explorer
#[strum(serialize = "Block Explorer")]
Explorer(ExplorerImportArgs),
///Initialize from a local json ABI file
#[strum(serialize = "Local ABI")]
Local(LocalImportArgs),
}
impl LocalOrExplorerImport {
// Helper method to get flags from either variant
pub fn get_flags(&self) -> (bool, bool) {
match self {
LocalOrExplorerImport::Explorer(args) => (args.all_events, args.single_contract),
LocalOrExplorerImport::Local(args) => (args.all_events, args.single_contract),
}
}
}
#[derive(Args, Debug, Default, Clone)]
pub struct ExplorerImportArgs {
///Network to import the contract from
#[arg(short, long)]
pub blockchain: Option<NetworkWithExplorer>,
///API token for the block explorer
#[arg(long)]
pub api_token: Option<String>,
///If selected, prompt will not ask for additional contracts/addresses/chains
#[arg(long, action)]
pub single_contract: bool,
///If selected, prompt will not ask to confirm selection of events on a contract
#[arg(long, action)]
pub all_events: bool,
}
#[derive(Debug, Clone)]
pub enum NetworkOrChainId {
NetworkName(Network),
ChainId(u64),
}
impl From<NetworkOrChainId> for u64 {
fn from(value: NetworkOrChainId) -> Self {
match value {
NetworkOrChainId::ChainId(val) => val,
NetworkOrChainId::NetworkName(name) => name as u64,
}
}
}
impl FromStr for NetworkOrChainId {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let res_network: Result<Network, _> = s.parse();
match res_network {
Ok(n) => Ok(NetworkOrChainId::NetworkName(n)),
Err(_) => {
let chain_id: u64 = s.parse().context("Invalid network name or id")?;
Ok(NetworkOrChainId::ChainId(chain_id))
}
}
}
}
#[derive(Args, Debug, Default, Clone)]
pub struct LocalImportArgs {
///The path to a json abi file
#[arg(short, long)]
pub abi_file: Option<String>,
///The name of the contract
#[arg(long)]
pub contract_name: Option<String>,
///Name or ID of the contract network
#[arg(short, long)]
pub blockchain: Option<NetworkOrChainId>,
///The rpc url to use if the network id used is unsupported by our hypersync
#[arg(short, long)]
pub rpc_url: Option<String>,
///The start block to use on this network
#[arg(short, long)]
pub start_block: Option<u64>,
///If selected, prompt will not ask for additional contracts/addresses/chains
#[arg(long, action)]
pub single_contract: bool,
///If selected, prompt will not ask to confirm selection of events on a contract
#[arg(long, action)]
pub all_events: bool,
}
}
pub mod fuel {
use clap::{Args, Subcommand};
use strum::{Display, EnumIter, EnumString};
use crate::{fuel, init_config};
#[derive(Subcommand, Debug, EnumIter, Display, EnumString, Clone)]
pub enum InitFlow {
///Initialize Fuel indexer by importing config from a contract for a given chain
#[strum(serialize = "Contract Import")]
ContractImport(ContractImportArgs),
///Initialize Fuel indexer from an example template
Template(TemplateArgs),
}
#[derive(Args, Debug, Default, Clone)]
pub struct ContractImportArgs {
///Choose to import a contract from a local abi or
///using get values from an explorer using a contract address
#[command(subcommand)]
pub local_or_explorer: Option<LocalOrExplorerImport>,
///Contract address to generate the config from
#[arg(global = true, short, long)]
pub contract_address: Option<fuel::address::Address>,
///If selected, prompt will not ask for additional contracts/addresses/chains
#[arg(long, action)]
pub single_contract: bool,
///If selected, prompt will not ask to confirm selection of events on a contract
#[arg(long, action)]
pub all_events: bool,
}
#[derive(Subcommand, Debug, EnumIter, EnumString, Display, Clone)]
pub enum LocalOrExplorerImport {
// Not supported https://forum.fuel.network/t/get-abi-by-contract-address/5535
// ///Initialize by pulling the contract ABI from a block explorer
// #[strum(serialize = "Block Explorer")]
// Explorer(ExplorerImportArgs),
// ----
///Initialize from a local json ABI file
#[strum(serialize = "Local ABI")]
Local(LocalImportArgs),
}
#[derive(Args, Debug, Default, Clone)]
pub struct LocalImportArgs {
///The path to a json abi file
#[arg(short, long)]
pub abi_file: Option<String>,
///The name of the contract
#[arg(long)]
pub contract_name: Option<String>,
}
#[derive(Args, Debug, Default, Clone)]
pub struct TemplateArgs {
///Name of the template to be used in initialization
#[arg(short, long)]
#[clap(value_enum)]
pub template: Option<init_config::fuel::Template>,
}
}
pub mod svm {
use clap::{Args, Subcommand};
use strum::{Display, EnumIter, EnumString};
use crate::init_config;
#[derive(Subcommand, Debug, EnumIter, Display, EnumString, Clone)]
pub enum InitFlow {
///Initialize Svm indexer from an example template
Template(TemplateArgs),
}
#[derive(Args, Debug, Default, Clone)]
pub struct TemplateArgs {
///Name of the template to be used in initialization
#[arg(short, long)]
#[clap(value_enum)]
pub template: Option<init_config::svm::Template>,
}
}
#[cfg(test)]
mod test {
use super::*;
use pretty_assertions::assert_eq;
use std::path::PathBuf;
#[test]
fn check_cli_help_md_is_up_to_date() {
let md_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("CommandLineHelp.md");
let md_current =
std::fs::read_to_string(md_path).expect("Failed reading CommandLineHelp.md");
let md_output = CommandLineArgs::generate_markdown_help();
//current is trimmed because then print command
//adds a line at the end of the md file
assert_eq!(
md_current.trim(),
md_output.trim(),
"Please run 'make update-generated-docs'"
);
}
}