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
mod cli;
use clap::{CommandFactory, Parser, Subcommand};
use cli::config::ConfigArgs;
use cli::run::RunArgs;
use cli::scratch::ScratchCommandArgs;
use cli::snaphot::SnapshotArgs;
use rested::config::{get_env_from_dir_path_or_from_home_dir, get_env_from_home_dir};
use rested::editing::edit;
use tracing::{error, info};
use std::collections::HashMap;
use std::fs;
#[derive(Parser, Debug)]
#[command(author, version, about)]
/// The CLI runtime for Rested, the language/interpreter for easily defining and running requests to an http server.
struct Cli {
#[command(subcommand)]
command: Command,
/// Set log level, one of trace, debug, info, warn, error
#[arg(short, long, default_value = "info", global = true)]
level: tracing::Level,
}
#[derive(Debug, Subcommand)]
enum Command {
/// Run a script written in the language
Run(RunArgs),
/// Open your default editor to start editing a temporary file
Scratch(ScratchCommandArgs),
/// Generate a static snapshot of the requests with all dynamic values evaluated.
Snap(SnapshotArgs),
/// Operate on the environment variables available in the runtime.
/// Looking into the `.env.rd.json` in the current directory, or that in the home directory.
Env {
/// Set to look at the `.env.rd.json` file in the current working directory.
/// Otherwise this command and its subcommands operate on the `.env.rd.json` file in your
/// home directory.
#[arg(long)]
cwd: bool,
#[command(subcommand)]
command: EnvCommand,
},
/// Generate a completions file for a specified shell
Completion {
// The shell for which to generate completions
shell: clap_complete::Shell,
},
/// Start the rested language server
Lsp,
/// Configure, or view current configurations
Config(ConfigArgs),
}
#[derive(Debug, Subcommand)]
enum EnvCommand {
/// View environment variables available in the runtime
Show,
/// Edit environment variables in your default editor.
Edit,
/// Set environment variables available in the runtime
Set {
/// Namespace for which to set environment variable
#[arg(short = 'n', long)]
namespace: Option<String>,
/// Of the environment variable
name: String,
/// Of the environment variable
value: String,
},
/// Operate on the variables namespaces available in the runtime
NS {
#[command(subcommand)]
command: EnvNamespaceCommand,
},
}
#[derive(Debug, Subcommand)]
enum EnvNamespaceCommand {
/// Set a new variables namespace available in the runtime
Add {
/// Of the namespace
name: String,
},
/// Remove a namespace
Rm {
/// Of the namespace
name: String,
},
}
fn main() {
let cli = Cli::parse();
tracing_subscriber::fmt()
.with_max_level(cli.level)
.with_writer(std::io::stderr)
.init();
if let Err(e) = run(cli) {
error!("{:#}", e);
}
}
fn run(cli: Cli) -> anyhow::Result<()> {
match cli.command {
Command::Env { command, cwd } => {
let cwd = if cwd {
Some(std::env::current_dir()?)
} else {
None
};
let mut env = get_env_from_dir_path_or_from_home_dir(cwd.as_deref())?;
match command {
EnvCommand::Set {
name,
value,
namespace,
} => {
if let Some(ns) = namespace {
env.select_variables_namespace(ns);
}
info!("setting variable '{}' with value '{}'", name, value);
env.set_variable(name, value)?;
}
EnvCommand::NS { command } => match command {
EnvNamespaceCommand::Add { name } => {
info!("adding namespace: {name}");
env.namespaced_variables.insert(name, HashMap::new());
env.save_to_file()?;
}
EnvNamespaceCommand::Rm { name } => {
info!("removing namespace: {name}");
env.namespaced_variables.remove(&name);
env.save_to_file()?;
}
},
EnvCommand::Show => println!("{}", fs::read_to_string(env.env_file_name)?),
EnvCommand::Edit => edit(&env.env_file_name)?,
}
}
Command::Completion { shell } => {
clap_complete::generate(shell, &mut Cli::command(), "rstd", &mut std::io::stdout())
}
Command::Lsp => rested::language_server::start(cli.level),
Command::Run(run) => {
let full_path = run.file.as_ref().and_then(|path| path.canonicalize().ok());
let workspace = full_path.as_ref().and_then(|p| p.parent());
if let Some(path) = full_path.as_ref() {
info!("script to run: {:?}", path);
}
if let Some(workspace) = workspace.as_ref() {
info!("indentified workspace: {:?}", workspace);
}
let env = get_env_from_dir_path_or_from_home_dir(workspace)?;
run.handle(env)?
}
Command::Scratch(scratch) => {
let env = get_env_from_home_dir()?;
scratch.handle(env)?
}
Command::Config(config) => config.handle()?,
Command::Snap(snap) => {
let full_path = snap.file.as_ref().and_then(|path| path.canonicalize().ok());
let workspace = full_path.as_ref().and_then(|p| p.parent());
if let Some(path) = full_path.as_ref() {
info!("script to snapshot: {:?}", path);
}
if let Some(workspace) = workspace.as_ref() {
info!("indentified workspace: {:?}", workspace);
}
let env = get_env_from_dir_path_or_from_home_dir(workspace)?;
snap.handle(env)?
}
};
Ok(())
}