github.com/psrajat/prototool@v1.3.0/internal/protoc/protoc.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package protoc
    22  
    23  import (
    24  	"github.com/golang/protobuf/protoc-gen-go/descriptor"
    25  	"github.com/uber/prototool/internal/file"
    26  	"github.com/uber/prototool/internal/settings"
    27  	"github.com/uber/prototool/internal/text"
    28  	"go.uber.org/zap"
    29  )
    30  
    31  // Downloader downloads and caches protobuf.
    32  type Downloader interface {
    33  	// Download protobuf.
    34  	//
    35  	// If already downloaded, this has no effect. This is thread-safe.
    36  	// This will download to ${XDG_CACHE_HOME}/prototool/$(uname -s)/$(uname -m)
    37  	// unless overridden by a DownloaderOption.
    38  	// If ${XDG_CACHE_HOME} is not set, it defaults to ${HOME}/Library/Caches on
    39  	// Darwin, and ${HOME}/.cache on Linux.
    40  	// If ${HOME} is not set, an error will be returned.
    41  	//
    42  	// Returns the path to the downloaded protobuf artifacts.
    43  	//
    44  	// ProtocPath and WellKnownTypesIncludePath implicitly call this.
    45  	Download() (string, error)
    46  
    47  	// Get the path to protoc.
    48  	//
    49  	// If not downloaded, this downloads and caches protobuf. This is thread-safe.
    50  	ProtocPath() (string, error)
    51  
    52  	// Get the path to include for the well-known types.
    53  	//
    54  	// Inside this directory will be the subdirectories google/protobuf.
    55  	//
    56  	// If not downloaded, this downloads and caches protobuf. This is thread-safe.
    57  	WellKnownTypesIncludePath() (string, error)
    58  
    59  	// Delete any downloaded artifacts.
    60  	//
    61  	// This is not thread-safe and no calls to other functions can be reliably
    62  	// made simultaneously.
    63  	Delete() error
    64  }
    65  
    66  // DownloaderOption is an option for a new Downloader.
    67  type DownloaderOption func(*downloader)
    68  
    69  // DownloaderWithLogger returns a DownloaderOption that uses the given logger.
    70  //
    71  // The default is to use zap.NewNop().
    72  func DownloaderWithLogger(logger *zap.Logger) DownloaderOption {
    73  	return func(downloader *downloader) {
    74  		downloader.logger = logger
    75  	}
    76  }
    77  
    78  // DownloaderWithCachePath returns a DownloaderOption that uses the given cachePath.
    79  //
    80  // The default is ${XDG_CACHE_HOME}/prototool/$(uname -s)/$(uname -m).
    81  func DownloaderWithCachePath(cachePath string) DownloaderOption {
    82  	return func(downloader *downloader) {
    83  		downloader.cachePath = cachePath
    84  	}
    85  }
    86  
    87  // DownloaderWithProtocBinPath returns a DownloaderOption that uses the given protoc binary path.
    88  func DownloaderWithProtocBinPath(protocBinPath string) DownloaderOption {
    89  	return func(downloader *downloader) {
    90  		downloader.protocBinPath = protocBinPath
    91  	}
    92  }
    93  
    94  // DownloaderWithProtocWKTPath returns a DownloaderOption that uses the given path to include
    95  // the well-known types.
    96  func DownloaderWithProtocWKTPath(protocWKTPath string) DownloaderOption {
    97  	return func(downloader *downloader) {
    98  		downloader.protocWKTPath = protocWKTPath
    99  	}
   100  }
   101  
   102  // DownloaderWithProtocURL returns a DownloaderOption that uses the given protoc zip file URL.
   103  //
   104  // The default is https://github.com/protocolbuffers/protobuf/releases/download/vVERSION/protoc-VERSION-OS-ARCH.zip.
   105  func DownloaderWithProtocURL(protocURL string) DownloaderOption {
   106  	return func(downloader *downloader) {
   107  		downloader.protocURL = protocURL
   108  	}
   109  }
   110  
   111  // NewDownloader returns a new Downloader for the given config and DownloaderOptions.
   112  func NewDownloader(config settings.Config, options ...DownloaderOption) (Downloader, error) {
   113  	return newDownloader(config, options...)
   114  }
   115  
   116  // CompileResult is the result of a compile
   117  type CompileResult struct {
   118  	// The failures from all calls.
   119  	Failures []*text.Failure
   120  	// Will not be set if there are any failures.
   121  	//
   122  	// Will only be set if the CompilerWithFileDescriptorSet
   123  	// option is used.
   124  	FileDescriptorSets []*descriptor.FileDescriptorSet
   125  }
   126  
   127  // Compiler compiles protobuf files.
   128  type Compiler interface {
   129  	// Compile the protobuf files with protoc.
   130  	//
   131  	// If there are compile failures, they will be returned in the slice
   132  	// and there will be no error. The caller can determine if this is
   133  	// an error case. If there is any other type of error, or some output
   134  	// from protoc cannot be interpreted, an error will be returned.
   135  	Compile(*file.ProtoSet) (*CompileResult, error)
   136  
   137  	// Return the protoc commands that would be run on Compile.
   138  	//
   139  	// This will ignore the CompilerWithFileDescriptorSet option.
   140  	ProtocCommands(*file.ProtoSet) ([]string, error)
   141  }
   142  
   143  // CompilerOption is an option for a new Compiler.
   144  type CompilerOption func(*compiler)
   145  
   146  // CompilerWithLogger returns a CompilerOption that uses the given logger.
   147  //
   148  // The default is to use zap.NewNop().
   149  func CompilerWithLogger(logger *zap.Logger) CompilerOption {
   150  	return func(compiler *compiler) {
   151  		compiler.logger = logger
   152  	}
   153  }
   154  
   155  // CompilerWithCachePath returns a CompilerOption that uses the given cachePath.
   156  //
   157  // The default is ${XDG_CACHE_HOME}/prototool/$(uname -s)/$(uname -m).
   158  func CompilerWithCachePath(cachePath string) CompilerOption {
   159  	return func(compiler *compiler) {
   160  		compiler.cachePath = cachePath
   161  	}
   162  }
   163  
   164  // CompilerWithProtocBinPath returns a CompilerOption that uses the given protoc binary path.
   165  //
   166  func CompilerWithProtocBinPath(protocBinPath string) CompilerOption {
   167  	return func(compiler *compiler) {
   168  		compiler.protocBinPath = protocBinPath
   169  	}
   170  }
   171  
   172  // CompilerWithProtocWKTPath returns a CompilerOption that uses the given path to include the
   173  // well-known types.
   174  func CompilerWithProtocWKTPath(protocWKTPath string) CompilerOption {
   175  	return func(compiler *compiler) {
   176  		compiler.protocWKTPath = protocWKTPath
   177  	}
   178  }
   179  
   180  // CompilerWithProtocURL returns a CompilerOption that uses the given protoc zip file URL.
   181  //
   182  // The default is https://github.com/protocolbuffers/protobuf/releases/download/vVERSION/protoc-VERSION-OS-ARCH.zip.
   183  func CompilerWithProtocURL(protocURL string) CompilerOption {
   184  	return func(compiler *compiler) {
   185  		compiler.protocURL = protocURL
   186  	}
   187  }
   188  
   189  // CompilerWithGen says to also generate the code.
   190  func CompilerWithGen() CompilerOption {
   191  	return func(compiler *compiler) {
   192  		compiler.doGen = true
   193  	}
   194  }
   195  
   196  // CompilerWithFileDescriptorSet says to also return the FileDescriptorSet.
   197  func CompilerWithFileDescriptorSet() CompilerOption {
   198  	return func(compiler *compiler) {
   199  		compiler.doFileDescriptorSet = true
   200  	}
   201  }
   202  
   203  // NewCompiler returns a new Compiler.
   204  func NewCompiler(options ...CompilerOption) Compiler {
   205  	return newCompiler(options...)
   206  }