Skip to content

Commit

Permalink
cli: Use OS-agnostic paths (#3307)
Browse files Browse the repository at this point in the history
  • Loading branch information
acheroncrypto authored Oct 10, 2024
1 parent aa48efb commit 5df7fbd
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 61 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- lang: Fix using non-instruction composite accounts with `declare_program!` ([#3290](https://github.com/coral-xyz/anchor/pull/3290)).
- idl: Fix instructions with tuple parameters not producing an error([#3294](https://github.com/coral-xyz/anchor/pull/3294)).
- ts: Update `engines.node` to `>= 17` ([#3301](https://github.com/coral-xyz/anchor/pull/3301)).
- cli: Use OS-agnostic paths ([#3307](https://github.com/coral-xyz/anchor/pull/3307)).

### Breaking

Expand Down
42 changes: 28 additions & 14 deletions cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,10 @@ impl WithPath<Config> {
let cargo = Manifest::from_path(path.join("Cargo.toml"))?;
let lib_name = cargo.lib_name()?;

let idl_filepath = format!("target/idl/{lib_name}.json");
let idl_filepath = Path::new("target")
.join("idl")
.join(&lib_name)
.with_extension("json");
let idl = fs::read(idl_filepath)
.ok()
.map(|bytes| serde_json::from_reader(&*bytes))
Expand All @@ -257,7 +260,10 @@ impl WithPath<Config> {
});
}
for (lib_name, path) in self.get_solidity_program_list()? {
let idl_filepath = format!("target/idl/{lib_name}.json");
let idl_filepath = Path::new("target")
.join("idl")
.join(&lib_name)
.with_extension("json");
let idl = fs::read(idl_filepath)
.ok()
.map(|bytes| serde_json::from_reader(&*bytes))
Expand Down Expand Up @@ -1131,7 +1137,7 @@ impl From<_Validator> for Validator {
url: _validator.url,
ledger: _validator
.ledger
.unwrap_or_else(|| DEFAULT_LEDGER_PATH.to_string()),
.unwrap_or_else(|| get_default_ledger_path().display().to_string()),
limit_ledger_size: _validator.limit_ledger_size,
rpc_port: _validator
.rpc_port
Expand Down Expand Up @@ -1169,7 +1175,10 @@ impl From<Validator> for _Validator {
}
}

pub const DEFAULT_LEDGER_PATH: &str = ".anchor/test-ledger";
pub fn get_default_ledger_path() -> PathBuf {
Path::new(".anchor").join("test-ledger")
}

const DEFAULT_BIND_ADDRESS: &str = "0.0.0.0";

impl Merge for _Validator {
Expand Down Expand Up @@ -1282,12 +1291,12 @@ impl Program {

// Lazily initializes the keypair file with a new key if it doesn't exist.
pub fn keypair_file(&self) -> Result<WithPath<File>> {
let deploy_dir_path = "target/deploy/";
fs::create_dir_all(deploy_dir_path)
.with_context(|| format!("Error creating directory with path: {deploy_dir_path}"))?;
let deploy_dir_path = Path::new("target").join("deploy");
fs::create_dir_all(&deploy_dir_path)
.with_context(|| format!("Error creating directory with path: {deploy_dir_path:?}"))?;
let path = std::env::current_dir()
.expect("Must have current dir")
.join(format!("target/deploy/{}-keypair.json", self.lib_name));
.join(deploy_dir_path.join(format!("{}-keypair.json", self.lib_name)));
if path.exists() {
return Ok(WithPath::new(
File::open(&path)
Expand All @@ -1303,11 +1312,10 @@ impl Program {
}

pub fn binary_path(&self, verifiable: bool) -> PathBuf {
let path = if verifiable {
format!("target/verifiable/{}.so", self.lib_name)
} else {
format!("target/deploy/{}.so", self.lib_name)
};
let path = Path::new("target")
.join(if verifiable { "verifiable" } else { "deploy" })
.join(&self.lib_name)
.with_extension("so");

std::env::current_dir()
.expect("Must have current dir")
Expand Down Expand Up @@ -1389,7 +1397,13 @@ macro_rules! home_path {

impl Default for $my_struct {
fn default() -> Self {
$my_struct(home_dir().unwrap().join($path).display().to_string())
$my_struct(
home_dir()
.unwrap()
.join($path.replace('/', std::path::MAIN_SEPARATOR_STR))
.display()
.to_string(),
)
}
}

Expand Down
124 changes: 77 additions & 47 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::config::{
AnchorPackage, BootstrapMode, BuildConfig, Config, ConfigOverride, Manifest, ProgramArch,
ProgramDeployment, ProgramWorkspace, ScriptsConfig, TestValidator, WithPath,
DEFAULT_LEDGER_PATH, SHUTDOWN_WAIT, STARTUP_WAIT,
get_default_ledger_path, AnchorPackage, BootstrapMode, BuildConfig, Config, ConfigOverride,
Manifest, ProgramArch, ProgramDeployment, ProgramWorkspace, ScriptsConfig, TestValidator,
WithPath, SHUTDOWN_WAIT, STARTUP_WAIT,
};
use anchor_client::Cluster;
use anchor_lang::idl::{IdlAccount, IdlInstruction, ERASED_AUTHORITY};
Expand Down Expand Up @@ -1028,7 +1028,8 @@ fn init(
}

// Build the migrations directory.
fs::create_dir_all("migrations")?;
let migrations_path = Path::new("migrations");
fs::create_dir_all(migrations_path)?;

let license = get_npm_init_license()?;

Expand All @@ -1038,8 +1039,7 @@ fn init(
let mut package_json = File::create("package.json")?;
package_json.write_all(rust_template::package_json(jest, license).as_bytes())?;

let mut deploy = File::create("migrations/deploy.js")?;

let mut deploy = File::create(migrations_path.join("deploy.js"))?;
deploy.write_all(rust_template::deploy_script().as_bytes())?;
} else {
// Build typescript config
Expand All @@ -1049,7 +1049,7 @@ fn init(
let mut ts_package_json = File::create("package.json")?;
ts_package_json.write_all(rust_template::ts_package_json(jest, license).as_bytes())?;

let mut deploy = File::create("migrations/deploy.ts")?;
let mut deploy = File::create(migrations_path.join("deploy.ts"))?;
deploy.write_all(rust_template::ts_deploy_script().as_bytes())?;
}

Expand Down Expand Up @@ -1171,7 +1171,11 @@ pub type Files = Vec<(PathBuf, String)>;
/// ```
pub fn create_files(files: &Files) -> Result<()> {
for (path, content) in files {
let path = Path::new(path);
let path = path
.display()
.to_string()
.replace('/', std::path::MAIN_SEPARATOR_STR);
let path = Path::new(&path);
if path.exists() {
continue;
}
Expand Down Expand Up @@ -1228,7 +1232,7 @@ pub fn expand(
let cfg_parent = workspace_cfg.path().parent().expect("Invalid Anchor.toml");
let cargo = Manifest::discover()?;

let expansions_path = cfg_parent.join(".anchor/expanded-macros");
let expansions_path = cfg_parent.join(".anchor").join("expanded-macros");
fs::create_dir_all(&expansions_path)?;

match cargo {
Expand Down Expand Up @@ -1347,13 +1351,13 @@ pub fn build(

let idl_out = match idl {
Some(idl) => Some(PathBuf::from(idl)),
None => Some(cfg_parent.join("target/idl")),
None => Some(cfg_parent.join("target").join("idl")),
};
fs::create_dir_all(idl_out.as_ref().unwrap())?;

let idl_ts_out = match idl_ts {
Some(idl_ts) => Some(PathBuf::from(idl_ts)),
None => Some(cfg_parent.join("target/types")),
None => Some(cfg_parent.join("target").join("types")),
};
fs::create_dir_all(idl_ts_out.as_ref().unwrap())?;

Expand Down Expand Up @@ -1563,9 +1567,10 @@ fn build_cwd_verifiable(
) -> Result<()> {
// Create output dirs.
let workspace_dir = cfg.path().parent().unwrap().canonicalize()?;
fs::create_dir_all(workspace_dir.join("target/verifiable"))?;
fs::create_dir_all(workspace_dir.join("target/idl"))?;
fs::create_dir_all(workspace_dir.join("target/types"))?;
let target_dir = workspace_dir.join("target");
fs::create_dir_all(target_dir.join("verifiable"))?;
fs::create_dir_all(target_dir.join("idl"))?;
fs::create_dir_all(target_dir.join("types"))?;
if !&cfg.workspace.types.is_empty() {
fs::create_dir_all(workspace_dir.join(&cfg.workspace.types))?;
}
Expand Down Expand Up @@ -1595,12 +1600,20 @@ fn build_cwd_verifiable(
let idl = generate_idl(cfg, skip_lint, no_docs, &cargo_args)?;
// Write out the JSON file.
println!("Writing the IDL file");
let out_file = workspace_dir.join(format!("target/idl/{}.json", idl.metadata.name));
let out_file = workspace_dir
.join("target")
.join("idl")
.join(&idl.metadata.name)
.with_extension("json");
write_idl(&idl, OutFile::File(out_file))?;

// Write out the TypeScript type.
println!("Writing the .ts file");
let ts_file = workspace_dir.join(format!("target/types/{}.ts", idl.metadata.name));
let ts_file = workspace_dir
.join("target")
.join("types")
.join(&idl.metadata.name)
.with_extension("ts");
fs::write(&ts_file, idl_ts(&idl)?)?;

// Copy out the TypeScript type.
Expand Down Expand Up @@ -1802,7 +1815,12 @@ fn docker_build_bpf(
println!("Copying out the build artifacts");
let out_file = cfg_parent
.canonicalize()?
.join(format!("target/verifiable/{binary_name}.so"))
.join(
Path::new("target")
.join("verifiable")
.join(&binary_name)
.with_extension("so"),
)
.display()
.to_string();

Expand Down Expand Up @@ -2053,8 +2071,10 @@ fn verify(
.path()
.parent()
.ok_or_else(|| anyhow!("Unable to find workspace root"))?
.join("target/verifiable/")
.join(format!("{binary_name}.so"));
.join("target")
.join("verifiable")
.join(&binary_name)
.with_extension("so");

let url = cluster_url(&cfg, &cfg.test_validator);
let bin_ver = verify_bin(program_id, &bin_path, &url)?;
Expand Down Expand Up @@ -3417,7 +3437,8 @@ fn validator_flags(
idl.address = address;

// Persist it.
let idl_out = PathBuf::from("target/idl")
let idl_out = Path::new("target")
.join("idl")
.join(&idl.metadata.name)
.with_extension("json");
write_idl(idl, OutFile::File(idl_out))?;
Expand Down Expand Up @@ -3547,20 +3568,24 @@ fn validator_flags(
}

fn stream_logs(config: &WithPath<Config>, rpc_url: &str) -> Result<Vec<std::process::Child>> {
let program_logs_dir = ".anchor/program-logs";
if Path::new(program_logs_dir).exists() {
fs::remove_dir_all(program_logs_dir)?;
let program_logs_dir = Path::new(".anchor").join("program-logs");
if program_logs_dir.exists() {
fs::remove_dir_all(&program_logs_dir)?;
}
fs::create_dir_all(program_logs_dir)?;
fs::create_dir_all(&program_logs_dir)?;

let mut handles = vec![];
for program in config.read_all_programs()? {
let idl = fs::read(format!("target/idl/{}.json", program.lib_name))?;
let idl_path = Path::new("target")
.join("idl")
.join(&program.lib_name)
.with_extension("json");
let idl = fs::read(idl_path)?;
let idl = convert_idl(&idl)?;

let log_file = File::create(format!(
"{}/{}.{}.log",
program_logs_dir, idl.address, program.lib_name,
))?;
let log_file = File::create(
program_logs_dir.join(format!("{}.{}.log", idl.address, program.lib_name)),
)?;
let stdio = std::process::Stdio::from(log_file);
let child = std::process::Command::new("solana")
.arg("logs")
Expand All @@ -3574,7 +3599,8 @@ fn stream_logs(config: &WithPath<Config>, rpc_url: &str) -> Result<Vec<std::proc
if let Some(test) = config.test_validator.as_ref() {
if let Some(genesis) = &test.genesis {
for entry in genesis {
let log_file = File::create(format!("{}/{}.log", program_logs_dir, entry.address))?;
let log_file =
File::create(program_logs_dir.join(&entry.address).with_extension("log"))?;
let stdio = std::process::Stdio::from(log_file);
let child = std::process::Command::new("solana")
.arg("logs")
Expand Down Expand Up @@ -3692,10 +3718,9 @@ fn test_validator_file_paths(test_validator: &Option<TestValidator>) -> Result<(
Some(TestValidator {
validator: Some(validator),
..
}) => &validator.ledger,
_ => DEFAULT_LEDGER_PATH,
}) => PathBuf::from(&validator.ledger),
_ => get_default_ledger_path(),
};
let ledger_path = Path::new(ledger_path);

if !ledger_path.is_relative() {
// Prevent absolute paths to avoid someone using / or similar, as the
Expand All @@ -3704,15 +3729,13 @@ fn test_validator_file_paths(test_validator: &Option<TestValidator>) -> Result<(
std::process::exit(1);
}
if ledger_path.exists() {
fs::remove_dir_all(ledger_path)?;
fs::remove_dir_all(&ledger_path)?;
}

fs::create_dir_all(ledger_path)?;
fs::create_dir_all(&ledger_path)?;

Ok((
ledger_path.to_owned(),
ledger_path.join("test-ledger-log.txt"),
))
let log_path = ledger_path.join("test-ledger-log.txt");
Ok((ledger_path, log_path))
}

fn cluster_url(cfg: &Config, test_validator: &Option<TestValidator>) -> String {
Expand Down Expand Up @@ -3825,7 +3848,8 @@ fn deploy(
idl.address = program_id.to_string();

// Persist it.
let idl_out = PathBuf::from("target/idl")
let idl_out = Path::new("target")
.join("idl")
.join(&idl.metadata.name)
.with_extension("json");
write_idl(idl, OutFile::File(idl_out))?;
Expand Down Expand Up @@ -4267,12 +4291,14 @@ fn run(cfg_override: &ConfigOverride, script: String, script_args: Vec<String>)
}

fn login(_cfg_override: &ConfigOverride, token: String) -> Result<()> {
let dir = shellexpand::tilde("~/.config/anchor");
if !Path::new(&dir.to_string()).exists() {
fs::create_dir(dir.to_string())?;
let anchor_dir = Path::new(&*shellexpand::tilde("~"))
.join(".config")
.join("anchor");
if !anchor_dir.exists() {
fs::create_dir(&anchor_dir)?;
}

std::env::set_current_dir(dir.to_string())?;
std::env::set_current_dir(&anchor_dir)?;

// Freely overwrite the entire file since it's not used for anything else.
let mut file = File::create("credentials")?;
Expand Down Expand Up @@ -4467,8 +4493,11 @@ fn registry_api_token(_cfg_override: &ConfigOverride) -> Result<String> {
struct Credentials {
registry: Registry,
}
let filename = shellexpand::tilde("~/.config/anchor/credentials");
let mut file = File::open(filename.to_string())?;
let filename = Path::new(&*shellexpand::tilde("~"))
.join(".config")
.join("anchor")
.join("credentials");
let mut file = File::open(filename)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;

Expand Down Expand Up @@ -4730,7 +4759,8 @@ fn get_node_dns_option() -> Result<&'static str> {
// of spaces in keypair/binary paths, but this should be fixed in the Solana CLI
// and removed here.
fn strip_workspace_prefix(absolute_path: String) -> String {
let workspace_prefix = std::env::current_dir().unwrap().display().to_string() + "/";
let workspace_prefix =
std::env::current_dir().unwrap().display().to_string() + std::path::MAIN_SEPARATOR_STR;
absolute_path
.strip_prefix(&workspace_prefix)
.unwrap_or(&absolute_path)
Expand Down

0 comments on commit 5df7fbd

Please sign in to comment.