Skip to content

Commit

Permalink
supports foundry config for sdependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
mario-eth committed Aug 8, 2023
1 parent d5a538f commit 5343252
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 53 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/target
dependencies/
dependencies/
foundry.toml
.dependency_reading.toml
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ tokio = "1.29.1"
tokio-dl-stream-to-disk = "1.0.0"
zip-extract = "0.1.2"
reqwest = "0.11.18"
toml_edit = "0.9.1"
toml_edit = "0.9.1"
lazy_static = "1.4.0"
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ WARNING! The `[remappings]` must be first then the `[dependencies]`. The `enable

The full list of dependencies is available [here](./all_dependencies.toml).

### CAVEATS

The add to remappings feature just appends to the `remappings.txt`` file, it does not delete old dependencies. So if you want to remove a dependency from remappings you have to do it manually.

### TODO

- Parallel downloads of the dependencies.
Expand Down
6 changes: 3 additions & 3 deletions soldeer.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@


[dependencies]
[sdependencies]
"@openzeppelin~v4.9.2" = "https://github.com/OpenZeppelin/openzeppelin-contracts/archive/refs/tags/v4.9.2.zip"
"@openzeppelin~v1.0.5" = "https://github.com/OpenZeppelin/openzeppelin-contracts/archive/refs/tags/v1.0.5.zip"
"@solady~v0.0.41" = "https://github.com/Vectorized/solady/archive/refs/tags/v0.0.41.zip"

[remappings]
[foundry]
enabled = true
foundry-config = true
102 changes: 63 additions & 39 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ use std::io::{ Write, BufRead, BufReader };
use crate::utils::get_current_working_dir;
extern crate toml_edit;
use toml_edit::{ Document, value };
use crate::FOUNDRY;

// TODO need to improve this, to propagate the error to main and not exit here.
pub fn read_config(filename: String) -> Vec<Dependency> {
pub fn read_config(filename: String, foundry_setup: &FOUNDRY) -> Vec<Dependency> {
let mut filename: String = filename;
if filename == "" {
filename = define_config_file();
filename = define_config_file(foundry_setup);
}
// Read the contents of the file using a `match` block
// to return the `data: Ok(c)` as a `String`
Expand Down Expand Up @@ -48,7 +49,7 @@ pub fn read_config(filename: String) -> Vec<Dependency> {
};

let mut dependencies: Vec<Dependency> = Vec::new();
data.dependencies.iter().for_each(|(k, v)| {
data.sdependencies.iter().for_each(|(k, v)| {
let parts: Vec<&str> = k.split("~").collect::<Vec<&str>>();
dependencies.push(Dependency {
name: parts.get(0).unwrap().to_string(),
Expand All @@ -60,36 +61,48 @@ pub fn read_config(filename: String) -> Vec<Dependency> {
return dependencies;
}

pub fn define_config_file() -> String {
pub fn define_config_file(foundry_setup: &FOUNDRY) -> String {
// reading the current directory to look for the config file
let working_dir: Result<PathBuf, std::io::Error> = get_current_working_dir();

let filename: String =
working_dir.unwrap().into_os_string().into_string().unwrap() + "/soldeer.toml";
let mut filename: String =
working_dir.as_ref().unwrap().clone().into_os_string().into_string().unwrap().to_owned() +
"/soldeer.toml";

if foundry_setup.config {
filename =
working_dir.as_ref().unwrap().clone().into_os_string().into_string().unwrap().clone() +
"/foundry.toml";
}
let exists: bool = Path::new(&filename).exists();
if exists {
println!("Config file exists.");
// println!("Config file exists.");
} else {
eprintln!("Config file does not exist. Program exited.");
exit(404);
}
return filename;
}
pub fn add_to_config(dependency_name: &str, dependency_version: &str, dependency_url: &str) {
pub fn add_to_config(
dependency_name: &str,
dependency_version: &str,
dependency_url: &str,
foundry_setup: &FOUNDRY
) {
println!("Adding dependency {}-{} to config file", dependency_name, dependency_version);
let filename: String = define_config_file();
let filename: String = define_config_file(foundry_setup);
let contents = read_file_to_string(filename.clone());
let mut doc: Document = contents.parse::<Document>().expect("invalid doc");

if !doc["dependencies"].get(format!("{}~{}", dependency_name, dependency_version)).is_none() {
if !doc["sdependencies"].get(format!("{}~{}", dependency_name, dependency_version)).is_none() {
println!(
"Dependency {}-{} already exists in the config file",
dependency_name,
dependency_version
);
return;
}
doc["dependencies"][format!("{}~{}", dependency_name, dependency_version)] =
doc["sdependencies"][format!("{}~{}", dependency_name, dependency_version)] =
value(dependency_url);
let mut file: std::fs::File = fs::OpenOptions
::new()
Expand All @@ -102,31 +115,39 @@ pub fn add_to_config(dependency_name: &str, dependency_version: &str, dependency
}
}

pub fn remappings() {
if !enable_remappings() {
return;
}
update_foundry();
}

fn update_foundry() {
pub fn remappings(foundry_setup: &FOUNDRY) {
if !Path::new("remappings.txt").exists() {
File::create("remappings.txt").unwrap();
}
println!("Updating foundry...");
let contents = read_file_to_string(String::from("remappings.txt"));

let existing_remappings: Vec<String> = contents
.split("\n")
.map(|s| s.to_string())
.collect();
let mut new_remappings: String = String::new();
let dependencies: Vec<Dependency> = read_config(String::new());
let dependencies: Vec<Dependency> = read_config(String::new(), foundry_setup);

let mut existing_remap: Vec<String> = Vec::new();
existing_remappings.iter().for_each(|remapping| {
let split: Vec<&str> = remapping.split("=").collect::<Vec<&str>>();
existing_remap.push(String::from(split[0]));
});

dependencies.iter().for_each(|dependency| {
println!("Adding a new remap {}", &dependency.name);
new_remappings.push_str(
&format!(
"{}=dependencies/{}-{}\n",
&dependency.name,
&dependency.name,
&dependency.version
)
);
let index = existing_remap.iter().position(|r| r == &dependency.name);
if index.is_none() {
println!("Adding a new remap {}", &dependency.name);
new_remappings.push_str(
&format!(
"{}=dependencies/{}-{}\n",
&dependency.name,
&dependency.name,
&dependency.version
)
);
}
});

if new_remappings.len() == 0 {
Expand All @@ -137,11 +158,10 @@ fn update_foundry() {
let mut file: std::fs::File = fs::OpenOptions
::new()
.write(true)
.truncate(true)
.append(false)
.append(true)
.open(Path::new("remappings.txt"))
.unwrap();
println!("New remappings: {}", &new_remappings);

match write!(file, "{}", &new_remappings) {
Ok(_) => {}
Err(e) => {
Expand Down Expand Up @@ -188,15 +208,15 @@ fn remove_empty_lines(filename: String) {
}
}

fn enable_remappings() -> bool {
let filename = define_config_file();
pub fn get_foundry_setup() -> Vec<bool> {
let filename = define_config_file(&(FOUNDRY { remappings: false, config: false }));

let contents: String = read_file_to_string(filename.clone());

// Use a `match` block to return the
// file `contents` as a `Data struct: Ok(d)`
// or handle any `errors: Err(_)`.
let data: Remmapings = match toml::from_str(&contents) {
let data: Foundry = match toml::from_str(&contents) {
// If successful, return data as `Data` struct.
// `d` is a local variable.
Ok(d) => d,
Expand All @@ -209,7 +229,11 @@ fn enable_remappings() -> bool {
exit(1);
}
};
return data.remappings.get("enabled").unwrap().as_bool().unwrap();

return vec![
data.foundry.get("enabled").unwrap().as_bool().unwrap(),
data.foundry.get("foundry-config").unwrap().as_bool().unwrap()
];
}

fn read_file_to_string(filename: String) -> String {
Expand All @@ -231,7 +255,7 @@ fn read_file_to_string(filename: String) -> String {
#[derive(Deserialize)]
#[derive(Debug)]
struct Data {
dependencies: Table,
sdependencies: Table,
}

// Dependency object used to store a dependency data
Expand All @@ -244,6 +268,6 @@ pub struct Dependency {

#[derive(Deserialize)]
#[derive(Debug)]
struct Remmapings {
remappings: Table,
struct Foundry {
foundry: Table,
}
6 changes: 4 additions & 2 deletions src/dependency_downloader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use zip_extract::ZipExtractError;

use crate::config::{ Dependency, read_config };
use crate::utils::get_current_working_dir;
use crate::FOUNDRY;

// TODOs:
// - needs to be downloaded in parallel
Expand Down Expand Up @@ -51,15 +52,16 @@ pub fn unzip_dependencies(dependencies: &Vec<Dependency>) -> Result<(), ZipExtra
pub async fn download_dependency_remote(
dependency_name: &String,
dependency_version: &String,
remote_url: &String
remote_url: &String,
foundry_setup: &FOUNDRY
) -> Result<String, DownloadError> {
let res: Response = get(format!("{}", remote_url)).await.unwrap();
let body: String = res.text().await.unwrap();
let tmp_path: std::path::PathBuf = get_current_working_dir()
.unwrap()
.join(".dependency_reading.toml");
fs::write(&tmp_path, body).expect("Unable to write file");
let dependencies: Vec<Dependency> = read_config((&tmp_path).to_str().unwrap().to_string());
let dependencies: Vec<Dependency> = read_config((&tmp_path).to_str().unwrap().to_string(), foundry_setup);
for dependency in dependencies.iter() {
if dependency.name == *dependency_name && dependency.version == *dependency_version {
println!("dependency url: {}", dependency.url);
Expand Down
37 changes: 30 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,45 @@ mod janitor;
use std::process::exit;
use std::env;

use crate::config::{ read_config, remappings, Dependency };
use crate::config::{ read_config, remappings, Dependency, get_foundry_setup };
use crate::dependency_downloader::{ download_dependencies, unzip_dependencies, unzip_dependency };
use crate::janitor::{ healthcheck_dependencies, cleanup_after };

const REMOTE_REPOSITORY: &str =
"https://raw.githubusercontent.com/mario-eth/soldeer/main/all_dependencies.toml";

#[derive(Debug)]
pub struct FOUNDRY {
remappings: bool,
config: bool,
}
#[tokio::main]
async fn main() {
let args: Vec<String> = env::args().collect();
let command: (String, String, String) = process_args(args).unwrap();

// setup the foundry setup, in case it's enabled inside the soldeer.toml, then the foundry.toml will be used for
// `sdependencies`
let f_setup_vec: Vec<bool> = get_foundry_setup();
let foundry_setup: FOUNDRY = FOUNDRY {
remappings: f_setup_vec[0],
config: f_setup_vec[1],
};

if command.0 == "install" && command.1 != "" {
let dependency_name: String = command.1.split("~").collect::<Vec<&str>>()[0].to_string();
let dependency_version: String = command.1.split("~").collect::<Vec<&str>>()[1].to_string();
let dependency_url: String;
let mut remote_url = REMOTE_REPOSITORY.to_string();
let mut remote_url: String = REMOTE_REPOSITORY.to_string();
if command.2 != "" {
remote_url = command.2;
}
match
dependency_downloader::download_dependency_remote(
&dependency_name,
&dependency_version,
&remote_url
&remote_url,
&foundry_setup
).await
{
Ok(url) => {
Expand All @@ -49,7 +63,12 @@ async fn main() {
}
}
// TODO this is kinda junky written, need to refactor and a better TOML writer
config::add_to_config(&dependency_name, &dependency_version, &dependency_url);
config::add_to_config(
&dependency_name,
&dependency_version,
&dependency_url,
&foundry_setup
);
match janitor::healthcheck_dependency(&dependency_name, &dependency_version) {
Ok(_) => {}
Err(err) => {
Expand All @@ -64,9 +83,11 @@ async fn main() {
exit(500);
}
}
remappings();
if foundry_setup.remappings {
remappings(&foundry_setup);
}
} else if command.0 == "update" || (command.0 == "install" && command.1 == "") {
let dependencies: Vec<Dependency> = read_config(String::new());
let dependencies: Vec<Dependency> = read_config(String::new(), &foundry_setup);
if download_dependencies(&dependencies, true).await.is_err() {
eprintln!("Error downloading dependencies");
exit(500);
Expand All @@ -88,7 +109,9 @@ async fn main() {
eprintln!("Error cleanup dependencies {:?}", result.err().unwrap().name);
exit(500);
}
remappings();
if foundry_setup.remappings {
remappings(&foundry_setup);
}
} else if command.0 == "help" {
println!(
"Usage: soldeer [command] [dependency] Example: dependency~version. the `~` is very important to differentiate between the name and the version that needs to be installed."
Expand Down

0 comments on commit 5343252

Please sign in to comment.