├── res ├── images │ ├── error-1.png │ ├── error-2.png │ ├── error-3.png │ ├── update.png │ ├── set-fuzzy.png │ ├── adding-notes.png │ ├── delete-pin.png │ ├── popular-tags.png │ ├── url_vs_tag.png │ ├── already-saved.png │ ├── authentication.png │ ├── configuration.png │ ├── fuzzy-search-tags.png │ ├── quicklook-preview.png │ ├── upgrade_available.png │ ├── workflow-screenshot.png │ ├── non-fuzzy-search-tags.png │ └── bookmarks-search-results.png ├── workflow │ ├── fuzzy.png │ ├── icon.png │ ├── pin_1.png │ ├── tag.png │ ├── url.png │ ├── config.png │ ├── delete.png │ ├── locked.png │ ├── private.png │ ├── search.png │ ├── suggest.png │ ├── tagonly.png │ ├── toread.png │ ├── unfuzzy.png │ ├── upload.png │ ├── bookmarks.png │ ├── erroricon.icns │ ├── no_of_pins.png │ ├── no_of_tags.png │ ├── no_result.png │ ├── no_suggest.png │ ├── qutebrowser-info.sh │ ├── tag_rename.png │ ├── unlocked.png │ ├── authenticate.png │ ├── auto_update.png │ ├── bookmarks-2.png │ ├── bookmarks-3.png │ ├── check_update.png │ ├── cloud_update.png │ ├── pinboard-pin.png │ ├── bookmark-delete.png │ ├── no_auto_update.png │ ├── pinboard-pin.icns │ ├── auto_update_cache.png │ ├── check_bookmarked_page.png │ ├── no_check_bookmarked_page.png │ ├── 00892451-3E5D-421F-B3ED-367DD1560720.png │ ├── 03AF5169-B606-486F-B432-98CF6E2BB0F2.png │ ├── 2DFDAFE5-6A0E-4E95-A1C5-30789A06C27C.png │ ├── 3A8F63FC-42D6-4F71-9822-5442E212FAC9.png │ ├── 3CFEFF60-C0B3-44A0-8761-FB5AA2F96547.png │ ├── 46667F34-E27E-4FBA-83B5-4A55C6FA2FD6.png │ ├── 5BBD268D-C102-4516-86B3-7A1DA7AE6AD8.png │ ├── 5D065041-109B-41B0-ADE0-62CA836178E5.png │ ├── 5F6E4E5A-1035-498B-A2CF-B7E3ACB85009.png │ ├── 69D5C481-E826-498C-A9CC-549AE2815D10.png │ ├── 78C8A61E-FD70-4CD9-BEC8-66A30106E128.png │ ├── 7A213534-8342-46AB-A4EA-4CCF95685833.png │ ├── 8CD4D7F7-49EA-44FF-878E-18B836627810.png │ ├── 8FBE3EBB-9672-493C-977C-95B832412F2E.png │ ├── 93A64ECE-BB64-492B-B845-7CB85B544D40.png │ ├── A1AB9903-87A7-4041-8EB9-F9E9C06C451B.png │ ├── A8EE818C-427B-476F-93FD-02825231464B.png │ ├── BD868971-C272-43FC-B20B-1C5471C1EBC1.png │ ├── C655280A-EE5C-4DA4-9A45-C40695E06751.png │ ├── D5939049-C73A-4872-9625-87A9F9BE886C.png │ ├── F495558F-7866-454F-B070-80417D1419B6.png │ ├── F5143EEF-D67B-4518-A5BA-1DFFD993A314.png │ ├── identify-browser.applescript │ ├── get-current-url.applescript.bak │ └── get-current-url.applescript └── fix_cargo_version.py ├── .gitignore ├── .circleci ├── json_pretty.sh ├── deploy.sh ├── script.sh ├── before_deploy.sh └── config.yml ├── ci ├── before_deploy.ps1 ├── install.sh ├── before_deploy.sh └── script.sh ├── Cargo.toml ├── LICENSE.md ├── src ├── commands │ ├── rename.rs │ ├── upgrade.rs │ ├── update.rs │ ├── browser_info.rs │ ├── post.rs │ ├── mod.rs │ ├── delete.rs │ ├── config.rs │ ├── search.rs │ └── list.rs ├── cli.rs ├── workflow_config.rs └── main.rs ├── create_alfred_workflow.sh ├── appveyor.yml ├── CHANGELOG.md ├── disable-travis ├── README.md └── Cargo.lock /res/images/error-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/error-1.png -------------------------------------------------------------------------------- /res/images/error-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/error-2.png -------------------------------------------------------------------------------- /res/images/error-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/error-3.png -------------------------------------------------------------------------------- /res/images/update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/update.png -------------------------------------------------------------------------------- /res/workflow/fuzzy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/fuzzy.png -------------------------------------------------------------------------------- /res/workflow/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/icon.png -------------------------------------------------------------------------------- /res/workflow/pin_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/pin_1.png -------------------------------------------------------------------------------- /res/workflow/tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/tag.png -------------------------------------------------------------------------------- /res/workflow/url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/url.png -------------------------------------------------------------------------------- /res/images/set-fuzzy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/set-fuzzy.png -------------------------------------------------------------------------------- /res/workflow/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/config.png -------------------------------------------------------------------------------- /res/workflow/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/delete.png -------------------------------------------------------------------------------- /res/workflow/locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/locked.png -------------------------------------------------------------------------------- /res/workflow/private.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/private.png -------------------------------------------------------------------------------- /res/workflow/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/search.png -------------------------------------------------------------------------------- /res/workflow/suggest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/suggest.png -------------------------------------------------------------------------------- /res/workflow/tagonly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/tagonly.png -------------------------------------------------------------------------------- /res/workflow/toread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/toread.png -------------------------------------------------------------------------------- /res/workflow/unfuzzy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/unfuzzy.png -------------------------------------------------------------------------------- /res/workflow/upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/upload.png -------------------------------------------------------------------------------- /res/images/adding-notes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/adding-notes.png -------------------------------------------------------------------------------- /res/images/delete-pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/delete-pin.png -------------------------------------------------------------------------------- /res/images/popular-tags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/popular-tags.png -------------------------------------------------------------------------------- /res/images/url_vs_tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/url_vs_tag.png -------------------------------------------------------------------------------- /res/workflow/bookmarks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/bookmarks.png -------------------------------------------------------------------------------- /res/workflow/erroricon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/erroricon.icns -------------------------------------------------------------------------------- /res/workflow/no_of_pins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/no_of_pins.png -------------------------------------------------------------------------------- /res/workflow/no_of_tags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/no_of_tags.png -------------------------------------------------------------------------------- /res/workflow/no_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/no_result.png -------------------------------------------------------------------------------- /res/workflow/no_suggest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/no_suggest.png -------------------------------------------------------------------------------- /res/workflow/qutebrowser-info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | printf "%s\n%s" "$QUTE_URL" "$QUTE_TITLE" | pbcopy 4 | 5 | -------------------------------------------------------------------------------- /res/workflow/tag_rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/tag_rename.png -------------------------------------------------------------------------------- /res/workflow/unlocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/unlocked.png -------------------------------------------------------------------------------- /res/images/already-saved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/already-saved.png -------------------------------------------------------------------------------- /res/images/authentication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/authentication.png -------------------------------------------------------------------------------- /res/images/configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/configuration.png -------------------------------------------------------------------------------- /res/workflow/authenticate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/authenticate.png -------------------------------------------------------------------------------- /res/workflow/auto_update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/auto_update.png -------------------------------------------------------------------------------- /res/workflow/bookmarks-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/bookmarks-2.png -------------------------------------------------------------------------------- /res/workflow/bookmarks-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/bookmarks-3.png -------------------------------------------------------------------------------- /res/workflow/check_update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/check_update.png -------------------------------------------------------------------------------- /res/workflow/cloud_update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/cloud_update.png -------------------------------------------------------------------------------- /res/workflow/pinboard-pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/pinboard-pin.png -------------------------------------------------------------------------------- /res/images/fuzzy-search-tags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/fuzzy-search-tags.png -------------------------------------------------------------------------------- /res/images/quicklook-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/quicklook-preview.png -------------------------------------------------------------------------------- /res/images/upgrade_available.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/upgrade_available.png -------------------------------------------------------------------------------- /res/workflow/bookmark-delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/bookmark-delete.png -------------------------------------------------------------------------------- /res/workflow/no_auto_update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/no_auto_update.png -------------------------------------------------------------------------------- /res/workflow/pinboard-pin.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/pinboard-pin.icns -------------------------------------------------------------------------------- /res/images/workflow-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/workflow-screenshot.png -------------------------------------------------------------------------------- /res/workflow/auto_update_cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/auto_update_cache.png -------------------------------------------------------------------------------- /res/images/non-fuzzy-search-tags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/non-fuzzy-search-tags.png -------------------------------------------------------------------------------- /res/images/bookmarks-search-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/images/bookmarks-search-results.png -------------------------------------------------------------------------------- /res/workflow/check_bookmarked_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/check_bookmarked_page.png -------------------------------------------------------------------------------- /res/workflow/no_check_bookmarked_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/no_check_bookmarked_page.png -------------------------------------------------------------------------------- /res/workflow/00892451-3E5D-421F-B3ED-367DD1560720.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/00892451-3E5D-421F-B3ED-367DD1560720.png -------------------------------------------------------------------------------- /res/workflow/03AF5169-B606-486F-B432-98CF6E2BB0F2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/03AF5169-B606-486F-B432-98CF6E2BB0F2.png -------------------------------------------------------------------------------- /res/workflow/2DFDAFE5-6A0E-4E95-A1C5-30789A06C27C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/2DFDAFE5-6A0E-4E95-A1C5-30789A06C27C.png -------------------------------------------------------------------------------- /res/workflow/3A8F63FC-42D6-4F71-9822-5442E212FAC9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/3A8F63FC-42D6-4F71-9822-5442E212FAC9.png -------------------------------------------------------------------------------- /res/workflow/3CFEFF60-C0B3-44A0-8761-FB5AA2F96547.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/3CFEFF60-C0B3-44A0-8761-FB5AA2F96547.png -------------------------------------------------------------------------------- /res/workflow/46667F34-E27E-4FBA-83B5-4A55C6FA2FD6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/46667F34-E27E-4FBA-83B5-4A55C6FA2FD6.png -------------------------------------------------------------------------------- /res/workflow/5BBD268D-C102-4516-86B3-7A1DA7AE6AD8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/5BBD268D-C102-4516-86B3-7A1DA7AE6AD8.png -------------------------------------------------------------------------------- /res/workflow/5D065041-109B-41B0-ADE0-62CA836178E5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/5D065041-109B-41B0-ADE0-62CA836178E5.png -------------------------------------------------------------------------------- /res/workflow/5F6E4E5A-1035-498B-A2CF-B7E3ACB85009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/5F6E4E5A-1035-498B-A2CF-B7E3ACB85009.png -------------------------------------------------------------------------------- /res/workflow/69D5C481-E826-498C-A9CC-549AE2815D10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/69D5C481-E826-498C-A9CC-549AE2815D10.png -------------------------------------------------------------------------------- /res/workflow/78C8A61E-FD70-4CD9-BEC8-66A30106E128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/78C8A61E-FD70-4CD9-BEC8-66A30106E128.png -------------------------------------------------------------------------------- /res/workflow/7A213534-8342-46AB-A4EA-4CCF95685833.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/7A213534-8342-46AB-A4EA-4CCF95685833.png -------------------------------------------------------------------------------- /res/workflow/8CD4D7F7-49EA-44FF-878E-18B836627810.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/8CD4D7F7-49EA-44FF-878E-18B836627810.png -------------------------------------------------------------------------------- /res/workflow/8FBE3EBB-9672-493C-977C-95B832412F2E.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/8FBE3EBB-9672-493C-977C-95B832412F2E.png -------------------------------------------------------------------------------- /res/workflow/93A64ECE-BB64-492B-B845-7CB85B544D40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/93A64ECE-BB64-492B-B845-7CB85B544D40.png -------------------------------------------------------------------------------- /res/workflow/A1AB9903-87A7-4041-8EB9-F9E9C06C451B.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/A1AB9903-87A7-4041-8EB9-F9E9C06C451B.png -------------------------------------------------------------------------------- /res/workflow/A8EE818C-427B-476F-93FD-02825231464B.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/A8EE818C-427B-476F-93FD-02825231464B.png -------------------------------------------------------------------------------- /res/workflow/BD868971-C272-43FC-B20B-1C5471C1EBC1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/BD868971-C272-43FC-B20B-1C5471C1EBC1.png -------------------------------------------------------------------------------- /res/workflow/C655280A-EE5C-4DA4-9A45-C40695E06751.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/C655280A-EE5C-4DA4-9A45-C40695E06751.png -------------------------------------------------------------------------------- /res/workflow/D5939049-C73A-4872-9625-87A9F9BE886C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/D5939049-C73A-4872-9625-87A9F9BE886C.png -------------------------------------------------------------------------------- /res/workflow/F495558F-7866-454F-B070-80417D1419B6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/F495558F-7866-454F-B070-80417D1419B6.png -------------------------------------------------------------------------------- /res/workflow/F5143EEF-D67B-4518-A5BA-1DFFD993A314.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs/alfred-pinboard-rs/master/res/workflow/F5143EEF-D67B-4518-A5BA-1DFFD993A314.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | cmake-build-debug 4 | CMakeLists.txt 5 | auth_token.txt 6 | .rustfmt.toml 7 | build.log 8 | AlfredPinboardRust.alfredworkflow 9 | Cargo.toml.back 10 | -------------------------------------------------------------------------------- /.circleci/json_pretty.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | grep -Eo '"[^"]*" *(: *([0-9]*|"[^"]*")[^{}\["]*|,)?|[^"\]\[\}\{]*|\{|\},?|\[|\],?|[0-9 ]*,?' | awk '{if ($0 ~ /^[}\]]/ ) offset-=4; printf "%*c%s\n", offset, " ", $0; if ($0 ~ /^[{\[]/) offset+=4}' 4 | -------------------------------------------------------------------------------- /res/fix_cargo_version.py: -------------------------------------------------------------------------------- 1 | import toml 2 | import sys 3 | 4 | c = toml.load("Cargo.toml") 5 | c['package']['version'] = sys.argv[1] 6 | c['profile'] = {'release': {'lto': True}} 7 | 8 | f = open("Cargo.toml", "w") 9 | _ = toml.dump(c, f) 10 | -------------------------------------------------------------------------------- /ci/before_deploy.ps1: -------------------------------------------------------------------------------- 1 | # This script takes care of packaging the build artifacts that will go in the 2 | # release zipfile 3 | 4 | $SRC_DIR = $PWD.Path 5 | $STAGE = [System.Guid]::NewGuid().ToString() 6 | 7 | Set-Location $ENV:Temp 8 | New-Item -Type Directory -Name $STAGE 9 | Set-Location $STAGE 10 | 11 | $ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip" 12 | 13 | # TODO Update this to package the right artifacts 14 | Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\hello.exe" '.\' 15 | 16 | 7z a "$ZIP" * 17 | 18 | Push-AppveyorArtifact "$ZIP" 19 | 20 | Remove-Item *.* -Force 21 | Set-Location .. 22 | Remove-Item $STAGE 23 | Set-Location $SRC_DIR 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "alfred-pinboard-rs" 3 | version = "0.15.12" 4 | authors = [ "Hamid Ghadyani ",] 5 | 6 | [dependencies] 7 | alfred = "4.0.1" 8 | serde = "1.0" 9 | serde_derive = "1.0" 10 | serde_json = "1.0" 11 | structopt = "0.3.12" 12 | semver = "0.9" 13 | failure = "0.1.5" 14 | dirs = "2.0" 15 | if_chain = "1.0.0" 16 | log = "0.4" 17 | env_logger = "0.7" 18 | 19 | [features] 20 | 21 | [dependencies.alfred-rs] 22 | version = "0.5" 23 | 24 | [dependencies.rusty-pin] 25 | git = "https://github.com/spamwax/rusty-pin" 26 | branch = "master" 27 | 28 | [dependencies.chrono] 29 | version = "0.4" 30 | features = [ "serde",] 31 | 32 | [profile.release] 33 | lto = true 34 | 35 | [package.metadata.docs.rs] 36 | targets = [ "x86_64-apple-ios", "x86_64-apple-darwin",] 37 | -------------------------------------------------------------------------------- /res/workflow/identify-browser.applescript: -------------------------------------------------------------------------------- 1 | on appIsRunning(appName) 2 | tell application "System Events" to (name of processes) contains appName 3 | end appIsRunning 4 | 5 | 6 | on run 7 | delay 2 8 | set theApplication to (name of (info for (path to frontmost application))) 9 | set supportedBrowser to true 10 | 11 | if theApplication is "qutebrowser.app" and appIsRunning("qutebrowser") then 12 | set supportedBrowser to false 13 | 14 | else if theApplication is "Firefox.app" and appIsRunning("Firefox") then 15 | set supportedBrowser to false 16 | 17 | else if {"Firefox Developer Edition.app", "FirefoxDeveloperEdition.app"} contains theApplication and appIsRunning("Firefox") then 18 | set supportedBrowser to false 19 | 20 | end if 21 | 22 | return supportedBrowser 23 | 24 | end run 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ### MIT License 2 | 3 | - Copyright (c) 2018 *Hamid R. Ghadyani* 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 | -------------------------------------------------------------------------------- /.circleci/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script takes care of building your crate and packaging it for release 3 | set -ex 4 | 5 | deploy() { 6 | prev_dir=$(pwd) 7 | cd /tmp 8 | curl -L -O https://github.com/tcnksm/ghr/releases/download/"$GHRELEASER_VERSION"/ghr_"$GHRELEASER_VERSION"_darwin_amd64.zip 9 | unzip ghr_"$GHRELEASER_VERSION"_darwin_amd64.zip 10 | ghr_exe=$(pwd)/ghr_"$GHRELEASER_VERSION"_darwin_amd64/ghr 11 | cd "$prev_dir" 12 | [ -f ./target/alfred-pinboard-rust-${CIRCLE_TAG}.alfredworkflow ] 13 | export artifacts=./target/alfred-pinboard-rust-${CIRCLE_TAG}.alfredworkflow 14 | echo ${CIRCLE_PROJECT_USERNAME} ${CIRCLE_PROJECT_REPONAME} ${CIRCLE_SHA1} ${CIRCLE_TAG} ${artifacts} 15 | "$ghr_exe" -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${CIRCLE_TAG} ${artifacts} 16 | } 17 | 18 | if [ -n "$CIRCLE_TEST" ]; then 19 | echo "CIRCLE_TEST is set, exitting" 20 | fi 21 | if [ -z "$CIRCLE_TAG" ]; then 22 | echo "Not a tagged commit, exitting." 23 | exit 1 24 | elif [ -z "$GITHUB_TOKEN" ]; then 25 | echo "Github access token not set, exitting." 26 | fi 27 | 28 | if [ -z "$GHRELEASER_VERSION" ]; then 29 | echo "ghr version was not set using v0.13.0" 30 | export GHRELEASER_VERSION="v0.13.0" 31 | fi 32 | 33 | deploy 34 | -------------------------------------------------------------------------------- /src/commands/rename.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use std::io::Write; 3 | 4 | impl<'api, 'pin> Runner<'api, 'pin> { 5 | pub fn rename(&mut self, cmd: &SubCommand) { 6 | match cmd { 7 | SubCommand::Rename { tags } => self.run(tags), 8 | _ => unreachable!(), 9 | } 10 | } 11 | 12 | // fn run(&mut self, tags: &Vec) { 13 | fn run(&mut self, tags: &[String]) { 14 | debug!("running rename::run"); 15 | debug!(" tags: {:?}", tags); 16 | if tags.len() != 2 || tags.iter().any(|tag| tag.is_empty()) { 17 | crate::show_error_alfred("Enter 2 tags please!"); 18 | } 19 | 20 | debug!(" calling rename API"); 21 | let r = self 22 | .pinboard 23 | .as_ref() 24 | .unwrap() 25 | .rename_tag(&tags[0], &tags[1]); 26 | debug!(" matching result: {:?}", &r); 27 | match r { 28 | Err(e) => { 29 | io::stdout() 30 | .write(format!("Error: {}", e).as_ref()) 31 | .expect("Couldn't write to stdout"); 32 | process::exit(1); 33 | } 34 | Ok(_) => { 35 | io::stdout() 36 | .write(b"Successfully renamed tag.") 37 | .expect("Couldn't write to stdout"); 38 | if self.config.as_ref().unwrap().auto_update_cache { 39 | self.update_cache(); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ci/install.sh: -------------------------------------------------------------------------------- 1 | set -ex 2 | 3 | main() { 4 | local target= 5 | if [ $TRAVIS_OS_NAME = linux ]; then 6 | target=x86_64-unknown-linux-musl 7 | sort=sort 8 | else 9 | target=x86_64-apple-darwin 10 | sort=gsort # for `sort --sort-version`, from brew's coreutils. 11 | fi 12 | 13 | # Builds for iOS are done on OSX, but require the specific target to be 14 | # installed. 15 | case $TARGET in 16 | aarch64-apple-ios) 17 | rustup target install aarch64-apple-ios 18 | ;; 19 | armv7-apple-ios) 20 | rustup target install armv7-apple-ios 21 | ;; 22 | armv7s-apple-ios) 23 | rustup target install armv7s-apple-ios 24 | ;; 25 | i386-apple-ios) 26 | rustup target install i386-apple-ios 27 | ;; 28 | x86_64-apple-ios) 29 | rustup target install x86_64-apple-ios 30 | ;; 31 | esac 32 | 33 | # This fetches latest stable release 34 | local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \ 35 | | cut -d/ -f3 \ 36 | | grep -E '^v[0.1.0-9.]+$' \ 37 | | $sort --version-sort \ 38 | | tail -n1) 39 | curl -LSfs https://japaric.github.io/trust/install.sh | \ 40 | sh -s -- \ 41 | --force \ 42 | --git japaric/cross \ 43 | --tag $tag \ 44 | --target $target 45 | } 46 | 47 | main 48 | -------------------------------------------------------------------------------- /src/commands/upgrade.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use std::io::Write; 3 | 4 | impl<'api, 'pin> Runner<'api, 'pin> { 5 | pub fn upgrade(&self, cmd: &SubCommand) { 6 | debug!("Starting in upgrade"); 7 | match *cmd { 8 | SubCommand::SelfUpdate { check, download } => { 9 | if check && download { 10 | eprintln!("Cannont check & download at the same time!"); 11 | process::exit(1); 12 | } 13 | let json_format = self.config.as_ref().unwrap().can_use_json(); 14 | if check { 15 | let none: Option> = None; 16 | if let Ok(item) = self.get_upgrade_item() { 17 | crate::write_to_alfred(vec![item], json_format, none); 18 | } else { 19 | let item = 20 | alfred::ItemBuilder::new("Error in getting upgrade info!").into_item(); 21 | crate::write_to_alfred(vec![item], json_format, none); 22 | } 23 | } else if download { 24 | let filename = self.updater.as_ref().unwrap().download_latest(); 25 | if let Ok(filename) = filename { 26 | if let Some(p) = filename.to_str() { 27 | let _ = io::stdout() 28 | .write(format!("Download successful: {}", p).as_bytes()); 29 | } else { 30 | let _ = io::stdout().write(b"Download OK, issue with its file name!"); 31 | } 32 | } else { 33 | let _ = 34 | io::stdout().write(b"Error: Couldn't download the latest workflow."); 35 | process::exit(1); 36 | } 37 | } 38 | } 39 | _ => unreachable!(), 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /create_alfred_workflow.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # set -x 4 | version_tag=$1 5 | msg=$2 6 | push_it=$3 7 | 8 | if [ -z "$version_tag" ]; then 9 | echo "You need to provide a semver tag: v0.9.10" 10 | exit 11 | fi 12 | 13 | alfred_pinboard_rs="/Volumes/Home/hamid/src/learn/rust/alfred-pinboard-rs" 14 | workflow_dir="$HOME/Dropbox/Alfred/Alfred.alfredpreferences/workflows/user.workflow.BE0BAA6E-408E-40A0-AEF2-922BFAA8BBF0" 15 | res_dir="$alfred_pinboard_rs/res/workflow" 16 | 17 | git checkout master || exit 18 | 19 | echo "Building new release..." 20 | cd "$alfred_pinboard_rs" || exit 21 | 22 | # Bump Cargo.toml version 23 | python res/fix_cargo_version.py "$version_tag" 24 | cargo build --release > build.log 2>&1 25 | 26 | echo "Copying resoursces from Alfred's workflow dir..." 27 | cp "$workflow_dir"/* "$res_dir" 28 | 29 | echo "Copying executable to workflow's folder..." 30 | strip target/release/alfred-pinboard-rs 31 | cp target/release/alfred-pinboard-rs "$res_dir" 32 | 33 | echo "Updating version in info.plist" 34 | # version_tag=$(git describe --tags --abbrev=0) 35 | defaults write "$res_dir"/info.plist version "$version_tag" 36 | plutil -convert xml1 "$res_dir"/info.plist 37 | cp "$res_dir"/info.plist "$workflow_dir" 38 | 39 | echo "Creating the workflow bundle..." 40 | rm -f AlfredPinboardRust.alfredworkflow 41 | cd "$res_dir" || exit 42 | rm -f AlfredPinboardRust.alfredworkflow 43 | 44 | zip -r AlfredPinboardRust.alfredworkflow ./* 45 | 46 | echo "Moving bundle to executable folder..." 47 | mv AlfredPinboardRust.alfredworkflow "$alfred_pinboard_rs" 48 | rm alfred-pinboard-rs 49 | 50 | cd "$alfred_pinboard_rs" || exit 51 | git add .circleci 52 | git add res/workflow 53 | git add res/images 54 | git add Cargo.toml 55 | git add Cargo.lock 56 | git add CHANGELOG.md 57 | git add README.md 58 | git add create_alfred_workflow.sh 59 | git add src 60 | 61 | commit_msg="Release version $version_tag" 62 | [ -n "$msg" ] && commit_msg="$commit_msg 63 | 64 | $msg" 65 | git pull origin master 66 | git commit -a -m "$commit_msg" 67 | git tag "$version_tag" 68 | 69 | if [ -n "$push_it" ]; then 70 | git push --tags 71 | sleep 5 72 | git push 73 | fi 74 | -------------------------------------------------------------------------------- /ci/before_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/bash 2 | # This script takes care of building your crate and packaging it for release 3 | 4 | set -ex 5 | 6 | main() { 7 | local src=$(pwd) \ 8 | stage= 9 | 10 | case $TRAVIS_OS_NAME in 11 | linux) 12 | stage=$(mktemp -d) 13 | ;; 14 | osx) 15 | stage=$(mktemp -d -t tmp) 16 | ;; 17 | esac 18 | 19 | # only build for macOS 20 | case $TARGET in 21 | x86_64-apple-darwin) 22 | build_release "$src" "$stage" 23 | ;; 24 | # i686-apple-darwin) 25 | # build_release "$src" "$stage" 26 | # ;; 27 | *) 28 | return 29 | ;; 30 | esac 31 | 32 | } 33 | 34 | build_release() { 35 | src=$1 36 | stage=$2 37 | test -f Cargo.lock || cargo generate-lockfile 38 | 39 | # TODO Update this to build the artifacts that matter to you 40 | # cross rustc --bin alfred-pinboard-rs --target "$TARGET" --release -- -C lto 41 | 42 | # TODO Update this to package the right artifacts 43 | res_dir="$src/res/workflow" 44 | 45 | # echo "Copying executable to workflow's folder..." 46 | cp "$src/target/$TARGET/release/alfred-pinboard-rs" "$stage" 47 | cp "$res_dir"/* "$stage" 48 | 49 | # echo "Creating the workflow bundle..." 50 | cd "$stage" || exit 51 | strip ./alfred-pinboard-rs || true 52 | rm -f AlfredPinboardRust.alfredworkflow 53 | 54 | zip -r AlfredPinboardRust.alfredworkflow ./* 55 | 56 | case $TARGET in 57 | x86_64-apple-darwin) 58 | cp ./AlfredPinboardRust.alfredworkflow "$src/target/alfred-pinboard-rust-$TRAVIS_TAG.alfredworkflow" 59 | ;; 60 | i686-apple-darwin) 61 | tar czf "$src/$TARGET-$CRATE_NAME-$TRAVIS_TAG.tar.gz" ./AlfredPinboardRust.alfredworkflow 62 | ;; 63 | *) 64 | return 65 | ;; 66 | esac 67 | cd "$src" 68 | 69 | rm -rf "$stage" 70 | 71 | } 72 | 73 | if [ -z "$TRAVIS_TAG" ]; then 74 | echo "Not a tagged commit. Exitting" 75 | exit 1 76 | else 77 | echo "This is a tagged commit, running before_deploy" 78 | fi 79 | 80 | main 81 | -------------------------------------------------------------------------------- /.circleci/script.sh: -------------------------------------------------------------------------------- 1 | # This script takes care of testing your crate 2 | 3 | set -ex 4 | 5 | run_tests() { 6 | runner="$1" 7 | working_dir="$2" 8 | # runner="cargo run --target "$TARGET" --" 9 | export alfred_debug=1 10 | export alfred_version="4.0.1" 11 | export alfred_workflow_version=0.15.1 12 | export alfred_workflow_uid=hamid63 13 | export alfred_workflow_name="RustyPin" 14 | export alfred_workflow_bundleid=cc.hamid.alfred-pinboard-rs 15 | workflow_dir="$working_dir/.config/alfred-pinboard-rs" 16 | mkdir -p "$workflow_dir" 17 | export alfred_workflow_data="$workflow_dir" 18 | export alfred_workflow_cache="$workflow_dir" 19 | case "$TARGET" in 20 | x86_64-apple-darwin) 21 | $runner config --authorization hamid:12345 22 | $runner config -d 23 | ;; 24 | x86_64-unknown-linux-gnu) 25 | ls -ld "$alfred_workflow_data" 26 | ls -ld "$alfred_workflow_cache" 27 | chown -R "$USER":"$USER" "$alfred_workflow_data" 28 | 29 | $runner config --authorization hamid:12345 30 | $runner config -d 31 | unset alfred_debug 32 | $runner config -d | .circleci/json_pretty.sh 33 | ;; 34 | i686-apple-darwin) 35 | $runner config --authorization hamid:12345 36 | $runner config -d 37 | ;; 38 | x86_64-unknown-freebsd) 39 | # $runner config --authorization hamid:12345 40 | # $runner config -d 41 | ;; 42 | armv7-linux-androideabi) 43 | $runner config --authorization hamid:12345 44 | $runner config -d 45 | ;; 46 | *) 47 | return 48 | ;; 49 | esac 50 | 51 | } 52 | 53 | # Build only 54 | if [ -z "$CIRCLE_TEST" ]; then 55 | arg= 56 | [[ "$TARGET" == "x86_64-apple-darwin" ]] && [[ "$BUILD_TYPE" == "release" ]] && arg="--release" 57 | cargo build $arg --target "$TARGET" 58 | elif [[ "$CIRCLE_TEST" == "false" ]]; then # Tests disabled 59 | echo "Tests Disabled. Finishing the job." 60 | # Test only 61 | elif [[ "$CIRCLE_TEST" == "true" ]]; then 62 | echo "$1" 63 | run_tests "$1" "$2" 64 | fi 65 | -------------------------------------------------------------------------------- /src/commands/update.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use chrono::prelude::*; 3 | use std::io::Write; 4 | 5 | #[allow(clippy::option_map_unit_fn)] 6 | impl<'api, 'pin> Runner<'api, 'pin> { 7 | pub fn update_cache(&mut self) { 8 | info!("Starting in update_cache"); 9 | match self 10 | .pinboard 11 | .as_ref() 12 | .unwrap() 13 | .is_cache_outdated(self.config.as_ref().unwrap().update_time) 14 | { 15 | Err(err) => { 16 | io::stdout() 17 | .write(format!("Error: {}", err).as_ref()) 18 | .expect("Couldn't write to stdout"); 19 | process::exit(1); 20 | } 21 | Ok(needs_update) => { 22 | if needs_update { 23 | debug!(" cache neeeds updating."); 24 | self.pinboard 25 | .as_mut() 26 | .unwrap() 27 | .update_cache() 28 | .unwrap_or_else(|err| { 29 | io::stdout() 30 | .write(format!("Error: {}", err).as_ref()) 31 | .expect("Couldn't write to stdout"); 32 | process::exit(1); 33 | }); 34 | self.config 35 | .as_mut() 36 | .map(|config| config.update_time = Utc::now()); 37 | if self.config.as_mut().unwrap().save().is_err() { 38 | io::stdout() 39 | .write(b"Error: Couldn't save update time to workflow's config file!") 40 | .expect("Couldn't write to stdout"); 41 | } 42 | io::stdout() 43 | .write(b"Updated cache files!") 44 | .expect("Couldn't write to stdout"); 45 | } else { 46 | debug!(" cache is up-to-date."); 47 | io::stdout() 48 | .write(b"Cache is already up-to-date!") 49 | .expect("Couldn't write to stdout"); 50 | } 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/commands/browser_info.rs: -------------------------------------------------------------------------------- 1 | use failure::{err_msg, Error}; 2 | use std::process::Command; 3 | 4 | #[derive(Debug)] 5 | pub struct BrowserActiveTabInfo { 6 | pub url: String, 7 | pub title: String, 8 | } 9 | 10 | const OSASCRIPT_OUTPUT_SPECIAL_SEPERATOR: &str = " fd850fc2e63511e79f720023dfdf24ec "; 11 | 12 | pub fn get() -> Result { 13 | debug!("Starting in browser_info::get"); 14 | let output = Command::new("osascript") 15 | .arg("-s") 16 | .arg("so") 17 | .arg("get-current-url.applescript") 18 | .output() 19 | .map_err(|e| err_msg(format!("{:?}: osascript", e)))?; 20 | if !output.status.success() { 21 | return Err(err_msg(format!("osascript error: code {}", output.status))); 22 | } 23 | // Get output of above command 24 | let osascript_result = String::from_utf8(output.stdout)?; 25 | // let osascript_result = String::from(r#"{"file:///Users/alwc/Downloads/test.pdf fd850fc2e63511e79f720023dfdf24ec file:///Users/alwc/Downloads/test.pdf"}"#); 26 | // let osascript_result = String::from(r#"{"safari-resource :/ErrorPage.html fd850fc2e63511e79f720023dfdf24ec Failed to open page"}"#); 27 | debug!(" osascript_result: {}", osascript_result); 28 | 29 | // Extract theURL and theTitle from output (assumed they are separated 30 | // by ' fd850fc2e63511e79f720023dfdf24ec ' (note spaces)) 31 | let trim_chars: &[_] = &['{', '}', '\n']; 32 | let tab_info: Vec<&str> = osascript_result 33 | .trim_matches(trim_chars) 34 | .split(OSASCRIPT_OUTPUT_SPECIAL_SEPERATOR) 35 | .map(|s| s.trim().trim_matches('"').trim()) 36 | .collect(); 37 | assert_eq!(2, tab_info.len()); 38 | 39 | // If theTitle is missing use theURL for title as well. 40 | let tab_info = match (tab_info[0].is_empty(), tab_info[1].is_empty()) { 41 | (true, _) => Err(err_msg("Cannot get browser's URL")), 42 | (false, true) => Ok(BrowserActiveTabInfo { 43 | url: tab_info[0].to_string(), 44 | title: tab_info[0].to_string(), 45 | }), 46 | _ => Ok(BrowserActiveTabInfo { 47 | url: tab_info[0].to_string(), 48 | title: tab_info[1].to_string(), 49 | }), 50 | }; 51 | debug!(" tab_info: {:?}", tab_info); 52 | tab_info 53 | } 54 | -------------------------------------------------------------------------------- /.circleci/before_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script takes care of building your crate and packaging it for release 3 | 4 | set -ex 5 | 6 | main() { 7 | local src=$(pwd) \ 8 | stage= 9 | 10 | case $CIRCLE_OS_NAME in 11 | linux) 12 | stage=$(mktemp -d) 13 | ;; 14 | macos) 15 | stage=$(mktemp -d -t tmp) 16 | ;; 17 | *) 18 | echo "$CIRCLE_OS_NAME not a supported OS" 19 | exit 1 20 | esac 21 | 22 | # only build for macOS 23 | case $TARGET in 24 | x86_64-apple-darwin) 25 | build_alfred_bundle "$src" "$stage" 26 | ;; 27 | # i686-apple-darwin) 28 | # build_alfred_bundle "$src" "$stage" 29 | # ;; 30 | *) 31 | return 32 | ;; 33 | esac 34 | 35 | } 36 | 37 | build_alfred_bundle() { 38 | src=$1 39 | stage=$2 40 | test -f Cargo.lock || cargo generate-lockfile 41 | 42 | # TODO Update this to build the artifacts that matter to you 43 | # cross rustc --bin alfred-pinboard-rs --target "$TARGET" --release -- -C lto 44 | 45 | # TODO Update this to package the right artifacts 46 | # res_dir="$src/res/workflow" 47 | res_dir="$src/res/workflow/" 48 | 49 | # echo "Copying executable to workflow's folder..." 50 | cp "$src/target/$TARGET/release/alfred-pinboard-rs" "$stage" 51 | cp "$res_dir"/* "$stage" 52 | 53 | # echo "Creating the workflow bundle..." 54 | cd "$stage" || exit 55 | strip ./alfred-pinboard-rs || true 56 | rm -f AlfredPinboardRust.alfredworkflow 57 | 58 | zip -r AlfredPinboardRust.alfredworkflow ./* 59 | 60 | case $TARGET in 61 | x86_64-apple-darwin) 62 | mv ./AlfredPinboardRust.alfredworkflow "$src/target/alfred-pinboard-rust-$CIRCLE_TAG.alfredworkflow" 63 | ;; 64 | i686-apple-darwin) 65 | tar czf "$src/$TARGET-$CRATE_NAME-$CIRCLE_TAG.tar.gz" ./AlfredPinboardRust.alfredworkflow 66 | ;; 67 | *) 68 | return 69 | ;; 70 | esac 71 | cd "$src" 72 | 73 | } 74 | 75 | if [ -z "$CIRCLE_TAG" ]; then 76 | echo "Not a tagged commit. Exitting" 77 | exit 1 78 | else 79 | echo "This is a tagged commit, running before_deploy" 80 | fi 81 | 82 | main 83 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Based on the "trust" template v0.1.2 2 | # https://github.com/japaric/trust/tree/v0.1.2 3 | 4 | environment: 5 | global: 6 | # TODO This is the Rust channel that build jobs will use by default but can be 7 | # overridden on a case by case basis down below 8 | RUST_VERSION: stable 9 | 10 | # TODO Update this to match the name of your project. 11 | CRATE_NAME: alfred-pinboard-rs 12 | 13 | # TODO These are all the build jobs. Adjust as necessary. Comment out what you 14 | # don't need 15 | matrix: 16 | # MinGW 17 | # - TARGET: i686-pc-windows-gnu 18 | # - TARGET: x86_64-pc-windows-gnu 19 | 20 | # MSVC 21 | - TARGET: i686-pc-windows-msvc 22 | - TARGET: x86_64-pc-windows-msvc 23 | RUST_BACKTRACE: 1 24 | alfred_debug: 1 25 | alfred_version: 4.0.1 26 | alfred_workflow_version: 0.11.1 27 | alfred_workflow_uid: hamid63 28 | alfred_workflow_name: RustyPin 29 | alfred_workflow_bundleid: 'cc.hamid.alfred-pinboard-rs' 30 | alfred_workflow_data: 'C:\projects\alfred-pinboard-rs' 31 | alfred_workflow_cache: 'C:\projects\alfred-pinboard-rs' 32 | 33 | 34 | init: 35 | - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) 36 | 37 | install: 38 | - ps: >- 39 | If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') { 40 | $Env:PATH += ';C:\msys64\mingw64\bin' 41 | } ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') { 42 | $Env:PATH += ';C:\msys64\mingw32\bin' 43 | } 44 | - curl -sSf -o rustup-init.exe https://win.rustup.rs/ 45 | - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION% 46 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin 47 | - rustc -Vv 48 | - cargo -V 49 | 50 | # TODO This is the "test phase", tweak it as you see fit 51 | test_script: 52 | - if [%APPVEYOR_REPO_TAG%]==[false] ( 53 | cargo build --target %TARGET% && 54 | cargo run --target %TARGET% -- config --authorization hamid:12345 && 55 | cargo run --target %TARGET% -- config -d && 56 | cargo test --target %TARGET% -- --nocapture --test-threads=1 57 | ) 58 | 59 | cache: 60 | - C:\Users\appveyor\.cargo\registry 61 | - target 62 | 63 | branches: 64 | only: 65 | - /^v?\d+\.\d+\.\d+.*$/ 66 | - master 67 | 68 | notifications: 69 | - provider: Email 70 | on_build_success: false 71 | 72 | # Building is done in the test phase, so we disable Appveyor's build phase. 73 | build: false 74 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.15.12] - 2020-04-03 10 | ### Fixed 11 | - Use rusty-pin 0.5.1 to fix #46 (empty tag list on Pinboard) 12 | 13 | ## [0.15.11] - 2020-03-22 14 | ### Added 15 | - Add basic support for tag renaming. 16 | 17 | ## [0.15.10] - 2020-03-12 18 | ### Fixed 19 | - Trying to address issue [#47](https://github.com/spamwax/alfred-pinboard-rs/issues/47) (Catalina osascript premissions) 20 | ### Added 21 | - Suport Microsoft Edge Browser 22 | ### Changed 23 | - Don't use `sed` hack to set username for url search on [pinboard](https://pinboard.in). A `username` environment variable is now passed to Alfred. 24 | 25 | ## [0.15.8] - 2019-08-29 26 | ### Changed 27 | - Holding `Control`/`Option` keys while posting a bookmark will now momentarily toggle `toread`/`shared` settings. ([Closes #38](https://github.com/spamwax/alfred-pinboard-rs/issues/38)) 28 | 29 | ## [0.15.7] - 2019-07-14 30 | - Preserve upper/lowercase of titles/urls/description. 31 | 32 | ## [0.15.6] - 2019-07-11 33 | ### Added 34 | - Holding CMD in search results now correctly shows either tags or URL based on users' settings. 35 | ### Fixed 36 | - Fix appveyor CI issue with directory names. 37 | 38 | ## [0.15.4] - 2019-06-17 39 | ### Added 40 | - Add option to either show TAGs or URLs in search results. 41 | - Add a combo modifier for search result to copy URL to clipboard. 42 | ### Fixed 43 | - Fix multiple issues related to release of Alfred 4 44 | - `pcheck` should now force a network call regardless of when last update check was done. 45 | - Fix: deleting a bookmark was not working. 46 | 47 | ## [0.14.9] - 2019-02-13 48 | ### Added 49 | - Add settings for notifying if page is already bookmarked. 50 | 51 | ## [0.14.8] - 2019-02-13 52 | ### Fixed 53 | - Workaround for Firefox ([Fixes #25](https://github.com/spamwax/alfred-pinboard-rs/issues/25)) 54 | 55 | ## [0.14.7] - 2019-01-30 56 | ### Added 57 | - Support [Brave Browser](brave.com) 58 | 59 | ## [0.14.6] - 2019-01-22 60 | ### Added 61 | - Minor improvements 62 | 63 | ## [0.14.5] - 2019-01-15 64 | ### Added 65 | - Show whether current page is already bookmarked. 66 | 67 | ## [0.14.4] - 2018-11-22 68 | ### Fixed 69 | - Fixes issue [#21](https://github.com/spamwax/alfred-pinboard-rs/issues/21) 70 | 71 | ## [0.14.1 - 0.14.3] - 2018-08-27 - 2018-10-31 72 | ### Fixed 73 | - Re-enable auto cache update 74 | - Using `;` to add description was broken 75 | - Recompile binary to fix an upstream bug 76 | 77 | ### Added 78 | - Add Opera support 79 | 80 | ## [0.14.0] - 2018-06-04 81 | ### Added 82 | - Workflow can notify and auto update itself. 83 | 84 | ## [0.13.3] - 2018-05-29 85 | ### Fixed 86 | - Fixes issue [#7](https://github.com/spamwax/alfred-pinboard-rs/issues/7) 87 | -------------------------------------------------------------------------------- /src/commands/post.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use std::io::Write; 3 | 4 | use super::browser_info; 5 | 6 | impl<'api, 'pin> Runner<'api, 'pin> { 7 | pub fn post(&mut self, cmd: SubCommand) { 8 | debug!("Starting in run"); 9 | let input_tags: Vec; 10 | let input_desc; 11 | // let conifg = self.config.as_ref().unwrap(); 12 | // let pinboard = self.pinboard.as_ref().unwrap(); 13 | match cmd { 14 | SubCommand::Post { 15 | tags, 16 | description, 17 | shared, 18 | toread, 19 | } => { 20 | input_tags = tags; 21 | input_desc = description; 22 | toread.map(|f| self.config.as_mut().map(|config| config.toread_new_pin = f)); 23 | shared.map(|f| { 24 | self.config 25 | .as_mut() 26 | .map(|config| config.private_new_pin = !f) 27 | }); 28 | } 29 | _ => unreachable!(), 30 | } 31 | 32 | let browser_tab_info = browser_info::get().unwrap_or_else(|e| { 33 | let _ = io::stdout() 34 | .write(format!("Error: {}", e).as_ref()) 35 | .expect("Couldn't write to stdout"); 36 | process::exit(1); 37 | }); 38 | 39 | let mut pin_builder = PinBuilder::new(&browser_tab_info.url, &browser_tab_info.title); 40 | pin_builder = pin_builder 41 | .tags(input_tags.join(" ")) 42 | .shared(if self.config.as_ref().unwrap().private_new_pin { 43 | "no" 44 | } else { 45 | "yes" 46 | }) 47 | .toread(if self.config.as_ref().unwrap().toread_new_pin { 48 | "yes" 49 | } else { 50 | "no" 51 | }); 52 | 53 | if let Some(desc) = input_desc { 54 | pin_builder = pin_builder.description(desc); 55 | } 56 | 57 | if let Err(e) = self 58 | .pinboard 59 | .as_mut() 60 | .unwrap() 61 | .add_pin(pin_builder.into_pin()) 62 | { 63 | if let Err(io_err) = io::stdout().write(format!("Error: {}", e).as_ref()) { 64 | error!( 65 | "Failed to post to Pinboard AND to notify user: {}", 66 | io_err.to_string() 67 | ); 68 | } 69 | } else { 70 | if let Err(io_err) = io::stdout() 71 | .write(format!("Successfully posted: {}\n", browser_tab_info.title).as_ref()) 72 | { 73 | error!( 74 | "Failed to notify user about posting to Pinboard successfully: {}", 75 | io_err.to_string() 76 | ); 77 | } 78 | if self.config.as_ref().unwrap().auto_update_cache { 79 | self.update_cache(); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /ci/script.sh: -------------------------------------------------------------------------------- 1 | # This script takes care of testing your crate 2 | 3 | set -ex 4 | 5 | run_phase() { 6 | # if [ ! -z "$DISABLE_TESTS" ]; then 7 | # return 8 | # fi 9 | export alfred_debug=1 10 | export alfred_version="4.0.1" 11 | export alfred_workflow_version=0.15.1 12 | export alfred_workflow_uid=hamid63 13 | export alfred_workflow_name="RustyPin" 14 | export alfred_workflow_bundleid=cc.hamid.alfred-pinboard-rs 15 | case "$TARGET" in 16 | x86_64-apple-darwin) 17 | export alfred_workflow_data=/Users/travis/.config/alfred-pinboard-rs 18 | export alfred_workflow_cache=/Users/travis/.config/alfred-pinboard-rs 19 | mkdir "/Users/travis/.config/alfred-pinboard-rs" 20 | cross run --target "$TARGET" -- config --authorization hamid:12345 21 | cross run --target "$TARGET" -- config -d 22 | ;; 23 | x86_64-unknown-linux-gnu) 24 | mkdir -p "$HOME/.config/alfred-pinboard-rs" 25 | export alfred_workflow_data=$HOME/.config/alfred-pinboard-rs 26 | export alfred_workflow_cache=$HOME/.config/alfred-pinboard-rs 27 | export RUST_BACKTRACE=1 28 | ls -ld $alfred_workflow_data 29 | ls -ld $alfred_workflow_cache 30 | chown -R $USER:$USER $alfred_workflow_data 31 | 32 | cross run --target "$TARGET" -- config --authorization hamid:12345 33 | cross run --target "$TARGET" -- config -d 34 | ;; 35 | i686-apple-darwin) 36 | mkdir "$HOME/.config/alfred-pinboard-rs" 37 | export alfred_workflow_data=$HOME/.config/alfred-pinboard-rs 38 | export alfred_workflow_cache=$HOME/.config/alfred-pinboard-rs 39 | cross run --target "$TARGET" -- config --authorization hamid:12345 40 | cross run --target "$TARGET" -- config -d 41 | ;; 42 | x86_64-unknown-freebsd) 43 | # mkdir "$HOME/.config/alfred-pinboard-rs" 44 | # export alfred_workflow_data=$HOME/.config/alfred-pinboard-rs 45 | # export alfred_workflow_cache=$HOME/.config/alfred-pinboard-rs 46 | # cross run --target "$TARGET" -- config --authorization hamid:12345 47 | # cross run --target "$TARGET" -- config -d 48 | ;; 49 | armv7-linux-androideabi) 50 | mkdir "$HOME/.config/alfred-pinboard-rs" 51 | export alfred_workflow_data=$HOME/.config/alfred-pinboard-rs 52 | export alfred_workflow_cache=$HOME/.config/alfred-pinboard-rs 53 | cross run --target "$TARGET" -- config --authorization hamid:12345 54 | ;; 55 | *) 56 | return 57 | ;; 58 | esac 59 | 60 | } 61 | 62 | # TODO This is the "test phase", tweak it as you see fit 63 | test_phase() { 64 | 65 | rustup target add --toolchain stable x86_64-unknown-freebsd 66 | if [ -n "$DISABLE_TESTS" ]; then 67 | cross build --target "$TARGET" 68 | return 69 | fi 70 | 71 | cargo test --target "$TARGET" -- --nocapture --test-threads=1 || return 72 | run_phase 73 | } 74 | 75 | # we don't run the "test phase" when doing deploys 76 | if [ -z "$TRAVIS_TAG" ]; then 77 | echo "Non tag commit, running only tests." 78 | test_phase 79 | fi 80 | -------------------------------------------------------------------------------- /src/commands/mod.rs: -------------------------------------------------------------------------------- 1 | use alfred; 2 | use std::io; 3 | use std::{env, process}; 4 | 5 | use crate::cli::SubCommand; 6 | use crate::workflow_config::Config; 7 | 8 | use rusty_pin::{PinBuilder, Pinboard, Tag}; 9 | 10 | pub mod config; 11 | mod delete; 12 | mod list; 13 | mod post; 14 | mod rename; 15 | mod search; 16 | mod update; 17 | mod upgrade; 18 | 19 | mod browser_info; 20 | 21 | use super::Error; 22 | use alfred_rs::updater::GithubReleaser; 23 | use alfred_rs::updater::Updater; 24 | 25 | pub(super) struct Runner<'api, 'pin> { 26 | pub config: Option, 27 | pub pinboard: Option>, 28 | pub updater: Option>, 29 | } 30 | 31 | impl<'api, 'pin> Runner<'api, 'pin> { 32 | fn write_output_items<'a, I>(&self, items: I) -> Result<(), Error> 33 | where 34 | I: IntoIterator>, 35 | { 36 | debug!("Starting in write_output_items"); 37 | let mut output_items = items.into_iter().collect::>(); 38 | 39 | let update_item = self.get_upgrade_item(); 40 | if let Ok(item) = update_item { 41 | output_items.push(item); 42 | } else { 43 | error!( 44 | "Error checking for workflow updates: {:?}", 45 | update_item.unwrap_err() 46 | ); 47 | } 48 | 49 | let json_format = self.config.as_ref().unwrap().can_use_json(); 50 | // Get username from auth_token 51 | let idx = self 52 | .config 53 | .as_ref() 54 | .unwrap() 55 | .auth_token 56 | .find(':') 57 | .ok_or_else(|| failure::err_msg("Bad Auth. Token!"))?; 58 | let username = &self.config.as_ref().unwrap().auth_token.as_str()[..idx]; 59 | crate::write_to_alfred( 60 | output_items, 61 | json_format, 62 | Some(vec![("username", username)]), 63 | ); 64 | Ok(()) 65 | } 66 | 67 | fn get_upgrade_item(&self) -> Result { 68 | debug!("Starting in get_upgrade_item"); 69 | self.updater.as_ref().unwrap().update_ready().map(|update| { 70 | if update { 71 | info!("Update is available"); 72 | // Since an update is available `latest_version().unwrap()` will not fail 73 | let new_version = self 74 | .updater 75 | .as_ref() 76 | .unwrap() 77 | .latest_avail_version() 78 | .unwrap(); 79 | let old_version = self.updater.as_ref().unwrap().current_version(); 80 | alfred::ItemBuilder::new("New Version Is Available for Rusty Pin Workflow! 🎉") 81 | .subtitle(format!( 82 | "Click to download & upgrade {} ⟶ {}", 83 | old_version, new_version 84 | )) 85 | .icon_path("auto_update.png") 86 | .variable("workflow_update_ready", "1") 87 | .arg("update") 88 | .into_item() 89 | } else { 90 | info!("Update *UNAVAILABLE*"); 91 | alfred::ItemBuilder::new("You have the latest version of workflow!") 92 | .icon_path("auto_update.png") 93 | .variable("workflow_update_ready", "0") 94 | .arg("update") 95 | .into_item() 96 | } 97 | }) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/commands/delete.rs: -------------------------------------------------------------------------------- 1 | use super::browser_info; 2 | use super::*; 3 | use alfred::ItemBuilder; 4 | use std::io::Write; 5 | 6 | /// Providing this command with a URL will try to remove the related bookmark from Pinboard. 7 | /// If no URL is provided, this command will fetch browser's tab info and show and Alfred item that 8 | /// can be used for deletion in next step. 9 | /// 10 | 11 | // TODO: right now we accept deleting tag & url at the same time. If user asks to delete a tag 12 | // only, this function will automatically grab browser's url and return an Alfred item containing 13 | // it while deleting the given tag as well. I believe these two options should be made exclusively 14 | // mutual. 15 | impl<'api, 'pin> Runner<'api, 'pin> { 16 | pub fn delete(&mut self, cmd: SubCommand) { 17 | debug!("Starting in delete"); 18 | let (url, tag) = match cmd { 19 | SubCommand::Delete { url, tag } => (url, tag), 20 | _ => unreachable!(), 21 | }; 22 | 23 | if let Some(tag) = tag { 24 | debug!(" tag: {}", tag); 25 | if let Err(e) = self.pinboard.as_ref().unwrap().delete_tag(tag) { 26 | let _ = io::stdout() 27 | .write(format!("Error: {}", e).as_ref()) 28 | .expect("Couldn't write to stdout"); 29 | process::exit(1); 30 | } else { 31 | let _ = io::stdout() 32 | .write(b"Successfully deleted tag.") 33 | .expect("Couldn't write to stdout"); 34 | if self.config.as_ref().unwrap().auto_update_cache { 35 | self.update_cache(); 36 | } 37 | } 38 | return; 39 | } 40 | if let Some(url) = url { 41 | debug!(" url: {}", url); 42 | if let Err(e) = self.pinboard.as_ref().unwrap().delete(&url) { 43 | let _ = io::stdout() 44 | .write(format!("Error: {}", e).as_ref()) 45 | .expect("Couldn't write to stdout"); 46 | process::exit(1); 47 | } else { 48 | let _ = io::stdout() 49 | .write(b"Successfully deleted bookmark.") 50 | .expect("Couldn't write to stdout"); 51 | if self.config.as_ref().unwrap().auto_update_cache { 52 | self.update_cache(); 53 | } 54 | } 55 | } else { 56 | let tab_info; 57 | let item = match browser_info::get() { 58 | Ok(browser_tab_info) => { 59 | tab_info = browser_tab_info; 60 | ItemBuilder::new(tab_info.title.as_str()) 61 | .subtitle(tab_info.url.as_str()) 62 | .arg(tab_info.url.as_str()) 63 | .quicklook_url(tab_info.url.as_str()) 64 | .text_large_type(tab_info.title.as_str()) 65 | .text_copy(tab_info.url.as_str()) 66 | .icon_path("bookmark-delete.png") 67 | .into_item() 68 | } 69 | Err(e) => { 70 | warn!("Couldn't get browser info: {:?}", e); 71 | ItemBuilder::new("Couldn't get browser's info!") 72 | .subtitle("Error") 73 | .icon_path("erroricon.icns") 74 | .into_item() 75 | } 76 | }; 77 | if let Err(e) = self.write_output_items(vec![item]) { 78 | error!("delete: Couldn't write to Alfred: {:?}", e); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /disable-travis: -------------------------------------------------------------------------------- 1 | # Based on the "trust" template v0.1.2 2 | # https://github.com/japaric/trust/tree/v0.1.2 3 | 4 | dist: trusty 5 | language: rust 6 | services: docker 7 | sudo: required 8 | 9 | # TODO Rust builds on stable by default, this can be 10 | # overridden on a case by case basis down below. 11 | 12 | env: 13 | global: 14 | # TODO Update this to match the name of your project. 15 | - CRATE_NAME=alfred-pinboard-rs 16 | 17 | matrix: 18 | # TODO These are all the build jobs. Adjust as necessary. Comment out what you 19 | # don't need 20 | include: 21 | # Android 22 | # - env: TARGET=armv7-linux-androideabi 23 | # - env: TARGET=i686-linux-android DISABLE_TESTS=1 24 | # - env: TARGET=x86_64-linux-android DISABLE_TESTS=1 25 | 26 | # iOS 27 | # - env: TARGET=aarch64-apple-ios DISABLE_TESTS=1 28 | # os: osx 29 | # - env: TARGET=armv7-apple-ios DISABLE_TESTS=1 30 | # os: osx 31 | 32 | # Linux 33 | - env: TARGET=x86_64-unknown-linux-gnu DISABLE_TESTS=1 34 | # - env: TARGET=i686-unknown-linux-gnu 35 | 36 | # OSX 37 | # - env: TARGET=i686-apple-darwin 38 | # os: osx 39 | - env: TARGET=x86_64-apple-darwin 40 | os: osx 41 | 42 | # *BSD 43 | - env: TARGET=i686-unknown-freebsd DISABLE_TESTS=1 44 | - env: TARGET=x86_64-unknown-freebsd DISABLE_TESTS=1 45 | # - env: TARGET=x86_64-unknown-netbsd DISABLE_TESTS=1 46 | 47 | # Bare metal 48 | # These targets don't support std and as such are likely not suitable for 49 | # most crates. 50 | # - env: TARGET=thumbv6m-none-eabi 51 | # - env: TARGET=thumbv7em-none-eabi 52 | # - env: TARGET=thumbv7em-none-eabihf 53 | # - env: TARGET=thumbv7m-none-eabi 54 | 55 | # Testing other channels 56 | # - env: TARGET=x86_64-unknown-linux-gnu 57 | # rust: nightly 58 | # - env: TARGET=x86_64-apple-darwin 59 | # os: osx 60 | # rust: nightly 61 | 62 | before_install: 63 | - set -e 64 | - rustup self update 65 | 66 | install: 67 | - sh ci/install.sh 68 | - source ~/.cargo/env || true 69 | 70 | script: 71 | - bash ci/script.sh 72 | 73 | after_script: set +e 74 | 75 | before_deploy: 76 | - sh ci/before_deploy.sh 77 | 78 | deploy: 79 | # TODO update `api_key.secure` 80 | # - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new 81 | # - Encrypt it: `travis encrypt 0123456789012345678901234567890123456789 82 | # - Paste the output down here 83 | api_key: 84 | secure: jr5wObeu13+vB664jOvl9Sc5azbHoCuXyn7ME28Bf/BbAMb/P80C5izzkSlGLaEu4W581GgRUvivUeYRqxP2aBZkyCqptgV+yeQdt6u+o/FPe5DW9oJij/23zbg7TLbO/lbGDfD9vJhN4MPRYoRm2/ldlpBBibeAIOowSlxF6Ks6MZQIsRM/6h6zvDBZEYYbU9R0nftYefsklfTH3m6OfJ9tzeVBE2X6mUvwRz3ZCDyNWO1bzJqndP/7LxkjSVbp+/L5IcHONwmbS8fDSSDReiNLRAlXp3RCUieHFU3tytVwQJrk+MqbpRLqmP35rb3w1Yl9g1iSg6Xq+Gc2XD+UPH6YcHlxAP04jhPmYaq6E/tFfTbTP7RIOTKCJvhrmhnksWbes9RWMj6r6C6jrs0PS7PzJ0o1b5d2Xx5l35JJ+A5nnmsV+G014pKhsKIFUHdNNXoFTaORphEcILn7tVjfNilvj3h9UIOlqai+s6pmqGNRjG79HN34C+4JP7m0Q8IpgBs18Y/Ldeku7IeZNbY0ZQcmbhOrWBsfW367uG0WyoBHBGO7DW6ygSYpTh7QbbT2LoRhOi6zfnWjA2ozq4C8v+idGOmVHC2YJzG1J7sG/DRSbOFtvYr3adWz7v6SzGUJrI/IVSUFMxVy7ANJcl9ppiMtqkc8s/1MPNShPmZSbjI= 85 | file_glob: true 86 | file: 87 | # - $TARGET-$CRATE_NAME-$TRAVIS_TAG.* 88 | - alfred-pinboard-rust-$TRAVIS_TAG.alfredworkflow 89 | on: 90 | # TODO Here you can pick which targets will generate binary releases 91 | # In this example, there are some targets that are tested using the stable 92 | # and nightly channels. This condition makes sure there is only one release 93 | # for such targets and that's generated using the stable channel 94 | condition: $TRAVIS_RUST_VERSION = stable 95 | tags: true 96 | provider: releases 97 | skip_cleanup: true 98 | 99 | cache: cargo 100 | before_cache: 101 | # Travis can't cache files that are not readable by "others" 102 | - chmod -R a+r $HOME/.cargo 103 | 104 | branches: 105 | only: 106 | # release tags 107 | - /^v?\d+\.\d+\.\d+.*$/ 108 | - master 109 | - develop 110 | 111 | notifications: 112 | email: 113 | on_success: never 114 | -------------------------------------------------------------------------------- /src/commands/config.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::AlfredError; 3 | use chrono::prelude::Local; 4 | 5 | pub fn run(x: SubCommand) { 6 | debug!("Starting in run"); 7 | let print_config; 8 | let mut config: Config; 9 | 10 | #[allow(clippy::option_map_unit_fn)] 11 | match x { 12 | SubCommand::Config { 13 | display, 14 | auth_token, 15 | number_pins, 16 | number_tags, 17 | shared, 18 | toread, 19 | fuzzy, 20 | tags_only, 21 | auto_update, 22 | suggest_tags, 23 | check_bookmarked_page, 24 | show_url_vs_tags, 25 | } => { 26 | print_config = display; 27 | config = Config::setup().unwrap_or_else(|err| { 28 | if_chain! { 29 | if auth_token.is_some(); 30 | if let Some(t) = err.as_fail().downcast_ref::(); 31 | if let AlfredError::MissingConfigFile = *t; 32 | then { 33 | let mut config = Config::new(); 34 | config.auth_token = auth_token.as_ref().unwrap().clone(); 35 | config 36 | } else { 37 | crate::show_error_alfred(err.to_string()); 38 | process::exit(1); 39 | } 40 | } 41 | }); 42 | // auth_token.map(|val| config.auth_token = val); 43 | auth_token.and_then(|val| { 44 | config.auth_token = val; 45 | Some(()) 46 | }); 47 | number_pins.map(|val| config.pins_to_show = val); 48 | number_tags.map(|val| config.tags_to_show = val); 49 | shared.map(|val| config.private_new_pin = !val); 50 | toread.map(|val| config.toread_new_pin = val); 51 | fuzzy.map(|val| config.fuzzy_search = val); 52 | tags_only.map(|val| config.tag_only_search = val); 53 | auto_update.map(|val| config.auto_update_cache = val); 54 | suggest_tags.map(|val| config.suggest_tags = val); 55 | check_bookmarked_page.map(|val| config.page_is_bookmarked = val); 56 | show_url_vs_tags.map(|val| config.show_url_vs_tags = val); 57 | } 58 | _ => unreachable!(), 59 | } 60 | 61 | if let Err(e) = config.save() { 62 | error!("Couldn't save config file: {:?}", e); 63 | } else { 64 | debug!( 65 | "Saved new configs to {} in: {}", 66 | crate::workflow_config::CONFIG_FILE_NAME, 67 | config.data_dir().to_string_lossy() 68 | ); 69 | } 70 | 71 | if print_config { 72 | show_config(&config); 73 | } 74 | } 75 | 76 | fn show_config(config: &Config) { 77 | debug!("Starting in show_config"); 78 | // TODO: Add support for Alfred 2 by returning XML <09-02-18, Hamid> // 79 | // If Using Alfred Version >=3 80 | if config.can_use_json() { 81 | use alfred::ItemBuilder; 82 | alfred::json::Builder::with_items(&[ 83 | ItemBuilder::new("Only search tags") 84 | .subtitle(format!("{:?}", config.tag_only_search)) 85 | .arg("pset tagonly") 86 | .icon_path("tagonly.png") 87 | .into_item(), 88 | ItemBuilder::new("Use fuzzy search") 89 | .subtitle(format!("{:?}", config.fuzzy_search)) 90 | .arg("pset fuzzy") 91 | .icon_path("fuzzy.png") 92 | .into_item(), 93 | ItemBuilder::new("Automatically update cache") 94 | .subtitle(format!("{:?}", config.auto_update_cache)) 95 | .arg("pset auto") 96 | .icon_path("auto_update_cache.png") 97 | .into_item(), 98 | ItemBuilder::new("Suggest popular tags for open browser tab") 99 | .subtitle(format!("{:?}", config.suggest_tags)) 100 | .arg("pset suggest_tags") 101 | .icon_path("suggest.png") 102 | .into_item(), 103 | ItemBuilder::new("Mark new bookmarks as toread") 104 | .subtitle(format!("{:?}", config.toread_new_pin)) 105 | .arg("pset toread") 106 | .icon_path("toread.png") 107 | .into_item(), 108 | ItemBuilder::new("Mark new bookmarks as private") 109 | .subtitle(format!("{:?}", config.private_new_pin)) 110 | .arg("pset shared") 111 | .icon_path("private.png") 112 | .into_item(), 113 | ItemBuilder::new("Check if page is bookmarked") 114 | .subtitle(format!("{:?}", config.page_is_bookmarked)) 115 | .arg("pset check_bookmarked") 116 | .icon_path("check_bookmarked_page.png") 117 | .into_item(), 118 | ItemBuilder::new("Show TAGs vs URLs in search results") 119 | .subtitle(format!("{:?}", config.show_url_vs_tags)) 120 | .arg("pset url_tag") 121 | .icon_path("url.png") 122 | .into_item(), 123 | ItemBuilder::new("Number of tags to show") 124 | .subtitle(format!("{:?}", config.tags_to_show)) 125 | .arg("pset tags") 126 | .icon_path("no_of_tags.png") 127 | .into_item(), 128 | ItemBuilder::new("Number of bookmarks to show") 129 | .subtitle(format!("{:?}", config.pins_to_show)) 130 | .arg("pset bookmarks") 131 | .icon_path("no_of_pins.png") 132 | .into_item(), 133 | ItemBuilder::new("Click to check for Workflow updates.") 134 | .arg("pcheck") 135 | .icon_path("check_update.png") 136 | .into_item(), 137 | ItemBuilder::new( 138 | config 139 | .update_time 140 | .with_timezone(&Local) 141 | .format("%Y-%m-%d %H:%M:%S") 142 | .to_string(), 143 | ) 144 | .subtitle("Latest cache update") 145 | .arg("pupdate") 146 | .icon_path("auto_update.png") 147 | .into_item(), 148 | ]) 149 | .write(io::stdout()) 150 | .expect("Couldn't build alfred items"); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/commands/search.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use alfred::{Item, ItemBuilder, Modifier}; 3 | 4 | use rusty_pin::pinboard::SearchType; 5 | 6 | // TODO: Investigate why content of text_copy is not used within Alfred when user presses ⌘-C 7 | impl<'api, 'pin> Runner<'api, 'pin> { 8 | pub fn search(&mut self, cmd: SubCommand) { 9 | debug!("Starting in search::run"); 10 | match cmd { 11 | SubCommand::Search { 12 | tags, 13 | title, 14 | description, 15 | url, 16 | query, 17 | } => { 18 | let mut search_fields = vec![]; 19 | if tags { 20 | search_fields.push(SearchType::TagOnly); 21 | } 22 | if title { 23 | search_fields.push(SearchType::TitleOnly); 24 | } 25 | if url { 26 | search_fields.push(SearchType::UrlOnly); 27 | } 28 | if description { 29 | search_fields.push(SearchType::DescriptionOnly); 30 | } 31 | // If user is not asking explicitly for search fields, then search based on 32 | // configuration set by user 33 | if search_fields.is_empty() { 34 | if self.config.as_ref().unwrap().tag_only_search { 35 | search_fields.push(SearchType::TagOnly); 36 | } else { 37 | search_fields = vec![ 38 | SearchType::TagOnly, 39 | SearchType::TitleOnly, 40 | SearchType::DescriptionOnly, 41 | ]; 42 | } 43 | } 44 | let pins_to_show = self.config.as_ref().unwrap().pins_to_show; 45 | let url_vs_tags = self.config.as_ref().unwrap().show_url_vs_tags; 46 | let pinboard = self.pinboard.as_ref().unwrap(); 47 | let items = process(query, &search_fields, pins_to_show, url_vs_tags, pinboard); 48 | if let Err(e) = self.write_output_items(items) { 49 | error!("search: Couldn't write to Alfred: {:?}", e); 50 | } 51 | } 52 | _ => unreachable!(), 53 | } 54 | } 55 | } 56 | 57 | // TODO: Write this function using From trait. <11-02-18, Hamid> // 58 | fn process<'a>( 59 | query: Vec, 60 | search_fields: &[SearchType], 61 | pins_to_show: u8, 62 | url_vs_tags: bool, 63 | pinboard: &'a Pinboard<'a, 'a>, 64 | ) -> Vec> { 65 | debug!("Starting in search::process"); 66 | match pinboard.search(&query, search_fields) { 67 | Err(e) => vec![crate::alfred_error_item(e.to_string())], 68 | Ok(r) => { 69 | match r { 70 | // No result was found. 71 | None => vec![ItemBuilder::new("No bookmarks found!") 72 | .icon_path("no_result.png") 73 | .into_item()], 74 | // Some results were found 75 | Some(pins) => pins 76 | .iter() 77 | // Only take pins_to_show of them to show 78 | .take(pins_to_show as usize) 79 | // Create Alfred items that support: 80 | // - quicklook 81 | // - opening bookmark in a browser 82 | // - showing large text 83 | // - holding modifiers to 84 | // show extended text, tags or open the link in https://pinboard.in 85 | .map(|pin| { 86 | let _none: Option = None; 87 | let (subtitle, modifier_subtitle) = if !url_vs_tags { 88 | (pin.url.as_ref(), pin.tags.as_ref()) 89 | } else { 90 | (pin.tags.as_ref(), pin.url.as_ref()) 91 | }; 92 | ItemBuilder::new(pin.title.as_ref()) 93 | .subtitle(subtitle) 94 | .arg(pin.url.as_ref()) 95 | .variable("tags", pin.tags.as_ref()) 96 | .subtitle_mod(Modifier::Command, modifier_subtitle) 97 | .quicklook_url(pin.url.as_ref()) 98 | .text_large_type(pin.title.as_ref()) 99 | .text_copy(pin.url.as_ref()) 100 | .icon_path("bookmarks.png") 101 | // Hold Control: Show extended description of bookmark. 102 | .modifier( 103 | Modifier::Control, 104 | pin.extended.clone(), 105 | Some(pin.url.as_ref()), 106 | true, 107 | None, 108 | ) 109 | // Hold Option: Pressing Enter opens the bookmark on Pinboard 110 | // FIXME: There should be a better way of locating an item on 111 | // Pinboard's website. Pinboard, however currently doesn't 112 | // provide a direct way of doing that! 113 | .modifier( 114 | Modifier::Option, 115 | // subtitle 116 | Some("Show bookmark in https://pinboard.in"), 117 | // Pinboard's website currently doesn't like extra stuff in 118 | // search query's string. 119 | // Workaround: Search for item's all tags plus strictly 120 | // ascii words in its title. 121 | // arg 122 | Some( 123 | [ 124 | pin.tags.as_ref(), 125 | " ", 126 | pin.title 127 | .split_whitespace() 128 | .filter(|s| s.len() != 1) 129 | .filter(|s| s.chars().all(char::is_alphanumeric)) 130 | .collect::>() 131 | .join(" ") 132 | .as_str(), 133 | ] 134 | .concat() 135 | .trim() 136 | .to_string(), 137 | ), 138 | true, 139 | None, 140 | ) 141 | .into_item() 142 | }) 143 | .collect::>(), 144 | } 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/cli.rs: -------------------------------------------------------------------------------- 1 | #[derive(StructOpt, Debug)] 2 | #[structopt(name = "alfred-pinboard")] 3 | /// Command line component of Alfred Workflow for Pinboard (Written in Rust!) 4 | pub struct Opt { 5 | #[structopt(name = "debug", default_value = "0", long = "debug")] 6 | pub debug_level: i8, 7 | #[structopt(subcommand)] 8 | pub cmd: SubCommand, 9 | } 10 | 11 | #[derive(StructOpt, Debug)] 12 | pub enum SubCommand { 13 | #[structopt(name = "config")] 14 | /// Configures options and settings of interacting with API and searching items. 15 | Config { 16 | /// Show all the configuration settings, after setting any given config options. 17 | #[structopt(name = "display", short = "d", long = "display")] 18 | display: bool, 19 | 20 | /// Set API authorization token. 21 | /// (Obtain it from your Pinboard account's setting page). 22 | #[structopt(name = "auth", long = "authorization", short = "a")] 23 | auth_token: Option, 24 | 25 | /// Number of bookmarks to show in Alfred's window. [default: 10] 26 | #[structopt(long = "bookmark-numbers", short = "p")] 27 | number_pins: Option, 28 | 29 | /// Number of tags to show in Alfred's window. [default: 10] 30 | #[structopt(long = "tag-numbers", short = "l")] 31 | number_tags: Option, 32 | 33 | /// By default, make all new bookmarks public/shared. [default: false] 34 | #[structopt(name = "shared", short = "s", long = "shared")] 35 | shared: Option, 36 | 37 | /// By default, set all new bookmarks' toread flag. [default: false] 38 | #[structopt(name = "toread", short = "r", long = "toread")] 39 | toread: Option, 40 | 41 | /// When searching tags/bookmarks, enable 'fuzzy' searching. (similar to `selecta`) [default: false] 42 | #[structopt(name = "fuzzy", short = "f", long = "fuzzy")] 43 | fuzzy: Option, 44 | 45 | /// When searching, only look up query in 'tag' field of bookmarks. [default: false] 46 | #[structopt(name = "tags_only", short = "t", long = "tags-only")] 47 | tags_only: Option, 48 | 49 | /// After posting a bookmark to Pinboard, update the local cache files. [default: true] 50 | #[structopt(name = "auto_update", short = "u", long = "auto-update")] 51 | auto_update: Option, 52 | 53 | /// When posting a new bookmark, show 3 popular tags for the URL (if available). [default: true] 54 | #[structopt(name = "suggest_tags", short = "o", long = "suggest-tags")] 55 | suggest_tags: Option, 56 | 57 | /// Check if the current browser page is already pinned. [default: false] 58 | #[structopt( 59 | name = "check_bookmarked_page", 60 | short = "b", 61 | long = "check-bookmarked-page" 62 | )] 63 | check_bookmarked_page: Option, 64 | /// Show urls (or tags) in search results' subtitle. [default: false (url)] 65 | #[structopt(name = "show-url-or-tags", short = "e", long = "show-urls-vs-tags")] 66 | show_url_vs_tags: Option, 67 | }, 68 | #[structopt(name = "list")] 69 | /// Lists all bookmarks (default) or tags. 70 | List { 71 | /// Only list tags 72 | #[structopt(name = "tags", long = "tags", short = "t")] 73 | tags: bool, 74 | /// Retrieve suggestion for tags from Pinboard API. Will be ignored if user is not listing 75 | /// tags. 76 | #[structopt(name = "suggest", long = "suggest", short = "s")] 77 | suggest: Option, 78 | /// Optional query word used to narrow the output list. 79 | /// Only works with --tags option! To narrow down bookmarks, use `search` sub-command 80 | query: Option, 81 | }, 82 | #[structopt(name = "post")] 83 | /// Creates a bookmark for the current page of the active browser. 84 | Post { 85 | /// Space-delimited list of tags for the url 86 | #[structopt(name = "tags", long = "tags", short = "t")] 87 | tags: Vec, 88 | /// Extra description note for the url 89 | #[structopt(name = "description", long = "description", short = "d")] 90 | description: Option, 91 | /// Mark this bookmark shared (overrides user's settings) 92 | #[structopt(name = "shared", long = "shared", short = "s")] 93 | shared: Option, 94 | /// Mark this bookmark as toread (overrides user's settings) 95 | #[structopt(name = "toread", long = "toread", short = "b")] 96 | toread: Option, 97 | }, 98 | #[structopt(name = "delete")] 99 | /// Deletes a bookmark for the current page of the active browser. 100 | /// Or deletes a tag (see TODO item in delete.rs) 101 | Delete { 102 | /// Url/bookmark to be deleted. 103 | /// If not given, the bookmark for active browser's tab will be returned. 104 | #[structopt(name = "url", long = "url", short = "u")] 105 | url: Option, 106 | /// Tag to be deleted. 107 | #[structopt(name = "tag", long = "tag", short = "t")] 108 | tag: Option, 109 | }, 110 | #[structopt(name = "rename")] 111 | /// Renames a tag. 112 | Rename { 113 | /// tags for renaming (tag1 -> tag2) 114 | #[structopt(name = "tags", min_values = 2, max_values = 2)] 115 | tags: Vec, 116 | }, 117 | 118 | #[structopt(name = "search")] 119 | /// Searches bookmarks. 120 | Search { 121 | /// Only search within tags, can be combined with other flags. 122 | #[structopt(name = "tags", long = "tags", short = "t")] 123 | tags: bool, 124 | 125 | /// Only search within title field, can be combined with other flags. 126 | #[structopt(name = "title", long = "title", short = "T")] 127 | title: bool, 128 | 129 | /// Only search within description field, can be combined with other flags. 130 | #[structopt(name = "description", long = "description", short = "d")] 131 | description: bool, 132 | 133 | /// Only search within url field, can be combined with other flags. 134 | #[structopt(name = "url", long = "url", short = "u")] 135 | url: bool, 136 | 137 | /// Query string to look for in all fields of bookmarks, unless modified by -t, -T or -u 138 | /// flags (space delimited). Bookmarks that have all of query strings will be 139 | /// returned. 140 | #[structopt(name = "query")] 141 | query: Vec, 142 | }, 143 | 144 | /// Update Workflow's cache by doing a full download from Pinboard. 145 | #[structopt(name = "update")] 146 | Update, 147 | 148 | /// Check for or download the latest version of this workflow 149 | #[structopt(name = "self")] 150 | SelfUpdate { 151 | /// Check if a new version is available 152 | #[structopt(name = "check", short = "c")] 153 | check: bool, 154 | 155 | /// Download the latest version of thir workflow and save it to its cache folder 156 | #[structopt(name = "download", short = "d")] 157 | download: bool, 158 | }, 159 | } 160 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | jobs: 4 | linux: 5 | parameters: 6 | target: 7 | type: string 8 | rust: 9 | type: string 10 | default: 1.42.0 11 | docker: 12 | - image: circleci/rust:stretch 13 | environment: 14 | RUST_BACKTRACE: "1" 15 | CIRCLE_OS_NAME: linux 16 | TARGET: "<< parameters.target >>" 17 | steps: 18 | - run: 19 | name: Install Dependencies 20 | command: | 21 | sudo sh -c 'echo "deb http://deb.debian.org/debian stretch-backports main" > /etc/apt/sources.list.d/backports.list' 22 | sudo apt-get update 23 | sudo apt-get clean 24 | sudo rm -r /var/lib/apt/lists/* 25 | - run: 26 | name: Install Rust "<< parameters.rust >>" 27 | command: 28 | curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain << parameters.rust >> 29 | - run: 30 | name: Add Rust Components 31 | command: | 32 | rustup component add clippy rustfmt 33 | rustc --version; cargo --version; rustup --version 34 | - checkout 35 | - run: 36 | name: Build 37 | command: | 38 | cargo generate-lockfile 39 | .circleci/script.sh 40 | - run: 41 | name: Run clippy & rustfmt 42 | command: | 43 | cargo fmt 44 | cargo clippy --all-targets --all-features -- -D warnings 45 | - persist_to_workspace: 46 | root: /home/circleci 47 | paths: 48 | - project 49 | tests: 50 | parameters: 51 | target: 52 | type: string 53 | rust: 54 | type: string 55 | default: 1.42.0 56 | docker: 57 | - image: circleci/rust:stretch 58 | environment: 59 | RUST_BACKTRACE: "1" 60 | TARGET: "<< parameters.target >>" 61 | CIRCLE_TEST: "true" # change to false to disable tests 62 | PROJECT_BUILD_WORKSPACE: /tmp/apr 63 | CIRCLE_OS_NAME: linux 64 | steps: 65 | # - checkout 66 | - attach_workspace: 67 | at: /tmp/apr 68 | - run: 69 | name: Attched? 70 | command: | 71 | echo $(pwd) 72 | ls /tmp/apr/* 73 | ls /tmp/apr/project || true 74 | - run: 75 | name: Run Tests 76 | command: | 77 | cd /tmp/apr/project 78 | export APR_EXEC=/tmp/apr/project/target/$TARGET/debug/alfred-pinboard-rs 79 | export working_dir=$(pwd) 80 | .circleci/script.sh $APR_EXEC $working_dir 81 | deploy: 82 | description: Deploy to Github from a linux container (not used in any workflows at the moment) 83 | docker: 84 | - image: circleci/golang:1.13 85 | environment: 86 | TARGET: x86_64-unknown-linux-gnu 87 | CIRCLECI_TEST: "false" 88 | steps: 89 | - attach_workspace: 90 | at: /tmp 91 | - checkout 92 | - run: 93 | command: | 94 | go get github.com/tcnksm/ghr 95 | export VERSION=${CIRCLE_TAG} 96 | [ -n ${GITHUB_TOKEN} ] && echo "I have it!" 97 | [ -z ${GITHUB_TOKEN} ] && echo "I DO NOT have it!" 98 | [ -f /tmp/target/alfred-pinboard-rust-${CIRCLE_TAG}.alfredworkflow ] 99 | export artifacts=/tmp/target/alfred-pinboard-rust-${CIRCLE_TAG}.alfredworkflow 100 | echo ${CIRCLE_PROJECT_USERNAME} ${CIRCLE_PROJECT_REPONAME} ${CIRCLE_SHA1} ${VERSION} ${artifacts} 101 | ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION} ${artifacts} 102 | 103 | macosimage: 104 | parameters: 105 | release: 106 | type: boolean 107 | default: false 108 | rust: 109 | type: string 110 | default: 1.42.0 111 | macos: 112 | xcode: "10.0" 113 | environment: 114 | RUST_BACKTRACE: "1" 115 | TARGET: x86_64-apple-darwin 116 | CIRCLE_OS_NAME: macos 117 | GHRELEASER_VERSION: v0.13.0 118 | steps: 119 | - run: 120 | name: Install Rust 121 | command: | 122 | sudo mkdir /opt 123 | curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain << parameters.rust >> 124 | sudo ln -s ~/.cargo/bin/* /usr/local/bin 125 | - run: 126 | name: Rust Version 127 | command: rustc --version; cargo --version; rustup --version 128 | - unless: 129 | condition: << parameters.release >> 130 | steps: 131 | - checkout 132 | - run: 133 | name: Build Debug 134 | command: | 135 | .circleci/script.sh 136 | - run: 137 | name: Running macOS Tests 138 | command: | 139 | export CIRCLE_TEST=true 140 | export APR_EXEC=./target/$TARGET/debug/alfred-pinboard-rs 141 | export working_dir=$(pwd) 142 | .circleci/script.sh $APR_EXEC $working_dir 143 | - when: 144 | condition: << parameters.release >> 145 | steps: 146 | - checkout 147 | - run: 148 | name: Building Release 149 | command: | 150 | export BUILD_TYPE=release 151 | .circleci/script.sh 152 | - run: 153 | name: Building Alfred Workflow Bundle 154 | command: .circleci/before_deploy.sh 155 | - run: 156 | name: Deploying to Github 157 | command: | 158 | export CIRCLE_TEST=false 159 | export VERSION=${CIRCLE_TAG} 160 | .circleci/deploy.sh 161 | 162 | workflows: 163 | linux_x86_64: 164 | jobs: 165 | - linux: 166 | name: Linux-64bit 167 | target: x86_64-unknown-linux-gnu 168 | rust: 1.42.0 169 | filters: 170 | branches: 171 | only: /.*/ 172 | tags: 173 | ignore: /v?[0-9]+.*/ 174 | - tests: 175 | name: Linux-64bit-test 176 | target: x86_64-unknown-linux-gnu 177 | rust: 1.42.0 178 | filters: 179 | branches: 180 | # only: [master, develop] 181 | only: /(master|develop|dependabot.*).*/ 182 | tags: 183 | ignore: /v?[0-9]+.*/ 184 | requires: 185 | - Linux-64bit 186 | 187 | # build-n-test-macos: 188 | # jobs: 189 | # - macosimage: 190 | # name: macOS-64bit 191 | # rust: 1.42.0 192 | # filters: 193 | # branches: 194 | # only: [master, develop] 195 | deploy-to-github: 196 | jobs: 197 | - macosimage: 198 | name: macOS-64bit-release 199 | rust: 1.42.0 200 | release: true 201 | filters: 202 | tags: 203 | only: /v?[0-9]+.*/ 204 | branches: 205 | ignore: /.*/ 206 | # - deploy: 207 | # name: Deploy to Github 208 | # release: true 209 | # requires: 210 | # - macOS-64bit-release 211 | # filters: 212 | # tags: 213 | # only: /v?[0-9]+.*/ 214 | # branches: 215 | # ignore: /.*/ 216 | 217 | -------------------------------------------------------------------------------- /res/workflow/get-current-url.applescript.bak: -------------------------------------------------------------------------------- 1 | on appIsRunning(appName) 2 | tell application "System Events" to (name of processes) contains appName 3 | end appIsRunning 4 | 5 | 6 | on run 7 | set theApplication to (name of (info for (path to frontmost application))) 8 | set theText to "" 9 | set theURL to "" 10 | 11 | if theApplication is "Google Chrome.app" and appIsRunning("Google Chrome") then 12 | set theResult to run script "tell application id \"com.google.chrome\" 13 | set theText to title of active tab of first window 14 | set theURL to get URL of active tab of first window 15 | return {theURL, theText} 16 | end tell" 17 | set theURL to item 1 of theResult 18 | set theText to item 2 of theResult 19 | 20 | else if theApplication is "Opera.app" and appIsRunning("Opera") then 21 | set theResult to run script "tell application id \"com.operasoftware.Opera\" 22 | set theText to title of active tab of first window 23 | set theURL to get URL of active tab of first window 24 | return {theURL, theText} 25 | end tell" 26 | set theURL to item 1 of theResult 27 | set theText to item 2 of theResult 28 | 29 | else if theApplication is "Opera Developer.app" and appIsRunning("Opera") then 30 | set theResult to run script "tell application id \"com.operasoftware.OperaDeveloper\" 31 | set theText to title of active tab of first window 32 | set theURL to get URL of active tab of first window 33 | return {theURL, theText} 34 | end tell" 35 | set theURL to item 1 of theResult 36 | set theText to item 2 of theResult 37 | 38 | else if theApplication is "Opera Beta.pp" and appIsRunning("Opera") then 39 | set theResult to run script "tell application id \"com.operasoftware.OperaNext\" 40 | set theText to title of active tab of first window 41 | set theURL to get URL of active tab of first window 42 | return {theURL, theText} 43 | end tell" 44 | set theURL to item 1 of theResult 45 | set theText to item 2 of theResult 46 | 47 | else if theApplication is "Vivaldi.app" and appIsRunning("Vivaldi") then 48 | set theResult to run script "tell application id \"com.vivaldi.Vivaldi\" 49 | set theText to title of active tab of first window 50 | set theURL to get URL of active tab of first window 51 | return {theURL, theText} 52 | end tell" 53 | set theURL to item 1 of theResult 54 | set theText to item 2 of theResult 55 | 56 | else if theApplication is "Brave Browser.app" and appIsRunning("Brave Browser") then 57 | set theResult to run script "tell application id \"com.brave.Browser\" 58 | set theText to title of active tab of first window 59 | set theURL to get URL of active tab of first window 60 | return {theURL, theText} 61 | end tell" 62 | set theURL to item 1 of theResult 63 | set theText to item 2 of theResult 64 | 65 | else if theApplication is "Brave Browser Beta.app" and appIsRunning("Brave Browser Beta") then 66 | set theResult to run script "tell application id \"com.brave.Browser.beta\" 67 | set theText to title of active tab of first window 68 | set theURL to get URL of active tab of first window 69 | return {theURL, theText} 70 | end tell" 71 | set theURL to item 1 of theResult 72 | set theText to item 2 of theResult 73 | 74 | else if theApplication is "Safari.app" and appIsRunning("Safari") then 75 | set theResult to run script "tell application id \"com.apple.safari\" 76 | set theTab to front document 77 | set theText to name of theTab 78 | set theURL to URL of theTab 79 | return {theURL, theText} 80 | end tell" 81 | set theURL to item 1 of theResult 82 | set theText to item 2 of theResult 83 | 84 | else if {"Safari Technology Preview.app", "SafariTechnologyPreview.app"} contains theApplication and appIsRunning("Safari Technology Preview") then 85 | set theResult to run script "tell application id \"com.apple.SafariTechnologyPreview\" 86 | set theTab to front document 87 | set theText to name of theTab 88 | set theURL to URL of theTab 89 | return {theURL, theText} 90 | end tell" 91 | set theURL to item 1 of theResult 92 | set theText to item 2 of theResult 93 | 94 | else if theApplication is "Chromium.app" and appIsRunning("Chromium") then 95 | set theResult to run script "tell application \"Chromium\" 96 | set theURL to URL of active tab of first window 97 | set theText to title of active tab of first window 98 | return {theURL, theText} 99 | end tell" 100 | set theURL to item 1 of theResult 101 | set theText to item 2 of theResult 102 | 103 | else if theApplication is "qutebrowser.app" and appIsRunning("qutebrowser") then 104 | set theResult to run script "tell application id \"org.qt-project.Qt.QtWebEngineCore\" 105 | activate 106 | end tell 107 | tell application \"System Events\" 108 | set myApp to name of first application process whose frontmost is true 109 | if myApp is \"qutebrowser\" then 110 | set scriptPath to quoted form of \"_path_to_qutebrowser_script_\" 111 | tell application \"System Events\" 112 | keystroke \":spawn --userscript \" & scriptPath & \"/qutebrowser-info.sh\" 113 | key code 36 114 | end tell 115 | end if 116 | end tell 117 | delay 10 118 | set userscriptOutput to get the clipboard 119 | set myList to paragraphs of userscriptOutput 120 | return myList" 121 | set theURL to item 1 of theResult 122 | set theText to item 2 of theResult 123 | 124 | else if theApplication is "Firefox.app" and appIsRunning("Firefox") then 125 | set theResult to run script "tell application id \"org.mozilla.firefox\" 126 | activate 127 | set w to item 1 of window 1 128 | set theText to name of w 129 | end tell 130 | tell application \"System Events\" 131 | set myApp to name of first application process whose frontmost is true 132 | if myApp is \"Firefox\" then 133 | tell application \"System Events\" 134 | key code 97 135 | delay 0.5 136 | keystroke \"c\" using command down 137 | end tell 138 | delay 0.5 139 | end if 140 | delay 0.5 141 | end tell 142 | set theURL to get the clipboard 143 | return {theURL, theText}" 144 | set theURL to item 1 of theResult 145 | set theText to item 2 of theResult 146 | 147 | else if {"Firefox Developer Edition.app", "FirefoxDeveloperEdition.app"} contains theApplication and appIsRunning("Firefox") then 148 | set theResult to run script "tell application id \"org.mozilla.firefoxdeveloperedition\" 149 | activate 150 | set w to item 1 of window 1 151 | set theText to name of w 152 | end tell 153 | tell application \"System Events\" 154 | set myApp to name of first application process whose frontmost is true 155 | if myApp is \"Firefox\" then 156 | tell application \"System Events\" 157 | keystroke \"l\" using command down 158 | delay 0.5 159 | keystroke \"c\" using command down 160 | end tell 161 | delay 0.5 162 | end if 163 | delay 0.5 164 | end tell 165 | set theURL to get the clipboard 166 | return {theURL, theText}" 167 | set theURL to item 1 of theResult 168 | set theText to item 2 of theResult 169 | 170 | end if 171 | 172 | return {theURL & " fd850fc2e63511e79f720023dfdf24ec " & theText} 173 | 174 | end run 175 | -------------------------------------------------------------------------------- /src/workflow_config.rs: -------------------------------------------------------------------------------- 1 | use chrono::prelude::*; 2 | use dirs::home_dir; 3 | use std::fs::{create_dir_all, File}; 4 | use std::io::BufReader; 5 | use std::path::PathBuf; 6 | 7 | use alfred; 8 | use alfred_rs::Data; 9 | use failure::Error; 10 | use serde_json; 11 | 12 | use semver::{Version, VersionReq}; 13 | 14 | use crate::AlfredError; 15 | 16 | pub(crate) const CONFIG_FILE_NAME: &str = "settings.json"; 17 | pub(crate) const CONFIG_KEY_NAME: &str = "settings"; 18 | 19 | const FILE_BUF_SIZE: usize = 4 * 1024 * 1024; 20 | 21 | #[derive(Debug, Serialize, Deserialize)] 22 | pub struct Config { 23 | /// Which version of Alfred we are being executed under 24 | #[serde(skip, default = "get_alfred_version")] 25 | pub alfred_version: Version, 26 | /// Number of bookmarks to show in Alfred 27 | pub pins_to_show: u8, 28 | /// Number of tags to show in Alfred 29 | pub tags_to_show: u8, 30 | /// Flag to perform search only on `tag` fields of bookmarks 31 | pub tag_only_search: bool, 32 | /// Flag to perform a fuzzy search 33 | pub fuzzy_search: bool, 34 | /// Flag to save bookmarks as private 35 | pub private_new_pin: bool, 36 | /// Flag to save bookmarks as toread 37 | pub toread_new_pin: bool, 38 | /// Flag to suggest popular tags for the browser's current url 39 | pub suggest_tags: bool, 40 | /// Flag to check if browser's page is already bookmarked 41 | #[serde(default)] 42 | pub page_is_bookmarked: bool, 43 | /// Flag to show either url or tags of current bookmark 44 | #[serde(default)] 45 | pub show_url_vs_tags: bool, 46 | /// Flag to update cache after each bookmark saving automatically. 47 | pub auto_update_cache: bool, 48 | /// Authentication Token 49 | pub auth_token: String, 50 | /// Last time cache was updated 51 | #[serde(default = "get_epoch")] 52 | pub update_time: DateTime, 53 | 54 | /// Folder to store volatile data of the workflow 55 | workflow_data_dir: PathBuf, 56 | /// Folder to store data of the workflow 57 | workflow_cache_dir: PathBuf, 58 | } 59 | 60 | impl<'a> Config { 61 | pub fn new() -> Self { 62 | debug!("Starting in new"); 63 | let mut cfg = Config { 64 | alfred_version: get_alfred_version(), 65 | pins_to_show: 10, 66 | tags_to_show: 10, 67 | tag_only_search: false, 68 | fuzzy_search: false, 69 | private_new_pin: true, 70 | toread_new_pin: false, 71 | suggest_tags: false, 72 | page_is_bookmarked: true, 73 | auto_update_cache: true, 74 | show_url_vs_tags: true, 75 | auth_token: String::new(), 76 | update_time: get_epoch(), 77 | workflow_data_dir: PathBuf::default(), 78 | workflow_cache_dir: PathBuf::default(), 79 | }; 80 | cfg.discover_dirs(); 81 | cfg 82 | } 83 | 84 | pub fn setup() -> Result { 85 | debug!("Starting in setup"); 86 | let (data_dir, cache_dir) = Config::get_workflow_dirs(); 87 | let config = Config::read(data_dir, cache_dir)?; 88 | Ok(config) 89 | } 90 | 91 | fn read(mut data_dir: PathBuf, cached_dir: PathBuf) -> Result { 92 | debug!("Starting in read"); 93 | data_dir.push(CONFIG_FILE_NAME); 94 | if data_dir.exists() { 95 | let config = Data::load(&data_dir)?; 96 | let config: Result = config 97 | .get(CONFIG_KEY_NAME) 98 | .map_or_else( 99 | || { 100 | // println!("--> Resorting to old config file format."); 101 | File::open(&data_dir) 102 | .map_err(|e| { 103 | let _err: Error = From::from(e); 104 | _err 105 | }) 106 | .and_then(|fp| { 107 | let buf_reader = BufReader::with_capacity(FILE_BUF_SIZE, fp); 108 | serde_json::from_reader(buf_reader) 109 | .map_err(|_| From::from(AlfredError::ConfigFileErr)) 110 | }) 111 | }, 112 | Ok, 113 | ) 114 | .map(|mut c: Config| { 115 | assert!(data_dir.pop()); 116 | c.workflow_data_dir = data_dir; 117 | c.workflow_cache_dir = cached_dir; 118 | c 119 | }); 120 | config 121 | } else { 122 | Err(From::from(AlfredError::MissingConfigFile)) 123 | } 124 | } 125 | 126 | pub fn save(&self) -> Result<(), Error> { 127 | debug!("Starting in save"); 128 | create_dir_all(&self.data_dir())?; 129 | 130 | let mut mydata = Data::load(CONFIG_FILE_NAME)?; 131 | mydata.clear(); 132 | mydata.set(CONFIG_KEY_NAME, self) 133 | } 134 | 135 | pub fn discover_dirs(&mut self) { 136 | debug!("Starting in discover_dirs"); 137 | let dirs = Config::get_workflow_dirs(); 138 | self.workflow_data_dir = dirs.0; 139 | self.workflow_cache_dir = dirs.1; 140 | } 141 | 142 | #[allow(dead_code)] 143 | pub fn cache_dir(&self) -> &PathBuf { 144 | &self.workflow_cache_dir 145 | } 146 | 147 | pub fn data_dir(&self) -> &PathBuf { 148 | &self.workflow_data_dir 149 | } 150 | 151 | pub fn can_use_json(&self) -> bool { 152 | // Alfred v3 & above support reading/writing Items in json format 153 | debug!("Starting in can_use_json"); 154 | let required_version = 155 | VersionReq::parse(">= 3").expect("Couldn't parse >= 3 version string"); 156 | required_version.matches(&self.alfred_version) 157 | } 158 | 159 | fn get_workflow_dirs() -> (PathBuf, PathBuf) { 160 | debug!("Starting in get_workflow_dirs"); 161 | let cache_dir = alfred::env::workflow_cache().unwrap_or_else(|| { 162 | let mut dir = home_dir().unwrap_or_else(|| PathBuf::from("")); 163 | dir.push(".cache"); 164 | dir.push("alfred-pinboard-rs"); 165 | dir 166 | }); 167 | debug!("cache_dir: {}", cache_dir.to_string_lossy()); 168 | if !cache_dir.exists() { 169 | // If we can't create directories, workflow won't be able to work, so we panic! 170 | debug!("creating cache_dir"); 171 | create_dir_all(&cache_dir).unwrap(); 172 | } 173 | let data_dir = alfred::env::workflow_data().unwrap_or_else(|| { 174 | let mut dir = home_dir().unwrap_or_else(|| PathBuf::from("")); 175 | dir.push(".config"); 176 | dir.push("alfred-pinboard-rs"); 177 | dir 178 | }); 179 | debug!("data_dir: {}", data_dir.to_string_lossy()); 180 | if !data_dir.exists() { 181 | // If we can't create directories, workflow won't be able to work, so we panic! 182 | debug!("creating data_dir"); 183 | create_dir_all(&data_dir).unwrap(); 184 | } 185 | 186 | (data_dir, cache_dir) 187 | } 188 | } 189 | 190 | fn get_alfred_version() -> Version { 191 | debug!("Starting in get_alfred_version"); 192 | alfred::env::version().map_or( 193 | Version::parse("2.0.0").expect("Parsing 2.0.0 shouldn't fail"), 194 | |ref s| { 195 | Version::parse(s).unwrap_or_else(|_| { 196 | if s.starts_with("4.") { 197 | Version::parse("4.0.0").expect("Parsing 4.0.0 shouldn't fail") 198 | } else if s.starts_with("3.") { 199 | Version::parse("3.0.0").expect("Parsing 3.0.0 shouldn't fail") 200 | } else { 201 | Version::parse("2.0.0").expect("Parsing 2.0.0 shouldn't fail") 202 | } 203 | }) 204 | }, 205 | ) 206 | } 207 | 208 | fn get_epoch() -> DateTime { 209 | debug!("Starting in get_epoch"); 210 | "1970-01-01T23:00:00Z" 211 | .parse::>() 212 | .expect("Couldn't create UTC epoch time") 213 | } 214 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // #![cfg_attr(feature = "dev", feature(plugin))] 2 | // #![cfg_attr(feature = "dev", plugin(clippy))] 3 | // #![cfg_attr( 4 | // feature = "dev", 5 | // warn( 6 | // cast_possible_truncation, cast_possible_wrap, cast_precision_loss, cast_sign_loss, mut_mut, 7 | // non_ascii_literal, result_unwrap_used, shadow_reuse, shadow_same, unicode_not_nfc, 8 | // wrong_self_convention, wrong_pub_self_convention 9 | // ) 10 | // )] 11 | // #![cfg_attr(feature = "dev", allow(string_extend_chars))] 12 | 13 | extern crate chrono; 14 | 15 | #[macro_use] 16 | extern crate failure; 17 | extern crate dirs; 18 | extern crate semver; 19 | extern crate serde; 20 | 21 | #[macro_use] 22 | extern crate serde_derive; 23 | extern crate serde_json; 24 | 25 | #[macro_use] 26 | extern crate structopt; 27 | // extern crate structopt_derive; 28 | 29 | extern crate env_logger; 30 | 31 | #[macro_use] 32 | extern crate log; 33 | 34 | #[macro_use] 35 | extern crate if_chain; 36 | 37 | extern crate alfred; 38 | extern crate alfred_rs; 39 | extern crate rusty_pin; 40 | 41 | use std::borrow::Cow; 42 | use std::collections::HashMap; 43 | use std::env; 44 | use std::io; 45 | use std::process; 46 | 47 | use alfred_rs::Updater; 48 | use failure::Error; 49 | use rusty_pin::Pinboard; 50 | use structopt::StructOpt; 51 | 52 | mod cli; 53 | mod commands; 54 | mod workflow_config; 55 | 56 | use crate::cli::{Opt, SubCommand}; 57 | use crate::workflow_config::Config; 58 | 59 | use crate::commands::Runner; 60 | // use commands::{config, delete, list, post, search, update}; 61 | use crate::commands::config; 62 | 63 | // TODO: add modifiers to delete commands output // 64 | // TODO: parse Alfred preferences and get number of visible items? // 65 | // TODO: Check for all alfred related env. variables before doing anything else. 66 | // This will prevent unnecessary loading and checking of cache files and then 67 | // panicing due to missing env. variables. 68 | // TODO: running ./alfred-pinboard-rs update from command line panics (starting from 69 | // fetch_latest_release) 70 | // TODO: Make sure that we don't show any json-like error in macOS's notification (check issue#27) 71 | // TODO: check timestamp of cached suggested tags and if it's too old then make a network call 72 | // otherwise use it. 73 | // TODO: add an option to disable/enable update checks 74 | // TODO: Dont show full JSON errors after alfred's window has closed, just send a notification <01-04-20, hamid> // 75 | // TODO: Can we do something about failuse of parsing user's bookmarks or when the network times out 76 | 77 | #[derive(Debug, Fail)] 78 | pub enum AlfredError { 79 | #[fail(display = "Config file may be corrupted")] 80 | ConfigFileErr, 81 | #[fail(display = "Missing config file (did you set API token?)")] 82 | MissingConfigFile, 83 | #[fail(display = "What did you do?")] 84 | Other, 85 | } 86 | 87 | fn main() { 88 | // env::set_var("alfred_workflow_data", "/Volumes/Home/hamid/tmp/rust"); 89 | // env::set_var("alfred_workflow_cache", "/Volumes/Home/hamid/tmp/rust"); 90 | // env::set_var("alfred_workflow_uid", "hamid63"); 91 | // env::set_var("alfred_workflow_name", "alfred-pinboard-rs"); 92 | // env::set_var("alfred_version", "3.6"); 93 | // env::set_var("RUST_LOG", "rusty_pin=debug,alfred_pinboard_rs=debug"); 94 | // If user has Alfred's debug panel open, print all debug info 95 | // by setting RUST_LOG environment variable. 96 | if alfred::env::is_debug() { 97 | env::set_var( 98 | "RUST_LOG", 99 | "rusty_pin=debug,alfred_rs=debug,alfred_pinboard_rs=debug", 100 | ); 101 | } 102 | 103 | env_logger::init(); 104 | 105 | debug!("Parsing input arguments."); 106 | let opt: Opt = Opt::from_args(); 107 | 108 | let pinboard; 109 | let config; 110 | debug!("Deciding on which command branch"); 111 | match opt.cmd { 112 | SubCommand::Config { .. } => config::run(opt.cmd), 113 | _ => { 114 | // If user is not configuring, we will abort upon any errors. 115 | let setup = setup().unwrap_or_else(|err| { 116 | show_error_alfred(err.to_string()); 117 | process::exit(1); 118 | }); 119 | 120 | let mut updater = Updater::gh("spamwax/alfred-pinboard-rs").unwrap(); 121 | 122 | // If running ./alfred-pinboard-rs self -c, we have to make a network call 123 | // We do this by forcing the check interval to be zero 124 | if let SubCommand::SelfUpdate { check, .. } = opt.cmd { 125 | if check { 126 | updater.set_interval(0); 127 | } 128 | } 129 | // updater.set_version("0.13.1"); 130 | // updater.set_interval(60); 131 | updater.init().expect("cannot start updater!"); 132 | 133 | pinboard = setup.1; 134 | config = setup.0; 135 | let mut runner = Runner { 136 | config: Some(config), 137 | pinboard: Some(pinboard), 138 | updater: Some(updater), 139 | }; 140 | match opt.cmd { 141 | SubCommand::Update => { 142 | runner.update_cache(); 143 | } 144 | SubCommand::List { .. } => { 145 | runner.list(opt.cmd); 146 | } 147 | SubCommand::Search { .. } => { 148 | runner.search(opt.cmd); 149 | } 150 | SubCommand::Post { .. } => { 151 | runner.post(opt.cmd); 152 | } 153 | SubCommand::Delete { .. } => { 154 | runner.delete(opt.cmd); 155 | } 156 | SubCommand::SelfUpdate { .. } => { 157 | runner.upgrade(&opt.cmd); 158 | } 159 | SubCommand::Rename { .. } => { 160 | runner.rename(&opt.cmd); 161 | } 162 | _ => unimplemented!(), 163 | } 164 | } 165 | } 166 | } 167 | 168 | fn setup<'a, 'p>() -> Result<(Config, Pinboard<'a, 'p>), Error> { 169 | debug!("Starting in setup"); 170 | let config = Config::setup()?; 171 | let mut pinboard = Pinboard::new(config.auth_token.clone(), alfred::env::workflow_cache())?; 172 | pinboard.enable_fuzzy_search(config.fuzzy_search); 173 | pinboard.enable_tag_only_search(config.tag_only_search); 174 | pinboard.enable_private_new_pin(config.private_new_pin); 175 | pinboard.enable_toread_new_pin(config.toread_new_pin); 176 | 177 | Ok((config, pinboard)) 178 | } 179 | 180 | fn write_to_alfred<'a, 'b, I, J>(items: I, supports_json: bool, vars: Option) 181 | where 182 | I: IntoIterator>, 183 | J: IntoIterator, 184 | { 185 | let exec_counter = env::var("apr_execution_counter").unwrap_or_else(|_| "1".to_string()); 186 | let output_items = items.into_iter().collect::>(); 187 | let mut variables: HashMap<&str, &str> = HashMap::new(); 188 | 189 | variables.insert("apr_execution_counter", exec_counter.as_str()); 190 | if let Some(items) = vars { 191 | items.into_iter().for_each(|(k, v)| { 192 | variables.insert(k, v); 193 | }); 194 | } 195 | 196 | debug!("variables: {:?}", variables); 197 | // Depending on alfred version use either json or xml output. 198 | if supports_json { 199 | alfred::json::Builder::with_items(output_items.as_slice()) 200 | .variables(variables) 201 | .write(io::stdout()) 202 | .expect("Couldn't write items to Alfred"); 203 | } else { 204 | alfred::xml::write_items(io::stdout(), &output_items) 205 | .expect("Couldn't write items to Alfred"); 206 | } 207 | } 208 | fn show_error_alfred<'a, T: Into>>(s: T) { 209 | debug!("Starting in show_error_alfred"); 210 | let item = alfred::ItemBuilder::new("Error") 211 | .subtitle(s) 212 | .icon_path("erroricon.icns") 213 | .into_item(); 214 | alfred::json::write_items(io::stdout(), &[item]).expect("Can't write to stdout"); 215 | std::process::exit(1); 216 | } 217 | 218 | fn alfred_error_item<'a, T: Into>>(s: T) -> alfred::Item<'a> { 219 | debug!("Starting in alfred_error"); 220 | alfred::ItemBuilder::new("Error") 221 | .subtitle(s) 222 | .icon_path("erroricon.icns") 223 | .into_item() 224 | } 225 | -------------------------------------------------------------------------------- /res/workflow/get-current-url.applescript: -------------------------------------------------------------------------------- 1 | on appIsRunning(appName) 2 | set osver to system version of (system info) 3 | considering numeric strings 4 | set catalina to (osver >= "10.15" and osver < "10.16") 5 | end considering 6 | if catalina then 7 | return true 8 | end if 9 | tell application "System Events" to (name of processes) contains appName 10 | -- set processName to run script "tell application \"System Events\" to (name of processes)" 11 | -- set ret to processName contains appName 12 | -- return ret 13 | end appIsRunning 14 | 15 | 16 | on run 17 | set theApplication to (name of (info for (path to frontmost application))) 18 | set theText to "" 19 | set theURL to "" 20 | 21 | if theApplication is "Google Chrome.app" and appIsRunning("Google Chrome") then 22 | set theResult to run script "tell application id \"com.google.chrome\" 23 | set theText to title of active tab of first window 24 | set theURL to get URL of active tab of first window 25 | return {theURL, theText} 26 | end tell" 27 | set theURL to item 1 of theResult 28 | set theText to item 2 of theResult 29 | 30 | else if theApplication is "Opera.app" and appIsRunning("Opera") then 31 | set theResult to run script "tell application id \"com.operasoftware.Opera\" 32 | set theText to title of active tab of first window 33 | set theURL to get URL of active tab of first window 34 | return {theURL, theText} 35 | end tell" 36 | set theURL to item 1 of theResult 37 | set theText to item 2 of theResult 38 | 39 | else if theApplication is "Opera Developer.app" and appIsRunning("Opera") then 40 | set theResult to run script "tell application id \"com.operasoftware.OperaDeveloper\" 41 | set theText to title of active tab of first window 42 | set theURL to get URL of active tab of first window 43 | return {theURL, theText} 44 | end tell" 45 | set theURL to item 1 of theResult 46 | set theText to item 2 of theResult 47 | 48 | else if theApplication is "Opera Beta.pp" and appIsRunning("Opera") then 49 | set theResult to run script "tell application id \"com.operasoftware.OperaNext\" 50 | set theText to title of active tab of first window 51 | set theURL to get URL of active tab of first window 52 | return {theURL, theText} 53 | end tell" 54 | set theURL to item 1 of theResult 55 | set theText to item 2 of theResult 56 | 57 | else if theApplication is "Vivaldi.app" and appIsRunning("Vivaldi") then 58 | set theResult to run script "tell application id \"com.vivaldi.Vivaldi\" 59 | set theText to title of active tab of first window 60 | set theURL to get URL of active tab of first window 61 | return {theURL, theText} 62 | end tell" 63 | set theURL to item 1 of theResult 64 | set theText to item 2 of theResult 65 | 66 | else if theApplication is "Brave Browser.app" and appIsRunning("Brave Browser") then 67 | set theResult to run script "tell application id \"com.brave.Browser\" 68 | set theText to title of active tab of first window 69 | set theURL to get URL of active tab of first window 70 | return {theURL, theText} 71 | end tell" 72 | set theURL to item 1 of theResult 73 | set theText to item 2 of theResult 74 | 75 | else if theApplication is "Brave Browser Beta.app" and appIsRunning("Brave Browser Beta") then 76 | set theResult to run script "tell application id \"com.brave.Browser.beta\" 77 | set theText to title of active tab of first window 78 | set theURL to get URL of active tab of first window 79 | return {theURL, theText} 80 | end tell" 81 | set theURL to item 1 of theResult 82 | set theText to item 2 of theResult 83 | 84 | else if theApplication is "Safari.app" and appIsRunning("Safari") then 85 | set theResult to run script "tell application id \"com.apple.safari\" 86 | set theTab to front document 87 | set theText to name of theTab 88 | set theURL to URL of theTab 89 | return {theURL, theText} 90 | end tell" 91 | set theURL to item 1 of theResult 92 | set theText to item 2 of theResult 93 | 94 | else if {"Safari Technology Preview.app", "SafariTechnologyPreview.app"} contains theApplication and appIsRunning("Safari Technology Preview") then 95 | set theResult to run script "tell application id \"com.apple.SafariTechnologyPreview\" 96 | set theTab to front document 97 | set theText to name of theTab 98 | set theURL to URL of theTab 99 | return {theURL, theText} 100 | end tell" 101 | set theURL to item 1 of theResult 102 | set theText to item 2 of theResult 103 | 104 | else if theApplication is "Chromium.app" and appIsRunning("Chromium") then 105 | set theResult to run script "tell application \"Chromium\" 106 | set theURL to URL of active tab of first window 107 | set theText to title of active tab of first window 108 | return {theURL, theText} 109 | end tell" 110 | set theURL to item 1 of theResult 111 | set theText to item 2 of theResult 112 | 113 | else if theApplication is "Microsoft Edge.app" and appIsRunning("Microsoft Edge") then 114 | set theResult to run script "tell application id \"com.microsoft.edgemac\" 115 | set theText to title of active tab of first window 116 | set theURL to get URL of active tab of first window 117 | return {theURL, theText} 118 | end tell" 119 | set theURL to item 1 of theResult 120 | set theText to item 2 of theResult 121 | 122 | else if theApplication is "qutebrowser.app" and appIsRunning("qutebrowser") then 123 | set theResult to run script "tell application id \"org.qt-project.Qt.QtWebEngineCore\" 124 | activate 125 | end tell 126 | tell application \"System Events\" 127 | set myApp to name of first application process whose frontmost is true 128 | end tell 129 | if myApp is \"qutebrowser\" then 130 | tell application \"System Events\" 131 | key code 53 -- ESC 132 | delay 0.5 133 | end tell 134 | tell application \"System Events\" -- yank url 135 | keystroke \"y\" 136 | delay 0.4 137 | keystroke \"y\" 138 | end tell 139 | delay 0.5 140 | set theURL to (get the clipboard as Unicode text) 141 | 142 | tell application \"System Events\" -- yank title 143 | keystroke \"y\" 144 | delay 0.4 145 | keystroke \"t\" 146 | end tell 147 | delay 0.5 148 | set theTitle to (the clipboard as Unicode text) 149 | end if 150 | do shell script \"pbcopy < /dev/null\" 151 | return {theURL, theTitle}" 152 | set theURL to item 1 of theResult 153 | set theText to item 2 of theResult 154 | 155 | else if theApplication is "Firefox.app" and appIsRunning("Firefox") then 156 | set theResult to run script "tell application id \"org.mozilla.firefox\" 157 | activate 158 | set w to item 1 of window 1 159 | set theText to name of w 160 | end tell 161 | tell application \"System Events\" 162 | set myApp to name of first application process whose frontmost is true 163 | if myApp is \"Firefox\" then 164 | tell application \"System Events\" 165 | key code 97 166 | delay 0.5 167 | keystroke \"c\" using command down 168 | end tell 169 | delay 0.5 170 | end if 171 | delay 0.5 172 | end tell 173 | set theURL to get the clipboard 174 | return {theURL, theText}" 175 | set theURL to item 1 of theResult 176 | set theText to item 2 of theResult 177 | 178 | else if {"Firefox Developer Edition.app", "FirefoxDeveloperEdition.app"} contains theApplication and appIsRunning("Firefox") then 179 | set theResult to run script "tell application id \"org.mozilla.firefoxdeveloperedition\" 180 | activate 181 | set w to item 1 of window 1 182 | set theText to name of w 183 | end tell 184 | tell application \"System Events\" 185 | set myApp to name of first application process whose frontmost is true 186 | if myApp is \"Firefox\" then 187 | tell application \"System Events\" 188 | keystroke \"l\" using command down 189 | delay 0.5 190 | keystroke \"c\" using command down 191 | end tell 192 | delay 0.5 193 | end if 194 | delay 0.5 195 | end tell 196 | set theURL to get the clipboard 197 | return {theURL, theText}" 198 | set theURL to item 1 of theResult 199 | set theText to item 2 of theResult 200 | 201 | end if 202 | 203 | return {theURL & " fd850fc2e63511e79f720023dfdf24ec " & theText} 204 | 205 | end run 206 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CircleCI](https://circleci.com/gh/spamwax/alfred-pinboard-rs.svg?style=svg)](https://circleci.com/gh/spamwax/alfred-pinboard-rs) 2 | [![Build status](https://ci.appveyor.com/api/projects/status/3g5uvuocs52yc444/branch/master?svg=true)](https://ci.appveyor.com/project/spamwax/alfred-pinboard-rs/branch/master) 3 | 4 | 5 | # Alfred Workflow for Pinboard 6 | 7 | 8 | Manage, post and **preview** your bookmarks on [Pinboard](https://pinboard.in) right from within [Alfred app](https://www.alfredapp.com). 9 | ### Important: [Update & Support for Alfred 3 Users](#alfred_3_support) 10 | ### Alfred 4: If upgrading workflow from `0.14.14` or before, you may have to directly [download](https://github.com/spamwax/alfred-pinboard-rs/releases/latest) latest version and then open it in Finder 11 | 12 | ## Features 13 | Pinboard is a great and reliable bookmarking service. Its [front page](https://pinboard.in) sums it all: 14 | "**Social Bookmarking for Introverts. Pinboard is a fast, no-nonsense bookmarking site.**" 15 | 16 | This plugin will let you: 17 | 18 | - _**post**_ a bookmark to Pinboard right from Alfred, with: 19 | - Fetching bookmark information from active browser's window 20 | - _tag_ auto-completion to show your current tags. 21 | - _popular_ tags for the current _url_ 22 | - and more ... 23 | - _**search**_ your current bookmarks 24 | - Tap Shift to show a preview of selected item without opening browser. 25 | - Tap Command+L to show _Large_ toast of title 26 | - Tap Command to show current item's _tags_ 27 | - Tap Control to show current item's extended notes/descriptioin. 28 | - Automatic [updates](#misc) of workflow 29 | - Many options that can be easily adjusted. (see below) 30 | 31 | ### TLDR; 32 | After initial [setup](#installation--setup): 33 | - For posting you just need to enter the Workflow's keyword ( `p` ) into Alfred's window and follow it with couple of tags and an optional description. The workflow will then post a bookmark for the window/tab of the active browser to Pinboard. 34 | 35 | - For searching, use ( `ps` ) and then type the search keywords. 36 | 37 | ### Supported Browsers: 38 | - Safari 39 | - Chromium 40 | - Firefox (See [known issues](#known_issues) ) 41 | - Opera 42 | - Vivaldi 43 | - Brave 44 | - qutebrowser (See [known issues](#known_issues) ) 45 | - Firefox Dev. Edition 46 | - Safari Tech. Preview 47 | - Chrome 48 | 49 | ## Installation / Setup 50 | After [downloading](https://github.com/spamwax/alfred-pinboard-rs/releases/latest) the latest version of the workflow and installing it in Alfred, you need to do a one-time setup to authenticate the Workflow. This Workflow only uses username/token method so you won't need to enter your password. (This is the *suggested* way of using Pinboard's API). 51 | If you don't have a token, get one from Pinbaord's [setting's page](https://pinboard.in/settings/password). 52 | 53 | Then invoke Alfred and enter your username:token after the ***"pa"*** keyword: 54 | 55 | ![image](./res/images/authentication.png) 56 | 57 | This workflow will keep a local cache of the tags and bookmarks that you have in Pinboard, and, by default, automatically update the cache. (See [manual updates](#cache_update) ) 58 | 59 | --- 60 | 61 | ## Usage (post a bookmark): 62 | The syntax to post a bookmark to Pinboard is : 63 | 64 | ``` 65 | p tag1 tag2 tag3 ; some optional note (semi-colon & note are optional) 66 | ``` 67 | 68 | The workflow will show a list of your current tags as you are typing: 69 | 70 | ![image](./res/images/non-fuzzy-search-tags.png) 71 | 72 | The number below each tag shows how many times you have used it in Pinboard bookmarks. 73 | You can move Alfred's highlighter to the desired tag and hit '**Tab**' to **autocomplete** it. 74 | 75 | To finish the process just press Enter. 76 | 77 | - If tag suggestion feature is enabled (see `pset suggest_tags`), 3 popular tags based on current active webpage will be added to the list of your tags. The list is fetched from Pinboard's API and is often helpful. However this feature will add a 1 second delay to showing the tag list after first keystroke. This delay is disabled for consequent keystrokes as the fetched popular tags are cached. 78 | 79 | ![image](./res/images/popular-tags.png) 80 | 81 | #### Modifiers (Control ⌃, Option ⌥) 82 | You can hold down modifiers to one-time change some of your settings: 83 | 84 | - Control ⌃ : will toggle `toread` setting momentarily. 85 | - Option ⌥ : will toggle `shared` setting momentarily. 86 | 87 | 88 | After entering last desired tag, you can hit enter to post the bookmark. 89 | If you want to add extra description to the bookmark you can add it after a semi-colon: 90 | 91 | ![image](./res/images/adding-notes.png) 92 | 93 | #### Already saved bookmark 94 | If the current page is already saved, you will be notified. However the workflow assumes that: 95 | 96 | - `http://example.com/list.html` 97 | - `https://example.com/list.html` 98 | - `http://example.com/list.html#fragment` 99 | 100 | are all different bookmarks and will not notify you about duplication! 101 | 102 | ![image](./res/images/already-saved.png) 103 | 104 | --- 105 | 106 | ## Usage (search bookmarks): 107 | Searching your bookmarks is easy. 108 | 109 | ``` 110 | ps query1 query2 query3 ... 111 | ``` 112 | 113 | Workflow will use the text you enter in Alfred and show list of bookmarks that contain **all** of the search keywords in any of the bookmarks information (Description of bookmark, its tags, its url and its extended notes). However, these search fields can be adjusted, see [settings](#config). 114 | 115 | So **the more** search keywords you enter **the less** results will be displayed as it tries to find the bookmarks that contain ***all*** of the keywords. 116 | 117 | The search result is ordered in descending order of dates they were posted to your Pinboard account. 118 | 119 | ![image](./res/images/bookmarks-search-results.png) 120 | 121 | To show tags (instead of URLS) in search results subtitles, use `pset url_tag`: 122 | 123 | ![image](./res/images/url_vs_tag.png) 124 | 125 | #### Modifier keys (Command ⌘, Control ⌃, Option ⌥) 126 | You can hold down modifiers to enable different behavior: 127 | 128 | - Control ⌃ : will show the extended description of selected bookmark. 129 | - Command ⌘ : will show tags of selected bookmark. 130 | - Option ⌥ : Holding `⌥` and pressing enter will open the bookmark in [Pinboard's website](https://pinboard.in). 131 | - Command ⌘ + Option ⌥ : Hitting Return ⏎ key with these combo modifiers will copy the bookmark's URL to clipboard. 132 | - Shift ⇧: **Tap** ⇧ to load a preview of bookmark without opening your browser 😎 ⤵︎ 133 | 134 | ![image](./res/images/quicklook-preview.png) 135 | 136 | --- 137 | 138 | ## Usage (delete a bookmark): 139 | ``` 140 | pind 141 | ``` 142 | 143 | To delete a bookmark, just make sure it is opened in your current browser's window. Then use `pind`. 144 | Proposed workflow for deleting a bookmark is to first open it in browser (search for it using this workflow's keyword `ps`, and hit enter) and then use `pind` keyword followed by enter. 145 | 146 | ![image](./res/images/delete-pin.png) 147 | 148 | ## Usage (rename a tag): 149 | ``` 150 | pr old_tag new_tag 151 | ``` 152 | 153 | **Note:** Pinboard tag renaming API lacks providing error message if `old_tag` is not in your tag collection!!! It basically says `success` even though no renaming was done! 154 | 155 | 156 | ## Settings 157 | 158 | You can configure the behavior of workflow by entering `pconf` in Alfred: 159 | 160 | ![image](./res/images/configuration.png) 161 | 162 | Selecting each setting and hitting ⏎ (Enter) will let you adjust it: 163 | 164 | ![image](./res/images/set-fuzzy.png) 165 | 166 | On top of using `pconf`, you can directly type following commands to also adjust the settings: 167 | 168 | - `pset fuzzy`: Enable/disable fuzzy search. 169 | - `pset suggest_tags`: When posting a new bookmark, list popular tags for the active page. Note that this information is fetched from Pinboard and sometimes is not very _accurate_. 170 | - `pset shared`: Mark all new bookmarks as _shared_. 171 | - `pset toread`: Mark all new bookmarks as _toread_. 172 | - `pset check_bookmarked`: Notify if active page is already bookmarked. 173 | - `pset tagonly`: Only search within _tag_ field while doing any look-up. 174 | - `pset auto`: After posting a new bookmark, automatically update the local cache. 175 | - `pset tags`: Set number of tags to show: `pset tags 25` 176 | - `pset bookmarks`: Set number of bookmarks to show: `pset bookmarks 12` 177 | - `pset url_tag`: Show either URLs or tags in search results subtitles 178 | 179 | ### Manual cache update 180 | 181 | To manually update the cache, you need to issue the ***`pu`*** command: 182 | 183 | ![image](./res/images/update.png) 184 | 185 | --- 186 | 187 | Most of configuration settings are self-explanatory. However `fuzzy` search may need a demo. 188 | 189 | When fuzzy search is enabled, the tags/bookmarks that contain the query letters in the given order are displayed: 190 | 191 | ![image](./res/images/fuzzy-search-tags.png) 192 | 193 | Otherwise, _normal_ search will search for consecutive characters in query: 194 | 195 | ![image](./res/images/non-fuzzy-search-tags.png) 196 | 197 | --- 198 | 199 | ## Misc. 200 | - Workflow will check for newever version of itself every 24 hours. This check only takes place when you actually use one of its keywords (no background service is ever used). You can also manually check for updates using `pcheck`. 201 | 202 | ![image](./res/images/upgrade_available.png) 203 | 204 | - This workflow tries to show some helpful errors in different cases. 205 | 206 | ![image](./res/images/error-1.png) 207 | ![image](./res/images/error-2.png) 208 | ![image](./res/images/error-3.png) 209 | 210 | - If you want to change some behavior take a look at Alfred's workflow page: 211 | 212 | ![image](./res/images/workflow-screenshot.png) 213 | 214 | --- 215 | 216 | ## Known Issues 217 | - **Firefox**: While tag suggestions and "Check if page is bookmarked" options are enabled, posting bookmark from Firefox is broken. Deleting bookmarks using `pind` won't work when Firefox is your active browser. Reason: Firefox does not properly support interacting with it programatically. 218 | - This workflow is setup to work with Aflred 4. It may or may not work with previous version as it has not been tested for them. 219 | 220 | ## Alfred 3 Support & Issues 221 | - Alfred 4 has made some changes to internal structure of workflows. Therefore if you updated this workflow through the built-in *automatic update*, it's very *likely* that it'll stop working. If that happens, you can fix it by first deleteing & then re-installing the workflow by [downloading the last version (0.14.11)](https://github.com/spamwax/alfred-pinboard-rs/releases/tag/0.14.11) that has Alfred 3 format. 222 | - Moving forward, new features, changes & bug fixes will first target Alfred 4 users and then (time permitting) will be ported back to Alfred 3. 223 | 224 | ## TODO 225 | 226 | I wish to add the following in the coming releases: 227 | 228 | - ~~Let users delete a selected bookmark from witin Alfred.~~ 229 | - ~~Add a proper logging facility to Rust code.~~ (uses log_env) 230 | - ~~Use a better error mechanism (maybe [failure](https://crates.io/crates/failure)?)~~ 231 | 232 | ## Feedback / Bugs 233 | This is my first non-trivial project using Rust language so so your [feedback or bug](https://github.com/spamwax/alfred-pinboard-rs/compare) reports are greatly appreciated. 234 | 235 | ## License 236 | This open source software is licensed under [MIT License](./LICENSE.md). 237 | -------------------------------------------------------------------------------- /src/commands/list.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use std::{thread, time}; 3 | 4 | use alfred::{Item, ItemBuilder, Modifier}; 5 | use alfred_rs::Data; 6 | use failure::Error; 7 | 8 | impl<'api, 'pin> Runner<'api, 'pin> { 9 | pub fn list(&self, cmd: SubCommand) { 10 | match cmd { 11 | SubCommand::List { 12 | tags, 13 | suggest, 14 | query, 15 | } => self.process(tags, suggest, query), 16 | _ => unreachable!(), 17 | } 18 | } 19 | 20 | fn process(&self, tags: bool, suggest: Option, q: Option) { 21 | debug!("Starting in list::process"); 22 | let config = self.config.as_ref().unwrap(); 23 | let pinboard = self.pinboard.as_ref().unwrap(); 24 | 25 | let private_pin = (!config.private_new_pin).to_string(); 26 | let toread_pin = config.toread_new_pin.to_string(); 27 | let option_subtitle = if config.private_new_pin { 28 | "Post the bookmark as PUBLIC." 29 | } else { 30 | "Post the bookmark as private." 31 | }; 32 | let control_subtitle = if config.toread_new_pin { 33 | "Mark the pin as NOT toread." 34 | } else { 35 | "Mark the pin as TOREAD." 36 | }; 37 | 38 | if tags { 39 | // Search the tags using the last 'word' in 'q' 40 | let queries = q.unwrap_or_else(String::new); 41 | 42 | // Check if user has entered ';' which indicates they are providing a description. 43 | // So no need to search for tags! 44 | if queries.contains(';') { 45 | let trim_chars: &[_] = &['\t', ' ', '\\', '\n']; 46 | let pin_info = queries 47 | .splitn(2, ';') 48 | .map(|s| s.trim_matches(trim_chars)) 49 | .collect::>(); 50 | debug!(" pin_info: {:?}", pin_info); 51 | let mut item = ItemBuilder::new("Hit Return to bookmark the page!") 52 | .icon_path("upload.png") 53 | .arg(queries.as_str()) 54 | .variable("shared", private_pin) 55 | .variable("toread", toread_pin) 56 | .variable("tags", pin_info[0]) 57 | .subtitle_mod(Modifier::Option, option_subtitle) 58 | .subtitle_mod(Modifier::Control, control_subtitle); 59 | if !pin_info[1].is_empty() { 60 | item = item.variable("description", pin_info[1]) 61 | } 62 | let item = vec![item.into_item()]; 63 | if let Err(e) = self.write_output_items(item) { 64 | error!("list: Couldn't write to Alfred: {:?}", e); 65 | } 66 | return; 67 | } 68 | 69 | let query_words: Vec<&str> = queries.split_whitespace().collect(); 70 | 71 | let last_query_word_tag; 72 | let mut popular_tags; 73 | let mut alfred_items = Vec::with_capacity(config.tags_to_show as usize + 1); 74 | 75 | // First try to get list of popular tags from Pinboard 76 | let tag_suggestion = suggest.unwrap_or(config.suggest_tags); 77 | popular_tags = if tag_suggestion { 78 | // if suggest.unwrap_or(config.suggest_tags) { 79 | suggest_tags() 80 | } else { 81 | vec![] 82 | }; 83 | 84 | let last_query_word = query_words.last().unwrap_or(&""); 85 | 86 | match pinboard.search_list_of_tags(last_query_word) { 87 | Err(e) => crate::show_error_alfred(e.to_string()), 88 | Ok(results) => { 89 | let prev_tags = if query_words.len() > 1 { 90 | // User has already searched for other tags, we should include those in the 91 | // 'autocomplete' field of the AlfredItem 92 | queries.get(0..=queries.rfind(' ').unwrap()).unwrap() 93 | } else { 94 | "" 95 | }; 96 | 97 | // No result means, we couldn't find a tag using the given query 98 | // Some result mean we found tags even though the query was empty as 99 | // search_list_of_tags returns all tags for empty queries. 100 | let items = match results { 101 | Some(i) => { 102 | debug!("Found {} tags.", i.len()); 103 | i 104 | } 105 | None => { 106 | assert!(!query_words.is_empty()); 107 | debug!("Didn't find any tag for `{}`", last_query_word); 108 | last_query_word_tag = 109 | Tag::new((*last_query_word).to_string(), 0).set_new(); 110 | vec![&last_query_word_tag] 111 | } 112 | }; 113 | let prev_tags_len = prev_tags.len(); 114 | // Show the tag with highest frequency matching the last query before popular/suggested tags. 115 | popular_tags.insert(0, items[0].clone()); 116 | alfred_items = popular_tags 117 | .iter() 118 | // Combine popular tags and returned tags from cache 119 | .chain(items.into_iter().skip(1).take(config.tags_to_show as usize)) 120 | // Remove tags that user has already selected 121 | .filter(|tag| { 122 | if !query_words.is_empty() { 123 | let upper = query_words.len() - 1; 124 | !query_words.as_slice()[0..upper] 125 | .iter() 126 | .any(|q| q == &tag.0.as_str()) 127 | } else { 128 | true 129 | } 130 | }) 131 | // transform tags to Alfred items 132 | .map(|tag| { 133 | let mut _args = String::with_capacity(prev_tags_len + tag.0.len()); 134 | _args.push_str(prev_tags); 135 | _args.push_str(&tag.0); 136 | ItemBuilder::new(tag.0.as_str()) 137 | .subtitle(tag.1.to_string()) 138 | .autocomplete(_args.clone()) 139 | .subtitle_mod(Modifier::Option, option_subtitle) 140 | .subtitle_mod(Modifier::Control, control_subtitle) 141 | .variable("tags", _args.clone()) 142 | .variable("shared", &private_pin) 143 | .variable("toread", &toread_pin) 144 | .arg(_args) 145 | .valid(true) 146 | .icon_path("tag.png") 147 | .into_item() 148 | }) 149 | .collect::>(); 150 | } 151 | } 152 | if config.page_is_bookmarked && is_page_bookmarked(&pinboard) { 153 | let bookmark_present = ItemBuilder::new("You already have the bookmark!") 154 | .icon_path("bookmark-delete.png") 155 | .into_item(); 156 | alfred_items.insert(0, bookmark_present); 157 | } 158 | if let Err(e) = self.write_output_items(alfred_items) { 159 | error!("list: Couldn't write to Alfred: {:?}", e); 160 | } 161 | } else { 162 | if q.is_some() && !q.unwrap().is_empty() { 163 | warn!( 164 | "Ignoring search query, will spit out {} of bookmarks.", 165 | config.pins_to_show 166 | ) 167 | } 168 | let items = pinboard 169 | .list_bookmarks() 170 | .unwrap_or_else(|| vec![]) 171 | .into_iter() 172 | .take(config.pins_to_show as usize) 173 | .map(|pin| { 174 | ItemBuilder::new(pin.title.as_ref()) 175 | .subtitle(pin.url.as_ref()) 176 | .arg(pin.url.as_ref()) 177 | .into_item() 178 | }) 179 | .collect::>(); 180 | if let Err(e) = self.write_output_items(items) { 181 | error!("list: Couldn't write to Alfred: {:?}", e); 182 | } 183 | } 184 | } 185 | } 186 | 187 | fn is_page_bookmarked(pinboard: &Pinboard) -> bool { 188 | let found; 189 | 190 | let exec_counter = env::var("apr_execution_counter") 191 | .unwrap_or_else(|_| "1".to_string()) 192 | .parse::() 193 | .unwrap_or(1); 194 | debug!("exec_counter: {}", exec_counter); 195 | 196 | if exec_counter == 1 { 197 | let tab_info = browser_info::get(); 198 | found = match tab_info { 199 | Ok(tab_info) => { 200 | debug!("tab_info: {:?}", tab_info); 201 | pinboard 202 | .find_url(&tab_info.url) 203 | .and_then(|op| { 204 | if let Some(vp) = op { 205 | assert!(!vp.is_empty()); 206 | Ok(!vp.is_empty()) 207 | } else { 208 | Ok(false) 209 | } 210 | }) 211 | .unwrap_or(false) 212 | } 213 | Err(_) => false, 214 | }; 215 | let _ = Data::save_to_file("bookmark_exists.json", &found); 216 | debug!("bookmark found from browser info: {}", found); 217 | } else { 218 | found = Data::load_from_file("bookmark_exists.json").unwrap_or(false); 219 | debug!("bookmark found from cache info: {}", found); 220 | } 221 | found 222 | } 223 | 224 | fn suggest_tags() -> Vec { 225 | let mut popular_tags = vec![]; 226 | let exec_counter = env::var("apr_execution_counter") 227 | .unwrap_or_else(|_| "1".to_string()) 228 | .parse::() 229 | .unwrap_or(1); 230 | 231 | use std::sync::mpsc; 232 | let (tx, rx) = mpsc::channel(); 233 | let thread_handle = thread::spawn(move || { 234 | warn!("inside spawn thread, about to call get_suggested_tags"); 235 | let r = retrieve_popular_tags(exec_counter); 236 | if let Ok(pt) = r { 237 | let tx_result = tx.send(pt); 238 | match tx_result { 239 | Ok(_) => warn!("Sent the popular tags from child thread"), 240 | Err(e) => warn!("Failed to send popular tags: {:?}", e), 241 | } 242 | } else { 243 | warn!("get_suggested_tags: {:?}", r); 244 | } 245 | }); 246 | if exec_counter == 1 { 247 | thread::sleep(time::Duration::from_millis(1000)); 248 | } else { 249 | thread_handle.join().expect("Child thread terminated"); 250 | } 251 | 252 | if let Ok(pt) = rx.try_recv() { 253 | warn!("* received popular tags from child: {:?}", pt); 254 | popular_tags = pt; 255 | } else { 256 | warn!("child didn't produce usable result."); 257 | } 258 | 259 | popular_tags 260 | } 261 | /// Retrieves popular tags from a Web API call for first run and caches them for subsequent runs. 262 | fn retrieve_popular_tags(exec_counter: usize) -> Result, Error> { 263 | debug!("Starting in get_suggested_tags"); 264 | 265 | // TODO: Don't create another pinboard instance. use the one list.rs receives to be shared with 266 | // the thread that runs this function. 267 | // FIXME: If run from outside Alfred (say terminal), 268 | // the cache folder for 'config' and 'pinboard' will be different. 269 | let config = Config::setup()?; 270 | let pinboard = Pinboard::new(config.auth_token, alfred::env::workflow_cache())?; 271 | 272 | // let ptags_fn = config.cache_dir().join("popular.tags.cache"); 273 | let ptags_fn = "popular.tags.cache"; 274 | let tags; 275 | // let metadata = fs::metadata("foo.txt")?; 276 | 277 | // if let Ok(time) = metadata.created() { 278 | // println!("{:?}", time); 279 | // } else { 280 | // println!("Not supported on this platform"); 281 | // } 282 | if exec_counter == 1 { 283 | let tab_info = browser_info::get()?; 284 | warn!("tab_info.url: {:?}", tab_info.url); 285 | tags = match pinboard.popular_tags(&tab_info.url) { 286 | Err(e) => vec![format!("ERROR: fetching popular tags: {:?}", e)], 287 | Ok(tags) => tags, 288 | }; 289 | info!("popular tags: {:?}", tags); 290 | Data::save_to_file(&ptags_fn, &tags)?; 291 | } else { 292 | warn!( 293 | "**** reading suggested tags from cache file: {:?}", 294 | ptags_fn 295 | ); 296 | use failure::err_msg; 297 | tags = Data::load_from_file(ptags_fn) 298 | .map_or(Err(err_msg("bad popular tags cache file")), Ok)?; 299 | } 300 | Ok(tags 301 | .into_iter() 302 | .map(|t| Tag::new(t, 0).set_popular()) 303 | .collect::>()) 304 | } 305 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "adler32" 5 | version = "1.0.4" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" 8 | 9 | [[package]] 10 | name = "aho-corasick" 11 | version = "0.6.10" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" 14 | dependencies = [ 15 | "memchr", 16 | ] 17 | 18 | [[package]] 19 | name = "aho-corasick" 20 | version = "0.7.10" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" 23 | dependencies = [ 24 | "memchr", 25 | ] 26 | 27 | [[package]] 28 | name = "alfred" 29 | version = "4.0.2" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "55e70f873d24b2638c6641064dc884c6f5509c14e2975102e7f751a71c53700c" 32 | dependencies = [ 33 | "serde_json", 34 | ] 35 | 36 | [[package]] 37 | name = "alfred-pinboard-rs" 38 | version = "0.15.12" 39 | dependencies = [ 40 | "alfred", 41 | "alfred-rs", 42 | "chrono", 43 | "dirs 2.0.2", 44 | "env_logger 0.7.1", 45 | "failure", 46 | "if_chain", 47 | "log", 48 | "rusty-pin", 49 | "semver", 50 | "serde", 51 | "serde_derive", 52 | "serde_json", 53 | "structopt", 54 | ] 55 | 56 | [[package]] 57 | name = "alfred-rs" 58 | version = "0.5.1" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "ea6c6080390910d2cc55f1d4a4ad7c986bb55b0402620469602702115a5dfbd8" 61 | dependencies = [ 62 | "alfred", 63 | "chrono", 64 | "env_logger 0.6.2", 65 | "failure", 66 | "log", 67 | "reqwest 0.8.8", 68 | "semver", 69 | "serde", 70 | "serde_derive", 71 | "serde_json", 72 | "tempfile", 73 | "time", 74 | "url 1.7.2", 75 | "url_serde", 76 | ] 77 | 78 | [[package]] 79 | name = "ansi_term" 80 | version = "0.11.0" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 83 | dependencies = [ 84 | "winapi 0.3.8", 85 | ] 86 | 87 | [[package]] 88 | name = "arrayref" 89 | version = "0.3.6" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 92 | 93 | [[package]] 94 | name = "arrayvec" 95 | version = "0.5.1" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" 98 | 99 | [[package]] 100 | name = "atty" 101 | version = "0.2.14" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 104 | dependencies = [ 105 | "hermit-abi", 106 | "libc", 107 | "winapi 0.3.8", 108 | ] 109 | 110 | [[package]] 111 | name = "autocfg" 112 | version = "0.1.7" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" 115 | 116 | [[package]] 117 | name = "autocfg" 118 | version = "1.0.0" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 121 | 122 | [[package]] 123 | name = "backtrace" 124 | version = "0.3.46" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e" 127 | dependencies = [ 128 | "backtrace-sys", 129 | "cfg-if", 130 | "libc", 131 | "rustc-demangle", 132 | ] 133 | 134 | [[package]] 135 | name = "backtrace-sys" 136 | version = "0.1.35" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118" 139 | dependencies = [ 140 | "cc", 141 | "libc", 142 | ] 143 | 144 | [[package]] 145 | name = "base64" 146 | version = "0.9.3" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" 149 | dependencies = [ 150 | "byteorder", 151 | "safemem", 152 | ] 153 | 154 | [[package]] 155 | name = "base64" 156 | version = "0.10.1" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" 159 | dependencies = [ 160 | "byteorder", 161 | ] 162 | 163 | [[package]] 164 | name = "base64" 165 | version = "0.11.0" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" 168 | 169 | [[package]] 170 | name = "bitflags" 171 | version = "0.9.1" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" 174 | 175 | [[package]] 176 | name = "bitflags" 177 | version = "1.2.1" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 180 | 181 | [[package]] 182 | name = "blake2b_simd" 183 | version = "0.5.10" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" 186 | dependencies = [ 187 | "arrayref", 188 | "arrayvec", 189 | "constant_time_eq", 190 | ] 191 | 192 | [[package]] 193 | name = "byteorder" 194 | version = "1.3.4" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" 197 | 198 | [[package]] 199 | name = "bytes" 200 | version = "0.4.12" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" 203 | dependencies = [ 204 | "byteorder", 205 | "either", 206 | "iovec", 207 | ] 208 | 209 | [[package]] 210 | name = "cc" 211 | version = "1.0.50" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" 214 | 215 | [[package]] 216 | name = "cfg-if" 217 | version = "0.1.10" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 220 | 221 | [[package]] 222 | name = "chrono" 223 | version = "0.4.11" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" 226 | dependencies = [ 227 | "num-integer", 228 | "num-traits", 229 | "serde", 230 | "time", 231 | ] 232 | 233 | [[package]] 234 | name = "clap" 235 | version = "2.33.0" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" 238 | dependencies = [ 239 | "ansi_term", 240 | "atty", 241 | "bitflags 1.2.1", 242 | "strsim", 243 | "textwrap", 244 | "unicode-width", 245 | "vec_map", 246 | ] 247 | 248 | [[package]] 249 | name = "cloudabi" 250 | version = "0.0.3" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 253 | dependencies = [ 254 | "bitflags 1.2.1", 255 | ] 256 | 257 | [[package]] 258 | name = "constant_time_eq" 259 | version = "0.1.5" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 262 | 263 | [[package]] 264 | name = "cookie" 265 | version = "0.12.0" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" 268 | dependencies = [ 269 | "time", 270 | "url 1.7.2", 271 | ] 272 | 273 | [[package]] 274 | name = "cookie_store" 275 | version = "0.7.0" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c" 278 | dependencies = [ 279 | "cookie", 280 | "failure", 281 | "idna 0.1.5", 282 | "log", 283 | "publicsuffix", 284 | "serde", 285 | "serde_json", 286 | "time", 287 | "try_from", 288 | "url 1.7.2", 289 | ] 290 | 291 | [[package]] 292 | name = "core-foundation" 293 | version = "0.2.3" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" 296 | dependencies = [ 297 | "core-foundation-sys 0.2.3", 298 | "libc", 299 | ] 300 | 301 | [[package]] 302 | name = "core-foundation" 303 | version = "0.7.0" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" 306 | dependencies = [ 307 | "core-foundation-sys 0.7.0", 308 | "libc", 309 | ] 310 | 311 | [[package]] 312 | name = "core-foundation-sys" 313 | version = "0.2.3" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" 316 | dependencies = [ 317 | "libc", 318 | ] 319 | 320 | [[package]] 321 | name = "core-foundation-sys" 322 | version = "0.7.0" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" 325 | 326 | [[package]] 327 | name = "crc32fast" 328 | version = "1.2.0" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" 331 | dependencies = [ 332 | "cfg-if", 333 | ] 334 | 335 | [[package]] 336 | name = "crossbeam-deque" 337 | version = "0.7.3" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" 340 | dependencies = [ 341 | "crossbeam-epoch", 342 | "crossbeam-utils", 343 | "maybe-uninit", 344 | ] 345 | 346 | [[package]] 347 | name = "crossbeam-epoch" 348 | version = "0.8.2" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" 351 | dependencies = [ 352 | "autocfg 1.0.0", 353 | "cfg-if", 354 | "crossbeam-utils", 355 | "lazy_static 1.4.0", 356 | "maybe-uninit", 357 | "memoffset", 358 | "scopeguard", 359 | ] 360 | 361 | [[package]] 362 | name = "crossbeam-queue" 363 | version = "0.2.1" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" 366 | dependencies = [ 367 | "cfg-if", 368 | "crossbeam-utils", 369 | ] 370 | 371 | [[package]] 372 | name = "crossbeam-utils" 373 | version = "0.7.2" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" 376 | dependencies = [ 377 | "autocfg 1.0.0", 378 | "cfg-if", 379 | "lazy_static 1.4.0", 380 | ] 381 | 382 | [[package]] 383 | name = "dirs" 384 | version = "1.0.5" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" 387 | dependencies = [ 388 | "libc", 389 | "redox_users", 390 | "winapi 0.3.8", 391 | ] 392 | 393 | [[package]] 394 | name = "dirs" 395 | version = "2.0.2" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" 398 | dependencies = [ 399 | "cfg-if", 400 | "dirs-sys", 401 | ] 402 | 403 | [[package]] 404 | name = "dirs-sys" 405 | version = "0.3.4" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" 408 | dependencies = [ 409 | "cfg-if", 410 | "libc", 411 | "redox_users", 412 | "winapi 0.3.8", 413 | ] 414 | 415 | [[package]] 416 | name = "dtoa" 417 | version = "0.4.5" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | checksum = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" 420 | 421 | [[package]] 422 | name = "either" 423 | version = "1.5.3" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" 426 | 427 | [[package]] 428 | name = "encoding_rs" 429 | version = "0.8.22" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28" 432 | dependencies = [ 433 | "cfg-if", 434 | ] 435 | 436 | [[package]] 437 | name = "env_logger" 438 | version = "0.5.13" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" 441 | dependencies = [ 442 | "atty", 443 | "humantime", 444 | "log", 445 | "regex 1.3.6", 446 | "termcolor", 447 | ] 448 | 449 | [[package]] 450 | name = "env_logger" 451 | version = "0.6.2" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" 454 | dependencies = [ 455 | "atty", 456 | "humantime", 457 | "log", 458 | "regex 1.3.6", 459 | "termcolor", 460 | ] 461 | 462 | [[package]] 463 | name = "env_logger" 464 | version = "0.7.1" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" 467 | dependencies = [ 468 | "atty", 469 | "humantime", 470 | "log", 471 | "regex 1.3.6", 472 | "termcolor", 473 | ] 474 | 475 | [[package]] 476 | name = "error-chain" 477 | version = "0.12.2" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd" 480 | dependencies = [ 481 | "version_check", 482 | ] 483 | 484 | [[package]] 485 | name = "failure" 486 | version = "0.1.7" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" 489 | dependencies = [ 490 | "backtrace", 491 | "failure_derive", 492 | ] 493 | 494 | [[package]] 495 | name = "failure_derive" 496 | version = "0.1.7" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" 499 | dependencies = [ 500 | "proc-macro2", 501 | "quote", 502 | "syn", 503 | "synstructure", 504 | ] 505 | 506 | [[package]] 507 | name = "flate2" 508 | version = "1.0.14" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42" 511 | dependencies = [ 512 | "cfg-if", 513 | "crc32fast", 514 | "libc", 515 | "miniz_oxide", 516 | ] 517 | 518 | [[package]] 519 | name = "fnv" 520 | version = "1.0.6" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" 523 | 524 | [[package]] 525 | name = "foreign-types" 526 | version = "0.3.2" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 529 | dependencies = [ 530 | "foreign-types-shared", 531 | ] 532 | 533 | [[package]] 534 | name = "foreign-types-shared" 535 | version = "0.1.1" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 538 | 539 | [[package]] 540 | name = "fuchsia-cprng" 541 | version = "0.1.1" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 544 | 545 | [[package]] 546 | name = "fuchsia-zircon" 547 | version = "0.3.3" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 550 | dependencies = [ 551 | "bitflags 1.2.1", 552 | "fuchsia-zircon-sys", 553 | ] 554 | 555 | [[package]] 556 | name = "fuchsia-zircon-sys" 557 | version = "0.3.3" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 560 | 561 | [[package]] 562 | name = "futures" 563 | version = "0.1.29" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" 566 | 567 | [[package]] 568 | name = "futures-cpupool" 569 | version = "0.1.8" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" 572 | dependencies = [ 573 | "futures", 574 | "num_cpus", 575 | ] 576 | 577 | [[package]] 578 | name = "getrandom" 579 | version = "0.1.14" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" 582 | dependencies = [ 583 | "cfg-if", 584 | "libc", 585 | "wasi", 586 | ] 587 | 588 | [[package]] 589 | name = "h2" 590 | version = "0.1.26" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | checksum = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" 593 | dependencies = [ 594 | "byteorder", 595 | "bytes", 596 | "fnv", 597 | "futures", 598 | "http", 599 | "indexmap", 600 | "log", 601 | "slab", 602 | "string", 603 | "tokio-io", 604 | ] 605 | 606 | [[package]] 607 | name = "heck" 608 | version = "0.3.1" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 611 | dependencies = [ 612 | "unicode-segmentation", 613 | ] 614 | 615 | [[package]] 616 | name = "hermit-abi" 617 | version = "0.1.10" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" 620 | dependencies = [ 621 | "libc", 622 | ] 623 | 624 | [[package]] 625 | name = "http" 626 | version = "0.1.21" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" 629 | dependencies = [ 630 | "bytes", 631 | "fnv", 632 | "itoa", 633 | ] 634 | 635 | [[package]] 636 | name = "http-body" 637 | version = "0.1.0" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" 640 | dependencies = [ 641 | "bytes", 642 | "futures", 643 | "http", 644 | "tokio-buf", 645 | ] 646 | 647 | [[package]] 648 | name = "httparse" 649 | version = "1.3.4" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" 652 | 653 | [[package]] 654 | name = "humantime" 655 | version = "1.3.0" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 658 | dependencies = [ 659 | "quick-error", 660 | ] 661 | 662 | [[package]] 663 | name = "hyper" 664 | version = "0.11.27" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | checksum = "34a590ca09d341e94cddf8e5af0bbccde205d5fbc2fa3c09dd67c7f85cea59d7" 667 | dependencies = [ 668 | "base64 0.9.3", 669 | "bytes", 670 | "futures", 671 | "futures-cpupool", 672 | "httparse", 673 | "iovec", 674 | "language-tags", 675 | "log", 676 | "mime", 677 | "net2", 678 | "percent-encoding 1.0.1", 679 | "relay", 680 | "time", 681 | "tokio-core", 682 | "tokio-io", 683 | "tokio-service", 684 | "unicase", 685 | "want 0.0.4", 686 | ] 687 | 688 | [[package]] 689 | name = "hyper" 690 | version = "0.12.35" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | checksum = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" 693 | dependencies = [ 694 | "bytes", 695 | "futures", 696 | "futures-cpupool", 697 | "h2", 698 | "http", 699 | "http-body", 700 | "httparse", 701 | "iovec", 702 | "itoa", 703 | "log", 704 | "net2", 705 | "rustc_version", 706 | "time", 707 | "tokio", 708 | "tokio-buf", 709 | "tokio-executor", 710 | "tokio-io", 711 | "tokio-reactor", 712 | "tokio-tcp", 713 | "tokio-threadpool", 714 | "tokio-timer", 715 | "want 0.2.0", 716 | ] 717 | 718 | [[package]] 719 | name = "hyper-tls" 720 | version = "0.1.4" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "ffb1bd5e518d3065840ab315dbbf44e4420e5f7d80e2cb93fa6ffffc50522378" 723 | dependencies = [ 724 | "futures", 725 | "hyper 0.11.27", 726 | "native-tls 0.1.5", 727 | "tokio-core", 728 | "tokio-io", 729 | "tokio-service", 730 | "tokio-tls", 731 | ] 732 | 733 | [[package]] 734 | name = "hyper-tls" 735 | version = "0.3.2" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" 738 | dependencies = [ 739 | "bytes", 740 | "futures", 741 | "hyper 0.12.35", 742 | "native-tls 0.2.4", 743 | "tokio-io", 744 | ] 745 | 746 | [[package]] 747 | name = "idna" 748 | version = "0.1.5" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" 751 | dependencies = [ 752 | "matches", 753 | "unicode-bidi", 754 | "unicode-normalization", 755 | ] 756 | 757 | [[package]] 758 | name = "idna" 759 | version = "0.2.0" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" 762 | dependencies = [ 763 | "matches", 764 | "unicode-bidi", 765 | "unicode-normalization", 766 | ] 767 | 768 | [[package]] 769 | name = "if_chain" 770 | version = "1.0.0" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d" 773 | 774 | [[package]] 775 | name = "indexmap" 776 | version = "1.3.2" 777 | source = "registry+https://github.com/rust-lang/crates.io-index" 778 | checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" 779 | dependencies = [ 780 | "autocfg 1.0.0", 781 | ] 782 | 783 | [[package]] 784 | name = "iovec" 785 | version = "0.1.4" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 788 | dependencies = [ 789 | "libc", 790 | ] 791 | 792 | [[package]] 793 | name = "itoa" 794 | version = "0.4.5" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" 797 | 798 | [[package]] 799 | name = "kernel32-sys" 800 | version = "0.2.2" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 803 | dependencies = [ 804 | "winapi 0.2.8", 805 | "winapi-build", 806 | ] 807 | 808 | [[package]] 809 | name = "language-tags" 810 | version = "0.2.2" 811 | source = "registry+https://github.com/rust-lang/crates.io-index" 812 | checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" 813 | 814 | [[package]] 815 | name = "lazy_static" 816 | version = "0.2.11" 817 | source = "registry+https://github.com/rust-lang/crates.io-index" 818 | checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" 819 | 820 | [[package]] 821 | name = "lazy_static" 822 | version = "1.4.0" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 825 | 826 | [[package]] 827 | name = "libc" 828 | version = "0.2.68" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" 831 | 832 | [[package]] 833 | name = "libflate" 834 | version = "0.1.27" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "d9135df43b1f5d0e333385cb6e7897ecd1a43d7d11b91ac003f4d2c2d2401fdd" 837 | dependencies = [ 838 | "adler32", 839 | "crc32fast", 840 | "rle-decode-fast", 841 | "take_mut", 842 | ] 843 | 844 | [[package]] 845 | name = "lock_api" 846 | version = "0.3.3" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" 849 | dependencies = [ 850 | "scopeguard", 851 | ] 852 | 853 | [[package]] 854 | name = "log" 855 | version = "0.4.8" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 858 | dependencies = [ 859 | "cfg-if", 860 | ] 861 | 862 | [[package]] 863 | name = "matches" 864 | version = "0.1.8" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 867 | 868 | [[package]] 869 | name = "maybe-uninit" 870 | version = "2.0.0" 871 | source = "registry+https://github.com/rust-lang/crates.io-index" 872 | checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 873 | 874 | [[package]] 875 | name = "memchr" 876 | version = "2.3.3" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" 879 | 880 | [[package]] 881 | name = "memoffset" 882 | version = "0.5.4" 883 | source = "registry+https://github.com/rust-lang/crates.io-index" 884 | checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" 885 | dependencies = [ 886 | "autocfg 1.0.0", 887 | ] 888 | 889 | [[package]] 890 | name = "mime" 891 | version = "0.3.16" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 894 | 895 | [[package]] 896 | name = "mime_guess" 897 | version = "2.0.3" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" 900 | dependencies = [ 901 | "mime", 902 | "unicase", 903 | ] 904 | 905 | [[package]] 906 | name = "miniz_oxide" 907 | version = "0.3.6" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | checksum = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5" 910 | dependencies = [ 911 | "adler32", 912 | ] 913 | 914 | [[package]] 915 | name = "mio" 916 | version = "0.6.21" 917 | source = "registry+https://github.com/rust-lang/crates.io-index" 918 | checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" 919 | dependencies = [ 920 | "cfg-if", 921 | "fuchsia-zircon", 922 | "fuchsia-zircon-sys", 923 | "iovec", 924 | "kernel32-sys", 925 | "libc", 926 | "log", 927 | "miow", 928 | "net2", 929 | "slab", 930 | "winapi 0.2.8", 931 | ] 932 | 933 | [[package]] 934 | name = "mio-uds" 935 | version = "0.6.7" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" 938 | dependencies = [ 939 | "iovec", 940 | "libc", 941 | "mio", 942 | ] 943 | 944 | [[package]] 945 | name = "miow" 946 | version = "0.2.1" 947 | source = "registry+https://github.com/rust-lang/crates.io-index" 948 | checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" 949 | dependencies = [ 950 | "kernel32-sys", 951 | "net2", 952 | "winapi 0.2.8", 953 | "ws2_32-sys", 954 | ] 955 | 956 | [[package]] 957 | name = "native-tls" 958 | version = "0.1.5" 959 | source = "registry+https://github.com/rust-lang/crates.io-index" 960 | checksum = "f74dbadc8b43df7864539cedb7bc91345e532fdd913cfdc23ad94f4d2d40fbc0" 961 | dependencies = [ 962 | "lazy_static 0.2.11", 963 | "libc", 964 | "openssl 0.9.24", 965 | "schannel", 966 | "security-framework 0.1.16", 967 | "security-framework-sys 0.1.16", 968 | "tempdir", 969 | ] 970 | 971 | [[package]] 972 | name = "native-tls" 973 | version = "0.2.4" 974 | source = "registry+https://github.com/rust-lang/crates.io-index" 975 | checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d" 976 | dependencies = [ 977 | "lazy_static 1.4.0", 978 | "libc", 979 | "log", 980 | "openssl 0.10.28", 981 | "openssl-probe", 982 | "openssl-sys", 983 | "schannel", 984 | "security-framework 0.4.2", 985 | "security-framework-sys 0.4.2", 986 | "tempfile", 987 | ] 988 | 989 | [[package]] 990 | name = "net2" 991 | version = "0.2.33" 992 | source = "registry+https://github.com/rust-lang/crates.io-index" 993 | checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" 994 | dependencies = [ 995 | "cfg-if", 996 | "libc", 997 | "winapi 0.3.8", 998 | ] 999 | 1000 | [[package]] 1001 | name = "num-integer" 1002 | version = "0.1.42" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" 1005 | dependencies = [ 1006 | "autocfg 1.0.0", 1007 | "num-traits", 1008 | ] 1009 | 1010 | [[package]] 1011 | name = "num-traits" 1012 | version = "0.2.11" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" 1015 | dependencies = [ 1016 | "autocfg 1.0.0", 1017 | ] 1018 | 1019 | [[package]] 1020 | name = "num_cpus" 1021 | version = "1.12.0" 1022 | source = "registry+https://github.com/rust-lang/crates.io-index" 1023 | checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" 1024 | dependencies = [ 1025 | "hermit-abi", 1026 | "libc", 1027 | ] 1028 | 1029 | [[package]] 1030 | name = "openssl" 1031 | version = "0.9.24" 1032 | source = "registry+https://github.com/rust-lang/crates.io-index" 1033 | checksum = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985" 1034 | dependencies = [ 1035 | "bitflags 0.9.1", 1036 | "foreign-types", 1037 | "lazy_static 1.4.0", 1038 | "libc", 1039 | "openssl-sys", 1040 | ] 1041 | 1042 | [[package]] 1043 | name = "openssl" 1044 | version = "0.10.28" 1045 | source = "registry+https://github.com/rust-lang/crates.io-index" 1046 | checksum = "973293749822d7dd6370d6da1e523b0d1db19f06c459134c658b2a4261378b52" 1047 | dependencies = [ 1048 | "bitflags 1.2.1", 1049 | "cfg-if", 1050 | "foreign-types", 1051 | "lazy_static 1.4.0", 1052 | "libc", 1053 | "openssl-sys", 1054 | ] 1055 | 1056 | [[package]] 1057 | name = "openssl-probe" 1058 | version = "0.1.2" 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" 1060 | checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" 1061 | 1062 | [[package]] 1063 | name = "openssl-sys" 1064 | version = "0.9.54" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986" 1067 | dependencies = [ 1068 | "autocfg 1.0.0", 1069 | "cc", 1070 | "libc", 1071 | "pkg-config", 1072 | "vcpkg", 1073 | ] 1074 | 1075 | [[package]] 1076 | name = "parking_lot" 1077 | version = "0.9.0" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" 1080 | dependencies = [ 1081 | "lock_api", 1082 | "parking_lot_core", 1083 | "rustc_version", 1084 | ] 1085 | 1086 | [[package]] 1087 | name = "parking_lot_core" 1088 | version = "0.6.2" 1089 | source = "registry+https://github.com/rust-lang/crates.io-index" 1090 | checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" 1091 | dependencies = [ 1092 | "cfg-if", 1093 | "cloudabi", 1094 | "libc", 1095 | "redox_syscall", 1096 | "rustc_version", 1097 | "smallvec 0.6.13", 1098 | "winapi 0.3.8", 1099 | ] 1100 | 1101 | [[package]] 1102 | name = "percent-encoding" 1103 | version = "1.0.1" 1104 | source = "registry+https://github.com/rust-lang/crates.io-index" 1105 | checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" 1106 | 1107 | [[package]] 1108 | name = "percent-encoding" 1109 | version = "2.1.0" 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" 1111 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1112 | 1113 | [[package]] 1114 | name = "pkg-config" 1115 | version = "0.3.17" 1116 | source = "registry+https://github.com/rust-lang/crates.io-index" 1117 | checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" 1118 | 1119 | [[package]] 1120 | name = "ppv-lite86" 1121 | version = "0.2.6" 1122 | source = "registry+https://github.com/rust-lang/crates.io-index" 1123 | checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" 1124 | 1125 | [[package]] 1126 | name = "proc-macro-error" 1127 | version = "0.4.12" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" 1130 | dependencies = [ 1131 | "proc-macro-error-attr", 1132 | "proc-macro2", 1133 | "quote", 1134 | "syn", 1135 | "version_check", 1136 | ] 1137 | 1138 | [[package]] 1139 | name = "proc-macro-error-attr" 1140 | version = "0.4.12" 1141 | source = "registry+https://github.com/rust-lang/crates.io-index" 1142 | checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" 1143 | dependencies = [ 1144 | "proc-macro2", 1145 | "quote", 1146 | "syn", 1147 | "syn-mid", 1148 | "version_check", 1149 | ] 1150 | 1151 | [[package]] 1152 | name = "proc-macro2" 1153 | version = "1.0.10" 1154 | source = "registry+https://github.com/rust-lang/crates.io-index" 1155 | checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" 1156 | dependencies = [ 1157 | "unicode-xid", 1158 | ] 1159 | 1160 | [[package]] 1161 | name = "publicsuffix" 1162 | version = "1.5.4" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" 1165 | dependencies = [ 1166 | "error-chain", 1167 | "idna 0.2.0", 1168 | "lazy_static 1.4.0", 1169 | "regex 1.3.6", 1170 | "url 2.1.1", 1171 | ] 1172 | 1173 | [[package]] 1174 | name = "quick-error" 1175 | version = "1.2.3" 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" 1177 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 1178 | 1179 | [[package]] 1180 | name = "quote" 1181 | version = "1.0.3" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" 1184 | dependencies = [ 1185 | "proc-macro2", 1186 | ] 1187 | 1188 | [[package]] 1189 | name = "rand" 1190 | version = "0.4.6" 1191 | source = "registry+https://github.com/rust-lang/crates.io-index" 1192 | checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" 1193 | dependencies = [ 1194 | "fuchsia-cprng", 1195 | "libc", 1196 | "rand_core 0.3.1", 1197 | "rdrand", 1198 | "winapi 0.3.8", 1199 | ] 1200 | 1201 | [[package]] 1202 | name = "rand" 1203 | version = "0.6.5" 1204 | source = "registry+https://github.com/rust-lang/crates.io-index" 1205 | checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 1206 | dependencies = [ 1207 | "autocfg 0.1.7", 1208 | "libc", 1209 | "rand_chacha 0.1.1", 1210 | "rand_core 0.4.2", 1211 | "rand_hc 0.1.0", 1212 | "rand_isaac", 1213 | "rand_jitter", 1214 | "rand_os", 1215 | "rand_pcg", 1216 | "rand_xorshift", 1217 | "winapi 0.3.8", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "rand" 1222 | version = "0.7.3" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 1225 | dependencies = [ 1226 | "getrandom", 1227 | "libc", 1228 | "rand_chacha 0.2.2", 1229 | "rand_core 0.5.1", 1230 | "rand_hc 0.2.0", 1231 | ] 1232 | 1233 | [[package]] 1234 | name = "rand_chacha" 1235 | version = "0.1.1" 1236 | source = "registry+https://github.com/rust-lang/crates.io-index" 1237 | checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 1238 | dependencies = [ 1239 | "autocfg 0.1.7", 1240 | "rand_core 0.3.1", 1241 | ] 1242 | 1243 | [[package]] 1244 | name = "rand_chacha" 1245 | version = "0.2.2" 1246 | source = "registry+https://github.com/rust-lang/crates.io-index" 1247 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 1248 | dependencies = [ 1249 | "ppv-lite86", 1250 | "rand_core 0.5.1", 1251 | ] 1252 | 1253 | [[package]] 1254 | name = "rand_core" 1255 | version = "0.3.1" 1256 | source = "registry+https://github.com/rust-lang/crates.io-index" 1257 | checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 1258 | dependencies = [ 1259 | "rand_core 0.4.2", 1260 | ] 1261 | 1262 | [[package]] 1263 | name = "rand_core" 1264 | version = "0.4.2" 1265 | source = "registry+https://github.com/rust-lang/crates.io-index" 1266 | checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 1267 | 1268 | [[package]] 1269 | name = "rand_core" 1270 | version = "0.5.1" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 1273 | dependencies = [ 1274 | "getrandom", 1275 | ] 1276 | 1277 | [[package]] 1278 | name = "rand_hc" 1279 | version = "0.1.0" 1280 | source = "registry+https://github.com/rust-lang/crates.io-index" 1281 | checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" 1282 | dependencies = [ 1283 | "rand_core 0.3.1", 1284 | ] 1285 | 1286 | [[package]] 1287 | name = "rand_hc" 1288 | version = "0.2.0" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 1291 | dependencies = [ 1292 | "rand_core 0.5.1", 1293 | ] 1294 | 1295 | [[package]] 1296 | name = "rand_isaac" 1297 | version = "0.1.1" 1298 | source = "registry+https://github.com/rust-lang/crates.io-index" 1299 | checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" 1300 | dependencies = [ 1301 | "rand_core 0.3.1", 1302 | ] 1303 | 1304 | [[package]] 1305 | name = "rand_jitter" 1306 | version = "0.1.4" 1307 | source = "registry+https://github.com/rust-lang/crates.io-index" 1308 | checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" 1309 | dependencies = [ 1310 | "libc", 1311 | "rand_core 0.4.2", 1312 | "winapi 0.3.8", 1313 | ] 1314 | 1315 | [[package]] 1316 | name = "rand_os" 1317 | version = "0.1.3" 1318 | source = "registry+https://github.com/rust-lang/crates.io-index" 1319 | checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" 1320 | dependencies = [ 1321 | "cloudabi", 1322 | "fuchsia-cprng", 1323 | "libc", 1324 | "rand_core 0.4.2", 1325 | "rdrand", 1326 | "winapi 0.3.8", 1327 | ] 1328 | 1329 | [[package]] 1330 | name = "rand_pcg" 1331 | version = "0.1.2" 1332 | source = "registry+https://github.com/rust-lang/crates.io-index" 1333 | checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" 1334 | dependencies = [ 1335 | "autocfg 0.1.7", 1336 | "rand_core 0.4.2", 1337 | ] 1338 | 1339 | [[package]] 1340 | name = "rand_xorshift" 1341 | version = "0.1.1" 1342 | source = "registry+https://github.com/rust-lang/crates.io-index" 1343 | checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" 1344 | dependencies = [ 1345 | "rand_core 0.3.1", 1346 | ] 1347 | 1348 | [[package]] 1349 | name = "rdrand" 1350 | version = "0.4.0" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 1353 | dependencies = [ 1354 | "rand_core 0.3.1", 1355 | ] 1356 | 1357 | [[package]] 1358 | name = "redox_syscall" 1359 | version = "0.1.56" 1360 | source = "registry+https://github.com/rust-lang/crates.io-index" 1361 | checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" 1362 | 1363 | [[package]] 1364 | name = "redox_users" 1365 | version = "0.3.4" 1366 | source = "registry+https://github.com/rust-lang/crates.io-index" 1367 | checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" 1368 | dependencies = [ 1369 | "getrandom", 1370 | "redox_syscall", 1371 | "rust-argon2", 1372 | ] 1373 | 1374 | [[package]] 1375 | name = "regex" 1376 | version = "0.2.11" 1377 | source = "registry+https://github.com/rust-lang/crates.io-index" 1378 | checksum = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" 1379 | dependencies = [ 1380 | "aho-corasick 0.6.10", 1381 | "memchr", 1382 | "regex-syntax 0.5.6", 1383 | "thread_local 0.3.6", 1384 | "utf8-ranges", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "regex" 1389 | version = "1.3.6" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" 1392 | dependencies = [ 1393 | "aho-corasick 0.7.10", 1394 | "memchr", 1395 | "regex-syntax 0.6.17", 1396 | "thread_local 1.0.1", 1397 | ] 1398 | 1399 | [[package]] 1400 | name = "regex-syntax" 1401 | version = "0.5.6" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" 1404 | dependencies = [ 1405 | "ucd-util", 1406 | ] 1407 | 1408 | [[package]] 1409 | name = "regex-syntax" 1410 | version = "0.6.17" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" 1413 | 1414 | [[package]] 1415 | name = "relay" 1416 | version = "0.1.1" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" 1419 | dependencies = [ 1420 | "futures", 1421 | ] 1422 | 1423 | [[package]] 1424 | name = "remove_dir_all" 1425 | version = "0.5.2" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" 1428 | dependencies = [ 1429 | "winapi 0.3.8", 1430 | ] 1431 | 1432 | [[package]] 1433 | name = "reqwest" 1434 | version = "0.8.8" 1435 | source = "registry+https://github.com/rust-lang/crates.io-index" 1436 | checksum = "738769ec83daf6c1929dc9dae7d69ed3779b55ae5c356e989dcd3aa677d8486e" 1437 | dependencies = [ 1438 | "bytes", 1439 | "encoding_rs", 1440 | "futures", 1441 | "hyper 0.11.27", 1442 | "hyper-tls 0.1.4", 1443 | "libflate", 1444 | "log", 1445 | "mime_guess", 1446 | "native-tls 0.1.5", 1447 | "serde", 1448 | "serde_json", 1449 | "serde_urlencoded", 1450 | "tokio-core", 1451 | "tokio-io", 1452 | "tokio-tls", 1453 | "url 1.7.2", 1454 | "uuid 0.6.5", 1455 | ] 1456 | 1457 | [[package]] 1458 | name = "reqwest" 1459 | version = "0.9.24" 1460 | source = "registry+https://github.com/rust-lang/crates.io-index" 1461 | checksum = "f88643aea3c1343c804950d7bf983bd2067f5ab59db6d613a08e05572f2714ab" 1462 | dependencies = [ 1463 | "base64 0.10.1", 1464 | "bytes", 1465 | "cookie", 1466 | "cookie_store", 1467 | "encoding_rs", 1468 | "flate2", 1469 | "futures", 1470 | "http", 1471 | "hyper 0.12.35", 1472 | "hyper-tls 0.3.2", 1473 | "log", 1474 | "mime", 1475 | "mime_guess", 1476 | "native-tls 0.2.4", 1477 | "serde", 1478 | "serde_json", 1479 | "serde_urlencoded", 1480 | "time", 1481 | "tokio", 1482 | "tokio-executor", 1483 | "tokio-io", 1484 | "tokio-threadpool", 1485 | "tokio-timer", 1486 | "url 1.7.2", 1487 | "uuid 0.7.4", 1488 | "winreg", 1489 | ] 1490 | 1491 | [[package]] 1492 | name = "rle-decode-fast" 1493 | version = "1.0.1" 1494 | source = "registry+https://github.com/rust-lang/crates.io-index" 1495 | checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" 1496 | 1497 | [[package]] 1498 | name = "rmp" 1499 | version = "0.8.9" 1500 | source = "registry+https://github.com/rust-lang/crates.io-index" 1501 | checksum = "0f10b46df14cf1ee1ac7baa4d2fbc2c52c0622a4b82fa8740e37bc452ac0184f" 1502 | dependencies = [ 1503 | "byteorder", 1504 | "num-traits", 1505 | ] 1506 | 1507 | [[package]] 1508 | name = "rmp-serde" 1509 | version = "0.13.7" 1510 | source = "registry+https://github.com/rust-lang/crates.io-index" 1511 | checksum = "011e1d58446e9fa3af7cdc1fb91295b10621d3ac4cb3a85cc86385ee9ca50cd3" 1512 | dependencies = [ 1513 | "byteorder", 1514 | "rmp", 1515 | "serde", 1516 | ] 1517 | 1518 | [[package]] 1519 | name = "rust-argon2" 1520 | version = "0.7.0" 1521 | source = "registry+https://github.com/rust-lang/crates.io-index" 1522 | checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" 1523 | dependencies = [ 1524 | "base64 0.11.0", 1525 | "blake2b_simd", 1526 | "constant_time_eq", 1527 | "crossbeam-utils", 1528 | ] 1529 | 1530 | [[package]] 1531 | name = "rustc-demangle" 1532 | version = "0.1.16" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" 1535 | 1536 | [[package]] 1537 | name = "rustc_version" 1538 | version = "0.2.3" 1539 | source = "registry+https://github.com/rust-lang/crates.io-index" 1540 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1541 | dependencies = [ 1542 | "semver", 1543 | ] 1544 | 1545 | [[package]] 1546 | name = "rusty-pin" 1547 | version = "0.5.0" 1548 | source = "git+https://github.com/spamwax/rusty-pin#1e3e64846abd26f0f19a151c367b2be408f4c45f" 1549 | dependencies = [ 1550 | "chrono", 1551 | "dirs 1.0.5", 1552 | "env_logger 0.5.13", 1553 | "failure", 1554 | "failure_derive", 1555 | "log", 1556 | "regex 0.2.11", 1557 | "reqwest 0.9.24", 1558 | "rmp-serde", 1559 | "serde", 1560 | "serde_derive", 1561 | "serde_json", 1562 | "url 1.7.2", 1563 | "url_serde", 1564 | ] 1565 | 1566 | [[package]] 1567 | name = "ryu" 1568 | version = "1.0.3" 1569 | source = "registry+https://github.com/rust-lang/crates.io-index" 1570 | checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" 1571 | 1572 | [[package]] 1573 | name = "safemem" 1574 | version = "0.3.3" 1575 | source = "registry+https://github.com/rust-lang/crates.io-index" 1576 | checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" 1577 | 1578 | [[package]] 1579 | name = "schannel" 1580 | version = "0.1.18" 1581 | source = "registry+https://github.com/rust-lang/crates.io-index" 1582 | checksum = "039c25b130bd8c1321ee2d7de7fde2659fa9c2744e4bb29711cfc852ea53cd19" 1583 | dependencies = [ 1584 | "lazy_static 1.4.0", 1585 | "winapi 0.3.8", 1586 | ] 1587 | 1588 | [[package]] 1589 | name = "scoped-tls" 1590 | version = "0.1.2" 1591 | source = "registry+https://github.com/rust-lang/crates.io-index" 1592 | checksum = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" 1593 | 1594 | [[package]] 1595 | name = "scopeguard" 1596 | version = "1.1.0" 1597 | source = "registry+https://github.com/rust-lang/crates.io-index" 1598 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1599 | 1600 | [[package]] 1601 | name = "security-framework" 1602 | version = "0.1.16" 1603 | source = "registry+https://github.com/rust-lang/crates.io-index" 1604 | checksum = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332" 1605 | dependencies = [ 1606 | "core-foundation 0.2.3", 1607 | "core-foundation-sys 0.2.3", 1608 | "libc", 1609 | "security-framework-sys 0.1.16", 1610 | ] 1611 | 1612 | [[package]] 1613 | name = "security-framework" 1614 | version = "0.4.2" 1615 | source = "registry+https://github.com/rust-lang/crates.io-index" 1616 | checksum = "572dfa3a0785509e7a44b5b4bebcf94d41ba34e9ed9eb9df722545c3b3c4144a" 1617 | dependencies = [ 1618 | "bitflags 1.2.1", 1619 | "core-foundation 0.7.0", 1620 | "core-foundation-sys 0.7.0", 1621 | "libc", 1622 | "security-framework-sys 0.4.2", 1623 | ] 1624 | 1625 | [[package]] 1626 | name = "security-framework-sys" 1627 | version = "0.1.16" 1628 | source = "registry+https://github.com/rust-lang/crates.io-index" 1629 | checksum = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead" 1630 | dependencies = [ 1631 | "core-foundation-sys 0.2.3", 1632 | "libc", 1633 | ] 1634 | 1635 | [[package]] 1636 | name = "security-framework-sys" 1637 | version = "0.4.2" 1638 | source = "registry+https://github.com/rust-lang/crates.io-index" 1639 | checksum = "8ddb15a5fec93b7021b8a9e96009c5d8d51c15673569f7c0f6b7204e5b7b404f" 1640 | dependencies = [ 1641 | "core-foundation-sys 0.7.0", 1642 | "libc", 1643 | ] 1644 | 1645 | [[package]] 1646 | name = "semver" 1647 | version = "0.9.0" 1648 | source = "registry+https://github.com/rust-lang/crates.io-index" 1649 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1650 | dependencies = [ 1651 | "semver-parser", 1652 | "serde", 1653 | ] 1654 | 1655 | [[package]] 1656 | name = "semver-parser" 1657 | version = "0.7.0" 1658 | source = "registry+https://github.com/rust-lang/crates.io-index" 1659 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1660 | 1661 | [[package]] 1662 | name = "serde" 1663 | version = "1.0.105" 1664 | source = "registry+https://github.com/rust-lang/crates.io-index" 1665 | checksum = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" 1666 | dependencies = [ 1667 | "serde_derive", 1668 | ] 1669 | 1670 | [[package]] 1671 | name = "serde_derive" 1672 | version = "1.0.105" 1673 | source = "registry+https://github.com/rust-lang/crates.io-index" 1674 | checksum = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" 1675 | dependencies = [ 1676 | "proc-macro2", 1677 | "quote", 1678 | "syn", 1679 | ] 1680 | 1681 | [[package]] 1682 | name = "serde_json" 1683 | version = "1.0.50" 1684 | source = "registry+https://github.com/rust-lang/crates.io-index" 1685 | checksum = "78a7a12c167809363ec3bd7329fc0a3369056996de43c4b37ef3cd54a6ce4867" 1686 | dependencies = [ 1687 | "itoa", 1688 | "ryu", 1689 | "serde", 1690 | ] 1691 | 1692 | [[package]] 1693 | name = "serde_urlencoded" 1694 | version = "0.5.5" 1695 | source = "registry+https://github.com/rust-lang/crates.io-index" 1696 | checksum = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" 1697 | dependencies = [ 1698 | "dtoa", 1699 | "itoa", 1700 | "serde", 1701 | "url 1.7.2", 1702 | ] 1703 | 1704 | [[package]] 1705 | name = "slab" 1706 | version = "0.4.2" 1707 | source = "registry+https://github.com/rust-lang/crates.io-index" 1708 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1709 | 1710 | [[package]] 1711 | name = "smallvec" 1712 | version = "0.6.13" 1713 | source = "registry+https://github.com/rust-lang/crates.io-index" 1714 | checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" 1715 | dependencies = [ 1716 | "maybe-uninit", 1717 | ] 1718 | 1719 | [[package]] 1720 | name = "smallvec" 1721 | version = "1.2.0" 1722 | source = "registry+https://github.com/rust-lang/crates.io-index" 1723 | checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" 1724 | 1725 | [[package]] 1726 | name = "string" 1727 | version = "0.2.1" 1728 | source = "registry+https://github.com/rust-lang/crates.io-index" 1729 | checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" 1730 | dependencies = [ 1731 | "bytes", 1732 | ] 1733 | 1734 | [[package]] 1735 | name = "strsim" 1736 | version = "0.8.0" 1737 | source = "registry+https://github.com/rust-lang/crates.io-index" 1738 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1739 | 1740 | [[package]] 1741 | name = "structopt" 1742 | version = "0.3.12" 1743 | source = "registry+https://github.com/rust-lang/crates.io-index" 1744 | checksum = "c8faa2719539bbe9d77869bfb15d4ee769f99525e707931452c97b693b3f159d" 1745 | dependencies = [ 1746 | "clap", 1747 | "lazy_static 1.4.0", 1748 | "structopt-derive", 1749 | ] 1750 | 1751 | [[package]] 1752 | name = "structopt-derive" 1753 | version = "0.4.5" 1754 | source = "registry+https://github.com/rust-lang/crates.io-index" 1755 | checksum = "3f88b8e18c69496aad6f9ddf4630dd7d585bcaf765786cb415b9aec2fe5a0430" 1756 | dependencies = [ 1757 | "heck", 1758 | "proc-macro-error", 1759 | "proc-macro2", 1760 | "quote", 1761 | "syn", 1762 | ] 1763 | 1764 | [[package]] 1765 | name = "syn" 1766 | version = "1.0.17" 1767 | source = "registry+https://github.com/rust-lang/crates.io-index" 1768 | checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" 1769 | dependencies = [ 1770 | "proc-macro2", 1771 | "quote", 1772 | "unicode-xid", 1773 | ] 1774 | 1775 | [[package]] 1776 | name = "syn-mid" 1777 | version = "0.5.0" 1778 | source = "registry+https://github.com/rust-lang/crates.io-index" 1779 | checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" 1780 | dependencies = [ 1781 | "proc-macro2", 1782 | "quote", 1783 | "syn", 1784 | ] 1785 | 1786 | [[package]] 1787 | name = "synstructure" 1788 | version = "0.12.3" 1789 | source = "registry+https://github.com/rust-lang/crates.io-index" 1790 | checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" 1791 | dependencies = [ 1792 | "proc-macro2", 1793 | "quote", 1794 | "syn", 1795 | "unicode-xid", 1796 | ] 1797 | 1798 | [[package]] 1799 | name = "take_mut" 1800 | version = "0.2.2" 1801 | source = "registry+https://github.com/rust-lang/crates.io-index" 1802 | checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" 1803 | 1804 | [[package]] 1805 | name = "tempdir" 1806 | version = "0.3.7" 1807 | source = "registry+https://github.com/rust-lang/crates.io-index" 1808 | checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" 1809 | dependencies = [ 1810 | "rand 0.4.6", 1811 | "remove_dir_all", 1812 | ] 1813 | 1814 | [[package]] 1815 | name = "tempfile" 1816 | version = "3.1.0" 1817 | source = "registry+https://github.com/rust-lang/crates.io-index" 1818 | checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" 1819 | dependencies = [ 1820 | "cfg-if", 1821 | "libc", 1822 | "rand 0.7.3", 1823 | "redox_syscall", 1824 | "remove_dir_all", 1825 | "winapi 0.3.8", 1826 | ] 1827 | 1828 | [[package]] 1829 | name = "termcolor" 1830 | version = "1.1.0" 1831 | source = "registry+https://github.com/rust-lang/crates.io-index" 1832 | checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" 1833 | dependencies = [ 1834 | "winapi-util", 1835 | ] 1836 | 1837 | [[package]] 1838 | name = "textwrap" 1839 | version = "0.11.0" 1840 | source = "registry+https://github.com/rust-lang/crates.io-index" 1841 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1842 | dependencies = [ 1843 | "unicode-width", 1844 | ] 1845 | 1846 | [[package]] 1847 | name = "thread_local" 1848 | version = "0.3.6" 1849 | source = "registry+https://github.com/rust-lang/crates.io-index" 1850 | checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 1851 | dependencies = [ 1852 | "lazy_static 1.4.0", 1853 | ] 1854 | 1855 | [[package]] 1856 | name = "thread_local" 1857 | version = "1.0.1" 1858 | source = "registry+https://github.com/rust-lang/crates.io-index" 1859 | checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" 1860 | dependencies = [ 1861 | "lazy_static 1.4.0", 1862 | ] 1863 | 1864 | [[package]] 1865 | name = "time" 1866 | version = "0.1.42" 1867 | source = "registry+https://github.com/rust-lang/crates.io-index" 1868 | checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 1869 | dependencies = [ 1870 | "libc", 1871 | "redox_syscall", 1872 | "winapi 0.3.8", 1873 | ] 1874 | 1875 | [[package]] 1876 | name = "tokio" 1877 | version = "0.1.22" 1878 | source = "registry+https://github.com/rust-lang/crates.io-index" 1879 | checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" 1880 | dependencies = [ 1881 | "bytes", 1882 | "futures", 1883 | "mio", 1884 | "num_cpus", 1885 | "tokio-codec", 1886 | "tokio-current-thread", 1887 | "tokio-executor", 1888 | "tokio-fs", 1889 | "tokio-io", 1890 | "tokio-reactor", 1891 | "tokio-sync", 1892 | "tokio-tcp", 1893 | "tokio-threadpool", 1894 | "tokio-timer", 1895 | "tokio-udp", 1896 | "tokio-uds", 1897 | ] 1898 | 1899 | [[package]] 1900 | name = "tokio-buf" 1901 | version = "0.1.1" 1902 | source = "registry+https://github.com/rust-lang/crates.io-index" 1903 | checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" 1904 | dependencies = [ 1905 | "bytes", 1906 | "either", 1907 | "futures", 1908 | ] 1909 | 1910 | [[package]] 1911 | name = "tokio-codec" 1912 | version = "0.1.2" 1913 | source = "registry+https://github.com/rust-lang/crates.io-index" 1914 | checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" 1915 | dependencies = [ 1916 | "bytes", 1917 | "futures", 1918 | "tokio-io", 1919 | ] 1920 | 1921 | [[package]] 1922 | name = "tokio-core" 1923 | version = "0.1.17" 1924 | source = "registry+https://github.com/rust-lang/crates.io-index" 1925 | checksum = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" 1926 | dependencies = [ 1927 | "bytes", 1928 | "futures", 1929 | "iovec", 1930 | "log", 1931 | "mio", 1932 | "scoped-tls", 1933 | "tokio", 1934 | "tokio-executor", 1935 | "tokio-io", 1936 | "tokio-reactor", 1937 | "tokio-timer", 1938 | ] 1939 | 1940 | [[package]] 1941 | name = "tokio-current-thread" 1942 | version = "0.1.7" 1943 | source = "registry+https://github.com/rust-lang/crates.io-index" 1944 | checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" 1945 | dependencies = [ 1946 | "futures", 1947 | "tokio-executor", 1948 | ] 1949 | 1950 | [[package]] 1951 | name = "tokio-executor" 1952 | version = "0.1.10" 1953 | source = "registry+https://github.com/rust-lang/crates.io-index" 1954 | checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" 1955 | dependencies = [ 1956 | "crossbeam-utils", 1957 | "futures", 1958 | ] 1959 | 1960 | [[package]] 1961 | name = "tokio-fs" 1962 | version = "0.1.7" 1963 | source = "registry+https://github.com/rust-lang/crates.io-index" 1964 | checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" 1965 | dependencies = [ 1966 | "futures", 1967 | "tokio-io", 1968 | "tokio-threadpool", 1969 | ] 1970 | 1971 | [[package]] 1972 | name = "tokio-io" 1973 | version = "0.1.13" 1974 | source = "registry+https://github.com/rust-lang/crates.io-index" 1975 | checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" 1976 | dependencies = [ 1977 | "bytes", 1978 | "futures", 1979 | "log", 1980 | ] 1981 | 1982 | [[package]] 1983 | name = "tokio-reactor" 1984 | version = "0.1.12" 1985 | source = "registry+https://github.com/rust-lang/crates.io-index" 1986 | checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" 1987 | dependencies = [ 1988 | "crossbeam-utils", 1989 | "futures", 1990 | "lazy_static 1.4.0", 1991 | "log", 1992 | "mio", 1993 | "num_cpus", 1994 | "parking_lot", 1995 | "slab", 1996 | "tokio-executor", 1997 | "tokio-io", 1998 | "tokio-sync", 1999 | ] 2000 | 2001 | [[package]] 2002 | name = "tokio-service" 2003 | version = "0.1.0" 2004 | source = "registry+https://github.com/rust-lang/crates.io-index" 2005 | checksum = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" 2006 | dependencies = [ 2007 | "futures", 2008 | ] 2009 | 2010 | [[package]] 2011 | name = "tokio-sync" 2012 | version = "0.1.8" 2013 | source = "registry+https://github.com/rust-lang/crates.io-index" 2014 | checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" 2015 | dependencies = [ 2016 | "fnv", 2017 | "futures", 2018 | ] 2019 | 2020 | [[package]] 2021 | name = "tokio-tcp" 2022 | version = "0.1.4" 2023 | source = "registry+https://github.com/rust-lang/crates.io-index" 2024 | checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" 2025 | dependencies = [ 2026 | "bytes", 2027 | "futures", 2028 | "iovec", 2029 | "mio", 2030 | "tokio-io", 2031 | "tokio-reactor", 2032 | ] 2033 | 2034 | [[package]] 2035 | name = "tokio-threadpool" 2036 | version = "0.1.18" 2037 | source = "registry+https://github.com/rust-lang/crates.io-index" 2038 | checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" 2039 | dependencies = [ 2040 | "crossbeam-deque", 2041 | "crossbeam-queue", 2042 | "crossbeam-utils", 2043 | "futures", 2044 | "lazy_static 1.4.0", 2045 | "log", 2046 | "num_cpus", 2047 | "slab", 2048 | "tokio-executor", 2049 | ] 2050 | 2051 | [[package]] 2052 | name = "tokio-timer" 2053 | version = "0.2.13" 2054 | source = "registry+https://github.com/rust-lang/crates.io-index" 2055 | checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" 2056 | dependencies = [ 2057 | "crossbeam-utils", 2058 | "futures", 2059 | "slab", 2060 | "tokio-executor", 2061 | ] 2062 | 2063 | [[package]] 2064 | name = "tokio-tls" 2065 | version = "0.1.4" 2066 | source = "registry+https://github.com/rust-lang/crates.io-index" 2067 | checksum = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913" 2068 | dependencies = [ 2069 | "futures", 2070 | "native-tls 0.1.5", 2071 | "tokio-core", 2072 | "tokio-io", 2073 | ] 2074 | 2075 | [[package]] 2076 | name = "tokio-udp" 2077 | version = "0.1.6" 2078 | source = "registry+https://github.com/rust-lang/crates.io-index" 2079 | checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" 2080 | dependencies = [ 2081 | "bytes", 2082 | "futures", 2083 | "log", 2084 | "mio", 2085 | "tokio-codec", 2086 | "tokio-io", 2087 | "tokio-reactor", 2088 | ] 2089 | 2090 | [[package]] 2091 | name = "tokio-uds" 2092 | version = "0.2.6" 2093 | source = "registry+https://github.com/rust-lang/crates.io-index" 2094 | checksum = "5076db410d6fdc6523df7595447629099a1fdc47b3d9f896220780fa48faf798" 2095 | dependencies = [ 2096 | "bytes", 2097 | "futures", 2098 | "iovec", 2099 | "libc", 2100 | "log", 2101 | "mio", 2102 | "mio-uds", 2103 | "tokio-codec", 2104 | "tokio-io", 2105 | "tokio-reactor", 2106 | ] 2107 | 2108 | [[package]] 2109 | name = "try-lock" 2110 | version = "0.1.0" 2111 | source = "registry+https://github.com/rust-lang/crates.io-index" 2112 | checksum = "ee2aa4715743892880f70885373966c83d73ef1b0838a664ef0c76fffd35e7c2" 2113 | 2114 | [[package]] 2115 | name = "try-lock" 2116 | version = "0.2.2" 2117 | source = "registry+https://github.com/rust-lang/crates.io-index" 2118 | checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" 2119 | 2120 | [[package]] 2121 | name = "try_from" 2122 | version = "0.3.2" 2123 | source = "registry+https://github.com/rust-lang/crates.io-index" 2124 | checksum = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" 2125 | dependencies = [ 2126 | "cfg-if", 2127 | ] 2128 | 2129 | [[package]] 2130 | name = "ucd-util" 2131 | version = "0.1.8" 2132 | source = "registry+https://github.com/rust-lang/crates.io-index" 2133 | checksum = "c85f514e095d348c279b1e5cd76795082cf15bd59b93207832abe0b1d8fed236" 2134 | 2135 | [[package]] 2136 | name = "unicase" 2137 | version = "2.6.0" 2138 | source = "registry+https://github.com/rust-lang/crates.io-index" 2139 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 2140 | dependencies = [ 2141 | "version_check", 2142 | ] 2143 | 2144 | [[package]] 2145 | name = "unicode-bidi" 2146 | version = "0.3.4" 2147 | source = "registry+https://github.com/rust-lang/crates.io-index" 2148 | checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 2149 | dependencies = [ 2150 | "matches", 2151 | ] 2152 | 2153 | [[package]] 2154 | name = "unicode-normalization" 2155 | version = "0.1.12" 2156 | source = "registry+https://github.com/rust-lang/crates.io-index" 2157 | checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" 2158 | dependencies = [ 2159 | "smallvec 1.2.0", 2160 | ] 2161 | 2162 | [[package]] 2163 | name = "unicode-segmentation" 2164 | version = "1.6.0" 2165 | source = "registry+https://github.com/rust-lang/crates.io-index" 2166 | checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" 2167 | 2168 | [[package]] 2169 | name = "unicode-width" 2170 | version = "0.1.7" 2171 | source = "registry+https://github.com/rust-lang/crates.io-index" 2172 | checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" 2173 | 2174 | [[package]] 2175 | name = "unicode-xid" 2176 | version = "0.2.0" 2177 | source = "registry+https://github.com/rust-lang/crates.io-index" 2178 | checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 2179 | 2180 | [[package]] 2181 | name = "url" 2182 | version = "1.7.2" 2183 | source = "registry+https://github.com/rust-lang/crates.io-index" 2184 | checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" 2185 | dependencies = [ 2186 | "idna 0.1.5", 2187 | "matches", 2188 | "percent-encoding 1.0.1", 2189 | ] 2190 | 2191 | [[package]] 2192 | name = "url" 2193 | version = "2.1.1" 2194 | source = "registry+https://github.com/rust-lang/crates.io-index" 2195 | checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" 2196 | dependencies = [ 2197 | "idna 0.2.0", 2198 | "matches", 2199 | "percent-encoding 2.1.0", 2200 | ] 2201 | 2202 | [[package]] 2203 | name = "url_serde" 2204 | version = "0.2.0" 2205 | source = "registry+https://github.com/rust-lang/crates.io-index" 2206 | checksum = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" 2207 | dependencies = [ 2208 | "serde", 2209 | "url 1.7.2", 2210 | ] 2211 | 2212 | [[package]] 2213 | name = "utf8-ranges" 2214 | version = "1.0.4" 2215 | source = "registry+https://github.com/rust-lang/crates.io-index" 2216 | checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba" 2217 | 2218 | [[package]] 2219 | name = "uuid" 2220 | version = "0.6.5" 2221 | source = "registry+https://github.com/rust-lang/crates.io-index" 2222 | checksum = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" 2223 | dependencies = [ 2224 | "cfg-if", 2225 | "rand 0.4.6", 2226 | ] 2227 | 2228 | [[package]] 2229 | name = "uuid" 2230 | version = "0.7.4" 2231 | source = "registry+https://github.com/rust-lang/crates.io-index" 2232 | checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" 2233 | dependencies = [ 2234 | "rand 0.6.5", 2235 | ] 2236 | 2237 | [[package]] 2238 | name = "vcpkg" 2239 | version = "0.2.8" 2240 | source = "registry+https://github.com/rust-lang/crates.io-index" 2241 | checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" 2242 | 2243 | [[package]] 2244 | name = "vec_map" 2245 | version = "0.8.1" 2246 | source = "registry+https://github.com/rust-lang/crates.io-index" 2247 | checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 2248 | 2249 | [[package]] 2250 | name = "version_check" 2251 | version = "0.9.1" 2252 | source = "registry+https://github.com/rust-lang/crates.io-index" 2253 | checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" 2254 | 2255 | [[package]] 2256 | name = "want" 2257 | version = "0.0.4" 2258 | source = "registry+https://github.com/rust-lang/crates.io-index" 2259 | checksum = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1" 2260 | dependencies = [ 2261 | "futures", 2262 | "log", 2263 | "try-lock 0.1.0", 2264 | ] 2265 | 2266 | [[package]] 2267 | name = "want" 2268 | version = "0.2.0" 2269 | source = "registry+https://github.com/rust-lang/crates.io-index" 2270 | checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" 2271 | dependencies = [ 2272 | "futures", 2273 | "log", 2274 | "try-lock 0.2.2", 2275 | ] 2276 | 2277 | [[package]] 2278 | name = "wasi" 2279 | version = "0.9.0+wasi-snapshot-preview1" 2280 | source = "registry+https://github.com/rust-lang/crates.io-index" 2281 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 2282 | 2283 | [[package]] 2284 | name = "winapi" 2285 | version = "0.2.8" 2286 | source = "registry+https://github.com/rust-lang/crates.io-index" 2287 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 2288 | 2289 | [[package]] 2290 | name = "winapi" 2291 | version = "0.3.8" 2292 | source = "registry+https://github.com/rust-lang/crates.io-index" 2293 | checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 2294 | dependencies = [ 2295 | "winapi-i686-pc-windows-gnu", 2296 | "winapi-x86_64-pc-windows-gnu", 2297 | ] 2298 | 2299 | [[package]] 2300 | name = "winapi-build" 2301 | version = "0.1.1" 2302 | source = "registry+https://github.com/rust-lang/crates.io-index" 2303 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 2304 | 2305 | [[package]] 2306 | name = "winapi-i686-pc-windows-gnu" 2307 | version = "0.4.0" 2308 | source = "registry+https://github.com/rust-lang/crates.io-index" 2309 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2310 | 2311 | [[package]] 2312 | name = "winapi-util" 2313 | version = "0.1.4" 2314 | source = "registry+https://github.com/rust-lang/crates.io-index" 2315 | checksum = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e" 2316 | dependencies = [ 2317 | "winapi 0.3.8", 2318 | ] 2319 | 2320 | [[package]] 2321 | name = "winapi-x86_64-pc-windows-gnu" 2322 | version = "0.4.0" 2323 | source = "registry+https://github.com/rust-lang/crates.io-index" 2324 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2325 | 2326 | [[package]] 2327 | name = "winreg" 2328 | version = "0.6.2" 2329 | source = "registry+https://github.com/rust-lang/crates.io-index" 2330 | checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" 2331 | dependencies = [ 2332 | "winapi 0.3.8", 2333 | ] 2334 | 2335 | [[package]] 2336 | name = "ws2_32-sys" 2337 | version = "0.2.1" 2338 | source = "registry+https://github.com/rust-lang/crates.io-index" 2339 | checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 2340 | dependencies = [ 2341 | "winapi 0.2.8", 2342 | "winapi-build", 2343 | ] 2344 | --------------------------------------------------------------------------------