cli: Fix Cargo.lock in workspace subdirectories when publishing (#593)
This commit is contained in:
parent
80e4030e45
commit
bd68e28f15
|
@ -15,6 +15,10 @@ incremented for features.
|
||||||
|
|
||||||
* cli: Programs embedded into genesis during tests will produce program logs.
|
* cli: Programs embedded into genesis during tests will produce program logs.
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* cli: Allows Cargo.lock to exist in workspace subdirectories when publishing ([#593](https://github.com/project-serum/anchor/pull/593)).
|
||||||
|
|
||||||
## [0.13.0] - 2021-08-08
|
## [0.13.0] - 2021-08-08
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
|
@ -159,6 +159,7 @@ dependencies = [
|
||||||
"tar",
|
"tar",
|
||||||
"tokio 1.4.0",
|
"tokio 1.4.0",
|
||||||
"toml",
|
"toml",
|
||||||
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -36,3 +36,4 @@ reqwest = { version = "0.11.4", features = ["multipart", "blocking"] }
|
||||||
tokio = "1.0"
|
tokio = "1.0"
|
||||||
pathdiff = "0.2.0"
|
pathdiff = "0.2.0"
|
||||||
cargo_toml = "0.9.2"
|
cargo_toml = "0.9.2"
|
||||||
|
walkdir = "2"
|
|
@ -9,6 +9,7 @@ use std::collections::BTreeMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -48,6 +49,68 @@ impl<T> std::convert::AsRef<T> for WithPath<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Manifest(cargo_toml::Manifest);
|
||||||
|
|
||||||
|
impl Manifest {
|
||||||
|
pub fn from_path(p: impl AsRef<Path>) -> Result<Self> {
|
||||||
|
cargo_toml::Manifest::from_path(p)
|
||||||
|
.map(Manifest)
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lib_name(&self) -> Result<String> {
|
||||||
|
if self.lib.is_some() && self.lib.as_ref().unwrap().name.is_some() {
|
||||||
|
Ok(self
|
||||||
|
.lib
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.name
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.to_string())
|
||||||
|
} else {
|
||||||
|
Ok(self
|
||||||
|
.package
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| anyhow!("package section not provided"))?
|
||||||
|
.name
|
||||||
|
.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Climbs each parent directory until we find a Cargo.toml.
|
||||||
|
pub fn discover() -> Result<Option<WithPath<Manifest>>> {
|
||||||
|
let _cwd = std::env::current_dir()?;
|
||||||
|
let mut cwd_opt = Some(_cwd.as_path());
|
||||||
|
|
||||||
|
while let Some(cwd) = cwd_opt {
|
||||||
|
for f in fs::read_dir(cwd)? {
|
||||||
|
let p = f?.path();
|
||||||
|
if let Some(filename) = p.file_name() {
|
||||||
|
if filename.to_str() == Some("Cargo.toml") {
|
||||||
|
let m = WithPath::new(Manifest::from_path(&p)?, p);
|
||||||
|
return Ok(Some(m));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found. Go up a directory level.
|
||||||
|
cwd_opt = cwd.parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Manifest {
|
||||||
|
type Target = cargo_toml::Manifest;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WithPath<Config> {
|
impl WithPath<Config> {
|
||||||
pub fn get_program_list(&self) -> Result<Vec<PathBuf>> {
|
pub fn get_program_list(&self) -> Result<Vec<PathBuf>> {
|
||||||
// Canonicalize the workspace filepaths to compare with relative paths.
|
// Canonicalize the workspace filepaths to compare with relative paths.
|
||||||
|
@ -82,7 +145,7 @@ impl WithPath<Config> {
|
||||||
let mut r = vec![];
|
let mut r = vec![];
|
||||||
for path in self.get_program_list()? {
|
for path in self.get_program_list()? {
|
||||||
let idl = anchor_syn::idl::file::parse(path.join("src/lib.rs"))?;
|
let idl = anchor_syn::idl::file::parse(path.join("src/lib.rs"))?;
|
||||||
let lib_name = extract_lib_name(&path.join("Cargo.toml"))?;
|
let lib_name = Manifest::from_path(&path.join("Cargo.toml"))?.lib_name()?;
|
||||||
r.push(Program {
|
r.push(Program {
|
||||||
lib_name,
|
lib_name,
|
||||||
path,
|
path,
|
||||||
|
@ -97,16 +160,53 @@ impl WithPath<Config> {
|
||||||
.workspace
|
.workspace
|
||||||
.members
|
.members
|
||||||
.iter()
|
.iter()
|
||||||
.map(|m| PathBuf::from(m).canonicalize().unwrap())
|
.map(|m| {
|
||||||
|
self.path()
|
||||||
|
.parent()
|
||||||
|
.unwrap()
|
||||||
|
.join(m)
|
||||||
|
.canonicalize()
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let exclude = self
|
let exclude = self
|
||||||
.workspace
|
.workspace
|
||||||
.exclude
|
.exclude
|
||||||
.iter()
|
.iter()
|
||||||
.map(|m| PathBuf::from(m).canonicalize().unwrap())
|
.map(|m| {
|
||||||
|
self.path()
|
||||||
|
.parent()
|
||||||
|
.unwrap()
|
||||||
|
.join(m)
|
||||||
|
.canonicalize()
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
Ok((members, exclude))
|
Ok((members, exclude))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_program(&self, name: &str) -> Result<Option<WithPath<Program>>> {
|
||||||
|
for program in self.read_all_programs()? {
|
||||||
|
let cargo_toml = program.path.join("Cargo.toml");
|
||||||
|
if !cargo_toml.exists() {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Did not find Cargo.toml at the path: {}",
|
||||||
|
program.path.display()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let p_lib_name = Manifest::from_path(&cargo_toml)?.lib_name()?;
|
||||||
|
if name == p_lib_name {
|
||||||
|
let path = self
|
||||||
|
.path()
|
||||||
|
.parent()
|
||||||
|
.unwrap()
|
||||||
|
.canonicalize()?
|
||||||
|
.join(&program.path);
|
||||||
|
return Ok(Some(WithPath::new(program, path)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> std::ops::Deref for WithPath<T> {
|
impl<T> std::ops::Deref for WithPath<T> {
|
||||||
|
@ -174,71 +274,51 @@ impl Config {
|
||||||
format!("projectserum/build:v{}", ver)
|
format!("projectserum/build:v{}", ver)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn discover(
|
pub fn discover(cfg_override: &ConfigOverride) -> Result<Option<WithPath<Config>>> {
|
||||||
cfg_override: &ConfigOverride,
|
|
||||||
) -> Result<Option<(WithPath<Config>, Option<PathBuf>)>> {
|
|
||||||
Config::_discover().map(|opt| {
|
Config::_discover().map(|opt| {
|
||||||
opt.map(|(mut cfg, cargo_toml)| {
|
opt.map(|mut cfg| {
|
||||||
if let Some(cluster) = cfg_override.cluster.clone() {
|
if let Some(cluster) = cfg_override.cluster.clone() {
|
||||||
cfg.provider.cluster = cluster;
|
cfg.provider.cluster = cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(wallet) = cfg_override.wallet.clone() {
|
if let Some(wallet) = cfg_override.wallet.clone() {
|
||||||
cfg.provider.wallet = wallet;
|
cfg.provider.wallet = wallet;
|
||||||
}
|
}
|
||||||
(cfg, cargo_toml)
|
cfg
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Searches all parent directories for an Anchor.toml file.
|
// Climbs each parent directory until we find an Anchor.toml.
|
||||||
fn _discover() -> Result<Option<(WithPath<Config>, Option<PathBuf>)>> {
|
fn _discover() -> Result<Option<WithPath<Config>>> {
|
||||||
// Set to true if we ever see a Cargo.toml file when traversing the
|
|
||||||
// parent directories.
|
|
||||||
let mut cargo_toml = None;
|
|
||||||
|
|
||||||
let _cwd = std::env::current_dir()?;
|
let _cwd = std::env::current_dir()?;
|
||||||
let mut cwd_opt = Some(_cwd.as_path());
|
let mut cwd_opt = Some(_cwd.as_path());
|
||||||
|
|
||||||
while let Some(cwd) = cwd_opt {
|
while let Some(cwd) = cwd_opt {
|
||||||
let files = fs::read_dir(cwd)?;
|
for f in fs::read_dir(cwd)? {
|
||||||
// Cargo.toml file for this directory level.
|
|
||||||
let mut cargo_toml_level = None;
|
|
||||||
let mut anchor_toml = None;
|
|
||||||
for f in files {
|
|
||||||
let p = f?.path();
|
let p = f?.path();
|
||||||
if let Some(filename) = p.file_name() {
|
if let Some(filename) = p.file_name() {
|
||||||
if filename.to_str() == Some("Cargo.toml") {
|
if filename.to_str() == Some("Anchor.toml") {
|
||||||
cargo_toml_level = Some(p);
|
let cfg = Config::from_path(&p)?;
|
||||||
} else if filename.to_str() == Some("Anchor.toml") {
|
return Ok(Some(WithPath::new(cfg, p)));
|
||||||
let mut cfg_file = File::open(&p)?;
|
|
||||||
let mut cfg_contents = String::new();
|
|
||||||
cfg_file.read_to_string(&mut cfg_contents)?;
|
|
||||||
let cfg = cfg_contents.parse()?;
|
|
||||||
anchor_toml = Some((cfg, p));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the Cargo.toml if it's for a single package, i.e., not the
|
|
||||||
// root workspace Cargo.toml.
|
|
||||||
if cargo_toml.is_none() && cargo_toml_level.is_some() {
|
|
||||||
let toml = cargo_toml::Manifest::from_path(cargo_toml_level.as_ref().unwrap())?;
|
|
||||||
if toml.workspace.is_none() {
|
|
||||||
cargo_toml = cargo_toml_level;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((cfg, parent)) = anchor_toml {
|
|
||||||
return Ok(Some((WithPath::new(cfg, parent), cargo_toml)));
|
|
||||||
}
|
|
||||||
|
|
||||||
cwd_opt = cwd.parent();
|
cwd_opt = cwd.parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_path(p: impl AsRef<Path>) -> Result<Self> {
|
||||||
|
let mut cfg_file = File::open(&p)?;
|
||||||
|
let mut cfg_contents = String::new();
|
||||||
|
cfg_file.read_to_string(&mut cfg_contents)?;
|
||||||
|
let cfg = cfg_contents.parse()?;
|
||||||
|
|
||||||
|
Ok(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn wallet_kp(&self) -> Result<Keypair> {
|
pub fn wallet_kp(&self) -> Result<Keypair> {
|
||||||
solana_sdk::signature::read_keypair_file(&self.provider.wallet.to_string())
|
solana_sdk::signature::read_keypair_file(&self.provider.wallet.to_string())
|
||||||
.map_err(|_| anyhow!("Unable to read keypair file"))
|
.map_err(|_| anyhow!("Unable to read keypair file"))
|
||||||
|
@ -382,21 +462,10 @@ pub struct GenesisEntry {
|
||||||
pub program: String,
|
pub program: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_lib_name(cargo_toml: impl AsRef<Path>) -> Result<String> {
|
|
||||||
let cargo_toml = cargo_toml::Manifest::from_path(cargo_toml)?;
|
|
||||||
if cargo_toml.lib.is_some() && cargo_toml.lib.as_ref().unwrap().name.is_some() {
|
|
||||||
Ok(cargo_toml.lib.unwrap().name.unwrap())
|
|
||||||
} else {
|
|
||||||
Ok(cargo_toml
|
|
||||||
.package
|
|
||||||
.ok_or_else(|| anyhow!("Package section not provided"))?
|
|
||||||
.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
pub lib_name: String,
|
pub lib_name: String,
|
||||||
|
// Canonicalized path to the program directory.
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
pub idl: Option<Idl>,
|
pub idl: Option<Idl>,
|
||||||
}
|
}
|
||||||
|
@ -463,7 +532,6 @@ pub struct ProgramWorkspace {
|
||||||
pub struct AnchorPackage {
|
pub struct AnchorPackage {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub address: String,
|
pub address: String,
|
||||||
pub path: String,
|
|
||||||
pub idl: Option<String>,
|
pub idl: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,19 +547,9 @@ impl AnchorPackage {
|
||||||
.ok_or_else(|| anyhow!("Program not provided in Anchor.toml"))?
|
.ok_or_else(|| anyhow!("Program not provided in Anchor.toml"))?
|
||||||
.get(&name)
|
.get(&name)
|
||||||
.ok_or_else(|| anyhow!("Program not provided in Anchor.toml"))?;
|
.ok_or_else(|| anyhow!("Program not provided in Anchor.toml"))?;
|
||||||
let path = program_details
|
|
||||||
.path
|
|
||||||
.clone()
|
|
||||||
// TODO: use a default path if one isn't provided?
|
|
||||||
.ok_or_else(|| anyhow!("Path to program binary not provided"))?;
|
|
||||||
let idl = program_details.idl.clone();
|
let idl = program_details.idl.clone();
|
||||||
let address = program_details.address.to_string();
|
let address = program_details.address.to_string();
|
||||||
Ok(Self {
|
Ok(Self { name, address, idl })
|
||||||
name,
|
|
||||||
path,
|
|
||||||
address,
|
|
||||||
idl,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
283
cli/src/lib.rs
283
cli/src/lib.rs
|
@ -1,4 +1,6 @@
|
||||||
use crate::config::{AnchorPackage, Config, ConfigOverride, Program, ProgramWorkspace, WithPath};
|
use crate::config::{
|
||||||
|
AnchorPackage, Config, ConfigOverride, Manifest, Program, ProgramWorkspace, WithPath,
|
||||||
|
};
|
||||||
use anchor_client::Cluster;
|
use anchor_client::Cluster;
|
||||||
use anchor_lang::idl::{IdlAccount, IdlInstruction};
|
use anchor_lang::idl::{IdlAccount, IdlInstruction};
|
||||||
use anchor_lang::{AccountDeserialize, AnchorDeserialize, AnchorSerialize};
|
use anchor_lang::{AccountDeserialize, AnchorDeserialize, AnchorSerialize};
|
||||||
|
@ -297,11 +299,8 @@ pub fn entry(opts: Opts) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(cfg_override: &ConfigOverride, name: String, typescript: bool) -> Result<()> {
|
fn init(cfg_override: &ConfigOverride, name: String, typescript: bool) -> Result<()> {
|
||||||
let cfg = Config::discover(cfg_override)?;
|
let _ =
|
||||||
|
Config::discover(cfg_override)?.ok_or_else(|| anyhow!("Workspace already initialized"))?;
|
||||||
if cfg.is_some() {
|
|
||||||
println!("Anchor workspace already initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::create_dir(name.clone())?;
|
fs::create_dir(name.clone())?;
|
||||||
std::env::set_current_dir(&name)?;
|
std::env::set_current_dir(&name)?;
|
||||||
|
@ -364,7 +363,7 @@ fn init(cfg_override: &ConfigOverride, name: String, typescript: bool) -> Result
|
||||||
|
|
||||||
// Creates a new program crate in the `programs/<name>` directory.
|
// Creates a new program crate in the `programs/<name>` directory.
|
||||||
fn new(cfg_override: &ConfigOverride, name: String) -> Result<()> {
|
fn new(cfg_override: &ConfigOverride, name: String) -> Result<()> {
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
match cfg.path().parent() {
|
match cfg.path().parent() {
|
||||||
None => {
|
None => {
|
||||||
println!("Unable to make new program");
|
println!("Unable to make new program");
|
||||||
|
@ -401,41 +400,14 @@ pub fn build(
|
||||||
stdout: Option<File>, // Used for the package registry server.
|
stdout: Option<File>, // Used for the package registry server.
|
||||||
stderr: Option<File>, // Used for the package registry server.
|
stderr: Option<File>, // Used for the package registry server.
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// Change directories to the given `program_name`, if given.
|
// Change to the workspace member directory, if needed.
|
||||||
let (cfg, _cargo) = Config::discover(cfg_override)?.expect("Not in workspace.");
|
|
||||||
|
|
||||||
let mut did_find_program = false;
|
|
||||||
if let Some(program_name) = program_name.as_ref() {
|
if let Some(program_name) = program_name.as_ref() {
|
||||||
for program in cfg.read_all_programs()? {
|
cd_member(cfg_override, program_name)?;
|
||||||
let cargo_toml = program.path.join("Cargo.toml");
|
|
||||||
if !cargo_toml.exists() {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"Did not find Cargo.toml at the path: {}",
|
|
||||||
program.path.display()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let p_lib_name = config::extract_lib_name(&cargo_toml)?;
|
|
||||||
if program_name.as_str() == p_lib_name {
|
|
||||||
let program_path = cfg
|
|
||||||
.path()
|
|
||||||
.parent()
|
|
||||||
.unwrap()
|
|
||||||
.canonicalize()?
|
|
||||||
.join(program.path);
|
|
||||||
std::env::set_current_dir(&program_path)?;
|
|
||||||
did_find_program = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !did_find_program && program_name.is_some() {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"{} is not part of the workspace",
|
|
||||||
program_name.as_ref().unwrap()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (cfg, cargo) = Config::discover(cfg_override)?.expect("Not in workspace.");
|
let cfg = Config::discover(cfg_override)?.expect("Not in workspace.");
|
||||||
|
let cargo = Manifest::discover()?;
|
||||||
|
|
||||||
let idl_out = match idl {
|
let idl_out = match idl {
|
||||||
Some(idl) => Some(PathBuf::from(idl)),
|
Some(idl) => Some(PathBuf::from(idl)),
|
||||||
None => {
|
None => {
|
||||||
|
@ -454,17 +426,37 @@ pub fn build(
|
||||||
};
|
};
|
||||||
|
|
||||||
match cargo {
|
match cargo {
|
||||||
None => build_all(&cfg, cfg.path(), idl_out, verifiable, solana_version)?,
|
// No Cargo.toml so build the entire workspace.
|
||||||
Some(ct) => build_cwd(
|
None => build_all(
|
||||||
&cfg,
|
&cfg,
|
||||||
ct,
|
cfg.path(),
|
||||||
idl_out,
|
idl_out,
|
||||||
verifiable,
|
verifiable,
|
||||||
solana_version,
|
solana_version,
|
||||||
stdout,
|
stdout,
|
||||||
stderr,
|
stderr,
|
||||||
)?,
|
)?,
|
||||||
};
|
// If the Cargo.toml is at the root, build the entire workspace.
|
||||||
|
Some(cargo) if cargo.path().parent() == cfg.path().parent() => build_all(
|
||||||
|
&cfg,
|
||||||
|
cfg.path(),
|
||||||
|
idl_out,
|
||||||
|
verifiable,
|
||||||
|
solana_version,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
)?,
|
||||||
|
// Cargo.toml represents a single package. Build it.
|
||||||
|
Some(cargo) => build_cwd(
|
||||||
|
&cfg,
|
||||||
|
cargo.path().to_path_buf(),
|
||||||
|
idl_out,
|
||||||
|
verifiable,
|
||||||
|
solana_version,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
)?,
|
||||||
|
}
|
||||||
|
|
||||||
set_workspace_dir_or_exit();
|
set_workspace_dir_or_exit();
|
||||||
|
|
||||||
|
@ -477,6 +469,8 @@ fn build_all(
|
||||||
idl_out: Option<PathBuf>,
|
idl_out: Option<PathBuf>,
|
||||||
verifiable: bool,
|
verifiable: bool,
|
||||||
solana_version: Option<String>,
|
solana_version: Option<String>,
|
||||||
|
stdout: Option<File>, // Used for the package registry server.
|
||||||
|
stderr: Option<File>, // Used for the package registry server.
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let cur_dir = std::env::current_dir()?;
|
let cur_dir = std::env::current_dir()?;
|
||||||
let r = match cfg_path.parent() {
|
let r = match cfg_path.parent() {
|
||||||
|
@ -489,8 +483,8 @@ fn build_all(
|
||||||
idl_out.clone(),
|
idl_out.clone(),
|
||||||
verifiable,
|
verifiable,
|
||||||
solana_version.clone(),
|
solana_version.clone(),
|
||||||
None,
|
stdout.as_ref().map(|f| f.try_clone()).transpose()?,
|
||||||
None,
|
stderr.as_ref().map(|f| f.try_clone()).transpose()?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -531,7 +525,7 @@ fn build_cwd_verifiable(
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// Create output dirs.
|
// Create output dirs.
|
||||||
let workspace_dir = cfg.path().parent().unwrap().canonicalize()?;
|
let workspace_dir = cfg.path().parent().unwrap().canonicalize()?;
|
||||||
fs::create_dir_all(workspace_dir.join("target/deploy"))?;
|
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/idl"))?;
|
||||||
|
|
||||||
let container_name = "anchor-program";
|
let container_name = "anchor-program";
|
||||||
|
@ -595,7 +589,7 @@ fn docker_build(
|
||||||
stdout: Option<File>,
|
stdout: Option<File>,
|
||||||
stderr: Option<File>,
|
stderr: Option<File>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let binary_name = config::extract_lib_name(&cargo_toml)?;
|
let binary_name = Manifest::from_path(&cargo_toml)?.lib_name()?;
|
||||||
|
|
||||||
// Docker vars.
|
// Docker vars.
|
||||||
let image_name = cfg.docker();
|
let image_name = cfg.docker();
|
||||||
|
@ -718,7 +712,7 @@ fn docker_build(
|
||||||
.parent()
|
.parent()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.canonicalize()?
|
.canonicalize()?
|
||||||
.join(format!("target/deploy/{}.so", binary_name))
|
.join(format!("target/verifiable/{}.so", binary_name))
|
||||||
.display()
|
.display()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
|
@ -774,45 +768,14 @@ fn verify(
|
||||||
program_name: Option<String>,
|
program_name: Option<String>,
|
||||||
solana_version: Option<String>,
|
solana_version: Option<String>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// Change directories to the given `program_name`, if given.
|
// Change to the workspace member directory, if needed.
|
||||||
let (cfg, _cargo) = Config::discover(cfg_override)?.expect("Not in workspace.");
|
|
||||||
let mut did_find_program = false;
|
|
||||||
if let Some(program_name) = program_name.as_ref() {
|
if let Some(program_name) = program_name.as_ref() {
|
||||||
for program in cfg.read_all_programs()? {
|
cd_member(cfg_override, program_name)?;
|
||||||
let cargo_toml = program.path.join("Cargo.toml");
|
|
||||||
if !cargo_toml.exists() {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"Did not find Cargo.toml at the path: {}",
|
|
||||||
program.path.display()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let p_lib_name = config::extract_lib_name(&cargo_toml)?;
|
|
||||||
if program_name.as_str() == p_lib_name {
|
|
||||||
let program_path = cfg
|
|
||||||
.path()
|
|
||||||
.parent()
|
|
||||||
.unwrap()
|
|
||||||
.canonicalize()?
|
|
||||||
.join(program.path);
|
|
||||||
std::env::set_current_dir(&program_path)?;
|
|
||||||
did_find_program = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !did_find_program && program_name.is_some() {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"{} is not part of the workspace",
|
|
||||||
program_name.as_ref().unwrap()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proceed with the command.
|
// Proceed with the command.
|
||||||
let (cfg, cargo) = Config::discover(cfg_override)?.expect("Not in workspace.");
|
let cfg = Config::discover(cfg_override)?.expect("Not in workspace.");
|
||||||
let cargo = cargo.ok_or_else(|| {
|
let cargo = Manifest::discover()?.ok_or_else(|| anyhow!("Cargo.toml not found"))?;
|
||||||
anyhow!("Must be inside program subdirectory if no program name is given.")
|
|
||||||
})?;
|
|
||||||
let program_dir = cargo.parent().unwrap();
|
|
||||||
|
|
||||||
// Build the program we want to verify.
|
// Build the program we want to verify.
|
||||||
let cur_dir = std::env::current_dir()?;
|
let cur_dir = std::env::current_dir()?;
|
||||||
|
@ -831,23 +794,12 @@ fn verify(
|
||||||
std::env::set_current_dir(&cur_dir)?;
|
std::env::set_current_dir(&cur_dir)?;
|
||||||
|
|
||||||
// Verify binary.
|
// Verify binary.
|
||||||
let binary_name = {
|
let binary_name = cargo.lib_name()?;
|
||||||
let cargo_toml = cargo_toml::Manifest::from_path(&cargo)?;
|
|
||||||
match cargo_toml.lib {
|
|
||||||
None => {
|
|
||||||
cargo_toml
|
|
||||||
.package
|
|
||||||
.ok_or_else(|| anyhow!("Package section not provided"))?
|
|
||||||
.name
|
|
||||||
}
|
|
||||||
Some(lib) => lib.name.ok_or_else(|| anyhow!("Name not provided"))?,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let bin_path = cfg
|
let bin_path = cfg
|
||||||
.path()
|
.path()
|
||||||
.parent()
|
.parent()
|
||||||
.ok_or_else(|| anyhow!("Unable to find workspace root"))?
|
.ok_or_else(|| anyhow!("Unable to find workspace root"))?
|
||||||
.join("target/deploy/")
|
.join("target/verifiable/")
|
||||||
.join(format!("{}.so", binary_name));
|
.join(format!("{}.so", binary_name));
|
||||||
|
|
||||||
let bin_ver = verify_bin(program_id, &bin_path, cfg.provider.cluster.url())?;
|
let bin_ver = verify_bin(program_id, &bin_path, cfg.provider.cluster.url())?;
|
||||||
|
@ -859,7 +811,6 @@ fn verify(
|
||||||
// Verify IDL (only if it's not a buffer account).
|
// Verify IDL (only if it's not a buffer account).
|
||||||
if let Some(local_idl) = extract_idl("src/lib.rs")? {
|
if let Some(local_idl) = extract_idl("src/lib.rs")? {
|
||||||
if bin_ver.state != BinVerificationState::Buffer {
|
if bin_ver.state != BinVerificationState::Buffer {
|
||||||
std::env::set_current_dir(program_dir)?;
|
|
||||||
let deployed_idl = fetch_idl(cfg_override, program_id)?;
|
let deployed_idl = fetch_idl(cfg_override, program_id)?;
|
||||||
if local_idl != deployed_idl {
|
if local_idl != deployed_idl {
|
||||||
println!("Error: IDLs don't match");
|
println!("Error: IDLs don't match");
|
||||||
|
@ -873,6 +824,27 @@ fn verify(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cd_member(cfg_override: &ConfigOverride, program_name: &str) -> Result<()> {
|
||||||
|
// Change directories to the given `program_name`, if given.
|
||||||
|
let cfg = Config::discover(cfg_override)?.expect("Not in workspace.");
|
||||||
|
|
||||||
|
for program in cfg.read_all_programs()? {
|
||||||
|
let cargo_toml = program.path.join("Cargo.toml");
|
||||||
|
if !cargo_toml.exists() {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Did not find Cargo.toml at the path: {}",
|
||||||
|
program.path.display()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let p_lib_name = Manifest::from_path(&cargo_toml)?.lib_name()?;
|
||||||
|
if program_name == p_lib_name {
|
||||||
|
std::env::set_current_dir(&program.path)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(anyhow!("{} is not part of the workspace", program_name,));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn verify_bin(program_id: Pubkey, bin_path: &Path, cluster: &str) -> Result<BinVerification> {
|
pub fn verify_bin(program_id: Pubkey, bin_path: &Path, cluster: &str) -> Result<BinVerification> {
|
||||||
let client = RpcClient::new(cluster.to_string());
|
let client = RpcClient::new(cluster.to_string());
|
||||||
|
|
||||||
|
@ -954,9 +926,7 @@ pub enum BinVerificationState {
|
||||||
|
|
||||||
// Fetches an IDL for the given program_id.
|
// Fetches an IDL for the given program_id.
|
||||||
fn fetch_idl(cfg_override: &ConfigOverride, idl_addr: Pubkey) -> Result<Idl> {
|
fn fetch_idl(cfg_override: &ConfigOverride, idl_addr: Pubkey) -> Result<Idl> {
|
||||||
let cfg = Config::discover(cfg_override)?
|
let cfg = Config::discover(cfg_override)?.expect("Inside a workspace");
|
||||||
.expect("Inside a workspace")
|
|
||||||
.0;
|
|
||||||
let client = RpcClient::new(cfg.provider.cluster.url().to_string());
|
let client = RpcClient::new(cfg.provider.cluster.url().to_string());
|
||||||
|
|
||||||
let mut account = client
|
let mut account = client
|
||||||
|
@ -1017,7 +987,7 @@ fn idl(cfg_override: &ConfigOverride, subcmd: IdlCommand) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn idl_init(cfg_override: &ConfigOverride, program_id: Pubkey, idl_filepath: String) -> Result<()> {
|
fn idl_init(cfg_override: &ConfigOverride, program_id: Pubkey, idl_filepath: String) -> Result<()> {
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
let keypair = cfg.provider.wallet.to_string();
|
let keypair = cfg.provider.wallet.to_string();
|
||||||
|
|
||||||
let bytes = std::fs::read(idl_filepath)?;
|
let bytes = std::fs::read(idl_filepath)?;
|
||||||
|
@ -1035,7 +1005,7 @@ fn idl_write_buffer(
|
||||||
program_id: Pubkey,
|
program_id: Pubkey,
|
||||||
idl_filepath: String,
|
idl_filepath: String,
|
||||||
) -> Result<Pubkey> {
|
) -> Result<Pubkey> {
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
let keypair = cfg.provider.wallet.to_string();
|
let keypair = cfg.provider.wallet.to_string();
|
||||||
|
|
||||||
let bytes = std::fs::read(idl_filepath)?;
|
let bytes = std::fs::read(idl_filepath)?;
|
||||||
|
@ -1051,7 +1021,7 @@ fn idl_write_buffer(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn idl_set_buffer(cfg_override: &ConfigOverride, program_id: Pubkey, buffer: Pubkey) -> Result<()> {
|
fn idl_set_buffer(cfg_override: &ConfigOverride, program_id: Pubkey, buffer: Pubkey) -> Result<()> {
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
let keypair = solana_sdk::signature::read_keypair_file(&cfg.provider.wallet.to_string())
|
let keypair = solana_sdk::signature::read_keypair_file(&cfg.provider.wallet.to_string())
|
||||||
.map_err(|_| anyhow!("Unable to read keypair file"))?;
|
.map_err(|_| anyhow!("Unable to read keypair file"))?;
|
||||||
let client = RpcClient::new(cfg.provider.cluster.url().to_string());
|
let client = RpcClient::new(cfg.provider.cluster.url().to_string());
|
||||||
|
@ -1105,7 +1075,7 @@ fn idl_upgrade(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn idl_authority(cfg_override: &ConfigOverride, program_id: Pubkey) -> Result<()> {
|
fn idl_authority(cfg_override: &ConfigOverride, program_id: Pubkey) -> Result<()> {
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
let client = RpcClient::new(cfg.provider.cluster.url().to_string());
|
let client = RpcClient::new(cfg.provider.cluster.url().to_string());
|
||||||
let idl_address = {
|
let idl_address = {
|
||||||
let account = client
|
let account = client
|
||||||
|
@ -1135,7 +1105,7 @@ fn idl_set_authority(
|
||||||
address: Option<Pubkey>,
|
address: Option<Pubkey>,
|
||||||
new_authority: Pubkey,
|
new_authority: Pubkey,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
// Misc.
|
// Misc.
|
||||||
let idl_address = match address {
|
let idl_address = match address {
|
||||||
None => IdlAccount::address(&program_id),
|
None => IdlAccount::address(&program_id),
|
||||||
|
@ -1306,7 +1276,7 @@ fn test(
|
||||||
skip_build: bool,
|
skip_build: bool,
|
||||||
extra_args: Vec<String>,
|
extra_args: Vec<String>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
// Build if needed.
|
// Build if needed.
|
||||||
if !skip_build {
|
if !skip_build {
|
||||||
build(cfg_override, None, false, None, None, None, None)?;
|
build(cfg_override, None, false, None, None, None, None)?;
|
||||||
|
@ -1534,7 +1504,7 @@ fn _deploy(
|
||||||
cfg_override: &ConfigOverride,
|
cfg_override: &ConfigOverride,
|
||||||
program_str: Option<String>,
|
program_str: Option<String>,
|
||||||
) -> Result<Vec<(Pubkey, Program)>> {
|
) -> Result<Vec<(Pubkey, Program)>> {
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
let url = cfg.provider.cluster.url().to_string();
|
let url = cfg.provider.cluster.url().to_string();
|
||||||
let keypair = cfg.provider.wallet.to_string();
|
let keypair = cfg.provider.wallet.to_string();
|
||||||
|
|
||||||
|
@ -1615,7 +1585,7 @@ fn upgrade(
|
||||||
let path: PathBuf = program_filepath.parse().unwrap();
|
let path: PathBuf = program_filepath.parse().unwrap();
|
||||||
let program_filepath = path.canonicalize()?.display().to_string();
|
let program_filepath = path.canonicalize()?.display().to_string();
|
||||||
|
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
let exit = std::process::Command::new("solana")
|
let exit = std::process::Command::new("solana")
|
||||||
.arg("program")
|
.arg("program")
|
||||||
.arg("deploy")
|
.arg("deploy")
|
||||||
|
@ -1655,7 +1625,7 @@ fn launch(
|
||||||
)?;
|
)?;
|
||||||
let programs = _deploy(cfg_override, program_name)?;
|
let programs = _deploy(cfg_override, program_name)?;
|
||||||
|
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
let keypair = cfg.provider.wallet.to_string();
|
let keypair = cfg.provider.wallet.to_string();
|
||||||
|
|
||||||
// Add metadata to all IDLs.
|
// Add metadata to all IDLs.
|
||||||
|
@ -1680,10 +1650,7 @@ fn launch(
|
||||||
// The Solana CLI doesn't redeploy a program if this file exists.
|
// The Solana CLI doesn't redeploy a program if this file exists.
|
||||||
// So remove it to make all commands explicit.
|
// So remove it to make all commands explicit.
|
||||||
fn clear_program_keys(cfg_override: &ConfigOverride) -> Result<()> {
|
fn clear_program_keys(cfg_override: &ConfigOverride) -> Result<()> {
|
||||||
let config = Config::discover(cfg_override)
|
let config = Config::discover(cfg_override).unwrap_or_default().unwrap();
|
||||||
.unwrap_or_default()
|
|
||||||
.unwrap()
|
|
||||||
.0;
|
|
||||||
|
|
||||||
for program in config.read_all_programs()? {
|
for program in config.read_all_programs()? {
|
||||||
let anchor_keypair_path = program.anchor_keypair_path();
|
let anchor_keypair_path = program.anchor_keypair_path();
|
||||||
|
@ -1827,7 +1794,7 @@ fn serialize_idl_ix(ix_inner: anchor_lang::idl::IdlInstruction) -> Result<Vec<u8
|
||||||
}
|
}
|
||||||
|
|
||||||
fn migrate(cfg_override: &ConfigOverride) -> Result<()> {
|
fn migrate(cfg_override: &ConfigOverride) -> Result<()> {
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
println!("Running migration deploy script");
|
println!("Running migration deploy script");
|
||||||
|
|
||||||
let url = cfg.provider.cluster.url().to_string();
|
let url = cfg.provider.cluster.url().to_string();
|
||||||
|
@ -1874,10 +1841,7 @@ fn migrate(cfg_override: &ConfigOverride) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_workspace_dir_or_exit() {
|
fn set_workspace_dir_or_exit() {
|
||||||
let d = match Config::discover(&ConfigOverride {
|
let d = match Config::discover(&ConfigOverride::default()) {
|
||||||
cluster: None,
|
|
||||||
wallet: None,
|
|
||||||
}) {
|
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("Not in anchor workspace.");
|
println!("Not in anchor workspace.");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
|
@ -1889,7 +1853,7 @@ fn set_workspace_dir_or_exit() {
|
||||||
println!("Not in anchor workspace.");
|
println!("Not in anchor workspace.");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
Some((cfg, _inside_cargo)) => {
|
Some(cfg) => {
|
||||||
match cfg.path().parent() {
|
match cfg.path().parent() {
|
||||||
None => {
|
None => {
|
||||||
println!("Unable to make new program");
|
println!("Unable to make new program");
|
||||||
|
@ -1938,7 +1902,7 @@ fn cluster(_cmd: ClusterCommand) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shell(cfg_override: &ConfigOverride) -> Result<()> {
|
fn shell(cfg_override: &ConfigOverride) -> Result<()> {
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
let programs = {
|
let programs = {
|
||||||
// Create idl map from all workspace programs.
|
// Create idl map from all workspace programs.
|
||||||
let mut idls: HashMap<String, Idl> = cfg
|
let mut idls: HashMap<String, Idl> = cfg
|
||||||
|
@ -2005,7 +1969,7 @@ fn shell(cfg_override: &ConfigOverride) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(cfg_override: &ConfigOverride, script: String) -> Result<()> {
|
fn run(cfg_override: &ConfigOverride, script: String) -> Result<()> {
|
||||||
with_workspace(cfg_override, |cfg, _cargo| {
|
with_workspace(cfg_override, |cfg| {
|
||||||
let script = cfg
|
let script = cfg
|
||||||
.scripts
|
.scripts
|
||||||
.get(&script)
|
.get(&script)
|
||||||
|
@ -2040,9 +2004,21 @@ fn login(_cfg_override: &ConfigOverride, token: String) -> Result<()> {
|
||||||
|
|
||||||
fn publish(cfg_override: &ConfigOverride, program_name: String) -> Result<()> {
|
fn publish(cfg_override: &ConfigOverride, program_name: String) -> Result<()> {
|
||||||
// Discover the various workspace configs.
|
// Discover the various workspace configs.
|
||||||
let (cfg, _cargo_path) = Config::discover(cfg_override)?.expect("Not in workspace.");
|
let cfg = Config::discover(cfg_override)?.expect("Not in workspace.");
|
||||||
|
|
||||||
if !Path::new("Cargo.lock").exists() {
|
let program = cfg
|
||||||
|
.get_program(&program_name)?
|
||||||
|
.ok_or_else(|| anyhow!("Workspace member not found"))?;
|
||||||
|
|
||||||
|
let program_cargo_lock = pathdiff::diff_paths(
|
||||||
|
program.path().join("Cargo.lock"),
|
||||||
|
cfg.path().parent().unwrap(),
|
||||||
|
)
|
||||||
|
.ok_or_else(|| anyhow!("Unable to diff Cargo.lock path"))?;
|
||||||
|
let cargo_lock = Path::new("Cargo.lock");
|
||||||
|
|
||||||
|
// There must be a Cargo.lock
|
||||||
|
if !program_cargo_lock.exists() && !cargo_lock.exists() {
|
||||||
return Err(anyhow!("Cargo.lock must exist for a verifiable build"));
|
return Err(anyhow!("Cargo.lock must exist for a verifiable build"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2081,29 +2057,59 @@ fn publish(cfg_override: &ConfigOverride, program_name: String) -> Result<()> {
|
||||||
let mut tar = tar::Builder::new(enc);
|
let mut tar = tar::Builder::new(enc);
|
||||||
|
|
||||||
// Files that will always be included if they exist.
|
// Files that will always be included if they exist.
|
||||||
|
println!("PACKING: Anchor.toml");
|
||||||
tar.append_path("Anchor.toml")?;
|
tar.append_path("Anchor.toml")?;
|
||||||
tar.append_path("Cargo.lock")?;
|
if cargo_lock.exists() {
|
||||||
|
println!("PACKING: Cargo.lock");
|
||||||
|
tar.append_path(cargo_lock)?;
|
||||||
|
}
|
||||||
if Path::new("Cargo.toml").exists() {
|
if Path::new("Cargo.toml").exists() {
|
||||||
|
println!("PACKING: Cargo.toml");
|
||||||
tar.append_path("Cargo.toml")?;
|
tar.append_path("Cargo.toml")?;
|
||||||
}
|
}
|
||||||
if Path::new("LICENSE").exists() {
|
if Path::new("LICENSE").exists() {
|
||||||
|
println!("PACKING: LICENSE");
|
||||||
tar.append_path("LICENSE")?;
|
tar.append_path("LICENSE")?;
|
||||||
}
|
}
|
||||||
if Path::new("README.md").exists() {
|
if Path::new("README.md").exists() {
|
||||||
|
println!("PACKING: README.md");
|
||||||
tar.append_path("README.md")?;
|
tar.append_path("README.md")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// All workspace programs.
|
// All workspace programs.
|
||||||
for path in cfg.get_program_list()? {
|
for path in cfg.get_program_list()? {
|
||||||
let mut relative_path = pathdiff::diff_paths(path, cfg.path().parent().unwrap())
|
let mut dirs = walkdir::WalkDir::new(&path)
|
||||||
.ok_or_else(|| anyhow!("Unable to diff paths"))?;
|
.into_iter()
|
||||||
|
.filter_entry(|e| !is_hidden(e));
|
||||||
|
|
||||||
// HACK for workspaces wtih single programs. Change this.
|
// Skip the parent dir.
|
||||||
if relative_path.display().to_string() == *"" {
|
let _ = dirs.next().unwrap()?;
|
||||||
relative_path = "src".into();
|
|
||||||
|
for entry in dirs {
|
||||||
|
let e = entry.map_err(|e| anyhow!("{:?}", e))?;
|
||||||
|
|
||||||
|
let e = pathdiff::diff_paths(e.path(), cfg.path().parent().unwrap())
|
||||||
|
.ok_or_else(|| anyhow!("Unable to diff paths"))?;
|
||||||
|
|
||||||
|
let path_str = e.display().to_string();
|
||||||
|
|
||||||
|
// Skip target dir.
|
||||||
|
if !path_str.contains("target/") && !path_str.contains("/target") {
|
||||||
|
// Only add the file if it's not empty.
|
||||||
|
let metadata = std::fs::File::open(&e)?.metadata()?;
|
||||||
|
if metadata.len() > 0 {
|
||||||
|
println!("PACKING: {}", e.display().to_string());
|
||||||
|
if e.is_dir() {
|
||||||
|
tar.append_dir_all(&e, &e)?;
|
||||||
|
} else {
|
||||||
|
tar.append_path(&e)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tar.append_dir_all(relative_path.clone(), relative_path)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tar pack complete.
|
||||||
tar.into_inner()?;
|
tar.into_inner()?;
|
||||||
|
|
||||||
// Upload the tarball to the server.
|
// Upload the tarball to the server.
|
||||||
|
@ -2158,22 +2164,27 @@ fn registry_api_token(_cfg_override: &ConfigOverride) -> Result<String> {
|
||||||
//
|
//
|
||||||
// The closure passed into this function must never change the working directory
|
// The closure passed into this function must never change the working directory
|
||||||
// to be outside the workspace. Doing so will have undefined behavior.
|
// to be outside the workspace. Doing so will have undefined behavior.
|
||||||
fn with_workspace<R>(
|
fn with_workspace<R>(cfg_override: &ConfigOverride, f: impl FnOnce(&WithPath<Config>) -> R) -> R {
|
||||||
cfg_override: &ConfigOverride,
|
|
||||||
f: impl FnOnce(&WithPath<Config>, Option<PathBuf>) -> R,
|
|
||||||
) -> R {
|
|
||||||
set_workspace_dir_or_exit();
|
set_workspace_dir_or_exit();
|
||||||
|
|
||||||
clear_program_keys(cfg_override).unwrap();
|
clear_program_keys(cfg_override).unwrap();
|
||||||
|
|
||||||
let (cfg, cargo_toml) = Config::discover(cfg_override)
|
let cfg = Config::discover(cfg_override)
|
||||||
.expect("Previously set the workspace dir")
|
.expect("Previously set the workspace dir")
|
||||||
.expect("Anchor.toml must always exist");
|
.expect("Anchor.toml must always exist");
|
||||||
|
|
||||||
let r = f(&cfg, cargo_toml);
|
let r = f(&cfg);
|
||||||
|
|
||||||
set_workspace_dir_or_exit();
|
set_workspace_dir_or_exit();
|
||||||
clear_program_keys(cfg_override).unwrap();
|
clear_program_keys(cfg_override).unwrap();
|
||||||
|
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_hidden(entry: &walkdir::DirEntry) -> bool {
|
||||||
|
entry
|
||||||
|
.file_name()
|
||||||
|
.to_str()
|
||||||
|
.map(|s| s == "." || s.starts_with('.') || s == "target")
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ cluster = "mainnet"
|
||||||
wallet = "~/.config/solana/id.json"
|
wallet = "~/.config/solana/id.json"
|
||||||
|
|
||||||
[programs.mainnet]
|
[programs.mainnet]
|
||||||
multisig = { address = "A9HAbnCwoD6f2NkZobKFf6buJoN9gUVVvX5PoUnDHS6u", path = "./target/deploy/multisig.so", idl = "./target/idl/multisig.json" }
|
multisig = "A9HAbnCwoD6f2NkZobKFf6buJoN9gUVVvX5PoUnDHS6u"
|
||||||
```
|
```
|
||||||
|
|
||||||
Here there are four sections.
|
Here there are four sections.
|
||||||
|
@ -53,8 +53,8 @@ Here there are four sections.
|
||||||
standard Anchor workflow, this can be ommitted. For programs not written in Anchor
|
standard Anchor workflow, this can be ommitted. For programs not written in Anchor
|
||||||
but still want to publish, this should be added.
|
but still want to publish, this should be added.
|
||||||
3. `[provider]` - configures the wallet and cluster settings. Here, `mainnet` is used because the registry only supports `mainnet` binary verification at the moment.
|
3. `[provider]` - configures the wallet and cluster settings. Here, `mainnet` is used because the registry only supports `mainnet` binary verification at the moment.
|
||||||
3. `[programs.mainnet]` - configures each program in the workpace. Here the
|
3. `[programs.mainnet]` - configures each program in the workpace, providing
|
||||||
`address` of the program to verify and the `path` to it's binary build artifact. For Anchor programs with an **IDL**, an `idl = "<path>"` field should also be provided.
|
the `address` of the program to verify.
|
||||||
|
|
||||||
::: tip
|
::: tip
|
||||||
When defining program in `[programs.mainnet]`, make sure the name provided
|
When defining program in `[programs.mainnet]`, make sure the name provided
|
||||||
|
|
Loading…
Reference in New Issue