diff --git a/scarb/src/core/lockfile.rs b/scarb/src/core/lockfile.rs index 2b13ef6e9..108e3c71a 100644 --- a/scarb/src/core/lockfile.rs +++ b/scarb/src/core/lockfile.rs @@ -1,5 +1,3 @@ -#![allow(dead_code)] - use anyhow::{anyhow, Context, Result}; use camino::Utf8Path; use semver::Version; @@ -69,13 +67,13 @@ impl Lockfile { pub fn from_path(path: impl AsRef) -> Result { if path.as_ref().is_file() { let content = fsx::read_to_string(path.as_ref()) - .with_context(|| format!("Failed to read lockfile at {}", path.as_ref()))?; + .with_context(|| format!("failed to read lockfile: {}", path.as_ref()))?; if content.is_empty() { Ok(Self::default()) } else { content .try_into() - .with_context(|| format!("Failed to parse lockfile at {}", path.as_ref())) + .with_context(|| format!("failed to parse lockfile: {}", path.as_ref())) } } else { Ok(Self::default()) diff --git a/scarb/src/core/workspace.rs b/scarb/src/core/workspace.rs index 842e68f41..8e0fffb82 100644 --- a/scarb/src/core/workspace.rs +++ b/scarb/src/core/workspace.rs @@ -10,7 +10,7 @@ use crate::core::config::Config; use crate::core::package::Package; use crate::core::PackageId; use crate::flock::RootFilesystem; -use crate::{DEFAULT_TARGET_DIR_NAME, MANIFEST_FILE_NAME}; +use crate::{DEFAULT_TARGET_DIR_NAME, LOCK_FILE_NAME, MANIFEST_FILE_NAME}; /// The core abstraction for working with a workspace of packages. /// @@ -86,6 +86,10 @@ impl<'c> Workspace<'c> { &self.manifest_path } + pub fn lockfile_path(&self) -> Utf8PathBuf { + self.root().join(LOCK_FILE_NAME) + } + pub fn target_dir(&self) -> &RootFilesystem { &self.target_dir } diff --git a/scarb/src/ops/lockfile.rs b/scarb/src/ops/lockfile.rs new file mode 100644 index 000000000..03db10759 --- /dev/null +++ b/scarb/src/ops/lockfile.rs @@ -0,0 +1,16 @@ +use crate::core::lockfile::Lockfile; +use crate::core::Workspace; +use crate::internal::fsx; +use anyhow::Result; + +#[tracing::instrument(skip_all, level = "debug")] +pub fn read_lockfile(ws: &Workspace<'_>) -> Result { + Lockfile::from_path(ws.lockfile_path()) +} + +#[tracing::instrument(skip_all, level = "debug")] +pub fn write_lockfile(ws: &Workspace<'_>, lockfile: Lockfile) -> Result<()> { + let path = ws.lockfile_path(); + fsx::write(path, lockfile.render()?.as_bytes())?; + Ok(()) +} diff --git a/scarb/src/ops/mod.rs b/scarb/src/ops/mod.rs index baa2f529c..509d4f36b 100644 --- a/scarb/src/ops/mod.rs +++ b/scarb/src/ops/mod.rs @@ -19,6 +19,7 @@ mod cache; mod clean; mod compile; mod fmt; +mod lockfile; mod manifest; mod metadata; mod new; diff --git a/scarb/src/ops/resolve.rs b/scarb/src/ops/resolve.rs index 594772dc1..ad057fda5 100644 --- a/scarb/src/ops/resolve.rs +++ b/scarb/src/ops/resolve.rs @@ -6,6 +6,7 @@ use futures::TryFutureExt; use itertools::Itertools; use crate::compiler::{CompilationUnit, CompilationUnitCairoPlugin, CompilationUnitComponent}; +use crate::core::lockfile::Lockfile; use crate::core::package::{Package, PackageClass, PackageId}; use crate::core::registry::cache::RegistryCache; use crate::core::registry::patch_map::PatchMap; @@ -19,6 +20,7 @@ use crate::core::{ TestTargetProps, TestTargetType, }; use crate::internal::to_version::ToVersion; +use crate::ops::lockfile::{read_lockfile, write_lockfile}; use crate::{resolver, DEFAULT_SOURCE_PATH}; pub struct WorkspaceResolve { @@ -95,7 +97,12 @@ pub fn resolve_workspace(ws: &Workspace<'_>) -> Result { .map(|pkg| pkg.manifest.summary.clone()) .collect::>(); - let resolve = resolver::resolve(&members_summaries, &patched, ws.config().ui()).await?; + let lockfile: Lockfile = read_lockfile(ws)?; + + let resolve = + resolver::resolve(&members_summaries, &patched, lockfile, ws.config().ui()).await?; + + write_lockfile(ws, Lockfile::from_resolve(&resolve))?; let packages = collect_packages_from_resolve_graph(&resolve, &patched).await?; diff --git a/scarb/src/resolver/mod.rs b/scarb/src/resolver/mod.rs index 25761c0a5..b1a056ac9 100644 --- a/scarb/src/resolver/mod.rs +++ b/scarb/src/resolver/mod.rs @@ -5,6 +5,7 @@ use indoc::{formatdoc, indoc}; use petgraph::graphmap::DiGraphMap; use scarb_ui::Ui; +use crate::core::lockfile::Lockfile; use crate::core::registry::Registry; use crate::core::resolver::{DependencyEdge, Resolve}; use crate::core::{DepKind, ManifestDependency, PackageId, Summary, TargetKind}; @@ -23,7 +24,12 @@ use crate::core::{DepKind, ManifestDependency, PackageId, Summary, TargetKind}; /// It is also advised to implement internal caching, as the resolver may frequently ask /// repetitive queries. #[tracing::instrument(level = "trace", skip_all)] -pub async fn resolve(summaries: &[Summary], registry: &dyn Registry, ui: &Ui) -> Result { +pub async fn resolve( + summaries: &[Summary], + registry: &dyn Registry, + _lockfile: Lockfile, + ui: &Ui, +) -> Result { // TODO(#2): This is very bad, use PubGrub here. let mut graph = DiGraphMap::::new(); @@ -174,6 +180,7 @@ mod tests { use similar_asserts::assert_serde_eq; use tokio::runtime::Builder; + use crate::core::lockfile::Lockfile; use crate::core::package::PackageName; use crate::core::registry::mock::{deps, pkgs, registry, MockRegistry}; use crate::core::{ManifestDependency, PackageId, Resolve, SourceId, TargetKind}; @@ -234,8 +241,9 @@ mod tests { }) .collect_vec(); + let lockfile = Lockfile::new(vec![].into_iter()); let ui = Ui::new(Verbose, OutputFormat::Text); - runtime.block_on(super::resolve(&summaries, ®istry, &ui)) + runtime.block_on(super::resolve(&summaries, ®istry, lockfile, &ui)) } fn package_id>(name: S) -> PackageId { diff --git a/scarb/tests/lockfile.rs b/scarb/tests/lockfile.rs new file mode 100644 index 000000000..c786aa44f --- /dev/null +++ b/scarb/tests/lockfile.rs @@ -0,0 +1,35 @@ +use std::fs; +use std::path::Path; + +use assert_fs::fixture::ChildPath; +use assert_fs::prelude::*; +use indoc::indoc; +use snapbox::cmd::Command; + +use scarb_test_support::cargo::cargo_bin; +use test_for_each_example::test_for_each_example; + +#[test_for_each_example] +fn create_lockfile_simple(example: &Path) { + let lockfile = ChildPath::new(example.join("Scarb.lock")); + if lockfile.exists() { + fs::remove_file(&lockfile) + .unwrap_or_else(|_| panic!("failed to remove {}", lockfile.to_str().unwrap())); + } + + lockfile.assert(predicates::path::missing()); + + Command::new(cargo_bin("scarb")) + .arg("fetch") + .current_dir(example) + .assert() + .success(); + + lockfile.assert(predicates::path::exists()); + lockfile.assert(predicates::str::starts_with(indoc! {r#" + # Code generated by scarb DO NOT EDIT. + version = 1 + + [[package]] + "#})); +}