Skip to content

Commit

Permalink
Support evaluating with submodules enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
grahamc committed Jan 8, 2025
1 parent d6b0137 commit 29407e6
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 32 deletions.
11 changes: 11 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ pub(crate) struct FlakeHubPushCli {
)]
pub(crate) error_on_conflict: bool,

/// Include submodules when evaluating the flake.
///
/// Adds `?submodules=1` to the flake while evaluating.
#[clap(
long,
env = "FLAKEHUB_PUSH_INCLUDE_SUBMODULES",
value_parser = EmptyBoolParser,
default_value_t = false
)]
pub(crate) include_submodules: bool,

/// Do less work on extremely large flakes.
///
/// This flag is intended to limit the scope of evaluations which are too large to complete on one machine.
Expand Down
125 changes: 96 additions & 29 deletions src/flake_info.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{
io::Write,
path::{Path, PathBuf},
};
use std::ffi::{OsStr, OsString};
use std::io::Write;
use std::path::{Path, PathBuf};

use color_eyre::eyre::{eyre, Result, WrapErr};
use serde::Deserialize;
Expand All @@ -14,9 +13,79 @@ use crate::flakehub_client::Tarball;
const FLAKE_URL_PLACEHOLDER_UUID: &str = "c9026fc0-ced9-48e0-aa3c-fc86c4c86df1";
const README_FILENAME_LOWERCASE: &str = "readme.md";

#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) enum SubmoduleParameter {
Include,
Exclude,
}

#[derive(Debug, Clone)]
struct LocalFlakeRef {
source_dir: std::path::PathBuf,

parent_dir: std::path::PathBuf,
directory_name: OsString,

submodules: SubmoduleParameter,
}

impl LocalFlakeRef {
pub fn try_new(source_dir: &std::path::Path, submodules: SubmoduleParameter) -> Result<Self> {
let parent_dir = source_dir
.parent()
.ok_or_else(|| eyre!("Getting parent directory"))?;

let directory_name = source_dir
.file_name()
.ok_or_else(|| eyre!("No file name of directory"))?;

Ok(Self {
source_dir: source_dir.to_path_buf(),
parent_dir: parent_dir.to_path_buf(),
directory_name: directory_name.into(),
submodules,
})
}

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

pub fn directory_name(&self) -> &OsStr {
&self.directory_name
}

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

/// Dirty: actually clones
pub fn as_os_string(&self) -> OsString {
let x = self.clone();
x.into_os_string()
}

pub fn into_os_string(self) -> OsString {
let mut flakeref = self.source_dir.into_os_string();

if self.submodules == SubmoduleParameter::Include {
flakeref.push("?submodules=1");
}

flakeref
}

pub fn display(&self) -> String {
let x = self.clone();
let y = x.into_os_string();
let z = y.to_string_lossy();
z.into_owned()
}
}

#[derive(Debug)]
pub struct FlakeMetadata {
pub(crate) source_dir: std::path::PathBuf,
local_flake_ref: LocalFlakeRef,
pub(crate) flake_locked_url: String,
pub(crate) metadata_json: serde_json::Value,
my_flake_is_too_big: bool,
Expand All @@ -26,27 +95,33 @@ pub struct FlakeMetadata {
pub struct FlakeOutputs(pub serde_json::Value);

impl FlakeMetadata {
pub async fn from_dir(directory: &Path, my_flake_is_too_big: bool) -> Result<Self> {
pub async fn from_dir(
source_dir: &Path,
submodules: SubmoduleParameter,
my_flake_is_too_big: bool,
) -> Result<Self> {
let local_flake_ref = LocalFlakeRef::try_new(source_dir, submodules)?;

let output = tokio::process::Command::new("nix")
.arg("flake")
.arg("metadata")
.arg("--json")
.arg("--no-write-lock-file")
.arg(directory)
.arg(local_flake_ref.as_os_string())
.output()
.await
.wrap_err_with(|| {
eyre!(
"Failed to execute `nix flake metadata --json {}`",
directory.display()
local_flake_ref.display()
)
})?;

let metadata_json: serde_json::Value = serde_json::from_slice(&output.stdout)
.wrap_err_with(|| {
eyre!(
"Parsing `nix flake metadata --json {}` as JSON",
directory.display()
local_flake_ref.display()
)
})?;

Expand Down Expand Up @@ -75,7 +150,7 @@ impl FlakeMetadata {
};

Ok(FlakeMetadata {
source_dir: source,
local_flake_ref: LocalFlakeRef::try_new(&source, submodules)?,
flake_locked_url: flake_locked_url.to_string(),
metadata_json,
my_flake_is_too_big,
Expand All @@ -95,19 +170,19 @@ impl FlakeMetadata {

command.arg("--json");
command.arg("--no-write-lock-file");
command.arg(&self.source_dir);
command.arg(&self.local_flake_ref.as_os_string());

let output = command.output().await.wrap_err_with(|| {
eyre!(
"Failed to execute `nix flake show --all-systems --json --no-write-lock-file {}`",
self.source_dir.display()
self.local_flake_ref.display()
)
})?;

if !output.status.success() {
let command = format!(
"nix flake show --all-systems --json --no-write-lock-file {}",
self.source_dir.display(),
self.local_flake_ref.display(),
);
let msg = format!(
"\
Expand All @@ -134,26 +209,26 @@ impl FlakeMetadata {
/// and committed/pushed that without the corresponding update to the flake.lock. Importantly,
/// this does not ensure anything about the recentness of the locked revs.
pub async fn check_lock_if_exists(&self) -> Result<()> {
if self.source_dir.join("flake.lock").exists() {
if self.local_flake_ref.directory().join("flake.lock").exists() {
let output = tokio::process::Command::new("nix")
.arg("flake")
.arg("metadata")
.arg("--json")
.arg("--no-update-lock-file")
.arg(&self.source_dir)
.arg(&self.local_flake_ref.as_os_string())
.output()
.await
.wrap_err_with(|| {
eyre!(
"Failed to execute `nix flake metadata --json --no-update-lock-file {}`",
self.source_dir.display()
self.local_flake_ref.display()
)
})?;

if !output.status.success() {
let command = format!(
"nix flake metadata --json --no-update-lock-file {}",
self.source_dir.display(),
self.local_flake_ref.display(),
);
let msg = format!(
"\
Expand Down Expand Up @@ -195,20 +270,12 @@ impl FlakeMetadata {
// `tar` works according to the current directory (yay)
// So we change dir and restory it after
// TODO: Fix this
let source = &self.source_dir; // refactor to be known when we create struct with from_dir
let current_dir = std::env::current_dir().wrap_err("Could not get current directory")?;
std::env::set_current_dir(
source
.parent()
.ok_or_else(|| eyre!("Getting parent directory"))?,
)?;
let dirname = self
.source_dir
.file_name()
.ok_or_else(|| eyre!("No file name of directory"))?;
std::env::set_current_dir(self.local_flake_ref.parent())?;
let dirname = self.local_flake_ref.directory_name();
tarball_builder
.append_dir_all(dirname, dirname)
.wrap_err_with(|| eyre!("Adding `{}` to tarball", self.source_dir.display()))?;
.wrap_err_with(|| eyre!("Adding `{}` to tarball", self.local_flake_ref.display()))?;
std::env::set_current_dir(current_dir).wrap_err("Could not set current directory")?;

let tarball = tarball_builder.into_inner().wrap_err("Creating tarball")?;
Expand Down Expand Up @@ -307,7 +374,7 @@ impl FlakeMetadata {

#[tracing::instrument(skip_all, fields(readme_dir))]
pub(crate) async fn get_readme_contents(&self) -> Result<Option<String>> {
let mut read_dir = tokio::fs::read_dir(&self.source_dir).await?;
let mut read_dir = tokio::fs::read_dir(self.local_flake_ref.directory()).await?;

let readme_path: Option<PathBuf> = {
let mut readme_path = None;
Expand Down
15 changes: 12 additions & 3 deletions src/release_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use color_eyre::eyre::{eyre, Context as _, Result};

use crate::cli::FlakeHubPushCli;
use crate::flake_info::FlakeMetadata;
use crate::flake_info::SubmoduleParameter;
use crate::flakehub_client::Tarball;
use crate::git_context::GitContext;
use crate::github::graphql::{MAX_LABEL_LENGTH, MAX_NUM_TOTAL_LABELS};
Expand Down Expand Up @@ -46,9 +47,17 @@ impl ReleaseMetadata {
// flake_dir is an absolute path of flake_root(aka git_root)/subdir
let flake_dir = local_git_root.join(&subdir);

let flake_metadata = FlakeMetadata::from_dir(&flake_dir, cli.my_flake_is_too_big)
.await
.wrap_err("Getting flake metadata")?;
let flake_metadata = FlakeMetadata::from_dir(
&flake_dir,
if cli.include_submodules {
SubmoduleParameter::Include
} else {
SubmoduleParameter::Exclude
},
cli.my_flake_is_too_big,
)
.await
.wrap_err("Getting flake metadata")?;
tracing::debug!("Got flake metadata: {:?}", flake_metadata);

// sanity checks
Expand Down

0 comments on commit 29407e6

Please sign in to comment.