Skip to content

Commit 0c2a16b

Browse files
author
Grant Wuerker
committed
hacking
1 parent 806c02c commit 0c2a16b

File tree

8 files changed

+285
-102
lines changed

8 files changed

+285
-102
lines changed

crates/resolver/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ toml = "0.8.13"
1515
serde = { version = "1", features = ["derive"] }
1616
git2 = "0.18.3"
1717
indexmap = "2.2"
18+
petgraph = "0.5.1"

crates/resolver/src/files.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use camino::Utf8PathBuf;
2-
use git::GitDesc;
3-
use local::LocalDesc;
2+
use git::{GitDesc, GitResolutionError};
3+
use local::{LocalDesc, LocalResolutionError};
44
use serde::Deserialize;
55

66
use crate::Resolver;
77

88
mod git;
99
mod local;
1010

11-
#[derive(Deserialize)]
11+
#[derive(Deserialize, Hash, Debug)]
1212
#[serde(untagged)]
1313
pub enum AnyFilesDesc {
1414
Local(LocalDesc),
@@ -18,8 +18,8 @@ pub enum AnyFilesDesc {
1818
pub struct AnyFilesResolver;
1919

2020
pub enum AnyFilesResolutionError {
21-
Local(local::LocalResolutionError),
22-
Git(git::GitResolutionError),
21+
Local(LocalResolutionError),
22+
Git(GitResolutionError),
2323
}
2424

2525
impl Resolver for AnyFilesResolver {

crates/resolver/src/files/git.rs

Lines changed: 87 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use camino::Utf8PathBuf;
2+
use git2::{Error as Git2Error, FetchOptions, Oid, Repository};
23
use serde::Deserialize;
4+
use std::fs;
35

46
use crate::Resolver;
57

6-
#[derive(Deserialize)]
8+
#[derive(Deserialize, Hash, Debug, Clone)]
79
pub struct GitDesc {
810
remote: String,
911
refspec: String,
@@ -14,7 +16,34 @@ pub struct GitResolver {
1416
pub default_clone_path: Utf8PathBuf,
1517
}
1618

17-
pub struct GitResolutionError;
19+
#[derive(Debug)]
20+
pub enum GitResolutionError {
21+
GitError(Git2Error),
22+
IoError(std::io::Error),
23+
InvalidOid,
24+
}
25+
26+
impl From<Git2Error> for GitResolutionError {
27+
fn from(error: Git2Error) -> Self {
28+
GitResolutionError::GitError(error)
29+
}
30+
}
31+
32+
impl From<std::io::Error> for GitResolutionError {
33+
fn from(error: std::io::Error) -> Self {
34+
GitResolutionError::IoError(error)
35+
}
36+
}
37+
38+
impl std::fmt::Display for GitResolutionError {
39+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40+
match self {
41+
GitResolutionError::GitError(e) => write!(f, "Git error: {}", e),
42+
GitResolutionError::IoError(e) => write!(f, "IO error: {}", e),
43+
GitResolutionError::InvalidOid => write!(f, "Invalid OID for refspec"),
44+
}
45+
}
46+
}
1847

1948
impl Resolver for GitResolver {
2049
type Config = ();
@@ -23,72 +52,65 @@ impl Resolver for GitResolver {
2352
type ResolutionError = GitResolutionError;
2453

2554
fn from_config(_: &Self::Config) -> Self {
26-
todo!("")
55+
todo!()
2756
}
2857

2958
fn resolve(&self, desc: &GitDesc) -> Result<Utf8PathBuf, GitResolutionError> {
30-
// check to see if the dep is already in the dep directory
31-
// check to see if the repo is already cached on the local fs
32-
// if it is, then check to see if the repo is valid with respect to the CID or refspec
33-
// if the repo is not cached, clone it
34-
// copy to dep directory
35-
// resolve the repo path
36-
todo!("")
59+
let clone_path = if let Some(ref local_path) = desc.local_path {
60+
Utf8PathBuf::from(local_path)
61+
} else {
62+
self.default_clone_path
63+
.join(format!("{}_{}", &desc.remote, &desc.refspec))
64+
};
65+
66+
if clone_path.exists() {
67+
let repo = Repository::open(&clone_path).map_err(GitResolutionError::from)?;
68+
69+
if !repo.find_reference(&desc.refspec).is_ok() {
70+
fs::remove_dir_all(&clone_path)?;
71+
self.clone_repo(&desc.remote, &clone_path, &desc.refspec)?;
72+
}
73+
} else {
74+
self.clone_repo(&desc.remote, &clone_path, &desc.refspec)?;
75+
}
76+
77+
Ok(clone_path)
3778
}
3879
}
3980

40-
// use git2::{FetchOptions, Oid, Repository};
41-
// use std::error::Error;
42-
// use std::path::Path;
43-
44-
// /// Fetch and checkout the specified refspec from the remote repository without
45-
// /// fetching any additional history.
46-
// pub fn fetch_and_checkout<P: AsRef<Path>>(
47-
// remote: &str,
48-
// target_directory: P,
49-
// refspec: &str,
50-
// ) -> Result<(), Box<dyn Error>> {
51-
// // We initialize the repo here so that we can be sure that we created a directory that
52-
// // needs to be clean up in case of an error. If the init fails, there won't be anything
53-
// // to clean up.
54-
// let repo = Repository::init(&target_directory)?;
55-
// let res = _fetch_and_checkout(remote, repo, refspec);
56-
// if res.is_err() {
57-
// std::fs::remove_dir_all(target_directory).expect("Failed to clean up directory");
58-
// }
59-
60-
// res
61-
// }
62-
63-
// fn _fetch_and_checkout(
64-
// remote: &str,
65-
// repo: Repository,
66-
// refspec: &str,
67-
// ) -> Result<(), Box<dyn Error>> {
68-
// let mut remote = repo.remote("origin", remote)?;
69-
70-
// let mut fetch_options = FetchOptions::new();
71-
72-
// fetch_options.depth(1);
73-
74-
// // Fetch the specified SHA1 with depth 1
75-
// if let Err(e) = remote.fetch(&[refspec], Some(&mut fetch_options), None) {
76-
// if let (git2::ErrorClass::Net, git2::ErrorCode::GenericError) = (e.class(), e.code()) {
77-
// // That's a pretty cryptic error for the common case of the refspec not existing.
78-
// // We keep the cryptic error (because it might have other causes) but add a hint.
79-
// return Err(format!("{}\nMake sure revision {} exists in remote", e, refspec).into());
80-
// } else {
81-
// return Err(e.into());
82-
// }
83-
// }
84-
85-
// // Find the fetched commit by SHA1
86-
// let oid = Oid::from_str(refspec)?;
87-
// let commit = repo.find_commit(oid)?;
88-
89-
// // Checkout the commit
90-
// repo.checkout_tree(commit.as_object(), None)?;
91-
// repo.set_head_detached(oid)?;
92-
93-
// Ok(())
94-
// }
81+
impl GitResolver {
82+
fn clone_repo(
83+
&self,
84+
remote: &str,
85+
target_directory: &Utf8PathBuf,
86+
refspec: &str,
87+
) -> Result<(), GitResolutionError> {
88+
let repo = Repository::init(target_directory)?;
89+
90+
self.fetch_and_checkout(remote, &repo, refspec)?;
91+
92+
Ok(())
93+
}
94+
95+
fn fetch_and_checkout(
96+
&self,
97+
remote: &str,
98+
repo: &Repository,
99+
refspec: &str,
100+
) -> Result<(), GitResolutionError> {
101+
let mut remote = repo.remote("origin", remote)?;
102+
103+
let mut fetch_options = FetchOptions::new();
104+
fetch_options.depth(1);
105+
106+
remote.fetch(&[refspec], Some(&mut fetch_options), None)?;
107+
108+
let oid = Oid::from_str(refspec).map_err(|_| GitResolutionError::InvalidOid)?;
109+
let commit = repo.find_commit(oid)?;
110+
111+
repo.checkout_tree(commit.as_object(), None)?;
112+
repo.set_head_detached(oid)?;
113+
114+
Ok(())
115+
}
116+
}

crates/resolver/src/files/local.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ use serde::Deserialize;
33

44
use super::Resolver;
55

6-
#[derive(Deserialize)]
6+
#[derive(Deserialize, Hash, Debug)]
77
pub struct LocalDesc {
88
pub path: String,
99
}
1010

1111
pub struct LocalResolver;
1212

1313
pub enum LocalResolutionError {
14-
Invalid,
15-
DoesNotExist,
14+
InvalidPath,
15+
PathDoesNotExist,
1616
}
1717

1818
impl Resolver for LocalResolver {
@@ -21,19 +21,19 @@ impl Resolver for LocalResolver {
2121
type Resource = Utf8PathBuf;
2222
type ResolutionError = LocalResolutionError;
2323

24-
fn from_config(config: &Self::Config) -> Self {
24+
fn from_config(_: &Self::Config) -> Self {
2525
todo!()
2626
}
2727

2828
fn resolve(&self, desc: &LocalDesc) -> Result<Utf8PathBuf, LocalResolutionError> {
2929
if let Ok(path) = Utf8PathBuf::try_from(desc.path.clone()) {
3030
if !path.exists() {
31-
Err(LocalResolutionError::DoesNotExist)
31+
Err(LocalResolutionError::PathDoesNotExist)
3232
} else {
3333
Ok(path)
3434
}
3535
} else {
36-
Err(LocalResolutionError::Invalid)
36+
Err(LocalResolutionError::InvalidPath)
3737
}
3838
}
3939
}

crates/resolver/src/ingot.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
use serde::Deserialize;
22
use smol_str::SmolStr;
3+
use std::hash::Hash;
34

45
use crate::files::AnyFilesDesc;
56

67
mod config;
8+
mod dep_graph;
79
mod src_files;
810

9-
#[derive(Deserialize)]
10-
pub struct IngotDesc<FD> {
11-
name: SmolStr,
12-
version: Option<String>,
11+
#[derive(Deserialize, Hash, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
12+
pub struct IngotDesc<FD>
13+
where
14+
FD: Hash,
15+
{
16+
pub version: Option<SmolStr>,
1317
#[serde(flatten)]
14-
files_desc: FD,
18+
pub files_desc: FD,
1519
}
1620

1721
pub type AnyIngotDesc = IngotDesc<AnyFilesDesc>;
Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,32 @@
1+
use camino::Utf8PathBuf;
2+
use serde::de::DeserializeOwned;
3+
use serde::Deserialize;
14
use smol_str::SmolStr;
5+
use std::hash::Hash;
6+
use std::{collections::HashMap, fs};
7+
use toml;
28

39
use crate::Resolver;
410

511
use super::IngotDesc;
612

7-
pub struct Config<FD> {
13+
#[derive(Deserialize)]
14+
pub struct Config<FD>
15+
where
16+
FD: Hash,
17+
{
818
pub name: SmolStr,
919
pub version: SmolStr,
10-
dependencies: Vec<IngotDesc<FD>>,
20+
pub dependencies: HashMap<SmolStr, IngotDesc<FD>>,
1121
}
1222

13-
pub struct ConfigResolutionError;
23+
#[derive(Debug)]
24+
pub enum ConfigResolutionError {
25+
FileNotFound,
26+
FileReadError(std::io::Error),
27+
TomlParseError(toml::de::Error),
28+
InvalidConfig(String),
29+
}
1430

1531
pub struct ConfigResolver<FR> {
1632
files_resolver: FR,
@@ -19,23 +35,48 @@ pub struct ConfigResolver<FR> {
1935
impl<FR> Resolver for ConfigResolver<FR>
2036
where
2137
FR: Resolver,
38+
FR::ResourceDesc: Hash,
39+
FR::Resource: AsRef<Utf8PathBuf>,
40+
Config<FR::ResourceDesc>: DeserializeOwned,
2241
{
2342
type Config = ();
2443
type ResourceDesc = IngotDesc<FR::ResourceDesc>;
2544
type Resource = Config<FR::ResourceDesc>;
2645
type ResolutionError = ConfigResolutionError;
2746

28-
fn from_config(config: &Self::Config) -> Self {
47+
fn from_config(_config: &Self::Config) -> Self {
2948
todo!()
3049
}
3150

3251
fn resolve(
3352
&self,
3453
desc: &IngotDesc<FR::ResourceDesc>,
3554
) -> Result<Config<FR::ResourceDesc>, ConfigResolutionError> {
36-
// load the config file data
37-
// parse the toml
38-
// check toml content (version, features, etc)
39-
//
55+
let config_path = self
56+
.files_resolver
57+
.resolve(&desc.files_desc)
58+
.map_err(|_| ConfigResolutionError::FileNotFound)?
59+
.as_ref()
60+
.join("fe.toml");
61+
62+
let file_content =
63+
fs::read_to_string(&config_path).map_err(ConfigResolutionError::FileReadError)?;
64+
65+
let config: Config<FR::ResourceDesc> =
66+
toml::from_str(&file_content).map_err(ConfigResolutionError::TomlParseError)?;
67+
68+
if config.name.is_empty() {
69+
return Err(ConfigResolutionError::InvalidConfig(
70+
"Invalid configuration: 'name' field is missing or empty.".to_string(),
71+
));
72+
}
73+
74+
if config.version.is_empty() {
75+
return Err(ConfigResolutionError::InvalidConfig(
76+
"Invalid configuration: 'version' field is missing or empty.".to_string(),
77+
));
78+
}
79+
80+
Ok(config)
4081
}
4182
}

0 commit comments

Comments
 (0)