Convert Client::_fetch_target's lookup fn into a method
This is a minor simplification of `Client::_fetch_target` to
factor out the interior lookup function in order to cut
out on a number of variables being passed in as arguments.
diff --git a/src/client.rs b/src/client.rs
index 55fc68f..bed58bf 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -440,169 +440,14 @@
// TODO this should check the local repo first
fn _fetch_target(&mut self, target: &TargetPath) -> Result<SafeReader<R::TargetRead>> {
- fn lookup<D_, L_, R_, T_>(
- tuf: &mut Tuf<D_>,
- config: &Config<T_>,
- default_terminate: bool,
- current_depth: u32,
- target: &VirtualTargetPath,
- snapshot: &SnapshotMetadata,
- targets: Option<&TargetsMetadata>,
- local: &mut L_,
- remote: &mut R_,
- ) -> (bool, Result<TargetDescription>)
- where
- D_: DataInterchange,
- L_: Repository<D_>,
- R_: Repository<D_>,
- T_: PathTranslator,
- {
- if current_depth > config.max_delegation_depth {
- warn!(
- "Walking the delegation graph would have exceeded the configured max depth: {}",
- config.max_delegation_depth
- );
- return (default_terminate, Err(Error::NotFound));
- }
-
- // these clones are dumb, but we need immutable values and not references for update
- // tuf in the loop below
- let targets = match targets {
- Some(t) => t.clone(),
- None => match tuf.targets() {
- Some(t) => t.clone(),
- None => {
- return (
- default_terminate,
- Err(Error::MissingMetadata(Role::Targets)),
- )
- }
- },
- };
-
- if let Some(t) = targets.targets().get(target) {
- return (default_terminate, Ok(t.clone()));
- }
-
- let delegations = match targets.delegations() {
- Some(d) => d,
- None => return (default_terminate, Err(Error::NotFound)),
- };
-
- for delegation in delegations.roles().iter() {
- if !delegation.paths().iter().any(|p| target.is_child(p)) {
- if delegation.terminating() {
- return (true, Err(Error::NotFound));
- } else {
- continue;
- }
- }
-
- let role_meta = match snapshot.meta().get(delegation.role()) {
- Some(m) => m,
- None if !delegation.terminating() => continue,
- None => return (true, Err(Error::NotFound)),
- };
-
- let (alg, value) = match crypto::hash_preference(role_meta.hashes()) {
- Ok(h) => h,
- Err(e) => return (delegation.terminating(), Err(e)),
- };
-
- let version = if tuf.root().consistent_snapshot() {
- MetadataVersion::Hash(value.clone())
- } else {
- MetadataVersion::None
- };
-
- let signed_meta = match local
- .fetch_metadata::<TargetsMetadata>(
- delegation.role(),
- &MetadataVersion::None,
- &Some(role_meta.size()),
- config.min_bytes_per_second(),
- Some((alg, value.clone())),
- )
- .or_else(|_| {
- remote.fetch_metadata::<TargetsMetadata>(
- delegation.role(),
- &version,
- &Some(role_meta.size()),
- config.min_bytes_per_second(),
- Some((alg, value.clone())),
- )
- }) {
- Ok(m) => m,
- Err(ref e) if !delegation.terminating() => {
- warn!("Failed to fetch metadata {:?}: {:?}", delegation.role(), e);
- continue;
- }
- Err(e) => {
- warn!("Failed to fetch metadata {:?}: {:?}", delegation.role(), e);
- return (true, Err(e));
- }
- };
-
- match tuf.update_delegation(delegation.role(), signed_meta.clone()) {
- Ok(_) => {
- match local.store_metadata(
- delegation.role(),
- &MetadataVersion::None,
- &signed_meta,
- ) {
- Ok(_) => (),
- Err(e) => warn!(
- "Error storing metadata {:?} locally: {:?}",
- delegation.role(),
- e
- ),
- }
-
- let meta = tuf.delegations().get(delegation.role()).unwrap().clone();
- let (term, res) = lookup(
- tuf,
- config,
- delegation.terminating(),
- current_depth + 1,
- target,
- snapshot,
- Some(meta.as_ref()),
- local,
- remote,
- );
-
- if term && res.is_err() {
- return (true, res);
- }
-
- // TODO end recursion early
- }
- Err(_) if !delegation.terminating() => continue,
- Err(e) => return (true, Err(e)),
- };
- }
-
- (default_terminate, Err(Error::NotFound))
- }
-
let virt = self.config.path_translator.real_to_virtual(target)?;
- let snapshot = self
- .tuf
+ let snapshot = self.tuf
.snapshot()
.ok_or_else(|| Error::MissingMetadata(Role::Snapshot))?
.clone();
- let (_, target_description) = lookup(
- &mut self.tuf,
- &self.config,
- false,
- 0,
- &virt,
- &snapshot,
- None,
- &mut self.local,
- &mut self.remote,
- );
+ let (_, target_description) =
+ self.lookup_target_description(false, 0, &virt, &snapshot, None);
let target_description = target_description?;
self.remote.fetch_target(
@@ -611,6 +456,142 @@
self.config.min_bytes_per_second,
)
}
+
+ fn lookup_target_description(
+ &mut self,
+ default_terminate: bool,
+ current_depth: u32,
+ target: &VirtualTargetPath,
+ snapshot: &SnapshotMetadata,
+ targets: Option<&TargetsMetadata>,
+ ) -> (bool, Result<TargetDescription>) {
+ if current_depth > self.config.max_delegation_depth {
+ warn!(
+ "Walking the delegation graph would have exceeded the configured max depth: {}",
+ self.config.max_delegation_depth
+ );
+ return (default_terminate, Err(Error::NotFound));
+ }
+
+ // these clones are dumb, but we need immutable values and not references for update
+ // tuf in the loop below
+ let targets = match targets {
+ Some(t) => t.clone(),
+ None => match self.tuf.targets() {
+ Some(t) => t.clone(),
+ None => {
+ return (
+ default_terminate,
+ Err(Error::MissingMetadata(Role::Targets)),
+ )
+ }
+ },
+ };
+
+ if let Some(t) = targets.targets().get(target) {
+ return (default_terminate, Ok(t.clone()));
+ }
+
+ let delegations = match targets.delegations() {
+ Some(d) => d,
+ None => return (default_terminate, Err(Error::NotFound)),
+ };
+
+ for delegation in delegations.roles().iter() {
+ if !delegation.paths().iter().any(|p| target.is_child(p)) {
+ if delegation.terminating() {
+ return (true, Err(Error::NotFound));
+ } else {
+ continue;
+ }
+ }
+
+ let role_meta = match snapshot.meta().get(delegation.role()) {
+ Some(m) => m,
+ None if !delegation.terminating() => continue,
+ None => return (true, Err(Error::NotFound)),
+ };
+
+ let (alg, value) = match crypto::hash_preference(role_meta.hashes()) {
+ Ok(h) => h,
+ Err(e) => return (delegation.terminating(), Err(e)),
+ };
+
+ let version = if self.tuf.root().consistent_snapshot() {
+ MetadataVersion::Hash(value.clone())
+ } else {
+ MetadataVersion::None
+ };
+
+ let signed_meta = match self.local
+ .fetch_metadata::<TargetsMetadata>(
+ delegation.role(),
+ &MetadataVersion::None,
+ &Some(role_meta.size()),
+ self.config.min_bytes_per_second(),
+ Some((alg, value.clone())),
+ )
+ .or_else(|_| {
+ self.remote.fetch_metadata::<TargetsMetadata>(
+ delegation.role(),
+ &version,
+ &Some(role_meta.size()),
+ self.config.min_bytes_per_second(),
+ Some((alg, value.clone())),
+ )
+ }) {
+ Ok(m) => m,
+ Err(ref e) if !delegation.terminating() => {
+ warn!("Failed to fetch metadata {:?}: {:?}", delegation.role(), e);
+ continue;
+ }
+ Err(e) => {
+ warn!("Failed to fetch metadata {:?}: {:?}", delegation.role(), e);
+ return (true, Err(e));
+ }
+ };
+
+ match self.tuf.update_delegation(delegation.role(), signed_meta.clone()) {
+ Ok(_) => {
+ match self.local.store_metadata(
+ delegation.role(),
+ &MetadataVersion::None,
+ &signed_meta,
+ ) {
+ Ok(_) => (),
+ Err(e) => warn!(
+ "Error storing metadata {:?} locally: {:?}",
+ delegation.role(),
+ e
+ ),
+ }
+
+ let meta = self.tuf
+ .delegations()
+ .get(delegation.role())
+ .unwrap()
+ .clone();
+ let (term, res) = self.lookup_target_description(
+ delegation.terminating(),
+ current_depth + 1,
+ target,
+ snapshot,
+ Some(meta.as_ref()),
+ );
+
+ if term && res.is_err() {
+ return (true, res);
+ }
+
+ // TODO end recursion early
+ }
+ Err(_) if !delegation.terminating() => continue,
+ Err(e) => return (true, Err(e)),
+ };
+ }
+
+ (default_terminate, Err(Error::NotFound))
+ }
}
/// Configuration for a TUF `Client`.