github.com/nikron/prototool@v1.3.0/README.md (about)

     1  # prototool [![Mit License][mit-img]][mit] [![GitHub Release][release-img]][release] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
     2  
     3  [Protobuf](https://developers.google.com/protocol-buffers) is one of the best interface description languages out there - it's widely adopted, and after over 15 years of use, it's practically bulletproof. However, working with Protobuf and maintaining consistency across your Protobuf files can be a pain - protoc, while being a tool that has stood the test of time, is non-trivial to use, and the Protobuf community has not developed common standards with regards to stub generation. Prototool aims to solve this by making working with Protobuf much simpler.
     4  
     5  Prototool lets you:
     6  
     7  - Handle installation of protoc and the import of all of the Well-Known Types behind the scenes in a platform-independent manner without any work on the part of the user.
     8  - Standardize building of your Protobuf files with a common configuration, abstracting away all of the pain of protoc for you.
     9  - Lint your Protobuf files with common linting rules according to a Style Guide.
    10  - Format your Protobuf files in a consistent manner.
    11  - Generate Protobuf files from a template that passes lint, taking care of package naming for you.
    12  - Generate stubs using any plugin based on a simple configuration file, including handling imports of all the Well-Known Types.
    13  - Call gRPC endpoints with ease, taking care of the JSON to binary conversion for you.
    14  - Output errors and lint failures in a common file:line:column:message format, making integration with editors possible, Vim integration is provided out of the box.
    15  
    16  Prototool accomplishes this by downloading and calling protoc on the fly for you, handing error messages from protoc and your plugins, and using the generated FileDescriptorSets for internal functionality, as well as wrapping a few great external libraries already in the Protobuf ecosystem.
    17  
    18    * [Installation](#installation)
    19    * [Quick Start](#quick-start)
    20    * [Full Example](#full-example)
    21    * [Configuration](#configuration)
    22    * [File Discovery](#file-discovery)
    23    * [Command Overview](#command-overview)
    24      * [prototool config init](#prototool-config-init)
    25      * [prototool compile](#prototool-compile)
    26      * [prototool generate](#prototool-generate)
    27      * [prototool lint](#prototool-lint)
    28      * [prototool format](#prototool-format)
    29      * [prototool create](#prototool-create)
    30      * [prototool files](#prototool-files)
    31      * [prototool grpc](#prototool-grpc)
    32    * [gRPC Example](#grpc-example)
    33    * [Tips and Tricks](#tips-and-tricks)
    34    * [Vim Integration](#vim-integration)
    35    * [Development](#development)
    36    * [FAQ](#faq)
    37      * [Pre-Cache Protoc](#pre-cache-protoc)
    38      * [Alpine Linux Issues](#alpine-linux-issues)
    39      * [Managing External Plugins/Docker](#managing-external-pluginsdocker)
    40      * [Lint/Format Choices](#lintformat-choices)
    41    * [Special Thanks](#special-thanks)
    42  
    43  ## Installation
    44  
    45  Prototool can be installed on Mac OS X via [Homebrew](https://brew.sh/) or Linux via [Linuxbrew](http://linuxbrew.sh/).
    46  
    47  ```bash
    48  brew install prototool
    49  ```
    50  
    51  This installs the `prototool` binary, along with bash completion, zsh completion, and man pages.
    52  You can also install all of the assets on Linux or without Homebrew from GitHub Releases.
    53  
    54  ```bash
    55  curl -sSL https://github.com/uber/prototool/releases/download/v1.3.0/prototool-$(uname -s)-$(uname -m).tar.gz | \
    56    tar -C /usr/local --strip-components 1 -xz
    57  ```
    58  
    59  If you do not want to install bash completion, zsh completion, or man mages, you can install just the
    60  `prototool` binary from GitHub Releases as well.
    61  
    62  ```bash
    63  curl -sSL https://github.com/uber/prototool/releases/download/v1.3.0/prototool-$(uname -s)-$(uname -m) \
    64    -o /usr/local/bin/prototool && \
    65    chmod +x /usr/local/bin/prototool
    66  ```
    67  
    68  Prototool is purposefully all put under internal in an attempt to emphasize that you should not install `prototool` with `go get`.
    69  Although you can technically `go get` from `internal`, we do not check in the vendor directory, so `go get` will not respect the
    70  versions in `glide.yaml`. We have specific version requirements, so not using these can and probably will result in errors when building
    71  `prototool` and/or result in unexpected runtime errors.
    72  
    73  ## Quick Start
    74  
    75  We'll start with a general overview of the commands. There are more commands, and we will get into usage below, but this shows the basic functionality.
    76  
    77  ```bash
    78  prototool help
    79  prototool lint path/to/foo.proto path/to/bar.proto # file mode, specify multiple specific files
    80  prototool lint idl/uber # directory mode, search for all .proto files recursively, obeying exclude_paths in prototool.yaml or prototool.json files
    81  prototool lint # same as "prototool lint .", by default the current directory is used in directory mode
    82  prototool create foo.proto # create the file foo.proto from a template that passes lint
    83  prototool files idl/uber # list the files that will be used after applying exclude_paths from corresponding prototool.yaml or prototool.json files
    84  prototool lint --list-linters # list all current lint rules being used
    85  prototool compile idl/uber # make sure all .proto files in idl/uber compile, but do not generate stubs
    86  prototool generate idl/uber # generate stubs, see the generation directives in the config file example
    87  prototool grpc idl/uber --address 0.0.0.0:8080 --method foo.ExcitedService/Exclamation --data '{"value":"hello"}' # call the foo.ExcitedService method Exclamation with the given data on 0.0.0.0:8080
    88  ```
    89  
    90  ## Full Example
    91  
    92  See the [example](example) directory.
    93  
    94  The make command `make example` runs prototool while installing the necessary plugins.
    95  
    96  ## Configuration
    97  
    98  Prototool operates using a config file named either `prototool.yaml` or `prototool.json`. Only one of `prototool.yaml` or `prototool.json` can exist in a given directory. For non-trivial use, you should have a config file checked in to at least the root of your repository. It is important because the directory of an associated config file is passed to `protoc` as an include directory with `-I`, so this is the logical location your Protobuf file imports should start from.
    99  
   100  Recommended base config file:
   101  
   102  ```yaml
   103  protoc:
   104    version: 3.6.1
   105  ```
   106  
   107  The command `prototool config init` will generate a config file in the current directory with all available configuration options commented out except `protoc.version`. See [etc/config/example/prototool.yaml](etc/config/example/prototool.yaml) for the config file that `prototool config init --uncomment` generates.
   108  
   109  When specifying a directory or set of files for Prototool to operate on, Prototool will search for config files for each directory starting at the given path, and going up a directory until hitting root. If no config file is found, Prototool will use default values and operate as if there was a config file in the current directory, including the current directory with `-I` to `protoc`.
   110  
   111  If multiple `prototool.yaml` or `prototool.json` files are found that match the input directory or files, an error will be returned.
   112  
   113  ## File Discovery
   114  
   115  In most Prototool commands, you will see help along the following lines:
   116  
   117  ```bash
   118  $ prototool help lint
   119  Lint proto files and compile with protoc to check for failures.
   120  
   121  Usage:
   122    prototool lint [dirOrFile] [flags]
   123  ```
   124  
   125  `dirOrFile` can take two forms:
   126  
   127  - You can specify exactly one directory. If this is done, Prototool goes up until it finds a `prototool.yaml` or `prototool.json` file (or uses the current directory if none is found), and then walks starting at this location for all `.proto` files, and these are used, except for files in the `excludes` lists in `prototool.yaml` or `prototool.json` files.
   128  - You can specify exactly one file. This has the effect as if you specified the directory of this file (using the logic above), but errors are only printed for that file. This is useful for e.g. Vim integration.
   129  - You can specify nothing. This has the effect as if you specified the current directory as the directory.
   130  
   131  The idea with "directory builds" is that you often need more than just one file to do a `protoc` call, for example if you have types in other files in the same package that are not referenced by their fully-qualified name, and/or if you need to know what directories to specify with `-I` to `protoc` (by default, the directory of the `prototool.yaml` or `prototool.json` file is used).
   132  
   133  ## Command Overview
   134  
   135  Let's go over some of the basic commands.
   136  
   137  ##### `prototool config init`
   138  
   139  Create a `prototool.yaml` file in the current directory, with all options except `protoc.version` commented out.
   140  
   141  ##### `prototool compile`
   142  
   143  Compile your Protobuf files, but do not generate stubs. This has the effect of calling `protoc` with `-o /dev/null`.
   144  
   145  ##### `prototool generate`
   146  
   147  Compile your Protobuf files and generate stubs according to the rules in your `prototool.yaml` or `prototool.json` file. See [example/idl/uber/prototool.yaml](example/idl/uber/prototool.yaml) for an example.
   148  
   149  ##### `prototool lint`
   150  
   151  Lint your Protobuf files. The default rule set follows the Style Guide at [etc/style/uber/uber.proto](etc/style/uber/uber.proto). You can add or exclude lint rules in your `prototool.yaml` or `prototool.json` file. The default rule set is "strict", and we are working on having two main sets of rules.
   152  
   153  ##### `prototool format`
   154  
   155  Format a Protobuf file and print the formatted file to stdout. There are flags to perform different actions:
   156  
   157  - `-d` Write a diff instead.
   158  - `-f` Fix the file according to the Style Guide.
   159  - `-l` Write a lint error in the form file:line:column:message if a file is unformatted.
   160  - `-w` Overwrite the existing file instead.
   161  
   162  Concretely, the `-f` flag can be used so that the values for `java_multiple_files`, `java_outer_classname`, and `java_package` are updated to reflect what is expected by the
   163  [Google Cloud APIs file structure](https://cloud.google.com/apis/design/file_structure), and the value of `go_package` is updated to reflect what we expect for the
   164  default Style Guide. By formatting, the linting for these values will pass by default. See the documentation below for `prototool create` for an example.
   165  
   166  ##### `prototool create`
   167  
   168  Create a Protobuf file from a template that passes lint. Assuming the filename `example_create_file.proto`, the file will look like the following:
   169  
   170  ```proto
   171  syntax = "proto3";
   172  
   173  package SOME.PKG;
   174  
   175  option go_package = "PKGpb";
   176  option java_multiple_files = true;
   177  option java_outer_classname = "ExampleCreateFileProto";
   178  option java_package = "com.SOME.PKG.pb";
   179  ```
   180  
   181  This matches what the linter expects. `SOME.PKG` will be computed as follows:
   182  
   183  - If `--package` is specified, `SOME.PKG` will be the value passed to `--package`.
   184  - Otherwise, if there is no `prototool.yaml` or `prototool.json` that would apply to the new file, use `uber.prototool.generated`.
   185  - Otherwise, if there is a `prototool.yaml` or `prototool.json` file, check if it has a `packages` setting under the
   186    `create` section (see [etc/config/example/prototool.yaml](etc/config/example/prototool.yaml) for an example).
   187    If it does, this package, concatenated with the relative path from the directory with the `prototool.yaml` or `prototool.json` file will be used.
   188  - Otherwise, if there is no `packages` directive, just use the relative path from the directory
   189    with the `prototool.yaml` or `prototool.json` file. If the file is in the same directory as the `prototoo.yaml` file,
   190    use `uber.prototool.generated`
   191  
   192  For example, assume you have the following file at `repo/prototool.yaml`:
   193  
   194  ```yaml
   195  create:
   196    packages:
   197      - directory: idl
   198        name: uber
   199      - directory: idl/baz
   200        name: special
   201  ```
   202  
   203  - `prototool create repo/idl/foo/bar/bar.proto` will have the package `uber.foo.bar`.
   204  - `prototool create repo/idl/bar.proto` will have the package `uber`.
   205  - `prototool create repo/idl/baz/baz.proto` will have the package `special`.
   206  - `prototool create repo/idl/baz/bat/bat.proto` will have the package `special.bat`.
   207  - `prototool create repo/another/dir/bar.proto` will have the package `another.dir`.
   208  - `prototool create repo/bar.proto` will have the package `uber.prototool.generated`.
   209  
   210  This is meant to mimic what you generally want - a base package for your idl directory, followed
   211  by packages matching the directory structure.
   212  
   213  Note you can override the directory that the `prototool.yaml` or `prototool.json` file is in as well. If we update our
   214  file at `repo/prototool.yaml` to this:
   215  
   216  ```yaml
   217  create:
   218    packages:
   219      - directory: .
   220        name: foo.bar
   221  ```
   222  
   223  Then `prototool create repo/bar.proto` will have the package `foo.bar`, and `prototool create repo/another/dir/bar.proto`
   224  will have the package `foo.bar.another.dir`.
   225  
   226  If [Vim integration](#vim-integration) is set up, files will be generated when you open a new Protobuf file.
   227  
   228  ##### `prototool files`
   229  
   230  Print the list of all files that will be used given the input `dirOrFile`. Useful for debugging.
   231  
   232  ##### `prototool grpc`
   233  
   234  Call a gRPC endpoint using a JSON input. What this does behind the scenes:
   235  
   236  - Compiles your Protobuf files with `protoc`, generating a `FileDescriptorSet`.
   237  - Uses the `FileDescriptorSet` to figure out the request and response type for the endpoint, and to convert the JSON input to binary.
   238  - Calls the gRPC endpoint.
   239  - Uses the `FileDescriptorSet` to convert the resulting binary back to JSON, and prints it out for you.
   240  
   241  All these steps take on the order of milliseconds, for example the overhead for a file with four dependencies is about 30ms, so there is little overhead for CLI calls to gRPC.
   242  
   243  ## gRPC Example
   244  
   245  There is a full example for gRPC in the [example](example) directory. Run `make init example` to make sure everything is installed and generated.
   246  
   247  Start the example server in a separate terminal by doing `go run example/cmd/excited/main.go`.
   248  
   249  `prototool grpc [dirOrFile] --address serverAddress --method package.service/Method --data 'requestData'`
   250  
   251  Either use `--data 'requestData'` as the the JSON data to input, or `--stdin` which will result in the input being read from stdin as JSON.
   252  
   253  ```bash
   254  $ make init example # make sure everything is built just in case
   255  
   256  $ prototool grpc example \
   257    --address 0.0.0.0:8080 \
   258    --method foo.ExcitedService/Exclamation \
   259    --data '{"value":"hello"}'
   260  {
   261    "value": "hello!"
   262  }
   263  
   264  $ prototool grpc example \
   265    --address 0.0.0.0:8080 \
   266    --method foo.ExcitedService/ExclamationServerStream \
   267    --data '{"value":"hello"}'
   268  {
   269    "value": "h"
   270  }
   271  {
   272    "value": "e"
   273  }
   274  {
   275    "value": "l"
   276  }
   277  {
   278    "value": "l"
   279  }
   280  {
   281    "value": "o"
   282  }
   283  {
   284    "value": "!"
   285  }
   286  
   287  $ cat input.json
   288  {"value":"hello"}
   289  {"value":"salutations"}
   290  
   291  $ cat input.json | prototool grpc example \
   292    --address 0.0.0.0:8080 \
   293    --method foo.ExcitedService/ExclamationClientStream \
   294    --stdin
   295  {
   296    "value": "hellosalutations!"
   297  }
   298  
   299  $ cat input.json | prototool grpc example \
   300    --address 0.0.0.0:8080 \
   301    --method foo.ExcitedService/ExclamationBidiStream \
   302    --stdin
   303  {
   304    "value": "hello!"
   305  }
   306  {
   307    "value": "salutations!"
   308  }
   309  ```
   310  
   311  ## Tips and Tricks
   312  
   313  Prototool is meant to help enforce a consistent development style for Protobuf, and as such you should follow some basic rules:
   314  
   315  - Have all your imports start from the directory your `prototool.yaml` or `prototool.json` file is in. While there is a configuration option `protoc.includes` to denote extra include directories, this is not recommended.
   316  - Have all Protobuf files in the same directory use the same `package`, and use the same values for `go_package`, `java_multiple_files`, `java_outer_classname`, and `java_package`.
   317  - Do not use long-form `go_package` values, ie use `foopb`, not `github.com/bar/baz/foo;foopb`. This helps `prototool generate` do the best job.
   318  
   319  ## Vim Integration
   320  
   321  This repository is a self-contained plugin for use with the [ALE Lint Engine](https://github.com/w0rp/ale). It should be similarly easy to add support for Syntastic, Neomake, etc.
   322  
   323  The Vim integration will currently provide lint errors, optionally regenerate all the stubs, and optionally format your files on save. It
   324  will also optionally create new files from a template when opened.
   325  
   326  The plugin is under [vim/prototool](vim/prototool), so your plugin manager needs to point there instead of the base of this repository. Assuming you are using [vim-plug](https://github.com/junegunn/vim-plug), copy/paste the following into your vimrc and you should be good to go. If you are using [Vundle](https://github.com/VundleVim/Vundle.vim), just replace `Plug` with `Vundle` below.
   327  
   328  ```vim
   329  " Prototool must be installed as a binary for the Vim integration to work.
   330  
   331  " Add ale and prototool with your package manager.
   332  " Note that Plug downloads from dev by default. There may be minor changes
   333  " to the Vim integration on dev between releases, but this won't be common.
   334  " To make sure you are on the same branch as your Prototool install, set
   335  " the branch field in the options for uber/prototool per the vim-plug
   336  " documentation. Vundle does not allow setting branches, so on Vundle,
   337  " go into plug directory and checkout the branch of the release you are on.
   338  Plug 'w0rp/ale'
   339  Plug 'uber/prototool', { 'rtp':'vim/prototool' }
   340  
   341  " We recommend setting just this for Golang, as well as the necessary set for proto.
   342  let g:ale_linters = {
   343  \   'go': ['golint'],
   344  \   'proto': ['prototool'],
   345  \}
   346  " We recommend you set this.
   347  let g:ale_lint_on_text_changed = 'never'
   348  " Set to 'lint' to not do code generation.
   349  " Set to 'compile' to not do linting either and just compile without code generation.
   350  "let g:ale_proto_prototool_command = 'compile'
   351  
   352  " We generally have <leader> mapped to ",", uncomment this to set leader.
   353  "let mapleader=","
   354  
   355  " ,f will toggle formatting on and off.
   356  " Change to PrototoolFormatFixToggle to toggle with --fix instead.
   357  nnoremap <silent> <leader>f :call PrototoolFormatToggle()<CR>
   358  " ,c will toggle create on and off.
   359  nnoremap <silent> <leader>c :call PrototoolCreateToggle()<CR>
   360  
   361  " Uncomment this to enable formatting by default.
   362  "call PrototoolFormatEnable()
   363  " Uncomment this to enable formatting with --fix by default.
   364  "call PrototoolFormatFixEnable()
   365  " Uncomment this to disable creating Protobuf files from a template by default.
   366  "call PrototoolCreateDisable()
   367  ```
   368  
   369  Editor integration is a key goal of Prototool. We've demonstrated support internally for Intellij, and hope that we have integration for more editors in the future.
   370  
   371  ## Development
   372  
   373  Prototool is under active development. If you want to help, here's some places to start:
   374  
   375  - Try out `prototool` and file feature requests or bug reports.
   376  - Submit PRs with any changes you'd like to see made.
   377  
   378  We appreciate any input you have!
   379  
   380  Before filing an issue or submitting a PR, make sure to review the [Issue Guidelines](https://github.com/uber/prototool/blob/dev/.github/ISSUE_TEMPLATE.md), and before submitting a PR, make sure to also review
   381  the [PR Guidelines](https://github.com/uber/prototool/blob/dev/.github/PULL_REQUEST_TEMPLATE.md). The Issue Guidelines will show up in the description field when filing a new issue, and the PR guidelines will show up in the
   382  description field when submitting a PR, but clear the description field of this pre-populated text once you've read it :-)
   383  
   384  Note that development of Prototool will only work with Golang 1.10 or newer. On initially cloning the repository, run `make init` if you have not already to download dependencies to `vendor`.
   385  
   386  Before submitting a PR, make sure to:
   387  
   388  - Run `make generate` to make sure there is no diff.
   389  - Run `make` to make sure all tests pass. This is functionally equivalent to the tests run on CI.
   390  
   391  All Golang code is purposefully under the `internal` package to not expose any API for the time being.
   392  
   393  ## FAQ
   394  
   395  ##### Pre-Cache Protoc
   396  
   397  *Question:* How do I download `protoc` ahead of time as part of a Docker build/CI pipeline?
   398  
   399  *Answer*: We used to have a command that did this, but removed it for simplicity and because the command as implemented did not properly
   400  read the configuration file to figure out what version of `protoc` to download. We may re-add this command in the future, however
   401  here is a technique to accomplish this, including as a `RUN` directive for Docker:
   402  
   403  ```bash
   404  # the first rm -rf call is not needed if this is a RUN directive for Docker
   405  rm -rf /tmp/prototool-bootstrap && \
   406    echo $'protoc\n  version: 3.6.1' > /tmp/prototool-bootstrap/prototool.yaml && \
   407    echo 'syntax = "proto3";' > /tmp/prototool-bootstrap/tmp.proto && \
   408    prototool compile /tmp/prototool-bootstrap && \
   409    rm -rf /tmp/prototool-bootstrap
   410  ```
   411  
   412  The better way to do this as part of a bash script would be to use `mktemp -d` i.e.:
   413  
   414  ```bash
   415  #!/bin/bash
   416  
   417  set -euo pipefail
   418  
   419  TMPDIR="$(mktemp -d)"
   420  trap 'rm -rf "${TMPDIR}"' EXIT
   421  
   422  echo $'protoc\n  version: 3.6.1' > "${TMPDIR}/prototool.yaml"
   423  echo 'syntax = "proto3";' > "${TMPDIR}/tmp.proto"
   424  prototool compile "${TMPDIR}"
   425  ```
   426  
   427  But for Darwin or Linux, the above should work.
   428  
   429  ##### Alpine Linux Issues
   430  
   431  *Question:* Help! Prototool is failing when I use it within a Docker image based on Alpine Linux!
   432  
   433  *Answer:* `apk add libc6-compat`
   434  
   435  `protoc` is not statically compiled, and adding this packages fixes the problem.
   436  
   437  ##### Managing External Plugins/Docker
   438  
   439  *Question:* Can Prototool manage my external plugins such as protoc-gen-go?
   440  
   441  *Answer:* Unfortunately, no. This was an explicit design decision - Prototool is not meant to "know the world", instead
   442  Prototool just takes care of what it is good at (managing your Protobuf build) to keep Prototool simple, leaving you to do
   443  external plugin management. Prototool does provide the ability to use the "built-in" output directives `cpp, csharp, java, js, objc, php, python, ruby`
   444  provided by `protoc` out of the box, however.
   445  
   446  If you want to have a consistent build environment for external plugins, we recommend creating a Docker image. Here's an example `Dockerfile` that
   447  results in a Docker image around 33MB that contains `prototool`, a cached `protoc`, and `protoc-gen-go`:
   448  
   449  ```dockerfile
   450  FROM golang:1.11.0-alpine3.8 AS build
   451  
   452  ARG PROTOTOOL_VERSION=1.3.0
   453  ARG PROTOC_VERSION=3.6.1
   454  ARG PROTOC_GEN_GO_VERSION=1.2.0
   455  
   456  RUN \
   457    apk update && \
   458    apk add curl git libc6-compat && \
   459    rm -rf /var/cache/apk/*
   460  RUN \
   461    curl -sSL https://github.com/uber/prototool/releases/download/v$PROTOTOOL_VERSION/prototool-Linux-x86_64 -o /bin/prototool && \
   462    chmod +x /bin/prototool
   463  RUN \
   464    mkdir /tmp/prototool-bootstrap && \
   465    echo $'protoc:\n  version:' $PROTOC_VERSION > /tmp/prototool-bootstrap/prototool.yaml && \
   466    echo 'syntax = "proto3";' > /tmp/prototool-bootstrap/tmp.proto && \
   467    prototool compile /tmp/prototool-bootstrap && \
   468    rm -rf /tmp/prototool-bootstrap
   469  RUN go get github.com/golang/protobuf/... && \
   470    cd /go/src/github.com/golang/protobuf && \
   471    git checkout v$PROTOC_GEN_GO_VERSION && \
   472    go install ./protoc-gen-go
   473  
   474  FROM alpine:3.8
   475  
   476  WORKDIR /in
   477  
   478  RUN \
   479    apk update && \
   480    apk add libc6-compat && \
   481    rm -rf /var/cache/apk/*
   482  
   483  COPY --from=build /bin/prototool /bin/prototool
   484  COPY --from=build /root/.cache/prototool /root/.cache/prototool
   485  COPY --from=build /go/bin/protoc-gen-go /bin/protoc-gen-go
   486  
   487  ENTRYPOINT ["/bin/prototool"]
   488  ```
   489  
   490  Assuming this is in a file named `Dockerfile` in your current directory, build the image with:
   491  
   492  ```bash
   493  docker build -t me/prototool-env .
   494  ```
   495  
   496  Then, assuming you are in the directory you want to pass to Prototool and you want to run `prototool compile`, run:
   497  
   498  ```bash
   499  docker run -v $(pwd):/in me/prototool-env compile
   500  ```
   501  
   502  ##### Lint/Format Choices
   503  
   504  *Question:* I don't like some of the choices made in the Style Guide and that are enforced by default by the linter and/or I don't like
   505  the choices made in the formatter. Can we change some things?
   506  
   507  *Answer:* Sorry, but we can't - The goal of Prototool is to provide a straightforward Style Guide and consistent formatting that minimizes various issues that arise from Protobuf usage across large organizations. There are pros and cons to many of the choices in the Style Guide, but it's our belief that the best answer is a **single** answer, sometimes regardless of what that single answer is.
   508  
   509  It is possible to ignore lint rules via configuration. However, especially if starting from a clean slate, we highly recommend using all default lint rules for consistency.
   510  
   511  Many of the lint rules exist to mitigate backwards compatibility problems as schemas evolves. For example: requiring a unique request-response pair per RPC - while this potentially resuls in duplicated messages, this makes it impossible to affect an adjacent RPC by adding or modifying an existing field.
   512  
   513  ## Special Thanks
   514  
   515  Prototool uses some external libraries that deserve special mention and thanks for their contribution to Prototool's functionality:
   516  
   517  - [github.com/emicklei/proto](https://github.com/emicklei/proto) - The Golang Protobuf parsing library that started it all, and is still used for the linting and formatting functionality. We can't thank Ernest Micklei enough for his help and putting up with all the [filed issues](https://github.com/emicklei/proto/issues?q=is%3Aissue+is%3Aclosed).
   518  - [github.com/jhump/protoreflect](https://github.com/jhump/protoreflect) - Used for the JSON to binary and back conversion. Josh Humphries is an amazing developer, thank you so much.
   519  - [github.com/fullstorydev/grpcurl](https://github.com/fullstorydev/grpcurl) - Still used for the gRPC functionality. Again a thank you to Josh Humphries and the team over at FullStory for their work.
   520  
   521  [mit-img]: http://img.shields.io/badge/License-MIT-blue.svg
   522  [mit]: https://github.com/uber/prototool/blob/master/LICENSE
   523  
   524  [release-img]: https://img.shields.io/github/release/uber/prototool/all.svg
   525  [release]: https://github.com/uber/prototool/releases
   526  
   527  [ci-img]: https://img.shields.io/travis/uber/prototool/dev.svg
   528  [ci]: https://travis-ci.org/uber/prototool/builds
   529  
   530  [cov-img]: https://codecov.io/gh/uber/prototool/branch/dev/graph/badge.svg
   531  [cov]: https://codecov.io/gh/uber/prototool/branch/dev