chore: remove orgize-sync package
This commit is contained in:
parent
5d26466e07
commit
b15900b100
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,6 +2,6 @@
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
|
||||||
orgize/benches/*.org
|
benches/*.org
|
||||||
.gdb_history
|
.gdb_history
|
||||||
perf.data*
|
perf.data*
|
||||||
|
|
|
@ -14,11 +14,7 @@ before_script:
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- cargo fmt --all -- --check
|
- cargo fmt --all -- --check
|
||||||
- if [ $TRAVIS_RUST_VERSION == "stable" ]; then
|
- cargo test --all-features
|
||||||
cargo test -p orgize-demos -p orgize --all-features;
|
|
||||||
else
|
|
||||||
cargo test -p orgize-sync --all-features;
|
|
||||||
fi
|
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
provider: heroku
|
provider: heroku
|
||||||
|
|
46
Cargo.toml
46
Cargo.toml
|
@ -1,9 +1,39 @@
|
||||||
[workspace]
|
[package]
|
||||||
members = [
|
name = "orgize"
|
||||||
"orgize",
|
version = "0.5.0"
|
||||||
"orgize-demos",
|
authors = ["PoiScript <poiscript@gmail.com>"]
|
||||||
"orgize-sync",
|
description = "A Rust library for parsing orgmode files."
|
||||||
]
|
repository = "https://github.com/PoiScript/orgize"
|
||||||
|
readme = "README.md"
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT"
|
||||||
|
keywords = ["orgmode", "emacs", "parser"]
|
||||||
|
exclude = ["/demos", "/fuzz"]
|
||||||
|
|
||||||
[profile.release]
|
[package.metadata.docs.rs]
|
||||||
lto = true
|
all-features = true
|
||||||
|
|
||||||
|
[badges]
|
||||||
|
travis-ci = { repository = "PoiScript/orgize" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["ser"]
|
||||||
|
ser = ["serde", "serde_indextree"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bytecount = "0.6.0"
|
||||||
|
chrono = { version = "0.4.9", optional = true }
|
||||||
|
indextree = "4.0.0"
|
||||||
|
jetscii = "0.4.4"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
memchr = "2.2.1"
|
||||||
|
# we don't need to parse any float number, so lexical crate is redundant
|
||||||
|
nom = { version = "5.0.1", default-features = false, features = ["std"] }
|
||||||
|
serde = { version = "1.0.101", optional = true, features = ["derive"] }
|
||||||
|
serde_indextree = { version = "0.2.0", optional = true }
|
||||||
|
syntect = { version = "3.3.0", optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
pretty_assertions = "0.6.1"
|
||||||
|
serde_json = "1.0.41"
|
||||||
|
slugify = "0.1.0"
|
||||||
|
|
2
Procfile
2
Procfile
|
@ -1 +1 @@
|
||||||
web: ./target/release/orgize-demos
|
web: ./demos/target/release/orgize-demos
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
VERSION="nightly"
|
RUST_CARGO_BUILD_FLAGS="--release --manifest-path demos/Cargo.toml"
|
||||||
RUST_CARGO_BUILD_FLAGS="--release -p orgize-demos"
|
|
||||||
|
|
1
demos/.gitignore
vendored
Normal file
1
demos/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
target
|
|
@ -5,8 +5,11 @@ authors = ["PoiScript <poiscript@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = { version = "1.0.8", default-features = false }
|
actix-web = { version = "1.0.8", default-features = false }
|
||||||
orgize = { path = "../orgize", features = ["syntect"] }
|
orgize = { path = "..", features = ["syntect"] }
|
||||||
serde = { version = "1.0.101", features = ["derive"] }
|
serde = { version = "1.0.101", features = ["derive"] }
|
||||||
serde_json = "1.0.41"
|
serde_json = "1.0.41"
|
|
@ -1,33 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "orgize-sync"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["PoiScript <poiscript@gmail.com>"]
|
|
||||||
description = "Sync your Org with your favourite applications."
|
|
||||||
repository = "https://github.com/PoiScript/orgize"
|
|
||||||
readme = "README.md"
|
|
||||||
edition = "2018"
|
|
||||||
license = "MIT"
|
|
||||||
keywords = ["orgmode"]
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["dotenv", "google_calendar", "toggl"]
|
|
||||||
google_calendar = []
|
|
||||||
toggl = []
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
app_dirs = "1.2.1"
|
|
||||||
chrono = { version = "0.4.9", features = ["serde"] }
|
|
||||||
colored = "1.8.0"
|
|
||||||
dotenv = { version = "0.14.1", optional = true }
|
|
||||||
futures-preview = "=0.3.0-alpha.18"
|
|
||||||
isahc = { version = "0.7.3", default-features = false, features = ["json", "http2", "static-curl"] }
|
|
||||||
orgize = { path = "../orgize", default-features = false, features = ["chrono"] }
|
|
||||||
serde = { version = "1.0.100", features = ["derive"] }
|
|
||||||
serde_json = "1.0.40"
|
|
||||||
structopt = "0.3.1"
|
|
||||||
tokio = "=0.2.0-alpha.4"
|
|
||||||
toml = "0.5.3"
|
|
||||||
url = "2.1.0"
|
|
|
@ -1,84 +0,0 @@
|
||||||
# Orgize-sync
|
|
||||||
|
|
||||||
Sync your Org with your favourite applications.
|
|
||||||
|
|
||||||
> This project is still in *alpha stage*. Don't forget to backup
|
|
||||||
> your orgmode files before trying!
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
### `Init`
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
### `Sync`
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
### `Conf`
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### General
|
|
||||||
|
|
||||||
> Field with default value is optional.
|
|
||||||
|
|
||||||
**Global**:
|
|
||||||
|
|
||||||
``` toml
|
|
||||||
# path to dotenv file
|
|
||||||
env_path = "./.env" # default is `${UserCache}/orgize-sync/.env`
|
|
||||||
|
|
||||||
# number of days to filter headline before today
|
|
||||||
up_days = 1 # default is 7
|
|
||||||
# number of days to filter headline after today
|
|
||||||
down_days = 1 # default is 7
|
|
||||||
```
|
|
||||||
|
|
||||||
**Pre-file**:
|
|
||||||
|
|
||||||
``` toml
|
|
||||||
[[file]]
|
|
||||||
# path to this orgmode file, required
|
|
||||||
path = "./notes.org"
|
|
||||||
# specify a name for this file, optional
|
|
||||||
name = "note"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Google Calendar
|
|
||||||
|
|
||||||
**Global**:
|
|
||||||
|
|
||||||
``` toml
|
|
||||||
[google_calendar]
|
|
||||||
# google oauth client id and client_secret, required
|
|
||||||
client_id = "xxx" # or environment variable `GOOGLE_CLIENT_ID`
|
|
||||||
client_secret = "xxx" # or environment variable `GOOGLE_CLIENT_SECRET`
|
|
||||||
|
|
||||||
# redirect url after authorizing
|
|
||||||
redirect_uri = "" # default is `http://localhost`
|
|
||||||
|
|
||||||
# control where to store access token and refresh token
|
|
||||||
token_dir = "" # default is `${UserCache}/orgize-sync`
|
|
||||||
token_filename = "" # default is `google-token.json`
|
|
||||||
```
|
|
||||||
|
|
||||||
**Pre-file**:
|
|
||||||
|
|
||||||
``` toml
|
|
||||||
[[file]]
|
|
||||||
# other fields ...
|
|
||||||
[file.google_calendar]
|
|
||||||
# which calendar to sync, required
|
|
||||||
calendar = ""
|
|
||||||
|
|
||||||
# whether to append new calendar event to the org mode
|
|
||||||
append_new = false # default is true
|
|
||||||
# where to append new calendar event
|
|
||||||
append_headline = "" # default is `Sync`
|
|
||||||
|
|
||||||
# which property to store event id
|
|
||||||
property = "" # default is `EVENT_ID`
|
|
||||||
```
|
|
|
@ -1,150 +0,0 @@
|
||||||
use std::env;
|
|
||||||
use std::fs;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use app_dirs::{app_root, AppDataType, AppInfo};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
pub use crate::conf::google_calendar::*;
|
|
||||||
use crate::error::Result;
|
|
||||||
|
|
||||||
const APP_INFO: AppInfo = AppInfo {
|
|
||||||
name: "orgize-sync",
|
|
||||||
author: "PoiScript",
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn user_config_path() -> PathBuf {
|
|
||||||
app_root(AppDataType::UserConfig, &APP_INFO).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn user_cache_path() -> PathBuf {
|
|
||||||
app_root(AppDataType::UserCache, &APP_INFO).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default_config_path() -> PathBuf {
|
|
||||||
let mut path = user_config_path();
|
|
||||||
path.push("conf.toml");
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default_env_path() -> PathBuf {
|
|
||||||
let mut path = user_cache_path();
|
|
||||||
path.push(".env");
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct Conf {
|
|
||||||
#[cfg(feature = "dotenv")]
|
|
||||||
pub env_path: PathBuf,
|
|
||||||
pub up_days: i64,
|
|
||||||
pub down_days: i64,
|
|
||||||
pub files: Vec<FileConf>,
|
|
||||||
#[cfg(feature = "google_calendar")]
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub google_calendar: Option<GoogleCalendarGlobalConf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Conf {
|
|
||||||
fn default() -> Self {
|
|
||||||
Conf {
|
|
||||||
#[cfg(feature = "dotenv")]
|
|
||||||
env_path: default_env_path(),
|
|
||||||
up_days: 7,
|
|
||||||
down_days: 7,
|
|
||||||
files: Vec::new(),
|
|
||||||
google_calendar: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct EnvConf {
|
|
||||||
pub env_path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for EnvConf {
|
|
||||||
fn default() -> Self {
|
|
||||||
EnvConf {
|
|
||||||
env_path: default_env_path(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Conf {
|
|
||||||
pub fn new(path: Option<PathBuf>) -> Result<Self> {
|
|
||||||
let path = path.unwrap_or_else(default_config_path);
|
|
||||||
|
|
||||||
let content = fs::read(&path).expect(&format!(
|
|
||||||
"Failed to read fileConf: {}",
|
|
||||||
path.as_path().display()
|
|
||||||
));
|
|
||||||
|
|
||||||
if cfg!(feature = "dotenv") {
|
|
||||||
let env_conf: EnvConf = toml::from_slice(&content)?;
|
|
||||||
if env_conf.env_path.as_path().exists() {
|
|
||||||
dotenv::from_path(env_conf.env_path.as_path())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(toml::from_slice(&content)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct FileConf {
|
|
||||||
pub path: String,
|
|
||||||
pub name: Option<String>,
|
|
||||||
#[cfg(feature = "google_calendar")]
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub google_calendar: Option<GoogleCalendarConf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "google_calendar")]
|
|
||||||
pub mod google_calendar {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct GoogleCalendarGlobalConf {
|
|
||||||
pub client_id: String,
|
|
||||||
pub client_secret: String,
|
|
||||||
pub token_dir: PathBuf,
|
|
||||||
pub token_filename: String,
|
|
||||||
pub redirect_uri: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for GoogleCalendarGlobalConf {
|
|
||||||
fn default() -> Self {
|
|
||||||
GoogleCalendarGlobalConf {
|
|
||||||
client_id: env::var("GOOGLE_CLIENT_ID").unwrap(),
|
|
||||||
client_secret: env::var("GOOGLE_CLIENT_SECRET").unwrap(),
|
|
||||||
token_dir: user_cache_path(),
|
|
||||||
token_filename: "google-token.json".into(),
|
|
||||||
redirect_uri: "http://localhost".into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct GoogleCalendarConf {
|
|
||||||
pub calendar: String,
|
|
||||||
pub append_new: bool,
|
|
||||||
pub append_headline: String,
|
|
||||||
pub property: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for GoogleCalendarConf {
|
|
||||||
fn default() -> Self {
|
|
||||||
GoogleCalendarConf {
|
|
||||||
calendar: String::new(),
|
|
||||||
append_new: false,
|
|
||||||
append_headline: "Sync".into(),
|
|
||||||
property: "EVENT_ID".into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
use app_dirs::AppDirsError;
|
|
||||||
use dotenv::Error as EnvError;
|
|
||||||
use isahc::http::Error as HttpError;
|
|
||||||
use isahc::Error as IsahcError;
|
|
||||||
use serde_json::Error as JsonError;
|
|
||||||
use std::convert::From;
|
|
||||||
use std::io::Error as IOError;
|
|
||||||
use toml::de::Error as TomlDeError;
|
|
||||||
use toml::ser::Error as TomlSerError;
|
|
||||||
use url::ParseError;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
AppDirs(AppDirsError),
|
|
||||||
Env(EnvError),
|
|
||||||
Http(IsahcError),
|
|
||||||
IO(IOError),
|
|
||||||
TomlDe(TomlDeError),
|
|
||||||
TomlSer(TomlSerError),
|
|
||||||
Json(JsonError),
|
|
||||||
Url(ParseError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<AppDirsError> for Error {
|
|
||||||
fn from(err: AppDirsError) -> Self {
|
|
||||||
Error::AppDirs(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<EnvError> for Error {
|
|
||||||
fn from(err: EnvError) -> Self {
|
|
||||||
Error::Env(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<IOError> for Error {
|
|
||||||
fn from(err: IOError) -> Self {
|
|
||||||
Error::IO(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<IsahcError> for Error {
|
|
||||||
fn from(err: IsahcError) -> Self {
|
|
||||||
Error::Http(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<HttpError> for Error {
|
|
||||||
fn from(err: HttpError) -> Self {
|
|
||||||
Error::Http(err.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TomlDeError> for Error {
|
|
||||||
fn from(err: TomlDeError) -> Self {
|
|
||||||
Error::TomlDe(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TomlSerError> for Error {
|
|
||||||
fn from(err: TomlSerError) -> Self {
|
|
||||||
Error::TomlSer(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<JsonError> for Error {
|
|
||||||
fn from(err: JsonError) -> Self {
|
|
||||||
Error::Json(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ParseError> for Error {
|
|
||||||
fn from(err: ParseError) -> Self {
|
|
||||||
Error::Url(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
|
|
@ -1,137 +0,0 @@
|
||||||
use chrono::{DateTime, Duration, Utc};
|
|
||||||
use colored::Colorize;
|
|
||||||
use isahc::prelude::{Request, RequestExt, ResponseExt};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::fs;
|
|
||||||
use std::io::{stdin, BufRead};
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
use crate::conf::GoogleCalendarGlobalConf;
|
|
||||||
use crate::error::Result;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct Auth {
|
|
||||||
access_token: String,
|
|
||||||
expires_at: DateTime<Utc>,
|
|
||||||
refresh_token: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Auth {
|
|
||||||
pub async fn new(conf: &GoogleCalendarGlobalConf) -> Result<Self> {
|
|
||||||
let mut path = conf.token_dir.clone();
|
|
||||||
path.push(&conf.token_filename);
|
|
||||||
if let Ok(json) = fs::read_to_string(path) {
|
|
||||||
Ok(serde_json::from_str(&json)?)
|
|
||||||
} else {
|
|
||||||
Auth::sign_in(conf).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save(&self, conf: &GoogleCalendarGlobalConf) -> Result<()> {
|
|
||||||
let mut path = conf.token_dir.clone();
|
|
||||||
path.push(&conf.token_filename);
|
|
||||||
fs::write(path, serde_json::to_string(&self)?)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn sign_in(config: &GoogleCalendarGlobalConf) -> Result<Self> {
|
|
||||||
let url = Url::parse_with_params(
|
|
||||||
"https://accounts.google.com/o/oauth2/v2/auth",
|
|
||||||
&[
|
|
||||||
("client_id", &*config.client_id),
|
|
||||||
("response_type", "code"),
|
|
||||||
("access_type", "offline"),
|
|
||||||
("redirect_uri", &*config.redirect_uri),
|
|
||||||
("scope", "https://www.googleapis.com/auth/calendar"),
|
|
||||||
],
|
|
||||||
)?;
|
|
||||||
|
|
||||||
println!("Visit: {}", url.as_str().underline());
|
|
||||||
println!("Follow the instructions and paste the code here:");
|
|
||||||
|
|
||||||
for line in stdin().lock().lines() {
|
|
||||||
let line = line?;
|
|
||||||
let code = line.trim();
|
|
||||||
|
|
||||||
if code.is_empty() {
|
|
||||||
continue;
|
|
||||||
} else if code == "q" {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut response = Request::post("https://www.googleapis.com/oauth2/v4/token")
|
|
||||||
.header("content-type", "application/x-www-form-urlencoded")
|
|
||||||
.body(format!(
|
|
||||||
"code={}&client_id={}&client_secret={}&grant_type={}&redirect_uri={}",
|
|
||||||
&code,
|
|
||||||
&config.client_id,
|
|
||||||
&config.client_secret,
|
|
||||||
"authorization_code",
|
|
||||||
"http://localhost"
|
|
||||||
))?
|
|
||||||
.send_async()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if response.status().is_success() {
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct ConfirmCodeResponse {
|
|
||||||
access_token: String,
|
|
||||||
expires_in: i64,
|
|
||||||
refresh_token: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
let json = response.json::<ConfirmCodeResponse>()?;
|
|
||||||
|
|
||||||
println!("Logging in successfully.");
|
|
||||||
|
|
||||||
let auth = Auth {
|
|
||||||
access_token: json.access_token,
|
|
||||||
expires_at: Utc::now() + Duration::seconds(json.expires_in),
|
|
||||||
refresh_token: json.refresh_token,
|
|
||||||
};
|
|
||||||
|
|
||||||
auth.save(config)?;
|
|
||||||
|
|
||||||
return Ok(auth);
|
|
||||||
} else {
|
|
||||||
panic!("Failed to authorize.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
panic!("Failed to authorize.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn refresh(&mut self, config: &GoogleCalendarGlobalConf) -> Result<()> {
|
|
||||||
let mut response = Request::post("https://www.googleapis.com/oauth2/v4/token")
|
|
||||||
.header("content-type", "application/x-www-form-urlencoded")
|
|
||||||
.body(format!(
|
|
||||||
"client_id={}&client_secret={}&refresh_token={}&grant_type={}",
|
|
||||||
&config.client_id, &config.client_secret, self.refresh_token, "refresh_token",
|
|
||||||
))?
|
|
||||||
.send_async()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if response.status().is_success() {
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct RefreshTokenResponse {
|
|
||||||
access_token: String,
|
|
||||||
expires_in: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
let json = response.json::<RefreshTokenResponse>()?;
|
|
||||||
|
|
||||||
self.access_token = json.access_token;
|
|
||||||
self.expires_at = Utc::now() + Duration::seconds(json.expires_in);
|
|
||||||
self.save(config)?;
|
|
||||||
} else {
|
|
||||||
panic!("");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_valid(&self) -> bool {
|
|
||||||
self.expires_at > Utc::now()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
pub mod auth;
|
|
|
@ -1,103 +0,0 @@
|
||||||
mod conf;
|
|
||||||
mod error;
|
|
||||||
mod google;
|
|
||||||
|
|
||||||
use std::fs;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use structopt::StructOpt;
|
|
||||||
use toml::to_string_pretty;
|
|
||||||
|
|
||||||
use crate::conf::{
|
|
||||||
default_config_path, default_env_path, user_cache_path, user_config_path, Conf, EnvConf,
|
|
||||||
};
|
|
||||||
use crate::error::Result;
|
|
||||||
use crate::google::auth::Auth;
|
|
||||||
|
|
||||||
#[derive(StructOpt, Debug)]
|
|
||||||
#[structopt(name = "orgize-sync")]
|
|
||||||
struct Opt {
|
|
||||||
#[structopt(subcommand)]
|
|
||||||
subcommand: Cmd,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(StructOpt, Debug)]
|
|
||||||
enum Cmd {
|
|
||||||
#[structopt(name = "init")]
|
|
||||||
Init,
|
|
||||||
#[structopt(name = "sync")]
|
|
||||||
Sync {
|
|
||||||
#[structopt(long = "skip-google-calendar")]
|
|
||||||
skip_google_calendar: bool,
|
|
||||||
#[structopt(long = "skip-toggl")]
|
|
||||||
skip_toggl: bool,
|
|
||||||
#[structopt(short = "c", long = "conf", parse(from_os_str))]
|
|
||||||
conf_path: Option<PathBuf>,
|
|
||||||
},
|
|
||||||
#[structopt(name = "conf")]
|
|
||||||
Conf {
|
|
||||||
#[structopt(short = "c", long = "conf", parse(from_os_str))]
|
|
||||||
conf_path: Option<PathBuf>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() -> Result<()> {
|
|
||||||
let opt = Opt::from_args();
|
|
||||||
|
|
||||||
match opt.subcommand {
|
|
||||||
Cmd::Init => {
|
|
||||||
fs::create_dir_all(user_config_path())?;
|
|
||||||
fs::create_dir_all(user_cache_path())?;
|
|
||||||
|
|
||||||
let default_env_path = default_env_path();
|
|
||||||
let default_config_path = default_config_path();
|
|
||||||
|
|
||||||
if default_env_path.as_path().exists() {
|
|
||||||
println!(
|
|
||||||
"{} already existed, skipping ...",
|
|
||||||
default_env_path.as_path().display()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
println!("Creating {} ...", default_env_path.as_path().display());
|
|
||||||
fs::write(default_env_path.clone(), "")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if default_config_path.as_path().exists() {
|
|
||||||
println!(
|
|
||||||
"{} already existed, skipping ...",
|
|
||||||
default_config_path.as_path().display()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
println!("Creating {} ...", default_config_path.as_path().display());
|
|
||||||
fs::write(
|
|
||||||
default_config_path,
|
|
||||||
to_string_pretty(&EnvConf {
|
|
||||||
env_path: default_env_path,
|
|
||||||
})?,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Cmd::Sync {
|
|
||||||
conf_path,
|
|
||||||
skip_google_calendar,
|
|
||||||
skip_toggl,
|
|
||||||
} => {
|
|
||||||
let conf = Conf::new(conf_path)?;
|
|
||||||
|
|
||||||
if cfg!(feature = "google_calendar") && !skip_google_calendar {
|
|
||||||
if let Some(google_calendar) = conf.google_calendar {
|
|
||||||
let auth = Auth::new(&google_calendar).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg!(feature = "toggl") && !skip_toggl {}
|
|
||||||
}
|
|
||||||
Cmd::Conf { conf_path } => {
|
|
||||||
let conf = Conf::new(conf_path)?;
|
|
||||||
|
|
||||||
println!("{}", to_string_pretty(&conf)?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "orgize"
|
|
||||||
version = "0.5.0"
|
|
||||||
authors = ["PoiScript <poiscript@gmail.com>"]
|
|
||||||
description = "A Rust library for parsing orgmode files."
|
|
||||||
repository = "https://github.com/PoiScript/orgize"
|
|
||||||
readme = "README.md"
|
|
||||||
edition = "2018"
|
|
||||||
license = "MIT"
|
|
||||||
keywords = ["orgmode", "emacs", "parser"]
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
|
|
||||||
[badges]
|
|
||||||
travis-ci = { repository = "PoiScript/orgize" }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["ser"]
|
|
||||||
ser = ["serde", "serde_indextree"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bytecount = "0.6.0"
|
|
||||||
chrono = { version = "0.4.9", optional = true }
|
|
||||||
indextree = "4.0.0"
|
|
||||||
jetscii = "0.4.4"
|
|
||||||
lazy_static = "1.4.0"
|
|
||||||
memchr = "2.2.1"
|
|
||||||
# we don't need to parse any float number, so lexical crate is redundant
|
|
||||||
nom = { version = "5.0.1", default-features = false, features = ["std"] }
|
|
||||||
serde = { version = "1.0.101", optional = true, features = ["derive"] }
|
|
||||||
serde_indextree = { version = "0.2.0", optional = true }
|
|
||||||
syntect = { version = "3.3.0", optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
pretty_assertions = "0.6.1"
|
|
||||||
serde_json = "1.0.41"
|
|
||||||
slugify = "0.1.0"
|
|
|
@ -1 +0,0 @@
|
||||||
../README.md
|
|
|
@ -62,5 +62,17 @@ fn parse() {
|
||||||
" :CUSTOM_ID: id\n"
|
" :CUSTOM_ID: id\n"
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_drawer::<VerboseError<&str>>(":PROPERTIES:\n :END:"),
|
||||||
|
Ok((
|
||||||
|
"",
|
||||||
|
(
|
||||||
|
Drawer {
|
||||||
|
name: "PROPERTIES".into()
|
||||||
|
},
|
||||||
|
""
|
||||||
)
|
)
|
||||||
|
))
|
||||||
|
);
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ use nom::{
|
||||||
/// Inline Babel Call Object
|
/// Inline Babel Call Object
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct InlineCall<'a> {
|
pub struct InlineCall<'a> {
|
||||||
/// Called code block name
|
/// Called code block name
|
||||||
pub name: Cow<'a, str>,
|
pub name: Cow<'a, str>,
|
|
@ -221,14 +221,13 @@
|
||||||
#![allow(clippy::range_plus_one)]
|
#![allow(clippy::range_plus_one)]
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
|
mod error;
|
||||||
pub mod elements;
|
pub mod elements;
|
||||||
pub mod export;
|
pub mod export;
|
||||||
mod node;
|
mod node;
|
||||||
mod org;
|
mod org;
|
||||||
mod parsers;
|
mod parsers;
|
||||||
|
|
||||||
mod error;
|
|
||||||
|
|
||||||
// Re-export of the indextree crate.
|
// Re-export of the indextree crate.
|
||||||
pub use indextree;
|
pub use indextree;
|
||||||
#[cfg(feature = "syntect")]
|
#[cfg(feature = "syntect")]
|
Loading…
Reference in a new issue