Skip to content

Commit 1276f73

Browse files
authored
Set custom RPC endpoints without breaking deployer lookups (#36)
* wip * Write default goki.toml * wip * configs -> endpoints * Remove wss * Update gitignore * Switch &cluster.url() to get_cluster_url * Clean up
1 parent 859a436 commit 1276f73

File tree

12 files changed

+189
-21
lines changed

12 files changed

+189
-21
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
target/
22
.goki/
3+
Goki.toml

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ serde_json = "1.0"
2222
sha2 = "0.10.0"
2323
solana-sdk = "1.9.0"
2424
tempfile = "3.2.0"
25+
toml = "0.5.8"
2526
tokio = { version = "1.14.0", features = ["full"] }
2627

2728
[[bin]]

src/cli.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
//! Goki entrypoint
22
3-
use crate::subcommands;
43
use anchor_client::Cluster;
54
use anyhow::Result;
65
use clap::ArgSettings::NextLineHelp;
76
use clap::Parser;
87
use std::path::PathBuf;
98

9+
use crate::subcommands;
10+
1011
const LOCATION_HELP: &str =
1112
"The location of the Solana program binary. This can be in one of the following formats:
1213

src/config.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
use anyhow::{Error, Result};
2+
use serde::{Deserialize, Serialize};
3+
use std::fs::{self, File};
4+
use std::io::Read;
5+
use std::path::{Path, PathBuf};
6+
use std::str::FromStr;
7+
use std::string::ToString;
8+
9+
pub struct WithPath<T> {
10+
inner: T,
11+
path: PathBuf,
12+
}
13+
14+
impl<T> WithPath<T> {
15+
pub fn new(inner: T, path: PathBuf) -> Self {
16+
Self { inner, path }
17+
}
18+
19+
pub fn path(&self) -> &PathBuf {
20+
&self.path
21+
}
22+
23+
pub fn into_inner(self) -> T {
24+
self.inner
25+
}
26+
}
27+
28+
impl<T> std::convert::AsRef<T> for WithPath<T> {
29+
fn as_ref(&self) -> &T {
30+
&self.inner
31+
}
32+
}
33+
34+
impl<T> std::ops::Deref for WithPath<T> {
35+
type Target = T;
36+
fn deref(&self) -> &Self::Target {
37+
&self.inner
38+
}
39+
}
40+
41+
impl<T> std::ops::DerefMut for WithPath<T> {
42+
fn deref_mut(&mut self) -> &mut Self::Target {
43+
&mut self.inner
44+
}
45+
}
46+
47+
#[derive(Debug, Default, Serialize, Deserialize)]
48+
pub struct Config {
49+
pub rpc_endpoints: RPC,
50+
}
51+
52+
#[derive(Clone, Debug, Serialize, Deserialize)]
53+
pub struct RPC {
54+
pub mainnet: String,
55+
pub devnet: String,
56+
pub testnet: String,
57+
pub localnet: String,
58+
pub debug: String,
59+
}
60+
61+
impl Default for RPC {
62+
fn default() -> Self {
63+
Self {
64+
mainnet: "https://api.mainnet-beta.solana.com".to_string(),
65+
devnet: "https://api.devnet.solana.com".to_string(),
66+
testnet: "https://api.testnet.solana.com".to_string(),
67+
localnet: "http://127.0.0.1:8899".to_string(),
68+
debug: "http://34.90.18.145:8899".to_string(),
69+
}
70+
}
71+
}
72+
73+
impl Config {
74+
// Climbs each parent directory until we find an Goki.toml.
75+
pub fn discover() -> Result<Option<WithPath<Config>>> {
76+
let _cwd = std::env::current_dir()?;
77+
let mut cwd_opt = Some(_cwd.as_path());
78+
79+
while let Some(cwd) = cwd_opt {
80+
for f in fs::read_dir(cwd)? {
81+
let p = f?.path();
82+
if let Some(filename) = p.file_name() {
83+
if filename.to_str() == Some("Goki.toml") {
84+
let cfg = Config::from_path(&p)?;
85+
return Ok(Some(WithPath::new(cfg, p)));
86+
}
87+
}
88+
}
89+
90+
cwd_opt = cwd.parent();
91+
}
92+
93+
Ok(None)
94+
}
95+
96+
fn from_path(p: impl AsRef<Path>) -> Result<Self> {
97+
let mut cfg_file = File::open(&p)?;
98+
let mut cfg_contents = String::new();
99+
cfg_file.read_to_string(&mut cfg_contents)?;
100+
let cfg = cfg_contents.parse()?;
101+
102+
Ok(cfg)
103+
}
104+
}
105+
106+
#[derive(Debug, Serialize, Deserialize)]
107+
struct _Config {
108+
rpc_endpoints: Option<RPC>,
109+
}
110+
111+
impl ToString for Config {
112+
fn to_string(&self) -> String {
113+
let cfg = _Config {
114+
rpc_endpoints: Some(RPC {
115+
..self.rpc_endpoints.clone()
116+
}),
117+
};
118+
119+
toml::to_string(&cfg).expect("Must be well formed")
120+
}
121+
}
122+
123+
impl FromStr for Config {
124+
type Err = Error;
125+
126+
fn from_str(s: &str) -> Result<Self, Self::Err> {
127+
let cfg: _Config = toml::from_str(s)
128+
.map_err(|e| anyhow::format_err!("Unable to deserialize config: {}", e.to_string()))?;
129+
Ok(Config {
130+
rpc_endpoints: cfg.rpc_endpoints.unwrap_or_default(),
131+
})
132+
}
133+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
pub mod macros;
55

66
pub mod cli;
7+
pub mod config;
78
pub mod location;
89
pub mod solana_cmd;
910
pub mod subcommands;

src/solana_cmd.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use anyhow::Result;
33
use solana_sdk::pubkey::Pubkey;
44
use std::{path::Path, process::Output};
55

6-
use crate::utils::{exec_command, get_deployer_kp_path};
6+
use crate::utils::{exec_command, get_cluster_url, get_deployer_kp_path};
77

88
/// Sets the buffer authority of a buffer.
99
pub fn set_buffer_authority(
@@ -15,7 +15,7 @@ pub fn set_buffer_authority(
1515
exec_command(
1616
std::process::Command::new("solana")
1717
.arg("--url")
18-
.arg(&cluster.url())
18+
.arg(get_cluster_url(cluster)?)
1919
.arg("--keypair")
2020
.arg(deployer_kp)
2121
.arg("program")
@@ -36,7 +36,7 @@ pub fn set_upgrade_authority(
3636
exec_command(
3737
std::process::Command::new("solana")
3838
.arg("--url")
39-
.arg(&cluster.url())
39+
.arg(get_cluster_url(cluster)?)
4040
.arg("--keypair")
4141
.arg(current_authority)
4242
.arg("program")
@@ -57,7 +57,7 @@ pub fn write_buffer(
5757
exec_command(
5858
std::process::Command::new("solana")
5959
.arg("--url")
60-
.arg(&cluster.url())
60+
.arg(get_cluster_url(cluster)?)
6161
.arg("--keypair")
6262
.arg(deployer_kp)
6363
.arg("program")
@@ -74,7 +74,7 @@ pub fn deploy(cluster: &Cluster, program_file: &Path, program_kp_path: &Path) ->
7474
exec_command(
7575
std::process::Command::new("solana")
7676
.arg("--url")
77-
.arg(&cluster.url())
77+
.arg(get_cluster_url(cluster)?)
7878
.arg("--keypair")
7979
.arg(&deployer_kp)
8080
.arg("program")
@@ -95,7 +95,7 @@ pub fn upgrade(
9595
exec_command(
9696
std::process::Command::new("solana")
9797
.arg("--url")
98-
.arg(&cluster.url())
98+
.arg(get_cluster_url(cluster)?)
9999
.arg("--keypair")
100100
.arg(upgrade_authority_kp)
101101
.arg("program")

src/subcommands/airdrop.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use anchor_client::Cluster;
22
use anyhow::{format_err, Result};
33
use std::path::{Path, PathBuf};
44

5-
use crate::utils::exec_command;
5+
use crate::utils::{exec_command, get_cluster_url};
66

77
pub fn process(cluster: Cluster, amount: &str) -> Result<()> {
88
if cluster == Cluster::Mainnet {
@@ -26,7 +26,7 @@ pub fn process(cluster: Cluster, amount: &str) -> Result<()> {
2626
exec_command(
2727
std::process::Command::new("solana")
2828
.arg("--url")
29-
.arg(cluster.url())
29+
.arg(get_cluster_url(&cluster)?)
3030
.arg("--keypair")
3131
.arg(keypair_path)
3232
.arg("airdrop")

src/subcommands/init.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
1-
use crate::utils::{exec_command, gen_keypair_file};
21
use anchor_client::Cluster;
32
use anyhow::{format_err, Result};
43
use colored::*;
54
use solana_sdk::{pubkey::Pubkey, signature::read_keypair_file, signer::Signer};
5+
use std::fs::File;
6+
use std::io::Write;
67
use std::{fs, path::Path};
78

9+
use crate::config::Config;
10+
use crate::utils::{exec_command, gen_keypair_file, get_cluster_url};
11+
812
pub fn process() -> Result<()> {
13+
if Config::discover()?.is_some() {
14+
println!("Goki.toml already exists in workspace")
15+
} else {
16+
let cfg = Config::default();
17+
let mut file = File::create("Goki.toml")?;
18+
file.write_all(cfg.to_string().as_bytes())?;
19+
}
20+
921
fs::create_dir_all(".goki/deployers/")?;
1022

1123
let mut result: Vec<(Cluster, Pubkey)> = vec![];
@@ -37,7 +49,7 @@ pub fn process() -> Result<()> {
3749
exec_command(
3850
std::process::Command::new("solana")
3951
.arg("--url")
40-
.arg(cluster.url())
52+
.arg(get_cluster_url(cluster)?)
4153
.arg("--keypair")
4254
.arg(keypair_path)
4355
.arg("airdrop")

src/subcommands/pull.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
use crate::location::fetch_program_file;
2-
use crate::utils::sha256_digest;
31
use anyhow::Result;
42
use colored::*;
53
use std::fs::File;
64
use std::io::BufReader;
75
use std::path::PathBuf;
86
use tempfile::NamedTempFile;
97

8+
use crate::location::fetch_program_file;
9+
use crate::utils::sha256_digest;
10+
1011
pub async fn process(location: &str, out: Option<PathBuf>) -> Result<()> {
1112
let mut temp_out_file = NamedTempFile::new()?;
1213
let program_file_path = match out.clone() {

0 commit comments

Comments
 (0)