├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── template.toml └── {{project_name}} ├── .editorconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG ├── Cargo.toml ├── LICENSE ├── README.md ├── appveyor.yml ├── build.rs ├── ci ├── before_deploy.ps1 ├── before_deploy.sh ├── install.sh └── script.sh └── src ├── cli.rs ├── errors.rs ├── main.rs └── terminal.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .idea/ 3 | my-cli 4 | My-CLI 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - beta 4 | 5 | sudo: false 6 | 7 | notifications: 8 | email: false 9 | 10 | before_script: 11 | - cargo install kickstart 12 | 13 | script: 14 | - kickstart validate template.toml 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Vincent Prouillet 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-cli-template 2 | 3 | A template to get started with writing cross-platforms CLI applications 4 | hosted on GitHub. 5 | 6 | ## Features 7 | 8 | - CLI app setup with clap 9 | - Optional terminal colours & styling 10 | - CI setup 11 | - Cross-platform binary release via [trust](https://github.com/japaric/trust) 12 | - Shell completion scripts setup 13 | - Various repo housekeeping: changelog, editorconfig etc 14 | 15 | All of the above is optional: you can pick only the features you want. 16 | 17 | ## Pre-requisites 18 | If you want to enable the publication of binaries, you will need to do the following steps first. 19 | 20 | ### Create the GitHub repo 21 | You might also need to enable it in Travis/AppVeyor. 22 | 23 | ### Encrypt a GH token for Travis 24 | Go to https://github.com/settings/tokens/new and create 1 `public_repo` tokens, the 25 | name is up to you but should be something like `{{project}} Travis` so it is easy to find. 26 | 27 | Encrypt the token by using the `travis` gem: 28 | 29 | ```bash 30 | $ travis encrypt $TOKEN -r $GH_USER/$GH_REPO 31 | ``` 32 | 33 | If your repo is using travis.com (likely now), you will also need to pass the `--com` flag. 34 | 35 | Copy the output somewhere, we will need it later! 36 | 37 | ### Encrypt it for AppVeyor 38 | Go to https://github.com/settings/tokens/new and create 1 `public_repo` tokens, the 39 | name is up to you but should be something like `{{project}} AppVeyor` so it is easy to find. 40 | 41 | Go to https://ci.appveyor.com/tools/encrypt and encrypt the second GitHub token. 42 | As before, you will also need the output later. 43 | 44 | ## Get started 45 | This is a [kickstart template](https://github.com/Keats/kickstart) so you 46 | will need to have `kickstart` installed: 47 | 48 | ```bash 49 | $ cargo install kickstart 50 | ``` 51 | 52 | Once you have it installed and have the encrypted tokens generated above if needed, run: 53 | 54 | ```bash 55 | $ kickstart https://github.com/Keats/rust-cli-template 56 | ``` 57 | 58 | ## Steps left for you 59 | 60 | - Check that the name repo name in the badges in the README match the actual one: it uses the project 61 | name by default 62 | 63 | 64 | ## Template TODOs 65 | 66 | - Is there an equivalent to Trust for GitLab? 67 | -------------------------------------------------------------------------------- /template.toml: -------------------------------------------------------------------------------- 1 | name = "Rust CLI template" 2 | description = "A template to get started with a Rust CLI application on the right foot" 3 | kickstart_version = 1 4 | ignore = [ 5 | ".gitignore", 6 | "README.md", 7 | "LICENSE", 8 | ".travis.yml", 9 | ] 10 | 11 | cleanup = [ 12 | {name = "license", value = "None", paths = ["{{project_name}}/LICENSE"]}, 13 | {name = "changelog", value = false, paths = ["{{project_name}}/CHANGELOG"]}, 14 | {name = "on_github", value = false, paths = ["{{project_name}}/.travis.yml", "{{project_name}}/appveyor.yml", "{{project_name}}/ci"]}, 15 | {name = "shell_completions", value = false, paths = ["{{project_name}}/build.rs", "{{project_name}}/completions"]}, 16 | {name = "editorconfig", value = false, paths = ["{{project_name}}/.editorconfig"]}, 17 | {name = "fancy_term", value = false, paths = ["{{project_name}}/src/terminal.rs"]}, 18 | ] 19 | 20 | [[variables]] 21 | name = "project_name" 22 | default = "My-CLI" 23 | prompt = "What's the name of the project?" 24 | validation = "^([a-zA-Z][a-zA-Z0-9_-]+)$" 25 | 26 | [[variables]] 27 | name = "bin" 28 | default = "my-cli" 29 | prompt = "What's the name of the executable?" 30 | validation = "^([a-zA-Z][a-zA-Z-_]+)$" 31 | 32 | [[variables]] 33 | name = "description" 34 | default = "A CLI application" 35 | prompt = "A short description of the app?" 36 | 37 | [[variables]] 38 | name = "author" 39 | default = "No One" 40 | prompt = "What is your name?" 41 | 42 | [[variables]] 43 | name = "email" 44 | default = "no@one.com" 45 | prompt = "What is your email?" 46 | 47 | [[variables]] 48 | name = "license" 49 | default = "MIT" 50 | prompt = "Which open-source license do you want to use?" 51 | choices = [ 52 | "MIT", 53 | "BSD", 54 | "GPLv3", 55 | "None", 56 | ] 57 | 58 | [[variables]] 59 | name = "on_github" 60 | default = true 61 | prompt = "Will the project be hosted on GitHub?" 62 | 63 | [[variables]] 64 | name = "gh_username" 65 | default = "" 66 | prompt = "What is your GitHub username?" 67 | only_if = { name = "on_github", value = true } 68 | 69 | [[variables]] 70 | name = "publish_binaries" 71 | default = true 72 | prompt = "Do you want to publish binary releases for Linux, MacOs and Windows?" 73 | only_if = { name = "on_github", value = true } 74 | 75 | [[variables]] 76 | name = "gh_token" 77 | default = "REPLACE_ME" 78 | prompt = "What is the Travis encrypted Travis token?" 79 | only_if = { name = "publish_binaries", value = true } 80 | 81 | [[variables]] 82 | name = "appveyor_token" 83 | default = "REPLACE_ME" 84 | prompt = "What is the AppVeyor encrypted Travis token?" 85 | only_if = { name = "publish_binaries", value = true } 86 | 87 | [[variables]] 88 | name = "ci_notifications" 89 | default = false 90 | prompt = "Do you want to be notified by email for every CI build?" 91 | only_if = { name = "publish_binaries", value = true } 92 | 93 | [[variables]] 94 | name = "shell_completions" 95 | default = true 96 | prompt = "Do you want to generate shell completions?" 97 | 98 | [[variables]] 99 | name = "fancy_term" 100 | default = false 101 | prompt = "Do you want to add colours/style to the terminal output?" 102 | 103 | [[variables]] 104 | name = "changelog" 105 | default = true 106 | prompt = "Do you want to keep a changelog?" 107 | 108 | [[variables]] 109 | name = "editorconfig" 110 | default = true 111 | prompt = "Do you want to use editorconfig (https://editorconfig.org)?" 112 | -------------------------------------------------------------------------------- /{{project_name}}/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 4 10 | 11 | [*.rs] 12 | indent_style = space 13 | indent_size = 4 14 | 15 | [*.toml] 16 | indent_style = space 17 | indent_size = 4 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /{{project_name}}/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | **/*.rs.bk 3 | 4 | .idea/ 5 | 6 | .vscode/* 7 | !.vscode/settings.json 8 | !.vscode/tasks.json 9 | !.vscode/launch.json 10 | !.vscode/extensions.json 11 | -------------------------------------------------------------------------------- /{{project_name}}/.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: rust 3 | services: docker 4 | 5 | env: 6 | global: 7 | - CRATE_NAME={{bin}} 8 | 9 | matrix: 10 | include: 11 | # Linux 12 | - env: TARGET=x86_64-unknown-linux-gnu 13 | # OSX 14 | - env: TARGET=x86_64-apple-darwin 15 | os: osx 16 | 17 | # Testing other channels 18 | - env: TARGET=x86_64-unknown-linux-gnu 19 | rust: beta 20 | - env: TARGET=x86_64-unknown-linux-gnu 21 | rust: nightly 22 | 23 | 24 | before_install: set -e 25 | 26 | install: 27 | - sh ci/install.sh 28 | - source ~/.cargo/env || true 29 | 30 | script: 31 | - bash ci/script.sh 32 | 33 | after_script: set +e 34 | 35 | before_deploy: 36 | - sh ci/before_deploy.sh 37 | 38 | deploy: 39 | api_key: 40 | # if you see REPLACE_ME here, fix it by following the README of the template 41 | secure: {{gh_token | default(value="")}} 42 | file_glob: true 43 | file: $CRATE_NAME-$TRAVIS_TAG-$TARGET.* 44 | on: 45 | condition: $TRAVIS_RUST_VERSION = stable 46 | tags: true 47 | provider: releases 48 | skip_cleanup: true 49 | 50 | cache: cargo 51 | before_cache: 52 | # Travis can't cache files that are not readable by "others" 53 | - chmod -R a+r $HOME/.cargo 54 | 55 | branches: 56 | only: 57 | # release tags 58 | - /^v\d+\.\d+\.\d+.*$/ 59 | - master 60 | 61 | notifications: 62 | email: {{ci_notifications | default(value=false)}} 63 | -------------------------------------------------------------------------------- /{{project_name}}/CHANGELOG: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.1.0 (unreleased) 4 | - Initial release 5 | -------------------------------------------------------------------------------- /{{project_name}}/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "{{project_name}}" 3 | description = "{{description}}" 4 | version = "0.1.0" 5 | authors = ["{{author}} <{{email}}>"] 6 | autobins = false 7 | {% if license != "None" -%} 8 | license = "{{license}}" 9 | {%- endif %} 10 | 11 | [[bin]] 12 | name = "{{bin}}" 13 | path = "src/main.rs" 14 | 15 | [dependencies] 16 | clap = "2" 17 | {% if fancy_term -%} 18 | term = "0.5" 19 | {%- endif -%} 20 | 21 | {%- if shell_completions %} 22 | 23 | [build-dependencies] 24 | clap = "2" 25 | {%- endif %} 26 | -------------------------------------------------------------------------------- /{{project_name}}/LICENSE: -------------------------------------------------------------------------------- 1 | {%- set year = now() | date(format="%Y") -%} 2 | {%- if license == "MIT" -%} 3 | MIT License 4 | 5 | Copyright (c) {{year}} {{author}} 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | {%- elif license == "BSD" -%} 25 | Copyright (c) {{year}}, {{author}} 26 | All rights reserved. 27 | 28 | Redistribution and use in source and binary forms, with or without modification, 29 | are permitted provided that the following conditions are met: 30 | 31 | * Redistributions of source code must retain the above copyright notice, this 32 | list of conditions and the following disclaimer. 33 | 34 | * Redistributions in binary form must reproduce the above copyright notice, this 35 | list of conditions and the following disclaimer in the documentation and/or 36 | other materials provided with the distribution. 37 | 38 | * Neither the name of {{ project_name }} nor the names of its 39 | contributors may be used to endorse or promote products derived from this 40 | software without specific prior written permission. 41 | 42 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 43 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 44 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 45 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 46 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 47 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 48 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 49 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 50 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51 | OF THE POSSIBILITY OF SUCH DAMAGE. 52 | {%- elif license == "GPLv3" -%} 53 | Copyright (c) {{year}}, {{author}} 54 | 55 | This program is free software: you can redistribute it and/or modify 56 | it under the terms of the GNU General Public License as published by 57 | the Free Software Foundation, either version 3 of the License, or 58 | (at your option) any later version. 59 | 60 | This program is distributed in the hope that it will be useful, 61 | but WITHOUT ANY WARRANTY; without even the implied warranty of 62 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 63 | GNU General Public License for more details. 64 | 65 | You should have received a copy of the GNU General Public License 66 | along with this program. If not, see . 67 | {%- endif -%} 68 | -------------------------------------------------------------------------------- /{{project_name}}/README.md: -------------------------------------------------------------------------------- 1 | # {{project_name}} 2 | 3 | {{description}} 4 | 5 | {%- if on_github -%} 6 | 7 | [![Linux build status](https://travis-ci.org/{{gh_username}}/{{project_name}}.svg?branch=master)](https://travis-ci.org/{{gh_username}}/{{project_name}}) 8 | [![Windows build status](https://ci.appveyor.com/api/projects/status/github/{{gh_username}}/{{project_name}}?svg=true)](https://ci.appveyor.com/project/{{gh_username}}/{{project_name}}) 9 | {%- endif %} 10 | 11 | {%- if license %} 12 | 13 | Licensed under {{license}}. 14 | {%- endif %} 15 | 16 | {%- if changelog %} 17 | 18 | ## Changelog 19 | 20 | Please see the [CHANGELOG](CHANGELOG.md) for a release history. 21 | {%- endif -%} 22 | 23 | {%- if publish_binaries %} 24 | 25 | ## Installation 26 | Binaries are automatically uploaded to GitHub for each version. 27 | {%- endif -%} 28 | -------------------------------------------------------------------------------- /{{project_name}}/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: {{bin}} 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 | 24 | # Testing other channels 25 | - TARGET: x86_64-pc-windows-gnu 26 | RUST_VERSION: nightly 27 | - TARGET: x86_64-pc-windows-msvc 28 | RUST_VERSION: nightly 29 | 30 | install: 31 | - ps: >- 32 | If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') { 33 | $Env:PATH += ';C:\msys64\mingw64\bin' 34 | } ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') { 35 | $Env:PATH += ';C:\msys64\mingw32\bin' 36 | } 37 | - curl -sSf -o rustup-init.exe https://win.rustup.rs/ 38 | - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION% 39 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin 40 | - rustc -Vv 41 | - cargo -V 42 | 43 | # TODO This is the "test phase", tweak it as you see fit 44 | test_script: 45 | # we don't run the "test phase" when doing deploys 46 | - if [%APPVEYOR_REPO_TAG%]==[false] ( 47 | cargo build --target %TARGET% && 48 | cargo build --target %TARGET% --release && 49 | cargo test --target %TARGET% && 50 | cargo test --target %TARGET% --release && 51 | cargo run --target %TARGET% && 52 | cargo run --target %TARGET% --release 53 | ) 54 | 55 | before_deploy: 56 | # TODO Update this to build the artifacts that matter to you 57 | - cargo rustc --target %TARGET% --release --bin {{bin}} -- -C lto 58 | - ps: ci\before_deploy.ps1 59 | 60 | deploy: 61 | artifact: /.*\.zip/ 62 | # TODO update `auth_token.secure` 63 | # - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new 64 | # - Encrypt it. Go to https://ci.appveyor.com/tools/encrypt 65 | # - Paste the output down here 66 | auth_token: 67 | secure: {{appveyor_token | default(value="")}} 68 | description: '' 69 | on: 70 | # TODO Here you can pick which targets will generate binary releases 71 | # In this example, there are some targets that are tested using the stable 72 | # and nightly channels. This condition makes sure there is only one release 73 | # for such targets and that's generated using the stable channel 74 | RUST_VERSION: stable 75 | appveyor_repo_tag: true 76 | provider: GitHub 77 | 78 | cache: 79 | - C:\Users\appveyor\.cargo\registry 80 | - target 81 | 82 | branches: 83 | only: 84 | # Release tags 85 | - /^v\d+\.\d+\.\d+.*$/ 86 | - master 87 | 88 | notifications: 89 | - provider: Email 90 | to: 91 | - {{email}} 92 | on_build_success: {{ci_notifications | default(value=false)}} 93 | 94 | # Building is done in the test phase, so we disable Appveyor's build phase. 95 | build: false 96 | -------------------------------------------------------------------------------- /{{project_name}}/build.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate clap; 3 | 4 | use clap::Shell; 5 | 6 | include!("src/cli.rs"); 7 | 8 | fn main() { 9 | // this might fail in CI 10 | let mut app = build_cli(); 11 | app.gen_completions("{{bin}}", Shell::Bash, "completions/"); 12 | app.gen_completions("{{bin}}", Shell::Fish, "completions/"); 13 | app.gen_completions("{{bin}}", Shell::Zsh, "completions/"); 14 | app.gen_completions("{{bin}}", Shell::PowerShell, "completions/"); 15 | } 16 | -------------------------------------------------------------------------------- /{{project_name}}/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\{{bin}}.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 | -------------------------------------------------------------------------------- /{{project_name}}/ci/before_deploy.sh: -------------------------------------------------------------------------------- 1 | # This script takes care of building your crate and packaging it for release 2 | 3 | set -ex 4 | 5 | main() { 6 | local src=$(pwd) \ 7 | stage= 8 | 9 | case $TRAVIS_OS_NAME in 10 | linux) 11 | stage=$(mktemp -d) 12 | ;; 13 | osx) 14 | stage=$(mktemp -d -t tmp) 15 | ;; 16 | esac 17 | 18 | test -f Cargo.lock || cargo generate-lockfile 19 | 20 | # TODO Update this to build the artifacts that matter to you 21 | cross rustc --bin {{bin}} --target $TARGET --release -- -C lto 22 | 23 | # TODO Update this to package the right artifacts 24 | cp target/$TARGET/release/{{bin}} $stage/ 25 | 26 | cd $stage 27 | tar czf $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz * 28 | cd $src 29 | 30 | rm -rf $stage 31 | } 32 | 33 | main 34 | -------------------------------------------------------------------------------- /{{project_name}}/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 | -------------------------------------------------------------------------------- /{{project_name}}/ci/script.sh: -------------------------------------------------------------------------------- 1 | # This script takes care of testing your crate 2 | 3 | set -ex 4 | 5 | # TODO This is the "test phase", tweak it as you see fit 6 | main() { 7 | cross build --target $TARGET 8 | cross build --target $TARGET --release 9 | 10 | if [ ! -z $DISABLE_TESTS ]; then 11 | return 12 | fi 13 | 14 | cross test --all --target $TARGET 15 | cross test --all --target $TARGET --release 16 | } 17 | 18 | # we don't run the "test phase" when doing deploys 19 | if [ -z $TRAVIS_TAG ]; then 20 | main 21 | fi 22 | -------------------------------------------------------------------------------- /{{project_name}}/src/cli.rs: -------------------------------------------------------------------------------- 1 | use clap::{App, Arg, SubCommand}; 2 | 3 | 4 | pub fn build_cli() -> App<'static, 'static> { 5 | App::new("{{bin}}") 6 | .version(crate_version!()) 7 | .author(crate_authors!()) 8 | .about(crate_description!()) 9 | .subcommands(vec![]) 10 | } 11 | -------------------------------------------------------------------------------- /{{project_name}}/src/errors.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error as StdError; 2 | use std::result; 3 | 4 | /// A crate private constructor for `Error`. 5 | pub(crate) fn new_error(kind: ErrorKind) -> Error { 6 | Error(Box::new(kind)) 7 | } 8 | 9 | /// A type alias for `Result`. 10 | pub type Result = result::Result; 11 | 12 | /// An error that can occur when encoding/decoding JWTs 13 | #[derive(Debug)] 14 | pub struct Error(Box); 15 | 16 | impl Error { 17 | /// Return the specific type of this error. 18 | pub fn kind(&self) -> &ErrorKind { 19 | &self.0 20 | } 21 | /// Unwrap this error into its underlying type. 22 | pub fn into_kind(self) -> ErrorKind { 23 | *self.0 24 | } 25 | } 26 | 27 | /// The specific type of an error. 28 | #[derive(Debug)] 29 | pub enum ErrorKind { 30 | // Add your errors there 31 | } 32 | -------------------------------------------------------------------------------- /{{project_name}}/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate clap; 3 | {%- if fancy_term %} 4 | 5 | extern crate term; 6 | {%- endif %} 7 | 8 | mod cli; 9 | mod errors; 10 | {%- if fancy_term %} 11 | mod terminal; 12 | {%- endif %} 13 | 14 | fn main() { 15 | let matches = cli::build_cli().get_matches(); 16 | // Do your thing here 17 | } 18 | -------------------------------------------------------------------------------- /{{project_name}}/src/terminal.rs: -------------------------------------------------------------------------------- 1 | use std::io::prelude::*; 2 | 3 | use term; 4 | 5 | // Some examples on how to use the term crate 6 | 7 | pub fn error(message: &str) { 8 | if let Some(mut t) = term::stderr() { 9 | match t.fg(term::color::BRIGHT_RED) { 10 | Ok(_) => { 11 | write!(t, "{}", message).unwrap(); 12 | t.reset().unwrap(); 13 | }, 14 | Err(_) => writeln!(t, "{}", message).unwrap() 15 | }; 16 | } else { 17 | eprint!("{}", message); 18 | } 19 | } 20 | 21 | 22 | pub fn success(message: &str) { 23 | if let Some(mut t) = term::stdout() { 24 | match t.fg(term::color::GREEN) { 25 | Ok(_) => { 26 | write!(t, "{}", message).unwrap(); 27 | t.reset().unwrap(); 28 | }, 29 | Err(_) => writeln!(t, "{}", message).unwrap() 30 | }; 31 | } else { 32 | eprint!("{}", message); 33 | } 34 | } 35 | 36 | --------------------------------------------------------------------------------