Skip to content

Commit

Permalink
Try avoiding a full clean in cargo sqlx prepare --merged (#1802)
Browse files Browse the repository at this point in the history
* refactor(sqlx-cli): Try avoiding a full clean with `--merged`

* docs(sqlx-cli): Sprinkle some comments on the metadata changes

* refactor(sqlx-cli): Make the new recompiltion setup unit-testable

* fix(sqlx-cli): Only pass in `$RUSTFLAGS` when set when using `--merged`

* refactor(sqlx-cli): `cargo clean -p` works by name so rip out pkgid code

* chore(sqlx-cli): Remove unused imports
  • Loading branch information
CosmicHorrorDev authored Jul 12, 2022
1 parent 7cdb68b commit 2c67e2a
Show file tree
Hide file tree
Showing 6 changed files with 30,854 additions and 26 deletions.
48 changes: 48 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions sqlx-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ glob = "0.3.0"
openssl = { version = "0.10.38", optional = true }
# workaround for https://github.com/rust-lang/rust/issues/29497
remove_dir_all = "0.7.0"
cargo_metadata = "0.14"
filetime = "0.2"

backoff = { version = "0.4.0", features = ["futures", "tokio"] }

Expand Down
1 change: 1 addition & 0 deletions sqlx-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::time::Duration;
use crate::opt::{Command, ConnectOpts, DatabaseCommand, MigrateCommand};

mod database;
mod metadata;
// mod migration;
// mod migrator;
mod migrate;
Expand Down
141 changes: 141 additions & 0 deletions sqlx-cli/src/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use anyhow::{Context, Result};
use cargo_metadata::{
Metadata as CargoMetadata, Package as MetadataPackage, PackageId as MetadataId,
};

use std::{
collections::{btree_map, BTreeMap, BTreeSet},
path::{Path, PathBuf},
str::FromStr,
};

/// The minimal amount of package information we care about
///
/// The package's `name` is used to `cargo clean -p` specific crates while the `src_paths` are
/// are used to trigger recompiles of packages within the workspace
#[derive(Debug)]
pub struct Package {
name: String,
src_paths: Vec<PathBuf>,
}

impl Package {
pub fn name(&self) -> &str {
&self.name
}

pub fn src_paths(&self) -> &[PathBuf] {
&self.src_paths
}
}

impl From<&MetadataPackage> for Package {
fn from(package: &MetadataPackage) -> Self {
let name = package.name.clone();
let src_paths = package
.targets
.iter()
.map(|target| target.src_path.clone().into_std_path_buf())
.collect();

Self { name, src_paths }
}
}

/// Contains metadata for the current project
pub struct Metadata {
/// Maps packages metadata id to the package
///
/// Currently `MetadataId` is used over `PkgId` because pkgid is not a UUID
packages: BTreeMap<MetadataId, Package>,
/// All of the crates in the current workspace
workspace_members: Vec<MetadataId>,
/// Maps each dependency to its set of dependents
reverse_deps: BTreeMap<MetadataId, BTreeSet<MetadataId>>,
/// The target directory of the project
///
/// Typically `target` at the workspace root, but can be overridden
target_directory: PathBuf,
}

impl Metadata {
pub fn package(&self, id: &MetadataId) -> Option<&Package> {
self.packages.get(id)
}

pub fn entries<'this>(&'this self) -> btree_map::Iter<'this, MetadataId, Package> {
self.packages.iter()
}

pub fn workspace_members(&self) -> &[MetadataId] {
&self.workspace_members
}

pub fn target_directory(&self) -> &Path {
&self.target_directory
}

/// Gets all dependents (direct and transitive) of `id`
pub fn all_dependents_of(&self, id: &MetadataId) -> BTreeSet<&MetadataId> {
let mut dependents = BTreeSet::new();
self.all_dependents_of_helper(id, &mut dependents);
dependents
}

fn all_dependents_of_helper<'this>(
&'this self,
id: &MetadataId,
dependents: &mut BTreeSet<&'this MetadataId>,
) {
if let Some(immediate_dependents) = self.reverse_deps.get(id) {
for immediate_dependent in immediate_dependents {
if dependents.insert(immediate_dependent) {
self.all_dependents_of_helper(&immediate_dependent, dependents);
}
}
}
}
}

impl FromStr for Metadata {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let CargoMetadata {
packages: metadata_packages,
workspace_members,
resolve,
target_directory,
..
} = serde_json::from_str(s)?;

let mut packages = BTreeMap::new();
for metadata_package in metadata_packages {
let package = Package::from(&metadata_package);
packages.insert(metadata_package.id, package);
}

let mut reverse_deps: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
let resolve =
resolve.context("Resolving the dependency graph failed (old version of cargo)")?;
for node in resolve.nodes {
for dep in node.deps {
let dependent = node.id.clone();
let dependency = dep.pkg;
reverse_deps
.entry(dependency)
.or_default()
.insert(dependent);
}
}

let target_directory = target_directory.into_std_path_buf();

Ok(Self {
packages,
workspace_members,
reverse_deps,
target_directory,
})
}
}
Loading

0 comments on commit 2c67e2a

Please sign in to comment.