Skip to content

Commit 004bc36

Browse files
feat: Make adding manifest to store optional. (#224)
Signed-off-by: Andrew Lilley Brinker <[email protected]>
1 parent 791bdb1 commit 004bc36

File tree

7 files changed

+122
-18
lines changed

7 files changed

+122
-18
lines changed

omnibor-cli/src/cli.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ impl Args {
9292
pub fn config(&self) -> Option<&Path> {
9393
self.config.as_deref().or_else(|| {
9494
DEFAULT_CONFIG
95-
.get_or_init(|| self.dir().map(|root| pathbuf![root, "omnibor.json"]))
95+
.get_or_init(|| self.dir().map(|root| pathbuf![root, "config.json"]))
9696
.as_deref()
9797
})
9898
}
@@ -145,7 +145,6 @@ pub struct IdArgs {
145145
#[arg(
146146
short = 'H',
147147
long = "hash",
148-
global = true,
149148
help_heading = IMPORTANT
150149
)]
151150
hash: Option<SelectedHash>,
@@ -206,8 +205,20 @@ pub struct ManifestCreateArgs {
206205
#[arg(short = 't', long = "target", help_heading = IMPORTANT)]
207206
pub target: PathBuf,
208207

208+
/// Do not store the manifest in the local store.
209+
#[arg(long = "no-store", help_heading = IMPORTANT)]
210+
pub no_store: bool,
211+
212+
/// Do not write the manifest to a local directory.
213+
#[arg(long = "no-out", help_heading = IMPORTANT)]
214+
pub no_out: bool,
215+
216+
/// Directory to write manifest out to.
217+
#[arg(short = 'o', long = "output", help_heading = IMPORTANT, value_name = "DIR")]
218+
pub output: Option<PathBuf>,
219+
209220
/// Hash algorithm to use for Artifact IDs.
210-
#[arg(short = 'H', long = "hash", global = true, env = "OMNIBOR_HASH")]
221+
#[arg(short = 'H', long = "hash", env = "OMNIBOR_HASH", help_heading = IMPORTANT)]
211222
pub hash: Option<SelectedHash>,
212223
}
213224

omnibor-cli/src/cmd/manifest/create.rs

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,42 @@ use crate::{
77
print::PrintSender,
88
};
99
use omnibor::{
10-
embedding::NoEmbed, hashes::Sha256, storage::FileSystemStorage, InputManifestBuilder,
11-
IntoArtifactId, RelationKind,
10+
embedding::{EmbeddingMode, NoEmbed},
11+
hashes::Sha256,
12+
storage::{FileSystemStorage, InMemoryStorage, Storage},
13+
ArtifactId, InputManifestBuilder, IntoArtifactId, RelationKind, ShouldStore,
14+
};
15+
use pathbuf::pathbuf;
16+
use std::{
17+
env::current_dir,
18+
fs::File,
19+
io::Write,
20+
path::{Path, PathBuf},
1221
};
13-
use tracing::debug;
1422

1523
/// Run the `manifest create` subcommand.
1624
pub async fn run(_tx: &PrintSender, app: &App, args: &ManifestCreateArgs) -> Result<()> {
17-
let root = app.args.dir().ok_or_else(|| Error::NoRoot)?;
18-
debug!(root = %root.display());
19-
20-
let storage = FileSystemStorage::new(root).map_err(Error::StorageInitFailed)?;
25+
let root = app.args.dir().ok_or(Error::NoRoot)?;
2126

22-
let mut builder = InputManifestBuilder::<Sha256, NoEmbed, _>::with_storage(storage);
27+
if args.no_store {
28+
let storage = InMemoryStorage::new();
29+
let builder = InputManifestBuilder::<Sha256, NoEmbed, _>::with_storage(storage);
30+
create_with_builder(args, builder)
31+
} else {
32+
let storage = FileSystemStorage::new(root).map_err(Error::StorageInitFailed)?;
33+
let builder = InputManifestBuilder::<Sha256, NoEmbed, _>::with_storage(storage);
34+
create_with_builder(args, builder)
35+
}
36+
}
2337

38+
fn create_with_builder<E, S>(
39+
args: &ManifestCreateArgs,
40+
mut builder: InputManifestBuilder<Sha256, E, S>,
41+
) -> Result<()>
42+
where
43+
E: EmbeddingMode,
44+
S: Storage<Sha256>,
45+
{
2446
for input in &args.inputs {
2547
let aid = input.clone().into_artifact_id().map_err(Error::IdFailed)?;
2648
builder
@@ -38,9 +60,44 @@ pub async fn run(_tx: &PrintSender, app: &App, args: &ManifestCreateArgs) -> Res
3860
.map_err(Error::AddRelationFailed)?;
3961
}
4062

41-
builder
42-
.finish(&args.target)
63+
let should_store = if args.no_store {
64+
ShouldStore::No
65+
} else {
66+
ShouldStore::Yes
67+
};
68+
69+
let transaction_ids = builder
70+
.finish(&args.target, should_store)
4371
.map_err(Error::ManifestBuildFailed)?;
4472

73+
let path = manifest_file_path(args.output.as_deref(), transaction_ids.target_aid())?;
74+
75+
let mut output_file = File::create_new(&path).map_err(|source| Error::CantWriteManifest {
76+
path: path.to_path_buf(),
77+
source,
78+
})?;
79+
80+
output_file
81+
// SAFETY: We just constructed the manifest, so we know it's fine.
82+
.write_all(&transaction_ids.manifest().as_bytes().unwrap())
83+
.map_err(|source| Error::CantWriteManifest {
84+
path: path.to_path_buf(),
85+
source,
86+
})?;
87+
4588
Ok(())
4689
}
90+
91+
fn manifest_file_path(output: Option<&Path>, target_aid: ArtifactId<Sha256>) -> Result<PathBuf> {
92+
let dir = match &output {
93+
Some(dir) => dir.to_path_buf(),
94+
None => match current_dir() {
95+
Ok(dir) => dir,
96+
Err(_) => return Err(Error::NoOutputDir),
97+
},
98+
};
99+
100+
let file_name = format!("{}.manifest", target_aid.as_hex());
101+
102+
Ok(pathbuf![&dir, &file_name])
103+
}

omnibor-cli/src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ pub enum Error {
6363
source: OmniborError,
6464
},
6565

66+
#[error("can't identify directory to write manifest")]
67+
NoOutputDir,
68+
69+
#[error("can't write manifest to '{}'", path.display())]
70+
CantWriteManifest { path: PathBuf, source: IoError },
71+
6672
#[error("work channel closed for sending")]
6773
WorkChannelCloseSend(#[source] SendError<PathBuf>),
6874

omnibor/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,12 @@ gitoid = { version = "0.8.0", path = "../gitoid", default-features = false, feat
4040
"std",
4141
"url",
4242
] }
43+
newline-converter = "0.3.0"
4344
pathbuf = "1.0.0"
4445
serde = { version = "1.0.197", optional = true }
4546
thiserror = "1.0.60"
4647
tokio = { version = "1.36.0", features = ["io-util"] }
48+
tracing = "0.1.40"
4749
url = "2.5.0"
4850
walkdir = "2.5.0"
4951

omnibor/src/input_manifest_builder.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ pub struct InputManifestBuilder<H: SupportedHash, M: EmbeddingMode, S: Storage<H
3030
storage: S,
3131
}
3232

33+
/// Should a manifest be stored after creation?
34+
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
35+
pub enum ShouldStore {
36+
/// Yes, store the manifest.
37+
Yes,
38+
/// No, do not store the manifest.
39+
No,
40+
}
41+
3342
impl<H: SupportedHash, M: EmbeddingMode, S: Storage<H>> Debug for InputManifestBuilder<H, M, S> {
3443
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
3544
f.debug_struct("InputManifestBuilder")
@@ -66,8 +75,12 @@ impl<H: SupportedHash, M: EmbeddingMode, S: Storage<H>> InputManifestBuilder<H,
6675
}
6776

6877
/// Complete the transaction without updating the target artifact.
69-
pub fn finish(&mut self, target: &Path) -> Result<TransactionIds<H>> {
70-
Self::finish_with_optional_embedding(self, target, M::mode())
78+
pub fn finish(
79+
&mut self,
80+
target: &Path,
81+
should_store: ShouldStore,
82+
) -> Result<TransactionIds<H>> {
83+
Self::finish_with_optional_embedding(self, target, M::mode(), should_store)
7184
}
7285

7386
/// Complete creation of a new [`InputManifest`], possibly embedding in the target.
@@ -79,12 +92,18 @@ impl<H: SupportedHash, M: EmbeddingMode, S: Storage<H>> InputManifestBuilder<H,
7992
&mut self,
8093
target: &Path,
8194
embed_mode: Mode,
95+
should_store: ShouldStore,
8296
) -> Result<TransactionIds<H>> {
8397
// Construct a new input manifest.
8498
let mut manifest = InputManifest::with_relations(self.relations.iter().cloned());
8599

86-
// Write the manifest to storage.
87-
let manifest_aid = self.storage.write_manifest(&manifest)?;
100+
let manifest_aid = if should_store == ShouldStore::Yes {
101+
// Write the manifest to storage.
102+
self.storage.write_manifest(&manifest)?
103+
} else {
104+
// Otherwise, just build it.
105+
ArtifactId::id_manifest(&manifest)?
106+
};
88107

89108
// Get the ArtifactID of the target, possibly embedding the
90109
// manifest ArtifactID into the target first.
@@ -116,6 +135,11 @@ impl<H: SupportedHash, M: EmbeddingMode, S: Storage<H>> InputManifestBuilder<H,
116135
manifest,
117136
})
118137
}
138+
139+
/// Get a reference to the underlying storage.
140+
pub fn storage(&self) -> &S {
141+
&self.storage
142+
}
119143
}
120144

121145
pub struct TransactionIds<H: SupportedHash> {
@@ -266,7 +290,7 @@ mod tests {
266290
.unwrap()
267291
.add_relation(RelationKind::Input, second_input_aid)
268292
.unwrap()
269-
.finish(&target)
293+
.finish(&target, ShouldStore::Yes)
270294
.unwrap();
271295

272296
// Check the ArtifactIDs of the target and the manifest.

omnibor/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,5 @@ pub use crate::input_manifest::InputManifest;
8787
pub use crate::input_manifest::Relation;
8888
pub use crate::input_manifest::RelationKind;
8989
pub use crate::input_manifest_builder::InputManifestBuilder;
90+
pub use crate::input_manifest_builder::ShouldStore;
9091
pub use crate::into_artifact_id::IntoArtifactId;

omnibor/src/storage.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use std::ops::Not as _;
2222
use std::path::Path;
2323
use std::path::PathBuf;
2424
use std::str::FromStr;
25+
use tracing::debug;
2526
use walkdir::DirEntry;
2627
use walkdir::WalkDir;
2728

@@ -263,6 +264,8 @@ fn artifact_id_from_dir_entry<H: SupportedHash>(entry: &DirEntry) -> Option<Arti
263264
format!("{}:{}", front, hash)
264265
};
265266

267+
debug!(gitoid_url = %gitoid_url);
268+
266269
ArtifactId::<H>::from_str(&gitoid_url).ok()
267270
}
268271

0 commit comments

Comments
 (0)