component.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. use crate::{
  2. discover_cluster_url,
  3. rust_template::create_component,
  4. templates::component::{component_type, component_type_import},
  5. workspace::with_workspace,
  6. };
  7. use anchor_cli::config::{ConfigOverride, ProgramDeployment};
  8. use anchor_lang_idl::types::Idl;
  9. use anyhow::{anyhow, Result};
  10. use std::{
  11. fs::{self, File, OpenOptions},
  12. io::Write,
  13. path::Path,
  14. process::Stdio,
  15. };
  16. // Create a new component from the template
  17. pub fn new_component(cfg_override: &ConfigOverride, name: String) -> Result<()> {
  18. with_workspace(cfg_override, |cfg| {
  19. match cfg.path().parent() {
  20. None => {
  21. println!("Unable to make new component");
  22. }
  23. Some(parent) => {
  24. std::env::set_current_dir(parent)?;
  25. let cluster = cfg.provider.cluster.clone();
  26. let programs = cfg.programs.entry(cluster).or_default();
  27. if programs.contains_key(&name) {
  28. return Err(anyhow!("Program already exists"));
  29. }
  30. programs.insert(
  31. name.clone(),
  32. ProgramDeployment {
  33. address: {
  34. create_component(&name)?;
  35. anchor_cli::rust_template::get_or_create_program_id(&name)
  36. },
  37. path: None,
  38. idl: None,
  39. },
  40. );
  41. let toml = cfg.to_string();
  42. fs::write("Anchor.toml", toml)?;
  43. println!("Created new component: {}", name);
  44. }
  45. };
  46. Ok(())
  47. })
  48. }
  49. pub fn extract_component_id(line: &str) -> Option<&str> {
  50. let component_id_marker = "#[component_id(";
  51. line.find(component_id_marker).map(|start| {
  52. let start = start + component_id_marker.len();
  53. let end = line[start..].find(')').unwrap() + start;
  54. line[start..end].trim_matches('"')
  55. })
  56. }
  57. pub fn fetch_idl_for_component(component_id: &str, url: &str) -> Result<String> {
  58. let output = std::process::Command::new("bolt")
  59. .arg("idl")
  60. .arg("fetch")
  61. .arg(component_id)
  62. .arg("--provider.cluster")
  63. .arg(url)
  64. .stdout(Stdio::piped())
  65. .stderr(Stdio::piped())
  66. .output()?;
  67. if output.status.success() {
  68. let idl_string = String::from_utf8(output.stdout)
  69. .map_err(|e| anyhow!("Failed to decode IDL output as UTF-8: {}", e))?
  70. .to_string();
  71. Ok(idl_string)
  72. } else {
  73. let error_message = String::from_utf8(output.stderr)
  74. .unwrap_or(format!(
  75. "Error trying to dynamically generate the type \
  76. for component {}, unable to fetch the idl. \nEnsure that the idl is available. Specify \
  77. the appropriate cluster using the --provider.cluster option",
  78. component_id
  79. ))
  80. .to_string();
  81. Err(anyhow!("Command failed with error: {}", error_message))
  82. }
  83. }
  84. pub fn generate_component_type_file(
  85. file_path: &Path,
  86. cfg_override: &ConfigOverride,
  87. component_id: &str,
  88. ) -> Result<()> {
  89. let url = discover_cluster_url(cfg_override)?;
  90. let idl_string = fetch_idl_for_component(component_id, &url)?;
  91. let idl: Idl = serde_json::from_str(&idl_string)?;
  92. let mut file = File::create(file_path)?;
  93. file.write_all(component_type(&idl, component_id)?.as_bytes())?;
  94. Ok(())
  95. }
  96. pub fn append_component_to_lib_rs(lib_rs_path: &Path, component_id: &str) -> Result<()> {
  97. let mut file = OpenOptions::new()
  98. .create(true)
  99. .append(true)
  100. .open(lib_rs_path)?;
  101. file.write_all(component_type_import(component_id).as_bytes())?;
  102. Ok(())
  103. }