diff --git a/azure/worker/bindings/http.py b/azure/worker/bindings/http.py index 7c2c4f0e5..32afd4b24 100644 --- a/azure/worker/bindings/http.py +++ b/azure/worker/bindings/http.py @@ -97,7 +97,7 @@ def to_proto(cls, obj: typing.Any, *, http=protos.RpcHttp( status_code=str(status), headers=headers, - is_raw=True, + enable_content_negotiation=False, body=body)) raise NotImplementedError diff --git a/azure/worker/protos/.gitignore b/azure/worker/protos/.gitignore index 49d7060ef..f43e6c214 100644 --- a/azure/worker/protos/.gitignore +++ b/azure/worker/protos/.gitignore @@ -1,2 +1,3 @@ +/_src *_pb2.py *_pb2_grpc.py diff --git a/azure/worker/protos/_src/.gitignore b/azure/worker/protos/_src/.gitignore new file mode 100644 index 000000000..940794e60 --- /dev/null +++ b/azure/worker/protos/_src/.gitignore @@ -0,0 +1,288 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs diff --git a/azure/worker/protos/_src/LICENSE b/azure/worker/protos/_src/LICENSE new file mode 100644 index 000000000..21071075c --- /dev/null +++ b/azure/worker/protos/_src/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/azure/worker/protos/_src/README.md b/azure/worker/protos/_src/README.md new file mode 100644 index 000000000..a780e4957 --- /dev/null +++ b/azure/worker/protos/_src/README.md @@ -0,0 +1,47 @@ +# Azure Functions Languge Worker Protobuf + +This repository contains the protobuf definition file which defines the gRPC service which is used between the Azure WebJobs Script host and the Azure Functions language workers. This repo is shared across many repos in many languages (for each worker) by using git commands. + +To use this repo in Azure Functions language workers, follow steps below to add this repo as a subtree (*Adding This Repo*). If this repo is already embedded in a language worker repo, follow the steps to update the consumed file (*Pulling Updates*). + +Learn more about Azure Function's projects on the [meta](https://github.com/azure/azure-functions) repo. + +## Adding This Repo + +From within the Azure Functions language worker repo: +1. Define remote branch for cleaner git commands + - `git remote add proto-file https://github.com/azure/azure-functions-language-worker-protobuf.git` + - `git fetch proto-file` +2. Index contents of azure-functions-worker-protobuf to language worker repo + - `git read-tree --prefix= -u proto-file/` +3. Add new path in language worker repo to .gitignore file + - In .gitignore, add path in language worker repo +4. Finalize with commit + - `git commit -m “Added subtree from https://github.com/azure/azure-functions-language-worker-protobuf. Branch: . Commit: ”` + - `git push` + +## Pulling Updates + +From within the Azure Functions language worker repo: +1. Define remote branch for cleaner git commands + - `git remote add proto-file https://github.com/mhoeger/azure-functions-language-worker-protobuf.git` + - `git fetch proto-file` +2. Merge updates + - `git merge -X subtree= --squash proto-file/` +3. Finalize with commit + - `git commit -m "Updated subtree from https://github.com/azure/azure-functions-language-worker-protobuf. Branch: . Commit: ”` + - `git push` + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/azure/worker/protos/azure/worker/protos/FunctionRpc.proto b/azure/worker/protos/_src/src/proto/FunctionRpc.proto similarity index 65% rename from azure/worker/protos/azure/worker/protos/FunctionRpc.proto rename to azure/worker/protos/_src/src/proto/FunctionRpc.proto index 281889391..f854ce87e 100644 --- a/azure/worker/protos/azure/worker/protos/FunctionRpc.proto +++ b/azure/worker/protos/_src/src/proto/FunctionRpc.proto @@ -17,8 +17,13 @@ service FunctionRpc { } message StreamingMessage { + // Used to identify message between host and worker string request_id = 1; + + // Payload of the message oneof content { + + // Worker initiates stream StartStream start_stream = 20; // Host sends capabilities/init data to worker @@ -48,12 +53,17 @@ message StreamingMessage { // Worker responds after loading with the load result FunctionLoadResponse function_load_response = 9; + // Host requests a given invocation InvocationRequest invocation_request = 4; + + // Worker responds to a given invocation InvocationResponse invocation_response = 5; + // Host sends cancel message to attempt to cancel an invocation. // If an invocation is cancelled, host will receive an invocation response with status cancelled. InvocationCancel invocation_cancel = 21; + // Worker logs a message back to the host RpcLog rpc_log = 2; } } @@ -63,11 +73,15 @@ message StreamingMessage { // protocol type // protocol version +// Worker sends the host information identifying itself message StartStream { + // id of the worker string worker_id = 2; } +// Host requests the worker to initialize itself message WorkerInitRequest { + // version of the host sending init request string host_version = 1; // A map of host supported features/capabilities @@ -78,27 +92,40 @@ message WorkerInitRequest { map log_categories = 3; } +// Worker responds with the result of initializing itself message WorkerInitResponse { + // Version of worker string worker_version = 1; // A map of worker supported features/capabilities map capabilities = 2; + + // Status of the response StatusResult result = 3; } +// Used by the host to determine success/failure/cancellation message StatusResult { + // Indicates Failure/Success/Cancelled enum Status { Failure = 0; Success = 1; Cancelled = 2; } + // Status for the given result Status status = 4; + + // Specific message about the result string result = 1; + + // Exception message (if exists) for the status RpcException exception = 2; + // Captured logs or relevant details can use the logs property repeated RpcLog logs = 3; } // TODO: investigate grpc heartbeat - don't limit to grpc implemention + // Message is empty by design - Will add more fields in future if needed message WorkerHeartbeat {} @@ -108,10 +135,11 @@ message WorkerTerminate { google.protobuf.Duration grace_period = 1; } +// Host notifies worker of file content change message FileChangeEventRequest { - // https://msdn.microsoft.com/en-us/library/t6xf43e0(v=vs.110).aspx + // Types of File change operations (See link for more info: https://msdn.microsoft.com/en-us/library/t6xf43e0(v=vs.110).aspx) enum Type { - Unknown = 0; + Unknown = 0; Created = 1; Deleted = 2; Changed = 4; @@ -119,71 +147,116 @@ message FileChangeEventRequest { All = 15; } + // type for this event Type type = 1; + + // full file path for the file change notification string full_path = 2; + + // Name of the function affected string name = 3; } +// Indicates whether worker reloaded successfully or needs a restart message WorkerActionResponse { + // indicates whether a restart is needed, or reload succesfully enum Action { Restart = 0; Reload = 1; } + // action for this response Action action = 1; + + // text reason for the response string reason = 2; } +// NOT USED message WorkerStatusRequest{ } +// NOT USED message WorkerStatusResponse { } +// Host tells the worker to load a Function message FunctionLoadRequest { // unique function identifier (avoid name collisions, facilitate reload case) string function_id = 1; + + // Metadata for the request RpcFunctionMetadata metadata = 2; } +// Worker tells host result of reload message FunctionLoadResponse { + // unique function identifier string function_id = 1; + + // Result of load operation StatusResult result = 2; // TODO: return type expected? } +// Information on how a Function should be loaded and its bindings message RpcFunctionMetadata { // TODO: do we want the host's name - the language worker might do a better job of assignment than the host string name = 4; + // base directory for the Function string directory = 1; + + // Script file specified string script_file = 2; + + // Entry point specified string entry_point = 3; + // Bindings info map bindings = 6; - - // not adding disabled or excluded as those (currently) are only relevant to host } +// Host requests worker to invoke a Function message InvocationRequest { + // Unique id for each invocation string invocation_id = 1; + + // Unique id for each Function string function_id = 2; + + // Input bindings (include trigger) repeated ParameterBinding input_data = 3; + + // binding metadata from trigger map trigger_metadata = 4; } +// Host requests worker to cancel invocation message InvocationCancel { + // Unique id for invocation string invocation_id = 2; + + // Time period before force shutdown google.protobuf.Duration grace_period = 1; // could also use absolute time } +// Worker responds with status of Invocation message InvocationResponse { + // Unique id for invocation string invocation_id = 1; + + // Output binding data repeated ParameterBinding output_data = 2; + + // data returned from Function (for $return and triggers with return support) TypedData return_value = 4; + + // Status of the invocation (success/failure/canceled) StatusResult result = 3; } +// Used to encapsulate data which could be a variety of types message TypedData { oneof data { string string = 1; @@ -191,30 +264,41 @@ message TypedData { bytes bytes = 3; bytes stream = 4; RpcHttp http = 5; - sint64 int = 6; + sint64 int = 6; double double = 7; } } +// Used to describe a given binding on invocation message ParameterBinding { + // Name for the binding string name = 1; + + // Data for the binding TypedData data = 2; } +// Used to describe a given binding on load message BindingInfo { + // Indicates whether it is an input or output binding (or a fancy inout binding) + enum Direction { + in = 0; + out = 1; + inout = 2; + } + + // Type of binding (e.g. HttpTrigger) string type = 2; - Direction direction = 3; - enum Direction { - in = 0; - out = 1; - inout = 2; - } + // Direction of the given binding + Direction direction = 3; } +// Used to send logs back to the Host message RpcLog { // Matching ILogger semantics // https://github.com/aspnet/Logging/blob/9506ccc3f3491488fe88010ef8b9eb64594abf95/src/Microsoft.Extensions.Logging/Logger.cs + // Level for the Log enum Level { Trace = 0; Debug = 1; @@ -225,24 +309,42 @@ message RpcLog { None = 6; } + // Unique id for invocation (if exists) string invocation_id = 1; + + // TOD: This should be an enum + // Category for the log (startup, load, invocation, etc.) string category = 2; + + // Level for the given log message Level level = 3; + + // Message for the given log string message = 4; + + // Id for the even associated with this log (if exists) string event_id = 5; + + // Exception (if exists) RpcException exception = 6; // json serialized property bag, or could use a type scheme like map string properties = 7; } +// Encapsulates an Exception message RpcException { + // Source of the exception string source = 3; + + // Stack trace for the exception string stack_trace = 1; + + // Textual message describing hte exception string message = 2; } -// TODO - solidify this +// TODO - solidify this or remove it message RpcHttp { string method = 1; string url = 2; @@ -251,6 +353,6 @@ message RpcHttp { map params = 10; string status_code = 12; map query = 15; - bool is_raw = 16; + bool enable_content_negotiation= 16; TypedData rawBody = 17; } \ No newline at end of file diff --git a/azure/worker/protos/_src/src/proto/google/protobuf/duration.proto b/azure/worker/protos/_src/src/proto/google/protobuf/duration.proto new file mode 100644 index 000000000..69743d634 --- /dev/null +++ b/azure/worker/protos/_src/src/proto/google/protobuf/duration.proto @@ -0,0 +1,117 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/duration"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DurationProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// +// # Examples +// +// Example 1: Compute Duration from two Timestamps in pseudo code. +// +// Timestamp start = ...; +// Timestamp end = ...; +// Duration duration = ...; +// +// duration.seconds = end.seconds - start.seconds; +// duration.nanos = end.nanos - start.nanos; +// +// if (duration.seconds < 0 && duration.nanos > 0) { +// duration.seconds += 1; +// duration.nanos -= 1000000000; +// } else if (durations.seconds > 0 && duration.nanos < 0) { +// duration.seconds -= 1; +// duration.nanos += 1000000000; +// } +// +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +// +// Timestamp start = ...; +// Duration duration = ...; +// Timestamp end = ...; +// +// end.seconds = start.seconds + duration.seconds; +// end.nanos = start.nanos + duration.nanos; +// +// if (end.nanos < 0) { +// end.seconds -= 1; +// end.nanos += 1000000000; +// } else if (end.nanos >= 1000000000) { +// end.seconds += 1; +// end.nanos -= 1000000000; +// } +// +// Example 3: Compute Duration from datetime.timedelta in Python. +// +// td = datetime.timedelta(days=3, minutes=10) +// duration = Duration() +// duration.FromTimedelta(td) +// +// # JSON Mapping +// +// In JSON format, the Duration type is encoded as a string rather than an +// object, where the string ends in the suffix "s" (indicating seconds) and +// is preceded by the number of seconds, with nanoseconds expressed as +// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +// microsecond should be expressed in JSON format as "3.000001s". +// +// +message Duration { + + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. Note: these bounds are computed from: + // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + int64 seconds = 1; + + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + int32 nanos = 2; +} \ No newline at end of file diff --git a/setup.py b/setup.py index dd89a52c5..544239ee3 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,8 @@ import distutils.cmd +import glob import os import pathlib +import shutil import subprocess import sys import tempfile @@ -13,8 +15,8 @@ # TODO: change this to something more stable when available. -WEBHOST_URL = ('https://ci.appveyor.com/api/buildjobs/o1fwxf4xscyfygt2' - '/artifacts/Functions.Binaries.2.0.11709-alpha.zip') +WEBHOST_URL = ('https://ci.appveyor.com/api/buildjobs/r1d0pxmtkib47bc4' + '/artifacts/Functions.Binaries.2.0.11737-alpha.zip') # Extensions necessary for non-core bindings. AZURE_EXTENSIONS = [ @@ -28,17 +30,39 @@ class BuildGRPC: """Generate gRPC bindings.""" def _gen_grpc(self): - cwd = os.getcwd() + root = pathlib.Path(__file__).parent + + proto_root_dir = root / 'azure' / 'worker' / 'protos' + proto_src_dir = proto_root_dir / '_src' / 'src' / 'proto' + staging_root_dir = root / 'build' / 'protos' + staging_dir = staging_root_dir / 'azure' / 'worker' / 'protos' + build_dir = staging_dir / 'azure' / 'worker' / 'protos' + + if os.path.exists(build_dir): + shutil.rmtree(build_dir) + + shutil.copytree(proto_src_dir, build_dir) subprocess.run([ sys.executable, '-m', 'grpc_tools.protoc', '-I', os.sep.join(('azure', 'worker', 'protos')), - '--python_out', cwd, - '--grpc_python_out', cwd, + '--python_out', str(staging_root_dir), + '--grpc_python_out', str(staging_root_dir), os.sep.join(('azure', 'worker', 'protos', 'azure', 'worker', 'protos', 'FunctionRpc.proto')), - ], check=True, stdout=sys.stdout, stderr=sys.stderr) + ], check=True, stdout=sys.stdout, stderr=sys.stderr, + cwd=staging_root_dir) + + compiled = glob.glob(str(staging_dir / '*.py')) + + if not compiled: + print('grpc_tools.protoc produced no Python files', + file=sys.stderr) + sys.exit(1) + + for f in compiled: + shutil.copy(f, proto_root_dir) class build(build.build, BuildGRPC):