summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPietro Albini <pietro@pietroalbini.org>2019-01-23 00:10:58 +0100
committerPietro Albini <pietro@pietroalbini.org>2019-01-23 00:10:58 +0100
commit37e834a30053909265b763feaa9dcda78a8ab914 (patch)
treec0e99488f55aa6c77fbdd80f0dbe749fd0217984 /src
parent260a5c06d9fb856dc0f65d97ba83d76bd4aaa945 (diff)
remove sync feature
Diffstat (limited to 'src')
-rw-r--r--src/main.rs6
-rw-r--r--src/schema.rs1
-rw-r--r--src/sync/lists.rs232
-rw-r--r--src/sync/mod.rs1
4 files changed, 1 insertions, 239 deletions
diff --git a/src/main.rs b/src/main.rs
index fb8f16c..7a9e009 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,5 @@
mod data;
mod schema;
-mod sync;
mod validate;
mod static_api;
@@ -14,8 +13,6 @@ use structopt::StructOpt;
enum Cli {
#[structopt(name = "check", help = "check if the configuration is correct")]
Check,
- #[structopt(name = "sync", help = "synchronize the configuration")]
- Sync,
#[structopt(name = "static-api", help = "generate the static API")]
StaticApi { dest: String },
#[structopt(name = "dump-team", help = "print the members of a team")]
@@ -42,9 +39,6 @@ fn run() -> Result<(), Error> {
Cli::Check => {
crate::validate::validate(&data)?;
}
- Cli::Sync => {
- sync::lists::run(&data)?;
- }
Cli::StaticApi { ref dest } => {
let dest = PathBuf::from(dest);
let generator = crate::static_api::Generator::new(&dest, &data)?;
diff --git a/src/schema.rs b/src/schema.rs
index bbd577c..a2427c9 100644
--- a/src/schema.rs
+++ b/src/schema.rs
@@ -292,6 +292,7 @@ impl List {
&self.address
}
+ #[allow(unused)]
pub(crate) fn access_level_str(&self) -> &str {
match self.access_level {
ListAccessLevel::Everyone => "everyone",
diff --git a/src/sync/lists.rs b/src/sync/lists.rs
deleted file mode 100644
index 1d457f3..0000000
--- a/src/sync/lists.rs
+++ /dev/null
@@ -1,232 +0,0 @@
-use crate::data::Data;
-use crate::schema::List;
-use curl::easy::{Easy, Form};
-use failure::{bail, format_err, Error, ResultExt};
-use std::cell::RefCell;
-use std::collections::{HashMap, HashSet};
-use std::env;
-use std::str;
-
-mod api {
- #[derive(serde_derive::Deserialize)]
- pub struct ListResponse {
- pub items: Vec<List>,
- pub paging: Paging,
- }
-
- #[derive(serde_derive::Deserialize)]
- pub struct List {
- pub access_level: String,
- pub address: String,
- pub members_count: u64,
- }
-
- #[derive(serde_derive::Deserialize)]
- pub struct Paging {
- pub first: String,
- pub last: String,
- pub next: String,
- pub previous: String,
- }
-
- #[derive(serde_derive::Deserialize)]
- pub struct MembersResponse {
- pub items: Vec<Member>,
- pub paging: Paging,
- }
-
- #[derive(serde_derive::Deserialize)]
- pub struct Member {
- pub address: String,
- }
-}
-
-#[derive(serde_derive::Deserialize)]
-struct Empty {}
-
-pub(crate) fn run(data: &Data) -> Result<(), Error> {
- let mailmap = data.lists()?;
-
- let mut lists = Vec::new();
- let mut response = get::<api::ListResponse>("/lists/pages")?;
- while response.items.len() > 0 {
- lists.extend(response.items);
- response = get::<api::ListResponse>(&response.paging.next)?;
- }
-
- let mut addr2list = HashMap::new();
- for list in mailmap.values() {
- if addr2list.insert(list.address(), list).is_some() {
- bail!("duplicate address: {}", list.address());
- }
- }
-
- for prev_list in lists {
- let address = &prev_list.address;
- match addr2list.remove(address.as_str()) {
- Some(new_list) => sync(&prev_list, &new_list)
- .with_context(|_| format!("failed to sync {}", address))?,
- None => del(&prev_list).with_context(|_| format!("failed to delete {}", address))?,
- }
- }
-
- for (_, list) in addr2list.iter() {
- create(list).with_context(|_| format!("failed to create {}", list.address()))?;
- }
-
- Ok(())
-}
-
-fn create(new: &List) -> Result<(), Error> {
- let mut form = Form::new();
- form.part("address")
- .contents(new.address().as_bytes())
- .add()?;
- form.part("access_level")
- .contents(new.access_level_str().as_bytes())
- .add()?;
- post::<Empty>("/lists", form)?;
-
- add_members(new.address(), new.emails())?;
- Ok(())
-}
-
-fn sync(prev: &api::List, new: &List) -> Result<(), Error> {
- assert_eq!(prev.address, new.address());
- let url = format!("/lists/{}", prev.address);
- if prev.access_level != new.access_level_str() {
- let mut form = Form::new();
- form.part("access_level")
- .contents(new.access_level_str().as_bytes())
- .add()?;
- put::<Empty>(&url, form)?;
- }
-
- let url = format!("{}/members/pages", url);
- let mut prev_members = HashSet::new();
- let mut response = get::<api::MembersResponse>(&url)?;
- while response.items.len() > 0 {
- prev_members.extend(response.items.into_iter().map(|member| member.address));
- response = get::<api::MembersResponse>(&response.paging.next)?;
- }
-
- let mut to_add = Vec::new();
- for member in new.emails() {
- if !prev_members.remove(member) {
- to_add.push(member.clone());
- }
- }
-
- if to_add.len() > 0 {
- add_members(new.address(), &to_add)?;
- }
- for member in prev_members {
- delete::<Empty>(&format!("/lists/{}/members/{}", new.address(), member))?;
- }
-
- Ok(())
-}
-
-fn add_members(address: &str, members: &[String]) -> Result<(), Error> {
- let url = format!("/lists/{}/members.json", address);
- let data = serde_json::to_string(members)?;
- let mut form = Form::new();
- form.part("members").contents(data.as_bytes()).add()?;
- post::<Empty>(&url, form)?;
- Ok(())
-}
-
-fn del(prev: &api::List) -> Result<(), Error> {
- delete::<Empty>(&format!("/lists/{}", prev.address))?;
- Ok(())
-}
-
-fn get<T: for<'de> serde::Deserialize<'de>>(url: &str) -> Result<T, Error> {
- execute(url, Method::Get)
-}
-
-fn post<T: for<'de> serde::Deserialize<'de>>(url: &str, form: Form) -> Result<T, Error> {
- execute(url, Method::Post(form))
-}
-
-fn put<T: for<'de> serde::Deserialize<'de>>(url: &str, form: Form) -> Result<T, Error> {
- execute(url, Method::Put(form))
-}
-
-fn delete<T: for<'de> serde::Deserialize<'de>>(url: &str) -> Result<T, Error> {
- execute(url, Method::Delete)
-}
-
-enum Method {
- Get,
- Delete,
- Post(Form),
- Put(Form),
-}
-
-fn execute<T: for<'de> serde::Deserialize<'de>>(url: &str, method: Method) -> Result<T, Error> {
- thread_local!(static HANDLE: RefCell<Easy> = RefCell::new(Easy::new()));
- let password =
- env::var("MAILGUN_API_TOKEN").map_err(|_| format_err!("must set $MAILGUN_API_TOKEN"))?;
- let result = HANDLE.with(|handle| {
- let mut handle = handle.borrow_mut();
- handle.reset();
- let url = if url.starts_with("https://") {
- url.to_string()
- } else {
- format!("https://api.mailgun.net/v3{}", url)
- };
- handle.url(&url)?;
- match method {
- Method::Get => {
- log::debug!("GET {}", url);
- handle.get(true)?;
- }
- Method::Delete => {
- log::debug!("DELETE {}", url);
- handle.custom_request("DELETE")?;
- }
- Method::Post(form) => {
- log::debug!("POST {}", url);
- handle.httppost(form)?;
- }
- Method::Put(form) => {
- log::debug!("PUT {}", url);
- handle.httppost(form)?;
- handle.custom_request("PUT")?;
- }
- }
- handle.username("api")?;
- handle.password(&password)?;
- handle.useragent("rust-lang/rust membership update")?;
- // handle.verbose(true)?;
- let mut result = Vec::new();
- let mut headers = Vec::new();
- {
- let mut transfer = handle.transfer();
- transfer.write_function(|data| {
- result.extend_from_slice(data);
- Ok(data.len())
- })?;
- transfer.header_function(|header| {
- if let Ok(s) = str::from_utf8(header) {
- headers.push(s.to_string());
- }
- true
- })?;
- transfer.perform()?;
- }
-
- let result =
- String::from_utf8(result).map_err(|_| format_err!("response was invalid utf-8"))?;
-
- log::trace!("headers: {:#?}", headers);
- log::trace!("json: {}", result);
- let code = handle.response_code()?;
- if code != 200 {
- bail!("failed to get a 200 code, got {}\n\n{}", code, result)
- }
- Ok(serde_json::from_str(&result).with_context(|_| "failed to parse json response")?)
- });
- Ok(result.with_context(|_| format!("failed to send request to {}", url))?)
-}
diff --git a/src/sync/mod.rs b/src/sync/mod.rs
deleted file mode 100644
index ccefbed..0000000
--- a/src/sync/mod.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub(crate) mod lists;