Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/artifact.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};

/// All the artifacts that the [Component] contains.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, Hash)]
pub struct Artifacts {
artifacts: Vec<Artifact>,
}
Expand All @@ -16,7 +16,7 @@ impl Artifacts {
/// Holds a URI used to fetch an artifact.
///
/// These URIs have the following format: `(https://|file://)<path>/<component name>(-<triplet>|.masp)`
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, Hash)]
struct Artifact(String);

#[derive(Debug, PartialEq)]
Expand Down
79 changes: 38 additions & 41 deletions src/channel.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{
borrow::Cow,
collections::HashMap,
collections::{BTreeMap, HashMap, hash_map::DefaultHasher},
fmt::{self, Display},
hash::{Hash, Hasher},
path::{Path, PathBuf},
Expand All @@ -18,14 +18,23 @@ use crate::{
version::{Authority, GitTarget},
};

#[derive(Serialize, Deserialize, Debug, Clone)]
/// Hash created to distinguish one installed channel from the another.
pub struct ChannelHash(String);

impl Display for ChannelHash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}

#[derive(Serialize, Deserialize, Debug, Clone, Hash)]
#[serde(untagged)]
pub enum MigrationStrategy {
NameChange { old_channel: semver::Version },
}

/// Tags used to identify special qualities of a specific channel.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, Hash)]
#[serde(rename_all = "snake_case")]
pub enum Tags {
/// The channel is partially installed, i.e. only a subset of components
Expand All @@ -42,7 +51,7 @@ pub enum Tags {
///
/// Different channels have different stability guarantees. See the specific details for the
/// channel you are interested in to learn more.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, Hash)]
pub struct Channel {
/// Channels are identified by their name. The name corresponds to the channel's version.
/// The version can contain suffixes such as "-custom", "-beta".
Expand Down Expand Up @@ -137,6 +146,12 @@ impl Channel {
installed_toolchains_dir.join(format!("{}", self.name))
}

pub fn content_hash(&self) -> ChannelHash {
let mut h = DefaultHasher::new();
self.hash(&mut h);
ChannelHash(format!("{:016x}", h.finish()))
}

/// Get all the aliases that the Channel is aware of
pub fn get_aliases(&self) -> HashMap<Alias, CliCommands> {
self.components.iter().fold(HashMap::new(), |mut acc, component| {
Expand Down Expand Up @@ -231,27 +246,6 @@ impl Channel {
}
}

impl Eq for Component {}

/// NOTE: Two component are "partially equal" if their names are the same.
///
/// This does not mean that they're equal, since they could differ in fields like versions. This is
/// implmented manually, in order to make use of HashSets with components.
impl PartialEq for Component {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}

impl Hash for Component {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.name.hash(state)
}
}

impl PartialEq for Channel {
fn eq(&self, other: &Self) -> bool {
// NOTE: To channels are equal regardless of their aliases
Expand All @@ -268,17 +262,19 @@ impl PartialEq for Channel {
return false;
}

let my_components: std::collections::HashSet<Component> =
self.components.clone().into_iter().collect();
// TODO: CHANGE
panic!();
// let my_components: std::collections::HashSet<Component> =
// self.components.clone().into_iter().collect();

let other_components: std::collections::HashSet<Component> =
self.components.clone().into_iter().collect();
// let other_components: std::collections::HashSet<Component> =
// self.components.clone().into_iter().collect();

let equal_components = other_components == my_components;
// let equal_components = other_components == my_components;

if !equal_components {
return false;
}
// if !equal_components {
// return false;
// }

true
}
Expand All @@ -300,7 +296,7 @@ impl Display for Channel {
}

/// A special alias/tag that a channel can posses. For more information see [`Channel::alias`].
#[derive(Serialize, Debug, PartialEq, Eq, Clone)]
#[derive(Serialize, Debug, PartialEq, Eq, Clone, Hash)]
#[serde(rename_all = "snake_case")]
pub enum ChannelAlias {
/// Represents `stable`. Only one [Channel] can be marked as `stable` at a time.
Expand Down Expand Up @@ -347,7 +343,7 @@ impl core::str::FromStr for ChannelAlias {
}

/// Represents the file that the [Component] will install in the system.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum InstalledFile {
/// The component installs an executable.
Expand Down Expand Up @@ -410,7 +406,7 @@ impl Display for InstalledFile {
/// Represents each possible "word" variant that is passed to the command line.
///
/// These are used to resolve an [Alias] to its associated command.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, Hash)]
#[serde(rename_all = "snake_case")]
pub enum CliCommand {
/// Resolve the command to a [Component]'s corresponding executable.
Expand Down Expand Up @@ -517,7 +513,7 @@ pub type Alias = String;
pub type CliCommands = Vec<CliCommand>;

/// An installable component of a toolchain
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, Hash)]
pub struct Component {
/// The canonical name of this toolchain component.
pub name: Cow<'static, str>,
Expand Down Expand Up @@ -576,8 +572,8 @@ pub struct Component {
/// },
/// ```
#[serde(default)]
#[serde(skip_serializing_if = "HashMap::is_empty")]
pub aliases: HashMap<Alias, CliCommands>,
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
pub aliases: BTreeMap<Alias, CliCommands>,
/// The file used by midenup's 'miden' to call the components executable.
///
/// If `None`, then the component's file will be saved as `miden <name>`. This distinction
Expand All @@ -590,7 +586,7 @@ pub struct Component {
pub initialization: Vec<String>,
/// Pre-built artifact.
#[serde(flatten)]
artifacts: Option<Artifacts>,
pub artifacts: Option<Artifacts>,
}

impl Component {
Expand All @@ -603,7 +599,7 @@ impl Component {
call_format: vec![],
rustup_channel: None,
installed_file: None,
aliases: HashMap::new(),
aliases: BTreeMap::new(),
symlink_name: None,
initialization: Vec::new(),
artifacts: None,
Expand Down Expand Up @@ -841,3 +837,4 @@ impl core::str::FromStr for UserChannel {
}
}
}

23 changes: 18 additions & 5 deletions src/commands/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,16 @@ fn cargo_bin_dir() -> anyhow::Result<PathBuf> {
///
/// ```text,ignore
/// $MIDENUP_HOME
/// |- opt/
/// | |- symlinks
/// |- toolchains
/// | |- stable/ --> <channel>/
/// | |- <channel>/
/// |- toolchains/
/// | |- stable --> <channel>
/// | |- <channel> --> ../installed_toolchains/<channel>-<hash>
/// |- installed_toolchains/
/// | |- <channel>-<hash>/
/// | | |- bin/
/// | | |- lib/
/// | | | |- std.masp
/// | | |- opt/
/// | | |- var/
/// |- config.toml
/// |- manifest.json
/// ```
Expand Down Expand Up @@ -95,6 +97,17 @@ pub fn setup_midenup(config: &Config) -> anyhow::Result<bool> {
already_initialized = false;
}

let installed_toolchains_dir = config.midenup_home.join("installed_toolchains");
if !installed_toolchains_dir.exists() {
std::fs::create_dir_all(&installed_toolchains_dir).with_context(|| {
format!(
"failed to initialize MIDENUP_HOME subdirectory: '{}'",
installed_toolchains_dir.display()
)
})?;
already_initialized = false;
}

// We check if the `miden` executable is accessible via the $PATH. This is most certainly not
// going to be the case the first time `midenup` is initialized.
let miden_is_accessible = std::process::Command::new("miden")
Expand Down
Loading
Loading