├── .gitignore ├── CONTRIBUTING.md ├── docs ├── requirements.txt ├── source │ ├── index.rst │ ├── conf.py │ └── _static │ │ └── css │ │ └── custom.css └── Makefile ├── src ├── logger.rs └── main.rs ├── SECURITY.md ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ ├── pages.yml │ └── rust.yml ├── Cargo.toml ├── LICENSE ├── events.gs ├── README.md ├── CODE_OF_CONDUCT.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | TODO 2 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | furo 2 | sphinx-mdinclude 3 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. mdinclude:: ../../README.md 2 | 3 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | project = '' 2 | copyright = '2022, Oscar Cortez' 3 | author = 'Oscar Cortez' 4 | release = '' 5 | 6 | extensions = [ 7 | 'sphinx_mdinclude', 8 | ] 9 | html_theme_options = { 10 | "sidebar_hide_name": True, 11 | } 12 | html_static_path = ['_static'] 13 | html_css_files = [ 14 | 'css/custom.css', 15 | ] 16 | html_theme = 'furo' 17 | -------------------------------------------------------------------------------- /docs/source/_static/css/custom.css: -------------------------------------------------------------------------------- 1 | .sidebar-drawer { 2 | background: var(--color-background-primary); 3 | border-right: 0; 4 | } 5 | 6 | .mobile-header { 7 | justify-content: end; 8 | } 9 | 10 | .sidebar-search-container, 11 | .header-left, 12 | .header-center { 13 | display: none !important; 14 | } 15 | 16 | .toc-scroll { 17 | border-left: 1px solid var(--color-background-border) !important; 18 | } 19 | 20 | .toc-tree { 21 | border-left: 0; 22 | } 23 | 24 | .mobile-header.scrolled { 25 | box-shadow: none; 26 | border-bottom: 1px solid var(--color-header-border) !important; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/logger.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | pub struct DummyLogger { 4 | verbosity: usize, 5 | } 6 | 7 | impl DummyLogger { 8 | pub fn new(verbosity: usize) -> Self { 9 | DummyLogger { verbosity } 10 | } 11 | 12 | pub fn log(&self, msg: T) { 13 | println!("{}", msg); 14 | } 15 | 16 | pub fn extra(&self, msg: T) { 17 | if self.verbosity > 0 { 18 | println!("{}", msg); 19 | } 20 | } 21 | 22 | pub fn debug(&self, msg: T) { 23 | if self.verbosity > 1 { 24 | println!("{}", msg); 25 | } 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: oscarmcm 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: BUG 5 | labels: bug 6 | assignees: oscarmcm 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Execute '....' 17 | 4. See error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Desktop (please complete the following information):** 26 | - Install Method: [e.g. Cargo, Build, Brew] 27 | - OS: [e.g. macOS 16] 28 | - Version: [e.g. 22] 29 | - Rust Version: [e.g. 2018] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "neocal" 3 | version = "0.5.0" 4 | edition = "2021" 5 | authors = ["Oscar Cortez "] 6 | license-file = "LICENSE" 7 | description = "Google Calendar Command Line Interface" 8 | readme = "README.md" 9 | exclude = ["events.gs"] 10 | documentation = "https://github.com/oscarmcm/neocal/wiki" 11 | homepage = "https://github.com/oscarmcm/neocal" 12 | repository = "https://github.com/oscarmcm/neocal" 13 | keywords = ["cli", "tui", "google", "calendar"] 14 | categories = ["command-line-utilities"] 15 | 16 | [dependencies] 17 | futures = "0.3" 18 | configparser = "3.0.0" 19 | term-table = "1.3.2" 20 | clap = { version = "3.2.16", features = ["derive", "suggestions", "color"] } 21 | reqwest = { version = "0.11.11", features = ["json"] } 22 | tokio = { version = "1.20.4", features = ["full"] } 23 | serde = { version = "1", features = ["derive"] } 24 | serde_json = "1" 25 | term_size = "0.3.2" 26 | home = "0.5.3" 27 | chrono = "0.4.20" 28 | url = "2.2.2" 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Oscar Cortez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /events.gs: -------------------------------------------------------------------------------- 1 | // The list of calendars I want to fetch information for 2 | const calendarIds = [ 3 | '', 4 | ]; 5 | 6 | // Arguments used to fetch calendar information. Change as needed. See 7 | // https://developers.google.com/calendar/v3/reference/events/list for more info 8 | const optionalParams = { 9 | showDeleted: false, 10 | singleEvents: true, 11 | orderBy: 'startTime', 12 | }; 13 | 14 | const doGet = (event = {}) => { 15 | const params = {...optionalParams, ...event.parameter}; 16 | const date = new Date(); 17 | 18 | if (!params.hasOwnProperty('timeMin')) { 19 | params['timeMin'] = (new Date(date.getFullYear(), date.getMonth(), 1)).toISOString(); 20 | }; 21 | if (!params.hasOwnProperty('timeMax')) { 22 | params['timeMax'] = (new Date(date.getFullYear(), date.getMonth() + 1, 0)).toISOString(); 23 | }; 24 | 25 | const calendarEvents = calendarIds.flatMap(item => Calendar.Events.list(item, params).items); 26 | const formattedEvents = calendarEvents.map(event => { 27 | let start_date = new Date(event.start.dateTime ? event.start.dateTime : event.start.date); 28 | let end_date = new Date(event.start.dateTime ? event.start.dateTime : event.start.date); 29 | return { 30 | 'summary': event.summary, 31 | 'description': event.description || '', 32 | 'start_date': start_date.toDateString(), 33 | 'start_date_time': event.start.dateTime || '', 34 | 'end_date': end_date.toDateString(), 35 | 'end_date_time': event.end.dateTime || '', 36 | 'call': event.hangoutLink || '', 37 | }; 38 | }); 39 | 40 | return ContentService.createTextOutput( 41 | JSON.stringify(formattedEvents) 42 | ).setMimeType(ContentService.MimeType.JSON); 43 | }; 44 | 45 | -------------------------------------------------------------------------------- /.github/workflows/pages.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Sphinx with GitHub Pages dependencies preinstalled 2 | 3 | on: 4 | # Runs on pushes targeting the default branch 5 | push: 6 | branches: ["main"] 7 | 8 | # Allows you to run this workflow manually from the Actions tab 9 | workflow_dispatch: 10 | 11 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 12 | permissions: 13 | contents: read 14 | pages: write 15 | id-token: write 16 | 17 | # Allow one concurrent deployment 18 | concurrency: 19 | group: "pages" 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | # Build job 24 | build: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: Checkout 28 | uses: actions/checkout@v3 29 | - name: Setup python 30 | uses: actions/setup-python@v2 31 | with: 32 | python-version: "3.10" 33 | architecture: x64 34 | - name: Get latest CMake and ninja 35 | # Using 'latest' branch, the most recent CMake and ninja are installed. 36 | uses: lukka/get-cmake@latest 37 | - uses: actions/checkout@v3 38 | - name: Install requirements and package 39 | run: | 40 | python -m pip install -U pip 41 | python -m pip install scikit-build 42 | - name: Setup Pages 43 | uses: actions/configure-pages@v1 44 | - name: Build HTML with sphinx 45 | run: | 46 | python -m pip install -r requirements.txt 47 | make html 48 | working-directory: docs/ 49 | - name: Upload artifact 50 | uses: actions/upload-pages-artifact@v1 51 | with: 52 | path: docs/build/html 53 | 54 | # Deployment job 55 | deploy: 56 | environment: 57 | name: github-pages 58 | url: ${{ steps.deployment.outputs.page_url }} 59 | runs-on: ubuntu-latest 60 | needs: build 61 | steps: 62 | - name: Deploy to GitHub Pages 63 | id: deployment 64 | uses: actions/deploy-pages@v1 65 | 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NeoCal 2 | 3 | **NeoCal** is a Google Calendar Command Line Interface that allows you to access your Google Calendar(s) from a command line. It uses Google Apps Script platform to build his own data source, making it less complicated to setup than using OAUTH config tokens. 4 | 5 | ## Installation 6 | 7 | You can either install it via `cargo` or download the binaries from GitHub releases. 8 | 9 | If you go the `cargo` route, you need to have it installed (usually using [rustup](https://rustup.rs)). In a terminal, run this command to install `neocal`: 10 | 11 | ``` 12 | cargo install neocal 13 | ``` 14 | 15 | Then you'll be able to run `neocal` from whichever directory you're in. 16 | 17 | If you want other installation option, please go to the [Wiki Page](https://github.com/oscarmcm/neocal/wiki/Installing-Options) 18 | 19 | ### SetUp 20 | 21 | Once you have it installed you need to follow 3 steps in order to complete the configuration: 22 | 23 | 1. [Get Calendar IDs](https://github.com/oscarmcm/neocal/wiki/Obtain-your-Google-Calendar’s-ID) 24 | 2. [Setup Google Apps Script](https://github.com/oscarmcm/neocal/wiki/Setup-Google-Apps-Script) 25 | 3. [Create Config File](https://github.com/oscarmcm/neocal/wiki/NeoCal-Config-File) 26 | 27 | ## How-To 28 | 29 | **NeoCal** provides a series of subcommands with the following functionality: 30 | 31 | ``` 32 | agenda Shows user calendar in Agenda-like view mode 33 | calendar Shows user calendar in Calendar-like view mode 34 | help Print this message or the help of the given subcommand(s) 35 | ``` 36 | 37 | And also comes with the following options: 38 | 39 | ``` 40 | -f, --for Name of the calendar to use 41 | -h, --help Print help information 42 | -s, --search Word to search in the calendar 43 | -t, --timezone Name of the Time Zone to return the events 44 | --today Get calendar entries for today 45 | --tomorrow Get calendar entries for tomorrow 46 | -V, --version Print version information 47 | --week Get calendar entries for the current week 48 | ``` 49 | 50 | Run with `--help/-h` for detailed usage. 51 | 52 | ## To-Do 53 | 54 | List of things to add support in order of importance: 55 | 56 | ### High 57 | 58 | 1. Add Calendar view 59 | 60 | ### Medium 61 | 62 | 1. Allow table style choices 63 | 2. List User Calendar 64 | 65 | ### Low 66 | 67 | 1. Create events from the CLI 68 | 2. Edit events from the CLI 69 | 3. Delete events from the CLI 70 | 4. Event Popup Reminders 71 | 5. Theme Support 72 | 6. Colorized output 73 | 74 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | name: Test rust ${{ matrix.rust }} on ${{ matrix.os }} 8 | 9 | runs-on: ${{ matrix.os }} 10 | 11 | strategy: 12 | matrix: 13 | os: [ubuntu-latest, macOS-latest, 'windows-latest'] 14 | rust: [stable] 15 | 16 | steps: 17 | - uses: hecrj/setup-rust-action@v1 18 | with: 19 | rust-version: ${{ matrix.rust }} 20 | components: rustfmt 21 | - uses: actions/checkout@v1 22 | - name: Check formatting 23 | run: cargo fmt -- --check 24 | - name: Run tests 25 | run: cargo test --verbose 26 | - name: Build release 27 | run: cargo build --verbose --release 28 | - name: Upload unix binary 29 | uses: actions/upload-artifact@v1 30 | if: matrix.os != 'windows-latest' 31 | with: 32 | name: neocal-${{ matrix.os }} 33 | path: target/release/neocal 34 | - name: Upload windows binary 35 | uses: actions/upload-artifact@v1 36 | if: matrix.os == 'windows-latest' 37 | with: 38 | name: neocal-${{ matrix.os }} 39 | path: target/release/neocal.exe 40 | 41 | release: 42 | name: Release 43 | needs: build 44 | if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') 45 | runs-on: ubuntu-latest 46 | 47 | steps: 48 | - name: Checkout code 49 | uses: actions/checkout@v1 50 | - uses: actions/download-artifact@v1 51 | with: 52 | name: neocal-ubuntu-latest 53 | path: dist/neocal-ubuntu-latest 54 | - uses: actions/download-artifact@v1 55 | with: 56 | name: neocal-macOS-latest 57 | path: dist/neocal-macOS-latest 58 | - uses: actions/download-artifact@v1 59 | with: 60 | name: neocal-windows-latest 61 | path: dist/neocal-windows-latest 62 | - name: List release files 63 | run: find dist/ 64 | - name: Create release 65 | id: create_release 66 | uses: actions/create-release@v1.0.0 67 | env: 68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 69 | with: 70 | tag_name: ${{ github.ref }} 71 | release_name: Release ${{ github.ref }} 72 | draft: false 73 | prerelease: false 74 | - name: Upload linux release asset 75 | uses: actions/upload-release-asset@v1.0.1 76 | env: 77 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 78 | with: 79 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 80 | asset_path: ./dist/neocal-ubuntu-latest/neocal 81 | asset_name: neocal-linux-x86_64 82 | asset_content_type: application/x-elf 83 | - name: Upload macos release asset 84 | uses: actions/upload-release-asset@v1.0.1 85 | env: 86 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 87 | with: 88 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 89 | asset_path: ./dist/neocal-macOS-latest/neocal 90 | asset_name: neocal-darwin-x86_64 91 | asset_content_type: application/x-mach-binary 92 | - name: Upload windows release asset 93 | uses: actions/upload-release-asset@v1.0.1 94 | env: 95 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 96 | with: 97 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 98 | asset_path: ./dist/neocal-windows-latest/neocal.exe 99 | asset_name: neocal-windows-x86_64.exe 100 | asset_content_type: application/vnd.microsoft.portable-executable 101 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | om.cortez.2010@gmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::error::Error; 3 | use std::path::Path; 4 | 5 | use chrono::{DateTime, Datelike, Duration, NaiveDate, Weekday}; 6 | use clap::{Parser, Subcommand}; 7 | use configparser::ini::Ini; 8 | use home; 9 | use reqwest; 10 | use serde::{Deserialize, Serialize}; 11 | use term_size; 12 | use term_table::{ 13 | row::Row, 14 | table_cell::{Alignment, TableCell}, 15 | }; 16 | use term_table::{Table, TableStyle}; 17 | use url::Url; 18 | 19 | #[derive(Serialize, Deserialize, Debug)] 20 | struct Event { 21 | summary: String, 22 | description: String, 23 | start_date: String, 24 | start_date_time: String, 25 | end_date: String, 26 | end_date_time: String, 27 | call: String, 28 | } 29 | 30 | #[derive(Parser)] 31 | #[clap(author="Oscar Cortez ", version, about="Google Calendar CLI", long_about = None)] 32 | #[clap(propagate_version = true)] 33 | struct Cli { 34 | #[clap(subcommand)] 35 | command: Option, 36 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_value)] 37 | /// Name of the calendar to use 38 | r#for: Option, 39 | 40 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_value)] 41 | /// Word to search in the calendar 42 | search: Option, 43 | 44 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_value)] 45 | /// Name of the Time Zone to return the events 46 | timezone: Option, 47 | 48 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_date)] 49 | /// Start date used to return the events 50 | begin_date: Option, 51 | 52 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_date)] 53 | /// End date used to return the events 54 | end_date: Option, 55 | 56 | #[clap(short, long, default_value_t=u32::MIN)] 57 | /// Number of weeks to return the events starting from the current week 58 | weeks: u32, 59 | 60 | #[clap(long)] 61 | /// Get calendar entries for the current week 62 | week: bool, 63 | 64 | #[clap(long)] 65 | /// Get calendar entries for today 66 | today: bool, 67 | 68 | #[clap(long)] 69 | /// Get calendar entries for tomorrow 70 | tomorrow: bool, 71 | 72 | #[clap(short, long, parse(from_occurrences))] 73 | verbosity: usize, 74 | } 75 | 76 | #[derive(Subcommand)] 77 | enum Commands { 78 | /// Shows user calendar in Agenda-like view mode 79 | Agenda { 80 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_value)] 81 | /// Name of the calendar to use 82 | r#for: Option, 83 | 84 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_value)] 85 | /// Word to search in the calendar 86 | search: Option, 87 | 88 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_value)] 89 | /// Name of the Time Zone to return the events 90 | timezone: Option, 91 | 92 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_date)] 93 | /// Start date used to return the events 94 | begin_date: Option, 95 | 96 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_date)] 97 | /// End date used to return the events 98 | end_date: Option, 99 | 100 | #[clap(short, long, default_value_t=u32::MIN)] 101 | /// Number of weeks to return the events starting from the current week 102 | weeks: u32, 103 | 104 | #[clap(long)] 105 | /// Get calendar entries for the current week 106 | week: bool, 107 | 108 | #[clap(long)] 109 | /// Get calendar entries for today 110 | today: bool, 111 | 112 | #[clap(long)] 113 | /// Get calendar entries for tomorrow 114 | tomorrow: bool, 115 | }, 116 | /// Show user calendar in Calendar-like view mode 117 | Calendar { 118 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_value)] 119 | /// Name of the calendar to use 120 | r#for: Option, 121 | 122 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_value)] 123 | /// Word to search in the calendar 124 | search: Option, 125 | 126 | #[clap(short, long, value_parser, forbid_empty_values = true, validator = validate_option_value)] 127 | /// Name of the Time Zone to return the events 128 | timezone: Option, 129 | 130 | #[clap(short, long, default_value_t=u32::MIN)] 131 | /// Number of weeks to return the events starting from the current week 132 | weeks: u32, 133 | }, 134 | } 135 | 136 | fn week_bounds(weeks_ahead: u32) -> (NaiveDate, NaiveDate) { 137 | let current_year = chrono::offset::Local::now().year(); 138 | let current_week = chrono::offset::Local::now().iso_week().week(); 139 | let mon = NaiveDate::from_isoywd(current_year, current_week, Weekday::Mon); 140 | let sun = NaiveDate::from_isoywd(current_year, current_week + weeks_ahead, Weekday::Sun); 141 | (mon, sun) 142 | } 143 | 144 | fn validate_option_value(name: &str) -> Result<(), std::io::Error> { 145 | if name.trim().len() != name.len() { 146 | Err(std::io::Error::new( 147 | std::io::ErrorKind::Other, 148 | "Values cannot have leading and/or trailing space", 149 | )) 150 | } else { 151 | Ok(()) 152 | } 153 | } 154 | 155 | fn validate_option_date(date: &str) -> Result<(), std::io::Error> { 156 | match NaiveDate::parse_from_str(date, "%Y-%m-%d") { 157 | Ok(_parsed_date) => Ok(()), 158 | Err(_err) => { 159 | let err_msg = format!( 160 | "Please make sure your dates are in the following format YYYY-MM-DD (ie. 2020-12-21), your dates is: {}", &date 161 | ); 162 | Err(std::io::Error::new(std::io::ErrorKind::Other, err_msg)) 163 | } 164 | } 165 | } 166 | 167 | fn render_agenda_view(events: Vec) -> std::io::Result<()> { 168 | if events.iter().len() == 0 { 169 | eprintln!("No Events were found."); 170 | }; 171 | 172 | let mut table = Table::new(); 173 | let mut event_date = ""; 174 | 175 | table.style = TableStyle::blank(); 176 | table.max_column_width = if let Some((w, _h)) = term_size::dimensions() { 177 | w - 60 178 | } else { 179 | 80 180 | }; 181 | 182 | for event in events.iter() { 183 | let event_time = if &event.start_date_time != "" && &event.end_date_time != "" { 184 | format!( 185 | "{} - {}", 186 | DateTime::parse_from_rfc3339(&event.start_date_time) 187 | .unwrap() 188 | .format("%H:%M") 189 | .to_string(), 190 | DateTime::parse_from_rfc3339(&event.end_date_time) 191 | .unwrap() 192 | .format("%H:%M") 193 | .to_string(), 194 | ) 195 | } else { 196 | "All Day".to_string() 197 | }; 198 | 199 | let mut table_row = [ 200 | TableCell::new(""), 201 | TableCell::new_with_alignment(event_time, 1, Alignment::Right), 202 | TableCell::new_with_alignment( 203 | format!("{}\n{}", &event.summary, &event.call), 204 | 1, 205 | Alignment::Left, 206 | ), 207 | ]; 208 | if event_date != &event.start_date { 209 | table.add_row(Row::new(vec![ 210 | TableCell::new(""), 211 | TableCell::new(""), 212 | TableCell::new(""), 213 | ])); 214 | table_row[0] = TableCell::new(&event.start_date); 215 | }; 216 | table.add_row(Row::new(table_row)); 217 | event_date = &event.start_date; 218 | } 219 | 220 | println!("{}", table.render()); 221 | return Ok(()); 222 | } 223 | 224 | fn render_calendar_view(_events: Vec) -> std::io::Result<()> { 225 | eprintln!("This command is not yet implemented."); 226 | return Ok(()); 227 | } 228 | 229 | async fn get_events( 230 | view_to_render: &str, 231 | url: &str, 232 | search: &str, 233 | timezone: &str, 234 | begin_date: &str, 235 | end_date: &str, 236 | weeks: &u32, 237 | week: &bool, 238 | today: &bool, 239 | tomorrow: &bool, 240 | ) -> Result<(), Box> { 241 | let mut endpoint = Url::parse(url)?; 242 | let client = reqwest::Client::new(); 243 | 244 | if search.len() != 0 { 245 | endpoint.query_pairs_mut().append_pair("q", search); 246 | }; 247 | if timezone.len() != 0 { 248 | endpoint.query_pairs_mut().append_pair("timeZone", timezone); 249 | }; 250 | if *weeks != 0 { 251 | let (mon, sun) = week_bounds(*weeks); 252 | let time_min = format!("{}T00:00:00.000Z", mon.format("%Y-%m-%d")); 253 | let time_max = format!("{}T23:59:59.000Z", sun.format("%Y-%m-%d")); 254 | let query = format!("timeMin={}&timeMax={}", time_min, time_max); 255 | endpoint.set_query(Some(&query)); 256 | }; 257 | if *week { 258 | let (mon, sun) = week_bounds(0); 259 | let time_min = format!("{}T00:00:00.000Z", mon.format("%Y-%m-%d")); 260 | let time_max = format!("{}T23:59:59.000Z", sun.format("%Y-%m-%d")); 261 | let query = format!("timeMin={}&timeMax={}", time_min, time_max); 262 | endpoint.set_query(Some(&query)); 263 | }; 264 | if *today { 265 | let today = chrono::offset::Local::now(); 266 | let time_min = format!("{}T00:00:00.000Z", today.format("%Y-%m-%d")); 267 | let time_max = format!("{}T23:59:59.000Z", today.format("%Y-%m-%d")); 268 | let query = format!("timeMin={}&timeMax={}", time_min, time_max); 269 | endpoint.set_query(Some(&query)); 270 | }; 271 | if *tomorrow { 272 | let tomorrow = chrono::offset::Local::now() + Duration::days(1); 273 | let time_min = format!("{}T00:00:00.000Z", tomorrow.format("%Y-%m-%d")); 274 | let time_max = format!("{}T23:59:59.000Z", tomorrow.format("%Y-%m-%d")); 275 | let query = format!("timeMin={}&timeMax={}", time_min, time_max); 276 | endpoint.set_query(Some(&query)); 277 | }; 278 | if begin_date.len() != 0 && end_date.len() != 0 { 279 | let time_min = format!("{}T00:00:00.000Z", begin_date); 280 | let time_max = format!("{}T23:59:59.000Z", end_date); 281 | let query = format!("timeMin={}&timeMax={}", time_min, time_max); 282 | endpoint.set_query(Some(&query)); 283 | }; 284 | 285 | let request = client 286 | .get(endpoint.as_str()) 287 | .header(reqwest::header::CONTENT_TYPE, "application/json") 288 | .header(reqwest::header::ACCEPT, "application/json") 289 | .send() 290 | .await 291 | .unwrap(); 292 | 293 | match request.status() { 294 | reqwest::StatusCode::OK => match request.json::>().await { 295 | Ok(events) => match view_to_render { 296 | "agenda" => render_agenda_view(events), 297 | "calendar" => render_calendar_view(events), 298 | _ => Err(std::io::Error::new( 299 | std::io::ErrorKind::Other, 300 | "Unrecognized view type", 301 | )), 302 | }, 303 | Err(err) => Err(std::io::Error::new( 304 | std::io::ErrorKind::Other, 305 | format!("The response didn't match the shape we expected. {}", err), 306 | )), 307 | }, 308 | reqwest::StatusCode::NOT_FOUND => Err(std::io::Error::new( 309 | std::io::ErrorKind::Other, 310 | "Looks like the Calendar URL does not exists.", 311 | )), 312 | reqwest::StatusCode::UNAUTHORIZED => Err(std::io::Error::new( 313 | std::io::ErrorKind::Other, 314 | "Looks like the Calendar URL is not public.", 315 | )), 316 | _ => Err(std::io::Error::new( 317 | std::io::ErrorKind::Other, 318 | "Uh oh! Something unexpected happened.", 319 | )), 320 | }; 321 | Ok(()) 322 | } 323 | 324 | #[tokio::main] 325 | async fn main() -> Result<(), Box> { 326 | let mut config = Ini::new(); 327 | let config_path = match env::var("NEOCAL_CONFIG_PATH") { 328 | Ok(val) => val, 329 | Err(_err) => match home::home_dir() { 330 | Some(path) => Path::join(&path, Path::new("./.config/neocal/config.ini")) 331 | .to_str() 332 | .unwrap() 333 | .to_string(), 334 | None => "".to_string(), 335 | }, 336 | }; 337 | if config_path.len() == 0 { 338 | eprintln!("Impossible to get your home dir!"); 339 | panic!(); 340 | }; 341 | 342 | config.load(config_path)?; 343 | let cli = Cli::parse(); 344 | 345 | match &cli.command { 346 | Some(Commands::Agenda { 347 | r#for, 348 | search, 349 | timezone, 350 | begin_date, 351 | end_date, 352 | weeks, 353 | week, 354 | today, 355 | tomorrow, 356 | }) => { 357 | let calendar_to_use = if r#for.is_none() { 358 | config.get("neocal", "default").unwrap() 359 | } else { 360 | r#for.as_ref().unwrap().to_string() 361 | }; 362 | let url = &config.get(&calendar_to_use, "endpoint").unwrap(); 363 | 364 | let mut selected_timezone = timezone.as_ref().unwrap_or(&"".to_string()).to_string(); 365 | if selected_timezone.len() == 0 { 366 | selected_timezone = config 367 | .get(&calendar_to_use, "timezone") 368 | .unwrap_or("".to_string()) 369 | .to_string(); 370 | }; 371 | if selected_timezone.len() == 0 { 372 | selected_timezone = config 373 | .get("neocal", "timezone") 374 | .unwrap_or("".to_string()) 375 | .to_string(); 376 | }; 377 | if selected_timezone.len() == 0 { 378 | selected_timezone = "".to_string(); 379 | }; 380 | 381 | match get_events( 382 | &String::from("agenda"), 383 | url, 384 | &search.as_ref().unwrap_or(&"".to_string()).to_string(), 385 | &selected_timezone, 386 | &begin_date.as_ref().unwrap_or(&"".to_string()), 387 | &end_date.as_ref().unwrap_or(&"".to_string()), 388 | &weeks, 389 | &week, 390 | &today, 391 | &tomorrow, 392 | ) 393 | .await 394 | { 395 | Ok(_) => {} 396 | Err(err) => eprintln!("Error rendering Agenda - {}", err), 397 | } 398 | } 399 | Some(Commands::Calendar { 400 | r#for, 401 | search, 402 | timezone, 403 | weeks, 404 | }) => { 405 | let calendar_to_use = if r#for.is_none() { 406 | config.get("neocal", "default").unwrap() 407 | } else { 408 | r#for.as_ref().unwrap().to_string() 409 | }; 410 | let url = &config.get(&calendar_to_use, "endpoint").unwrap(); 411 | 412 | let mut selected_timezone = timezone.as_ref().unwrap_or(&"".to_string()).to_string(); 413 | if selected_timezone.len() == 0 { 414 | selected_timezone = config 415 | .get(&calendar_to_use, "timezone") 416 | .unwrap_or("".to_string()) 417 | .to_string(); 418 | }; 419 | if selected_timezone.len() == 0 { 420 | selected_timezone = config 421 | .get("neocal", "timezone") 422 | .unwrap_or("".to_string()) 423 | .to_string(); 424 | }; 425 | if selected_timezone.len() == 0 { 426 | selected_timezone = "".to_string(); 427 | }; 428 | 429 | match get_events( 430 | &String::from("calendar"), 431 | url, 432 | &search.as_ref().unwrap_or(&"".to_string()).to_string(), 433 | &selected_timezone, 434 | &"".to_string(), 435 | &"".to_string(), 436 | &weeks, 437 | &false, 438 | &false, 439 | &false, 440 | ) 441 | .await 442 | { 443 | Ok(_) => {} 444 | Err(err) => eprintln!("Error rendering Calendar - {}", err), 445 | } 446 | } 447 | None => { 448 | let view_to_use = config.get("neocal", "mode").unwrap(); 449 | let calendar_to_use = cli 450 | .r#for 451 | .unwrap_or(config.get("neocal", "default").unwrap()); 452 | let url = &config.get(&calendar_to_use, "endpoint").unwrap(); 453 | let timezone = cli.timezone.unwrap_or( 454 | config 455 | .get(&calendar_to_use, "timezone") 456 | .unwrap_or(config.get("neocal", "timezone").unwrap_or("".to_string())), 457 | ); 458 | match view_to_use.as_str() { 459 | "agenda" => match get_events( 460 | &String::from("agenda"), 461 | url, 462 | &cli.search.unwrap_or("".to_string()).to_string(), 463 | &timezone, 464 | &cli.begin_date.unwrap_or("".to_string()).to_string(), 465 | &cli.end_date.unwrap_or("".to_string()).to_string(), 466 | &cli.weeks, 467 | &cli.week, 468 | &cli.today, 469 | &cli.tomorrow, 470 | ) 471 | .await 472 | { 473 | Ok(_) => {} 474 | Err(err) => eprintln!("Error rendering Agenda - {}", err), 475 | }, 476 | "calendar" => match get_events( 477 | &String::from("calendar"), 478 | url, 479 | &cli.search.unwrap_or("".to_string()).to_string(), 480 | &timezone, 481 | &"".to_string(), 482 | &"".to_string(), 483 | &cli.weeks, 484 | &false, 485 | &false, 486 | &false, 487 | ) 488 | .await 489 | { 490 | Ok(_) => {} 491 | Err(err) => eprintln!("Error rendering Calendar - {}", err), 492 | }, 493 | _ => eprintln!("Unrecognized view type."), 494 | } 495 | } 496 | }; 497 | 498 | Ok(()) 499 | } 500 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "atty" 16 | version = "0.2.14" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 19 | dependencies = [ 20 | "hermit-abi", 21 | "libc", 22 | "winapi", 23 | ] 24 | 25 | [[package]] 26 | name = "autocfg" 27 | version = "1.1.0" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 30 | 31 | [[package]] 32 | name = "base64" 33 | version = "0.13.0" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 36 | 37 | [[package]] 38 | name = "bitflags" 39 | version = "1.3.2" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 42 | 43 | [[package]] 44 | name = "bumpalo" 45 | version = "3.12.0" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" 48 | 49 | [[package]] 50 | name = "bytes" 51 | version = "1.2.1" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" 54 | 55 | [[package]] 56 | name = "cc" 57 | version = "1.0.73" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 60 | 61 | [[package]] 62 | name = "cfg-if" 63 | version = "1.0.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 66 | 67 | [[package]] 68 | name = "chrono" 69 | version = "0.4.20" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "6127248204b9aba09a362f6c930ef6a78f2c1b2215f8a7b398c06e1083f17af0" 72 | dependencies = [ 73 | "js-sys", 74 | "num-integer", 75 | "num-traits", 76 | "time", 77 | "wasm-bindgen", 78 | "winapi", 79 | ] 80 | 81 | [[package]] 82 | name = "clap" 83 | version = "3.2.16" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9" 86 | dependencies = [ 87 | "atty", 88 | "bitflags", 89 | "clap_derive", 90 | "clap_lex", 91 | "indexmap", 92 | "once_cell", 93 | "strsim", 94 | "termcolor", 95 | "textwrap", 96 | ] 97 | 98 | [[package]] 99 | name = "clap_derive" 100 | version = "3.2.15" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "9ba52acd3b0a5c33aeada5cdaa3267cdc7c594a98731d4268cdc1532f4264cb4" 103 | dependencies = [ 104 | "heck", 105 | "proc-macro-error", 106 | "proc-macro2", 107 | "quote", 108 | "syn", 109 | ] 110 | 111 | [[package]] 112 | name = "clap_lex" 113 | version = "0.2.4" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" 116 | dependencies = [ 117 | "os_str_bytes", 118 | ] 119 | 120 | [[package]] 121 | name = "configparser" 122 | version = "3.0.0" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "06821ea598337a8412cf47c5b71c3bc694a7f0aed188ac28b836fab164a2c202" 125 | 126 | [[package]] 127 | name = "core-foundation" 128 | version = "0.9.3" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" 131 | dependencies = [ 132 | "core-foundation-sys", 133 | "libc", 134 | ] 135 | 136 | [[package]] 137 | name = "core-foundation-sys" 138 | version = "0.8.3" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 141 | 142 | [[package]] 143 | name = "encoding_rs" 144 | version = "0.8.31" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" 147 | dependencies = [ 148 | "cfg-if", 149 | ] 150 | 151 | [[package]] 152 | name = "fastrand" 153 | version = "1.8.0" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" 156 | dependencies = [ 157 | "instant", 158 | ] 159 | 160 | [[package]] 161 | name = "fnv" 162 | version = "1.0.7" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 165 | 166 | [[package]] 167 | name = "foreign-types" 168 | version = "0.3.2" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 171 | dependencies = [ 172 | "foreign-types-shared", 173 | ] 174 | 175 | [[package]] 176 | name = "foreign-types-shared" 177 | version = "0.1.1" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 180 | 181 | [[package]] 182 | name = "form_urlencoded" 183 | version = "1.0.1" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 186 | dependencies = [ 187 | "matches", 188 | "percent-encoding", 189 | ] 190 | 191 | [[package]] 192 | name = "futures" 193 | version = "0.3.21" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" 196 | dependencies = [ 197 | "futures-channel", 198 | "futures-core", 199 | "futures-executor", 200 | "futures-io", 201 | "futures-sink", 202 | "futures-task", 203 | "futures-util", 204 | ] 205 | 206 | [[package]] 207 | name = "futures-channel" 208 | version = "0.3.21" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" 211 | dependencies = [ 212 | "futures-core", 213 | "futures-sink", 214 | ] 215 | 216 | [[package]] 217 | name = "futures-core" 218 | version = "0.3.21" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" 221 | 222 | [[package]] 223 | name = "futures-executor" 224 | version = "0.3.21" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" 227 | dependencies = [ 228 | "futures-core", 229 | "futures-task", 230 | "futures-util", 231 | ] 232 | 233 | [[package]] 234 | name = "futures-io" 235 | version = "0.3.21" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" 238 | 239 | [[package]] 240 | name = "futures-macro" 241 | version = "0.3.21" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" 244 | dependencies = [ 245 | "proc-macro2", 246 | "quote", 247 | "syn", 248 | ] 249 | 250 | [[package]] 251 | name = "futures-sink" 252 | version = "0.3.21" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" 255 | 256 | [[package]] 257 | name = "futures-task" 258 | version = "0.3.21" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" 261 | 262 | [[package]] 263 | name = "futures-util" 264 | version = "0.3.21" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" 267 | dependencies = [ 268 | "futures-channel", 269 | "futures-core", 270 | "futures-io", 271 | "futures-macro", 272 | "futures-sink", 273 | "futures-task", 274 | "memchr", 275 | "pin-project-lite", 276 | "pin-utils", 277 | "slab", 278 | ] 279 | 280 | [[package]] 281 | name = "h2" 282 | version = "0.3.17" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" 285 | dependencies = [ 286 | "bytes", 287 | "fnv", 288 | "futures-core", 289 | "futures-sink", 290 | "futures-util", 291 | "http", 292 | "indexmap", 293 | "slab", 294 | "tokio", 295 | "tokio-util", 296 | "tracing", 297 | ] 298 | 299 | [[package]] 300 | name = "hashbrown" 301 | version = "0.12.3" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 304 | 305 | [[package]] 306 | name = "heck" 307 | version = "0.4.0" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 310 | 311 | [[package]] 312 | name = "hermit-abi" 313 | version = "0.1.19" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 316 | dependencies = [ 317 | "libc", 318 | ] 319 | 320 | [[package]] 321 | name = "home" 322 | version = "0.5.3" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" 325 | dependencies = [ 326 | "winapi", 327 | ] 328 | 329 | [[package]] 330 | name = "http" 331 | version = "0.2.8" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" 334 | dependencies = [ 335 | "bytes", 336 | "fnv", 337 | "itoa", 338 | ] 339 | 340 | [[package]] 341 | name = "http-body" 342 | version = "0.4.5" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 345 | dependencies = [ 346 | "bytes", 347 | "http", 348 | "pin-project-lite", 349 | ] 350 | 351 | [[package]] 352 | name = "httparse" 353 | version = "1.7.1" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" 356 | 357 | [[package]] 358 | name = "httpdate" 359 | version = "1.0.2" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 362 | 363 | [[package]] 364 | name = "hyper" 365 | version = "0.14.20" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" 368 | dependencies = [ 369 | "bytes", 370 | "futures-channel", 371 | "futures-core", 372 | "futures-util", 373 | "h2", 374 | "http", 375 | "http-body", 376 | "httparse", 377 | "httpdate", 378 | "itoa", 379 | "pin-project-lite", 380 | "socket2", 381 | "tokio", 382 | "tower-service", 383 | "tracing", 384 | "want", 385 | ] 386 | 387 | [[package]] 388 | name = "hyper-tls" 389 | version = "0.5.0" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 392 | dependencies = [ 393 | "bytes", 394 | "hyper", 395 | "native-tls", 396 | "tokio", 397 | "tokio-native-tls", 398 | ] 399 | 400 | [[package]] 401 | name = "idna" 402 | version = "0.2.3" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 405 | dependencies = [ 406 | "matches", 407 | "unicode-bidi", 408 | "unicode-normalization", 409 | ] 410 | 411 | [[package]] 412 | name = "indexmap" 413 | version = "1.9.1" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" 416 | dependencies = [ 417 | "autocfg", 418 | "hashbrown", 419 | ] 420 | 421 | [[package]] 422 | name = "instant" 423 | version = "0.1.12" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 426 | dependencies = [ 427 | "cfg-if", 428 | ] 429 | 430 | [[package]] 431 | name = "ipnet" 432 | version = "2.5.0" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" 435 | 436 | [[package]] 437 | name = "itoa" 438 | version = "1.0.3" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" 441 | 442 | [[package]] 443 | name = "js-sys" 444 | version = "0.3.59" 445 | source = "registry+https://github.com/rust-lang/crates.io-index" 446 | checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" 447 | dependencies = [ 448 | "wasm-bindgen", 449 | ] 450 | 451 | [[package]] 452 | name = "lazy_static" 453 | version = "1.4.0" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 456 | 457 | [[package]] 458 | name = "libc" 459 | version = "0.2.127" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b" 462 | 463 | [[package]] 464 | name = "lock_api" 465 | version = "0.4.7" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" 468 | dependencies = [ 469 | "autocfg", 470 | "scopeguard", 471 | ] 472 | 473 | [[package]] 474 | name = "log" 475 | version = "0.4.17" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 478 | dependencies = [ 479 | "cfg-if", 480 | ] 481 | 482 | [[package]] 483 | name = "matches" 484 | version = "0.1.9" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 487 | 488 | [[package]] 489 | name = "memchr" 490 | version = "2.5.0" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 493 | 494 | [[package]] 495 | name = "mime" 496 | version = "0.3.16" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 499 | 500 | [[package]] 501 | name = "mio" 502 | version = "0.8.4" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" 505 | dependencies = [ 506 | "libc", 507 | "log", 508 | "wasi 0.11.0+wasi-snapshot-preview1", 509 | "windows-sys", 510 | ] 511 | 512 | [[package]] 513 | name = "native-tls" 514 | version = "0.2.10" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" 517 | dependencies = [ 518 | "lazy_static", 519 | "libc", 520 | "log", 521 | "openssl", 522 | "openssl-probe", 523 | "openssl-sys", 524 | "schannel", 525 | "security-framework", 526 | "security-framework-sys", 527 | "tempfile", 528 | ] 529 | 530 | [[package]] 531 | name = "neocal" 532 | version = "0.5.0" 533 | dependencies = [ 534 | "chrono", 535 | "clap", 536 | "configparser", 537 | "futures", 538 | "home", 539 | "reqwest", 540 | "serde", 541 | "serde_json", 542 | "term-table", 543 | "term_size", 544 | "tokio", 545 | "url", 546 | ] 547 | 548 | [[package]] 549 | name = "num-integer" 550 | version = "0.1.45" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 553 | dependencies = [ 554 | "autocfg", 555 | "num-traits", 556 | ] 557 | 558 | [[package]] 559 | name = "num-traits" 560 | version = "0.2.15" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 563 | dependencies = [ 564 | "autocfg", 565 | ] 566 | 567 | [[package]] 568 | name = "num_cpus" 569 | version = "1.13.1" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 572 | dependencies = [ 573 | "hermit-abi", 574 | "libc", 575 | ] 576 | 577 | [[package]] 578 | name = "once_cell" 579 | version = "1.13.0" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" 582 | 583 | [[package]] 584 | name = "openssl" 585 | version = "0.10.55" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" 588 | dependencies = [ 589 | "bitflags", 590 | "cfg-if", 591 | "foreign-types", 592 | "libc", 593 | "once_cell", 594 | "openssl-macros", 595 | "openssl-sys", 596 | ] 597 | 598 | [[package]] 599 | name = "openssl-macros" 600 | version = "0.1.0" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" 603 | dependencies = [ 604 | "proc-macro2", 605 | "quote", 606 | "syn", 607 | ] 608 | 609 | [[package]] 610 | name = "openssl-probe" 611 | version = "0.1.5" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 614 | 615 | [[package]] 616 | name = "openssl-sys" 617 | version = "0.9.90" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" 620 | dependencies = [ 621 | "cc", 622 | "libc", 623 | "pkg-config", 624 | "vcpkg", 625 | ] 626 | 627 | [[package]] 628 | name = "os_str_bytes" 629 | version = "6.2.0" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4" 632 | 633 | [[package]] 634 | name = "parking_lot" 635 | version = "0.12.1" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 638 | dependencies = [ 639 | "lock_api", 640 | "parking_lot_core", 641 | ] 642 | 643 | [[package]] 644 | name = "parking_lot_core" 645 | version = "0.9.3" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" 648 | dependencies = [ 649 | "cfg-if", 650 | "libc", 651 | "redox_syscall", 652 | "smallvec", 653 | "windows-sys", 654 | ] 655 | 656 | [[package]] 657 | name = "percent-encoding" 658 | version = "2.1.0" 659 | source = "registry+https://github.com/rust-lang/crates.io-index" 660 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 661 | 662 | [[package]] 663 | name = "pin-project-lite" 664 | version = "0.2.9" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 667 | 668 | [[package]] 669 | name = "pin-utils" 670 | version = "0.1.0" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 673 | 674 | [[package]] 675 | name = "pkg-config" 676 | version = "0.3.25" 677 | source = "registry+https://github.com/rust-lang/crates.io-index" 678 | checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" 679 | 680 | [[package]] 681 | name = "proc-macro-error" 682 | version = "1.0.4" 683 | source = "registry+https://github.com/rust-lang/crates.io-index" 684 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 685 | dependencies = [ 686 | "proc-macro-error-attr", 687 | "proc-macro2", 688 | "quote", 689 | "syn", 690 | "version_check", 691 | ] 692 | 693 | [[package]] 694 | name = "proc-macro-error-attr" 695 | version = "1.0.4" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 698 | dependencies = [ 699 | "proc-macro2", 700 | "quote", 701 | "version_check", 702 | ] 703 | 704 | [[package]] 705 | name = "proc-macro2" 706 | version = "1.0.43" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" 709 | dependencies = [ 710 | "unicode-ident", 711 | ] 712 | 713 | [[package]] 714 | name = "quote" 715 | version = "1.0.21" 716 | source = "registry+https://github.com/rust-lang/crates.io-index" 717 | checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" 718 | dependencies = [ 719 | "proc-macro2", 720 | ] 721 | 722 | [[package]] 723 | name = "redox_syscall" 724 | version = "0.2.16" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 727 | dependencies = [ 728 | "bitflags", 729 | ] 730 | 731 | [[package]] 732 | name = "regex" 733 | version = "1.6.0" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" 736 | dependencies = [ 737 | "aho-corasick", 738 | "memchr", 739 | "regex-syntax", 740 | ] 741 | 742 | [[package]] 743 | name = "regex-syntax" 744 | version = "0.6.27" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" 747 | 748 | [[package]] 749 | name = "remove_dir_all" 750 | version = "0.5.3" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 753 | dependencies = [ 754 | "winapi", 755 | ] 756 | 757 | [[package]] 758 | name = "reqwest" 759 | version = "0.11.11" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" 762 | dependencies = [ 763 | "base64", 764 | "bytes", 765 | "encoding_rs", 766 | "futures-core", 767 | "futures-util", 768 | "h2", 769 | "http", 770 | "http-body", 771 | "hyper", 772 | "hyper-tls", 773 | "ipnet", 774 | "js-sys", 775 | "lazy_static", 776 | "log", 777 | "mime", 778 | "native-tls", 779 | "percent-encoding", 780 | "pin-project-lite", 781 | "serde", 782 | "serde_json", 783 | "serde_urlencoded", 784 | "tokio", 785 | "tokio-native-tls", 786 | "tower-service", 787 | "url", 788 | "wasm-bindgen", 789 | "wasm-bindgen-futures", 790 | "web-sys", 791 | "winreg", 792 | ] 793 | 794 | [[package]] 795 | name = "ryu" 796 | version = "1.0.11" 797 | source = "registry+https://github.com/rust-lang/crates.io-index" 798 | checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" 799 | 800 | [[package]] 801 | name = "schannel" 802 | version = "0.1.20" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" 805 | dependencies = [ 806 | "lazy_static", 807 | "windows-sys", 808 | ] 809 | 810 | [[package]] 811 | name = "scopeguard" 812 | version = "1.1.0" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 815 | 816 | [[package]] 817 | name = "security-framework" 818 | version = "2.6.1" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" 821 | dependencies = [ 822 | "bitflags", 823 | "core-foundation", 824 | "core-foundation-sys", 825 | "libc", 826 | "security-framework-sys", 827 | ] 828 | 829 | [[package]] 830 | name = "security-framework-sys" 831 | version = "2.6.1" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" 834 | dependencies = [ 835 | "core-foundation-sys", 836 | "libc", 837 | ] 838 | 839 | [[package]] 840 | name = "serde" 841 | version = "1.0.142" 842 | source = "registry+https://github.com/rust-lang/crates.io-index" 843 | checksum = "e590c437916fb6b221e1d00df6e3294f3fccd70ca7e92541c475d6ed6ef5fee2" 844 | dependencies = [ 845 | "serde_derive", 846 | ] 847 | 848 | [[package]] 849 | name = "serde_derive" 850 | version = "1.0.142" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "34b5b8d809babe02f538c2cfec6f2c1ed10804c0e5a6a041a049a4f5588ccc2e" 853 | dependencies = [ 854 | "proc-macro2", 855 | "quote", 856 | "syn", 857 | ] 858 | 859 | [[package]] 860 | name = "serde_json" 861 | version = "1.0.83" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" 864 | dependencies = [ 865 | "itoa", 866 | "ryu", 867 | "serde", 868 | ] 869 | 870 | [[package]] 871 | name = "serde_urlencoded" 872 | version = "0.7.1" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 875 | dependencies = [ 876 | "form_urlencoded", 877 | "itoa", 878 | "ryu", 879 | "serde", 880 | ] 881 | 882 | [[package]] 883 | name = "signal-hook-registry" 884 | version = "1.4.0" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 887 | dependencies = [ 888 | "libc", 889 | ] 890 | 891 | [[package]] 892 | name = "slab" 893 | version = "0.4.7" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" 896 | dependencies = [ 897 | "autocfg", 898 | ] 899 | 900 | [[package]] 901 | name = "smallvec" 902 | version = "1.9.0" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" 905 | 906 | [[package]] 907 | name = "socket2" 908 | version = "0.4.4" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" 911 | dependencies = [ 912 | "libc", 913 | "winapi", 914 | ] 915 | 916 | [[package]] 917 | name = "strsim" 918 | version = "0.10.0" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 921 | 922 | [[package]] 923 | name = "syn" 924 | version = "1.0.99" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" 927 | dependencies = [ 928 | "proc-macro2", 929 | "quote", 930 | "unicode-ident", 931 | ] 932 | 933 | [[package]] 934 | name = "tempfile" 935 | version = "3.3.0" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" 938 | dependencies = [ 939 | "cfg-if", 940 | "fastrand", 941 | "libc", 942 | "redox_syscall", 943 | "remove_dir_all", 944 | "winapi", 945 | ] 946 | 947 | [[package]] 948 | name = "term-table" 949 | version = "1.3.2" 950 | source = "registry+https://github.com/rust-lang/crates.io-index" 951 | checksum = "d5e59d7fb313157de2a568be8d81e4d7f9af6e50e697702e8e00190a6566d3b8" 952 | dependencies = [ 953 | "lazy_static", 954 | "regex", 955 | "unicode-width", 956 | ] 957 | 958 | [[package]] 959 | name = "term_size" 960 | version = "0.3.2" 961 | source = "registry+https://github.com/rust-lang/crates.io-index" 962 | checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9" 963 | dependencies = [ 964 | "libc", 965 | "winapi", 966 | ] 967 | 968 | [[package]] 969 | name = "termcolor" 970 | version = "1.1.3" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 973 | dependencies = [ 974 | "winapi-util", 975 | ] 976 | 977 | [[package]] 978 | name = "textwrap" 979 | version = "0.15.0" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" 982 | 983 | [[package]] 984 | name = "time" 985 | version = "0.1.44" 986 | source = "registry+https://github.com/rust-lang/crates.io-index" 987 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 988 | dependencies = [ 989 | "libc", 990 | "wasi 0.10.0+wasi-snapshot-preview1", 991 | "winapi", 992 | ] 993 | 994 | [[package]] 995 | name = "tinyvec" 996 | version = "1.6.0" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 999 | dependencies = [ 1000 | "tinyvec_macros", 1001 | ] 1002 | 1003 | [[package]] 1004 | name = "tinyvec_macros" 1005 | version = "0.1.0" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1008 | 1009 | [[package]] 1010 | name = "tokio" 1011 | version = "1.20.4" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "eb78f30e4b41e98ca4cce5acb51168a033839a7af9e42b380355808e14e98ee0" 1014 | dependencies = [ 1015 | "autocfg", 1016 | "bytes", 1017 | "libc", 1018 | "memchr", 1019 | "mio", 1020 | "num_cpus", 1021 | "parking_lot", 1022 | "pin-project-lite", 1023 | "signal-hook-registry", 1024 | "socket2", 1025 | "tokio-macros", 1026 | "winapi", 1027 | ] 1028 | 1029 | [[package]] 1030 | name = "tokio-macros" 1031 | version = "1.8.0" 1032 | source = "registry+https://github.com/rust-lang/crates.io-index" 1033 | checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" 1034 | dependencies = [ 1035 | "proc-macro2", 1036 | "quote", 1037 | "syn", 1038 | ] 1039 | 1040 | [[package]] 1041 | name = "tokio-native-tls" 1042 | version = "0.3.0" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" 1045 | dependencies = [ 1046 | "native-tls", 1047 | "tokio", 1048 | ] 1049 | 1050 | [[package]] 1051 | name = "tokio-util" 1052 | version = "0.7.3" 1053 | source = "registry+https://github.com/rust-lang/crates.io-index" 1054 | checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" 1055 | dependencies = [ 1056 | "bytes", 1057 | "futures-core", 1058 | "futures-sink", 1059 | "pin-project-lite", 1060 | "tokio", 1061 | "tracing", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "tower-service" 1066 | version = "0.3.2" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1069 | 1070 | [[package]] 1071 | name = "tracing" 1072 | version = "0.1.36" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" 1075 | dependencies = [ 1076 | "cfg-if", 1077 | "pin-project-lite", 1078 | "tracing-core", 1079 | ] 1080 | 1081 | [[package]] 1082 | name = "tracing-core" 1083 | version = "0.1.29" 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" 1085 | checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" 1086 | dependencies = [ 1087 | "once_cell", 1088 | ] 1089 | 1090 | [[package]] 1091 | name = "try-lock" 1092 | version = "0.2.3" 1093 | source = "registry+https://github.com/rust-lang/crates.io-index" 1094 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1095 | 1096 | [[package]] 1097 | name = "unicode-bidi" 1098 | version = "0.3.8" 1099 | source = "registry+https://github.com/rust-lang/crates.io-index" 1100 | checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" 1101 | 1102 | [[package]] 1103 | name = "unicode-ident" 1104 | version = "1.0.3" 1105 | source = "registry+https://github.com/rust-lang/crates.io-index" 1106 | checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" 1107 | 1108 | [[package]] 1109 | name = "unicode-normalization" 1110 | version = "0.1.21" 1111 | source = "registry+https://github.com/rust-lang/crates.io-index" 1112 | checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" 1113 | dependencies = [ 1114 | "tinyvec", 1115 | ] 1116 | 1117 | [[package]] 1118 | name = "unicode-width" 1119 | version = "0.1.9" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 1122 | 1123 | [[package]] 1124 | name = "url" 1125 | version = "2.2.2" 1126 | source = "registry+https://github.com/rust-lang/crates.io-index" 1127 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 1128 | dependencies = [ 1129 | "form_urlencoded", 1130 | "idna", 1131 | "matches", 1132 | "percent-encoding", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "vcpkg" 1137 | version = "0.2.15" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1140 | 1141 | [[package]] 1142 | name = "version_check" 1143 | version = "0.9.4" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1146 | 1147 | [[package]] 1148 | name = "want" 1149 | version = "0.3.0" 1150 | source = "registry+https://github.com/rust-lang/crates.io-index" 1151 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1152 | dependencies = [ 1153 | "log", 1154 | "try-lock", 1155 | ] 1156 | 1157 | [[package]] 1158 | name = "wasi" 1159 | version = "0.10.0+wasi-snapshot-preview1" 1160 | source = "registry+https://github.com/rust-lang/crates.io-index" 1161 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 1162 | 1163 | [[package]] 1164 | name = "wasi" 1165 | version = "0.11.0+wasi-snapshot-preview1" 1166 | source = "registry+https://github.com/rust-lang/crates.io-index" 1167 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1168 | 1169 | [[package]] 1170 | name = "wasm-bindgen" 1171 | version = "0.2.82" 1172 | source = "registry+https://github.com/rust-lang/crates.io-index" 1173 | checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" 1174 | dependencies = [ 1175 | "cfg-if", 1176 | "wasm-bindgen-macro", 1177 | ] 1178 | 1179 | [[package]] 1180 | name = "wasm-bindgen-backend" 1181 | version = "0.2.82" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" 1184 | dependencies = [ 1185 | "bumpalo", 1186 | "log", 1187 | "once_cell", 1188 | "proc-macro2", 1189 | "quote", 1190 | "syn", 1191 | "wasm-bindgen-shared", 1192 | ] 1193 | 1194 | [[package]] 1195 | name = "wasm-bindgen-futures" 1196 | version = "0.4.32" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad" 1199 | dependencies = [ 1200 | "cfg-if", 1201 | "js-sys", 1202 | "wasm-bindgen", 1203 | "web-sys", 1204 | ] 1205 | 1206 | [[package]] 1207 | name = "wasm-bindgen-macro" 1208 | version = "0.2.82" 1209 | source = "registry+https://github.com/rust-lang/crates.io-index" 1210 | checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" 1211 | dependencies = [ 1212 | "quote", 1213 | "wasm-bindgen-macro-support", 1214 | ] 1215 | 1216 | [[package]] 1217 | name = "wasm-bindgen-macro-support" 1218 | version = "0.2.82" 1219 | source = "registry+https://github.com/rust-lang/crates.io-index" 1220 | checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" 1221 | dependencies = [ 1222 | "proc-macro2", 1223 | "quote", 1224 | "syn", 1225 | "wasm-bindgen-backend", 1226 | "wasm-bindgen-shared", 1227 | ] 1228 | 1229 | [[package]] 1230 | name = "wasm-bindgen-shared" 1231 | version = "0.2.82" 1232 | source = "registry+https://github.com/rust-lang/crates.io-index" 1233 | checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" 1234 | 1235 | [[package]] 1236 | name = "web-sys" 1237 | version = "0.3.59" 1238 | source = "registry+https://github.com/rust-lang/crates.io-index" 1239 | checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" 1240 | dependencies = [ 1241 | "js-sys", 1242 | "wasm-bindgen", 1243 | ] 1244 | 1245 | [[package]] 1246 | name = "winapi" 1247 | version = "0.3.9" 1248 | source = "registry+https://github.com/rust-lang/crates.io-index" 1249 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1250 | dependencies = [ 1251 | "winapi-i686-pc-windows-gnu", 1252 | "winapi-x86_64-pc-windows-gnu", 1253 | ] 1254 | 1255 | [[package]] 1256 | name = "winapi-i686-pc-windows-gnu" 1257 | version = "0.4.0" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1260 | 1261 | [[package]] 1262 | name = "winapi-util" 1263 | version = "0.1.5" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1266 | dependencies = [ 1267 | "winapi", 1268 | ] 1269 | 1270 | [[package]] 1271 | name = "winapi-x86_64-pc-windows-gnu" 1272 | version = "0.4.0" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1275 | 1276 | [[package]] 1277 | name = "windows-sys" 1278 | version = "0.36.1" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" 1281 | dependencies = [ 1282 | "windows_aarch64_msvc", 1283 | "windows_i686_gnu", 1284 | "windows_i686_msvc", 1285 | "windows_x86_64_gnu", 1286 | "windows_x86_64_msvc", 1287 | ] 1288 | 1289 | [[package]] 1290 | name = "windows_aarch64_msvc" 1291 | version = "0.36.1" 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" 1293 | checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" 1294 | 1295 | [[package]] 1296 | name = "windows_i686_gnu" 1297 | version = "0.36.1" 1298 | source = "registry+https://github.com/rust-lang/crates.io-index" 1299 | checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" 1300 | 1301 | [[package]] 1302 | name = "windows_i686_msvc" 1303 | version = "0.36.1" 1304 | source = "registry+https://github.com/rust-lang/crates.io-index" 1305 | checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" 1306 | 1307 | [[package]] 1308 | name = "windows_x86_64_gnu" 1309 | version = "0.36.1" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" 1312 | 1313 | [[package]] 1314 | name = "windows_x86_64_msvc" 1315 | version = "0.36.1" 1316 | source = "registry+https://github.com/rust-lang/crates.io-index" 1317 | checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" 1318 | 1319 | [[package]] 1320 | name = "winreg" 1321 | version = "0.10.1" 1322 | source = "registry+https://github.com/rust-lang/crates.io-index" 1323 | checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" 1324 | dependencies = [ 1325 | "winapi", 1326 | ] 1327 | --------------------------------------------------------------------------------