diff mbox series

Support pagination when using --count

Message ID 20180810062103.11968-1-andrew.donnellan@au1.ibm.com
State Accepted
Headers show
Series Support pagination when using --count | expand

Commit Message

Andrew Donnellan Aug. 10, 2018, 6:21 a.m. UTC
Add support for pagination when using --count. We extract the Link header
from the Patchwork response to find the correct URL for the next page.

The pagination is potentially racy, as new patches could come in and
disturb the ordering, but this is a limitation on the Patchwork side at
present and is unlikely to be a significant problem.

Closes: #17 ("Enable the ability to go to page 2 (and beyond) of Patchwork results")
Signed-off-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com>
---
 src/main.rs      | 29 ++++++++++++++++-------------
 src/patchwork.rs | 41 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 56 insertions(+), 14 deletions(-)
diff mbox series

Patch

diff --git a/src/main.rs b/src/main.rs
index b16bb31bb4b4..ba9e6dba1371 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -401,9 +401,6 @@  fn main() {
         return;
     }
 
-    // The number of patches tested so far.  If --count isn't provided, this is unused.
-    let mut patch_count = 0;
-
     /*
      * Poll Patchwork for new patches.
      * If the patch is standalone (not part of a series), apply it.
@@ -411,9 +408,19 @@  fn main() {
      * Spawn tests.
      */
     'daemon: loop {
-        let patch_list = patchwork
-            .get_patch_query(&args.flag_project)
-            .unwrap_or_else(|err| panic!("Failed to obtain patch list: {}", err));
+        let patch_list;
+
+        // TODO: This is hacky and we should refactor out daemon vs patch/count
+        // mode
+        if args.flag_count > 0 {
+            patch_list = patchwork
+                .get_patch_query_num(&args.flag_project, args.flag_count as usize)
+                .unwrap_or_else(|err| panic!("Failed to obtain patch list: {}", err));
+        } else {
+            patch_list = patchwork
+                .get_patch_query(&args.flag_project)
+                .unwrap_or_else(|err| panic!("Failed to obtain patch list: {}", err));
+        }
         info!("snowpatch is ready to test new revisions from Patchwork.");
         for patch in patch_list {
             // If it's already been tested, we can skip it
@@ -481,13 +488,9 @@  fn main() {
                     patchwork.post_test_result(result, &patch.checks).unwrap();
                 }
             }
-            if args.flag_count > 0 {
-                patch_count += 1;
-                debug!("Tested {} patches out of {}", patch_count, args.flag_count);
-                if patch_count >= args.flag_count {
-                    break 'daemon;
-                }
-            }
+        }
+        if args.flag_count > 0 {
+            break;
         }
         info!("Finished testing new revisions, sleeping.");
         thread::sleep(Duration::new(settings.patchwork.polling_interval * 60, 0));
diff --git a/src/patchwork.rs b/src/patchwork.rs
index c9c335472496..31ac8ef95911 100644
--- a/src/patchwork.rs
+++ b/src/patchwork.rs
@@ -25,7 +25,9 @@  use std::result::Result;
 use tempdir::TempDir;
 
 use reqwest;
-use reqwest::header::{qitem, Accept, Authorization, Basic, Connection, ContentType, Headers};
+use reqwest::header::{
+    qitem, Accept, Authorization, Basic, Connection, ContentType, Headers, Link, RelationType,
+};
 use reqwest::Client;
 use reqwest::Response;
 use reqwest::StatusCode;
@@ -306,6 +308,43 @@  impl PatchworkServer {
             .unwrap_or_else(|err| panic!("Failed to connect to Patchwork: {}", err)))
     }
 
+    fn get_next_link(&self, resp: &Response) -> Option<String> {
+        let next = resp.headers().get::<Link>()?;
+        for val in next.values() {
+            if let Some(rel) = val.rel() {
+                if rel.iter().any(|reltype| reltype == &RelationType::Next) {
+                    return Some(val.link().to_string());
+                }
+            }
+        }
+        None
+    }
+
+    pub fn get_patch_query_num(
+        &self,
+        project: &str,
+        num_patches: usize,
+    ) -> Result<Vec<Patch>, serde_json::Error> {
+        let mut list: Vec<Patch> = vec![];
+        let mut url = Some(format!(
+            "{}{}/patches/{}&project={}",
+            &self.url, PATCHWORK_API, PATCHWORK_QUERY, project
+        ));
+
+        while let Some(real_url) = url {
+            let resp = self.get_url(&real_url)
+                .unwrap_or_else(|err| panic!("Failed to connect to Patchwork: {}", err));
+            url = self.get_next_link(&resp);
+            let new_patches: Vec<Patch> = serde_json::from_reader(resp)?;
+            list.extend(new_patches);
+            if list.len() >= num_patches {
+                break;
+            }
+        }
+        list.truncate(num_patches);
+        Ok(list)
+    }
+
     pub fn get_patch_dependencies(&self, patch: &Patch) -> Vec<Patch> {
         // We assume the list of patches in a series are in order.
         let mut dependencies: Vec<Patch> = vec![];