diff --git a/go/protopace/compatibility.go b/go/protopace/compatibility.go index 13e279be5..ee90df999 100644 --- a/go/protopace/compatibility.go +++ b/go/protopace/compatibility.go @@ -31,6 +31,7 @@ func Check(schema schema.Schema, previousSchema schema.Schema) error { "FIELD_SAME_NAME", "FIELD_SAME_JSON_NAME", "FILE_NO_DELETE", + "ENUM_NO_DELETE", }, nil, nil, diff --git a/go/protopace/schema/google/type/README.md b/go/protopace/schema/google/type/README.md new file mode 100644 index 000000000..adf1563a8 --- /dev/null +++ b/go/protopace/schema/google/type/README.md @@ -0,0 +1,7 @@ +## Google Common Types + +This package contains definitions of common types for Google APIs. +All types defined in this package are suitable for different APIs to +exchange data, and will never break binary compatibility. They should +have design quality comparable to major programming languages like +Java and C#. diff --git a/go/protopace/schema/google/type/calendar_period.proto b/go/protopace/schema/google/type/calendar_period.proto new file mode 100644 index 000000000..25a8f6441 --- /dev/null +++ b/go/protopace/schema/google/type/calendar_period.proto @@ -0,0 +1,56 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option go_package = "google.golang.org/genproto/googleapis/type/calendarperiod;calendarperiod"; +option java_multiple_files = true; +option java_outer_classname = "CalendarPeriodProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// A `CalendarPeriod` represents the abstract concept of a time period that has +// a canonical start. Grammatically, "the start of the current +// `CalendarPeriod`." All calendar times begin at midnight UTC. +enum CalendarPeriod { + // Undefined period, raises an error. + CALENDAR_PERIOD_UNSPECIFIED = 0; + + // A day. + DAY = 1; + + // A week. Weeks begin on Monday, following + // [ISO 8601](https://en.wikipedia.org/wiki/ISO_week_date). + WEEK = 2; + + // A fortnight. The first calendar fortnight of the year begins at the start + // of week 1 according to + // [ISO 8601](https://en.wikipedia.org/wiki/ISO_week_date). + FORTNIGHT = 3; + + // A month. + MONTH = 4; + + // A quarter. Quarters start on dates 1-Jan, 1-Apr, 1-Jul, and 1-Oct of each + // year. + QUARTER = 5; + + // A half-year. Half-years start on dates 1-Jan and 1-Jul. + HALF = 6; + + // A year. + YEAR = 7; +} diff --git a/go/protopace/schema/google/type/color.proto b/go/protopace/schema/google/type/color.proto new file mode 100644 index 000000000..3e57c1fb2 --- /dev/null +++ b/go/protopace/schema/google/type/color.proto @@ -0,0 +1,174 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +import "google/protobuf/wrappers.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/color;color"; +option java_multiple_files = true; +option java_outer_classname = "ColorProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a color in the RGBA color space. This representation is designed +// for simplicity of conversion to/from color representations in various +// languages over compactness. For example, the fields of this representation +// can be trivially provided to the constructor of `java.awt.Color` in Java; it +// can also be trivially provided to UIColor's `+colorWithRed:green:blue:alpha` +// method in iOS; and, with just a little work, it can be easily formatted into +// a CSS `rgba()` string in JavaScript. +// +// This reference page doesn't carry information about the absolute color +// space +// that should be used to interpret the RGB value (e.g. sRGB, Adobe RGB, +// DCI-P3, BT.2020, etc.). By default, applications should assume the sRGB color +// space. +// +// When color equality needs to be decided, implementations, unless +// documented otherwise, treat two colors as equal if all their red, +// green, blue, and alpha values each differ by at most 1e-5. +// +// Example (Java): +// +// import com.google.type.Color; +// +// // ... +// public static java.awt.Color fromProto(Color protocolor) { +// float alpha = protocolor.hasAlpha() +// ? protocolor.getAlpha().getValue() +// : 1.0; +// +// return new java.awt.Color( +// protocolor.getRed(), +// protocolor.getGreen(), +// protocolor.getBlue(), +// alpha); +// } +// +// public static Color toProto(java.awt.Color color) { +// float red = (float) color.getRed(); +// float green = (float) color.getGreen(); +// float blue = (float) color.getBlue(); +// float denominator = 255.0; +// Color.Builder resultBuilder = +// Color +// .newBuilder() +// .setRed(red / denominator) +// .setGreen(green / denominator) +// .setBlue(blue / denominator); +// int alpha = color.getAlpha(); +// if (alpha != 255) { +// result.setAlpha( +// FloatValue +// .newBuilder() +// .setValue(((float) alpha) / denominator) +// .build()); +// } +// return resultBuilder.build(); +// } +// // ... +// +// Example (iOS / Obj-C): +// +// // ... +// static UIColor* fromProto(Color* protocolor) { +// float red = [protocolor red]; +// float green = [protocolor green]; +// float blue = [protocolor blue]; +// FloatValue* alpha_wrapper = [protocolor alpha]; +// float alpha = 1.0; +// if (alpha_wrapper != nil) { +// alpha = [alpha_wrapper value]; +// } +// return [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; +// } +// +// static Color* toProto(UIColor* color) { +// CGFloat red, green, blue, alpha; +// if (![color getRed:&red green:&green blue:&blue alpha:&alpha]) { +// return nil; +// } +// Color* result = [[Color alloc] init]; +// [result setRed:red]; +// [result setGreen:green]; +// [result setBlue:blue]; +// if (alpha <= 0.9999) { +// [result setAlpha:floatWrapperWithValue(alpha)]; +// } +// [result autorelease]; +// return result; +// } +// // ... +// +// Example (JavaScript): +// +// // ... +// +// var protoToCssColor = function(rgb_color) { +// var redFrac = rgb_color.red || 0.0; +// var greenFrac = rgb_color.green || 0.0; +// var blueFrac = rgb_color.blue || 0.0; +// var red = Math.floor(redFrac * 255); +// var green = Math.floor(greenFrac * 255); +// var blue = Math.floor(blueFrac * 255); +// +// if (!('alpha' in rgb_color)) { +// return rgbToCssColor(red, green, blue); +// } +// +// var alphaFrac = rgb_color.alpha.value || 0.0; +// var rgbParams = [red, green, blue].join(','); +// return ['rgba(', rgbParams, ',', alphaFrac, ')'].join(''); +// }; +// +// var rgbToCssColor = function(red, green, blue) { +// var rgbNumber = new Number((red << 16) | (green << 8) | blue); +// var hexString = rgbNumber.toString(16); +// var missingZeros = 6 - hexString.length; +// var resultBuilder = ['#']; +// for (var i = 0; i < missingZeros; i++) { +// resultBuilder.push('0'); +// } +// resultBuilder.push(hexString); +// return resultBuilder.join(''); +// }; +// +// // ... +message Color { + // The amount of red in the color as a value in the interval [0, 1]. + float red = 1; + + // The amount of green in the color as a value in the interval [0, 1]. + float green = 2; + + // The amount of blue in the color as a value in the interval [0, 1]. + float blue = 3; + + // The fraction of this color that should be applied to the pixel. That is, + // the final pixel color is defined by the equation: + // + // `pixel color = alpha * (this color) + (1.0 - alpha) * (background color)` + // + // This means that a value of 1.0 corresponds to a solid color, whereas + // a value of 0.0 corresponds to a completely transparent color. This + // uses a wrapper message rather than a simple float scalar so that it is + // possible to distinguish between a default value and the value being unset. + // If omitted, this color object is rendered as a solid color + // (as if the alpha value had been explicitly given a value of 1.0). + google.protobuf.FloatValue alpha = 4; +} diff --git a/go/protopace/schema/google/type/date.proto b/go/protopace/schema/google/type/date.proto new file mode 100644 index 000000000..6370cd869 --- /dev/null +++ b/go/protopace/schema/google/type/date.proto @@ -0,0 +1,52 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/date;date"; +option java_multiple_files = true; +option java_outer_classname = "DateProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a whole or partial calendar date, such as a birthday. The time of +// day and time zone are either specified elsewhere or are insignificant. The +// date is relative to the Gregorian Calendar. This can represent one of the +// following: +// +// * A full date, with non-zero year, month, and day values +// * A month and day value, with a zero year, such as an anniversary +// * A year on its own, with zero month and day values +// * A year and month value, with a zero day, such as a credit card expiration +// date +// +// Related types are [google.type.TimeOfDay][google.type.TimeOfDay] and +// `google.protobuf.Timestamp`. +message Date { + // Year of the date. Must be from 1 to 9999, or 0 to specify a date without + // a year. + int32 year = 1; + + // Month of a year. Must be from 1 to 12, or 0 to specify a year without a + // month and day. + int32 month = 2; + + // Day of a month. Must be from 1 to 31 and valid for the year and month, or 0 + // to specify a year by itself or a year and month where the day isn't + // significant. + int32 day = 3; +} diff --git a/go/protopace/schema/google/type/datetime.proto b/go/protopace/schema/google/type/datetime.proto new file mode 100644 index 000000000..a363a41ef --- /dev/null +++ b/go/protopace/schema/google/type/datetime.proto @@ -0,0 +1,104 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +import "google/protobuf/duration.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/datetime;datetime"; +option java_multiple_files = true; +option java_outer_classname = "DateTimeProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents civil time (or occasionally physical time). +// +// This type can represent a civil time in one of a few possible ways: +// +// * When utc_offset is set and time_zone is unset: a civil time on a calendar +// day with a particular offset from UTC. +// * When time_zone is set and utc_offset is unset: a civil time on a calendar +// day in a particular time zone. +// * When neither time_zone nor utc_offset is set: a civil time on a calendar +// day in local time. +// +// The date is relative to the Proleptic Gregorian Calendar. +// +// If year is 0, the DateTime is considered not to have a specific year. month +// and day must have valid, non-zero values. +// +// This type may also be used to represent a physical time if all the date and +// time fields are set and either case of the `time_offset` oneof is set. +// Consider using `Timestamp` message for physical time instead. If your use +// case also would like to store the user's timezone, that can be done in +// another field. +// +// This type is more flexible than some applications may want. Make sure to +// document and validate your application's limitations. +message DateTime { + // Optional. Year of date. Must be from 1 to 9999, or 0 if specifying a + // datetime without a year. + int32 year = 1; + + // Required. Month of year. Must be from 1 to 12. + int32 month = 2; + + // Required. Day of month. Must be from 1 to 31 and valid for the year and + // month. + int32 day = 3; + + // Required. Hours of day in 24 hour format. Should be from 0 to 23. An API + // may choose to allow the value "24:00:00" for scenarios like business + // closing time. + int32 hours = 4; + + // Required. Minutes of hour of day. Must be from 0 to 59. + int32 minutes = 5; + + // Required. Seconds of minutes of the time. Must normally be from 0 to 59. An + // API may allow the value 60 if it allows leap-seconds. + int32 seconds = 6; + + // Required. Fractions of seconds in nanoseconds. Must be from 0 to + // 999,999,999. + int32 nanos = 7; + + // Optional. Specifies either the UTC offset or the time zone of the DateTime. + // Choose carefully between them, considering that time zone data may change + // in the future (for example, a country modifies their DST start/end dates, + // and future DateTimes in the affected range had already been stored). + // If omitted, the DateTime is considered to be in local time. + oneof time_offset { + // UTC offset. Must be whole seconds, between -18 hours and +18 hours. + // For example, a UTC offset of -4:00 would be represented as + // { seconds: -14400 }. + google.protobuf.Duration utc_offset = 8; + + // Time zone. + TimeZone time_zone = 9; + } +} + +// Represents a time zone from the +// [IANA Time Zone Database](https://www.iana.org/time-zones). +message TimeZone { + // IANA Time Zone Database time zone, e.g. "America/New_York". + string id = 1; + + // Optional. IANA Time Zone Database version number, e.g. "2019a". + string version = 2; +} diff --git a/go/protopace/schema/google/type/dayofweek.proto b/go/protopace/schema/google/type/dayofweek.proto new file mode 100644 index 000000000..e16c19469 --- /dev/null +++ b/go/protopace/schema/google/type/dayofweek.proto @@ -0,0 +1,50 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option go_package = "google.golang.org/genproto/googleapis/type/dayofweek;dayofweek"; +option java_multiple_files = true; +option java_outer_classname = "DayOfWeekProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a day of the week. +enum DayOfWeek { + // The day of the week is unspecified. + DAY_OF_WEEK_UNSPECIFIED = 0; + + // Monday + MONDAY = 1; + + // Tuesday + TUESDAY = 2; + + // Wednesday + WEDNESDAY = 3; + + // Thursday + THURSDAY = 4; + + // Friday + FRIDAY = 5; + + // Saturday + SATURDAY = 6; + + // Sunday + SUNDAY = 7; +} diff --git a/go/protopace/schema/google/type/decimal.proto b/go/protopace/schema/google/type/decimal.proto new file mode 100644 index 000000000..293d08273 --- /dev/null +++ b/go/protopace/schema/google/type/decimal.proto @@ -0,0 +1,95 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/decimal;decimal"; +option java_multiple_files = true; +option java_outer_classname = "DecimalProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// A representation of a decimal value, such as 2.5. Clients may convert values +// into language-native decimal formats, such as Java's [BigDecimal][] or +// Python's [decimal.Decimal][]. +// +// [BigDecimal]: +// https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/math/BigDecimal.html +// [decimal.Decimal]: https://docs.python.org/3/library/decimal.html +message Decimal { + // The decimal value, as a string. + // + // The string representation consists of an optional sign, `+` (`U+002B`) + // or `-` (`U+002D`), followed by a sequence of zero or more decimal digits + // ("the integer"), optionally followed by a fraction, optionally followed + // by an exponent. + // + // The fraction consists of a decimal point followed by zero or more decimal + // digits. The string must contain at least one digit in either the integer + // or the fraction. The number formed by the sign, the integer and the + // fraction is referred to as the significand. + // + // The exponent consists of the character `e` (`U+0065`) or `E` (`U+0045`) + // followed by one or more decimal digits. + // + // Services **should** normalize decimal values before storing them by: + // + // - Removing an explicitly-provided `+` sign (`+2.5` -> `2.5`). + // - Replacing a zero-length integer value with `0` (`.5` -> `0.5`). + // - Coercing the exponent character to lower-case (`2.5E8` -> `2.5e8`). + // - Removing an explicitly-provided zero exponent (`2.5e0` -> `2.5`). + // + // Services **may** perform additional normalization based on its own needs + // and the internal decimal implementation selected, such as shifting the + // decimal point and exponent value together (example: `2.5e-1` <-> `0.25`). + // Additionally, services **may** preserve trailing zeroes in the fraction + // to indicate increased precision, but are not required to do so. + // + // Note that only the `.` character is supported to divide the integer + // and the fraction; `,` **should not** be supported regardless of locale. + // Additionally, thousand separators **should not** be supported. If a + // service does support them, values **must** be normalized. + // + // The ENBF grammar is: + // + // DecimalString = + // [Sign] Significand [Exponent]; + // + // Sign = '+' | '-'; + // + // Significand = + // Digits ['.'] [Digits] | [Digits] '.' Digits; + // + // Exponent = ('e' | 'E') [Sign] Digits; + // + // Digits = { '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' }; + // + // Services **should** clearly document the range of supported values, the + // maximum supported precision (total number of digits), and, if applicable, + // the scale (number of digits after the decimal point), as well as how it + // behaves when receiving out-of-bounds values. + // + // Services **may** choose to accept values passed as input even when the + // value has a higher precision or scale than the service supports, and + // **should** round the value to fit the supported scale. Alternatively, the + // service **may** error with `400 Bad Request` (`INVALID_ARGUMENT` in gRPC) + // if precision would be lost. + // + // Services **should** error with `400 Bad Request` (`INVALID_ARGUMENT` in + // gRPC) if the service receives a value outside of the supported range. + string value = 1; +} diff --git a/go/protopace/schema/google/type/expr.proto b/go/protopace/schema/google/type/expr.proto new file mode 100644 index 000000000..544e66874 --- /dev/null +++ b/go/protopace/schema/google/type/expr.proto @@ -0,0 +1,73 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option go_package = "google.golang.org/genproto/googleapis/type/expr;expr"; +option java_multiple_files = true; +option java_outer_classname = "ExprProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a textual expression in the Common Expression Language (CEL) +// syntax. CEL is a C-like expression language. The syntax and semantics of CEL +// are documented at https://github.com/google/cel-spec. +// +// Example (Comparison): +// +// title: "Summary size limit" +// description: "Determines if a summary is less than 100 chars" +// expression: "document.summary.size() < 100" +// +// Example (Equality): +// +// title: "Requestor is owner" +// description: "Determines if requestor is the document owner" +// expression: "document.owner == request.auth.claims.email" +// +// Example (Logic): +// +// title: "Public documents" +// description: "Determine whether the document should be publicly visible" +// expression: "document.type != 'private' && document.type != 'internal'" +// +// Example (Data Manipulation): +// +// title: "Notification string" +// description: "Create a notification string with a timestamp." +// expression: "'New message received at ' + string(document.create_time)" +// +// The exact variables and functions that may be referenced within an expression +// are determined by the service that evaluates it. See the service +// documentation for additional information. +message Expr { + // Textual representation of an expression in Common Expression Language + // syntax. + string expression = 1; + + // Optional. Title for the expression, i.e. a short string describing + // its purpose. This can be used e.g. in UIs which allow to enter the + // expression. + string title = 2; + + // Optional. Description of the expression. This is a longer text which + // describes the expression, e.g. when hovered over it in a UI. + string description = 3; + + // Optional. String indicating the location of the expression for error + // reporting, e.g. a file name and a position in the file. + string location = 4; +} diff --git a/go/protopace/schema/google/type/fraction.proto b/go/protopace/schema/google/type/fraction.proto new file mode 100644 index 000000000..06f072322 --- /dev/null +++ b/go/protopace/schema/google/type/fraction.proto @@ -0,0 +1,33 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option go_package = "google.golang.org/genproto/googleapis/type/fraction;fraction"; +option java_multiple_files = true; +option java_outer_classname = "FractionProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a fraction in terms of a numerator divided by a denominator. +message Fraction { + // The numerator in the fraction, e.g. 2 in 2/3. + int64 numerator = 1; + + // The value by which the numerator is divided, e.g. 3 in 2/3. Must be + // positive. + int64 denominator = 2; +} diff --git a/go/protopace/schema/google/type/interval.proto b/go/protopace/schema/google/type/interval.proto new file mode 100644 index 000000000..fcf94c866 --- /dev/null +++ b/go/protopace/schema/google/type/interval.proto @@ -0,0 +1,46 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +import "google/protobuf/timestamp.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/interval;interval"; +option java_multiple_files = true; +option java_outer_classname = "IntervalProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a time interval, encoded as a Timestamp start (inclusive) and a +// Timestamp end (exclusive). +// +// The start must be less than or equal to the end. +// When the start equals the end, the interval is empty (matches no time). +// When both start and end are unspecified, the interval matches any time. +message Interval { + // Optional. Inclusive start of the interval. + // + // If specified, a Timestamp matching this interval will have to be the same + // or after the start. + google.protobuf.Timestamp start_time = 1; + + // Optional. Exclusive end of the interval. + // + // If specified, a Timestamp matching this interval will have to be before the + // end. + google.protobuf.Timestamp end_time = 2; +} diff --git a/go/protopace/schema/google/type/latlng.proto b/go/protopace/schema/google/type/latlng.proto new file mode 100644 index 000000000..daeba48b4 --- /dev/null +++ b/go/protopace/schema/google/type/latlng.proto @@ -0,0 +1,37 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/latlng;latlng"; +option java_multiple_files = true; +option java_outer_classname = "LatLngProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// An object that represents a latitude/longitude pair. This is expressed as a +// pair of doubles to represent degrees latitude and degrees longitude. Unless +// specified otherwise, this must conform to the +// WGS84 +// standard. Values must be within normalized ranges. +message LatLng { + // The latitude in degrees. It must be in the range [-90.0, +90.0]. + double latitude = 1; + + // The longitude in degrees. It must be in the range [-180.0, +180.0]. + double longitude = 2; +} diff --git a/go/protopace/schema/google/type/localized_text.proto b/go/protopace/schema/google/type/localized_text.proto new file mode 100644 index 000000000..82d083c43 --- /dev/null +++ b/go/protopace/schema/google/type/localized_text.proto @@ -0,0 +1,36 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/localized_text;localized_text"; +option java_multiple_files = true; +option java_outer_classname = "LocalizedTextProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Localized variant of a text in a particular language. +message LocalizedText { + // Localized string in the language corresponding to `language_code' below. + string text = 1; + + // The text's BCP-47 language code, such as "en-US" or "sr-Latn". + // + // For more information, see + // http://www.unicode.org/reports/tr35/#Unicode_locale_identifier. + string language_code = 2; +} diff --git a/go/protopace/schema/google/type/money.proto b/go/protopace/schema/google/type/money.proto new file mode 100644 index 000000000..c61094336 --- /dev/null +++ b/go/protopace/schema/google/type/money.proto @@ -0,0 +1,42 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/money;money"; +option java_multiple_files = true; +option java_outer_classname = "MoneyProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents an amount of money with its currency type. +message Money { + // The three-letter currency code defined in ISO 4217. + string currency_code = 1; + + // The whole units of the amount. + // For example if `currencyCode` is `"USD"`, then 1 unit is one US dollar. + int64 units = 2; + + // Number of nano (10^-9) units of the amount. + // The value must be between -999,999,999 and +999,999,999 inclusive. + // If `units` is positive, `nanos` must be positive or zero. + // If `units` is zero, `nanos` can be positive, zero, or negative. + // If `units` is negative, `nanos` must be negative or zero. + // For example $-1.75 is represented as `units`=-1 and `nanos`=-750,000,000. + int32 nanos = 3; +} diff --git a/go/protopace/schema/google/type/month.proto b/go/protopace/schema/google/type/month.proto new file mode 100644 index 000000000..19982cb51 --- /dev/null +++ b/go/protopace/schema/google/type/month.proto @@ -0,0 +1,65 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option go_package = "google.golang.org/genproto/googleapis/type/month;month"; +option java_multiple_files = true; +option java_outer_classname = "MonthProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a month in the Gregorian calendar. +enum Month { + // The unspecified month. + MONTH_UNSPECIFIED = 0; + + // The month of January. + JANUARY = 1; + + // The month of February. + FEBRUARY = 2; + + // The month of March. + MARCH = 3; + + // The month of April. + APRIL = 4; + + // The month of May. + MAY = 5; + + // The month of June. + JUNE = 6; + + // The month of July. + JULY = 7; + + // The month of August. + AUGUST = 8; + + // The month of September. + SEPTEMBER = 9; + + // The month of October. + OCTOBER = 10; + + // The month of November. + NOVEMBER = 11; + + // The month of December. + DECEMBER = 12; +} diff --git a/go/protopace/schema/google/type/phone_number.proto b/go/protopace/schema/google/type/phone_number.proto new file mode 100644 index 000000000..370d1623d --- /dev/null +++ b/go/protopace/schema/google/type/phone_number.proto @@ -0,0 +1,113 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/phone_number;phone_number"; +option java_multiple_files = true; +option java_outer_classname = "PhoneNumberProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// An object representing a phone number, suitable as an API wire format. +// +// This representation: +// +// - should not be used for locale-specific formatting of a phone number, such +// as "+1 (650) 253-0000 ext. 123" +// +// - is not designed for efficient storage +// - may not be suitable for dialing - specialized libraries (see references) +// should be used to parse the number for that purpose +// +// To do something meaningful with this number, such as format it for various +// use-cases, convert it to an `i18n.phonenumbers.PhoneNumber` object first. +// +// For instance, in Java this would be: +// +// com.google.type.PhoneNumber wireProto = +// com.google.type.PhoneNumber.newBuilder().build(); +// com.google.i18n.phonenumbers.Phonenumber.PhoneNumber phoneNumber = +// PhoneNumberUtil.getInstance().parse(wireProto.getE164Number(), "ZZ"); +// if (!wireProto.getExtension().isEmpty()) { +// phoneNumber.setExtension(wireProto.getExtension()); +// } +// +// Reference(s): +// - https://github.com/google/libphonenumber +message PhoneNumber { + // An object representing a short code, which is a phone number that is + // typically much shorter than regular phone numbers and can be used to + // address messages in MMS and SMS systems, as well as for abbreviated dialing + // (e.g. "Text 611 to see how many minutes you have remaining on your plan."). + // + // Short codes are restricted to a region and are not internationally + // dialable, which means the same short code can exist in different regions, + // with different usage and pricing, even if those regions share the same + // country calling code (e.g. US and CA). + message ShortCode { + // Required. The BCP-47 region code of the location where calls to this + // short code can be made, such as "US" and "BB". + // + // Reference(s): + // - http://www.unicode.org/reports/tr35/#unicode_region_subtag + string region_code = 1; + + // Required. The short code digits, without a leading plus ('+') or country + // calling code, e.g. "611". + string number = 2; + } + + // Required. Either a regular number, or a short code. New fields may be + // added to the oneof below in the future, so clients should ignore phone + // numbers for which none of the fields they coded against are set. + oneof kind { + // The phone number, represented as a leading plus sign ('+'), followed by a + // phone number that uses a relaxed ITU E.164 format consisting of the + // country calling code (1 to 3 digits) and the subscriber number, with no + // additional spaces or formatting, e.g.: + // - correct: "+15552220123" + // - incorrect: "+1 (555) 222-01234 x123". + // + // The ITU E.164 format limits the latter to 12 digits, but in practice not + // all countries respect that, so we relax that restriction here. + // National-only numbers are not allowed. + // + // References: + // - https://www.itu.int/rec/T-REC-E.164-201011-I + // - https://en.wikipedia.org/wiki/E.164. + // - https://en.wikipedia.org/wiki/List_of_country_calling_codes + string e164_number = 1; + + // A short code. + // + // Reference(s): + // - https://en.wikipedia.org/wiki/Short_code + ShortCode short_code = 2; + } + + // The phone number's extension. The extension is not standardized in ITU + // recommendations, except for being defined as a series of numbers with a + // maximum length of 40 digits. Other than digits, some other dialing + // characters such as ',' (indicating a wait) or '#' may be stored here. + // + // Note that no regions currently use extensions with short codes, so this + // field is normally only set in conjunction with an E.164 number. It is held + // separately from the E.164 number to allow for short code extensions in the + // future. + string extension = 3; +} diff --git a/go/protopace/schema/google/type/postal_address.proto b/go/protopace/schema/google/type/postal_address.proto new file mode 100644 index 000000000..7023a9b3e --- /dev/null +++ b/go/protopace/schema/google/type/postal_address.proto @@ -0,0 +1,134 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/postaladdress;postaladdress"; +option java_multiple_files = true; +option java_outer_classname = "PostalAddressProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a postal address, e.g. for postal delivery or payments addresses. +// Given a postal address, a postal service can deliver items to a premise, P.O. +// Box or similar. +// It is not intended to model geographical locations (roads, towns, +// mountains). +// +// In typical usage an address would be created via user input or from importing +// existing data, depending on the type of process. +// +// Advice on address input / editing: +// - Use an i18n-ready address widget such as +// https://github.com/google/libaddressinput) +// - Users should not be presented with UI elements for input or editing of +// fields outside countries where that field is used. +// +// For more guidance on how to use this schema, please see: +// https://support.google.com/business/answer/6397478 +message PostalAddress { + // The schema revision of the `PostalAddress`. This must be set to 0, which is + // the latest revision. + // + // All new revisions **must** be backward compatible with old revisions. + int32 revision = 1; + + // Required. CLDR region code of the country/region of the address. This + // is never inferred and it is up to the user to ensure the value is + // correct. See http://cldr.unicode.org/ and + // http://www.unicode.org/cldr/charts/30/supplemental/territory_information.html + // for details. Example: "CH" for Switzerland. + string region_code = 2; + + // Optional. BCP-47 language code of the contents of this address (if + // known). This is often the UI language of the input form or is expected + // to match one of the languages used in the address' country/region, or their + // transliterated equivalents. + // This can affect formatting in certain countries, but is not critical + // to the correctness of the data and will never affect any validation or + // other non-formatting related operations. + // + // If this value is not known, it should be omitted (rather than specifying a + // possibly incorrect default). + // + // Examples: "zh-Hant", "ja", "ja-Latn", "en". + string language_code = 3; + + // Optional. Postal code of the address. Not all countries use or require + // postal codes to be present, but where they are used, they may trigger + // additional validation with other parts of the address (e.g. state/zip + // validation in the U.S.A.). + string postal_code = 4; + + // Optional. Additional, country-specific, sorting code. This is not used + // in most regions. Where it is used, the value is either a string like + // "CEDEX", optionally followed by a number (e.g. "CEDEX 7"), or just a number + // alone, representing the "sector code" (Jamaica), "delivery area indicator" + // (Malawi) or "post office indicator" (e.g. Côte d'Ivoire). + string sorting_code = 5; + + // Optional. Highest administrative subdivision which is used for postal + // addresses of a country or region. + // For example, this can be a state, a province, an oblast, or a prefecture. + // Specifically, for Spain this is the province and not the autonomous + // community (e.g. "Barcelona" and not "Catalonia"). + // Many countries don't use an administrative area in postal addresses. E.g. + // in Switzerland this should be left unpopulated. + string administrative_area = 6; + + // Optional. Generally refers to the city/town portion of the address. + // Examples: US city, IT comune, UK post town. + // In regions of the world where localities are not well defined or do not fit + // into this structure well, leave locality empty and use address_lines. + string locality = 7; + + // Optional. Sublocality of the address. + // For example, this can be neighborhoods, boroughs, districts. + string sublocality = 8; + + // Unstructured address lines describing the lower levels of an address. + // + // Because values in address_lines do not have type information and may + // sometimes contain multiple values in a single field (e.g. + // "Austin, TX"), it is important that the line order is clear. The order of + // address lines should be "envelope order" for the country/region of the + // address. In places where this can vary (e.g. Japan), address_language is + // used to make it explicit (e.g. "ja" for large-to-small ordering and + // "ja-Latn" or "en" for small-to-large). This way, the most specific line of + // an address can be selected based on the language. + // + // The minimum permitted structural representation of an address consists + // of a region_code with all remaining information placed in the + // address_lines. It would be possible to format such an address very + // approximately without geocoding, but no semantic reasoning could be + // made about any of the address components until it was at least + // partially resolved. + // + // Creating an address only containing a region_code and address_lines, and + // then geocoding is the recommended way to handle completely unstructured + // addresses (as opposed to guessing which parts of the address should be + // localities or administrative areas). + repeated string address_lines = 9; + + // Optional. The recipient at the address. + // This field may, under certain circumstances, contain multiline information. + // For example, it might contain "care of" information. + repeated string recipients = 10; + + // Optional. The name of the organization at the address. + string organization = 11; +} diff --git a/go/protopace/schema/google/type/quaternion.proto b/go/protopace/schema/google/type/quaternion.proto new file mode 100644 index 000000000..416de30cf --- /dev/null +++ b/go/protopace/schema/google/type/quaternion.proto @@ -0,0 +1,94 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/quaternion;quaternion"; +option java_multiple_files = true; +option java_outer_classname = "QuaternionProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// A quaternion is defined as the quotient of two directed lines in a +// three-dimensional space or equivalently as the quotient of two Euclidean +// vectors (https://en.wikipedia.org/wiki/Quaternion). +// +// Quaternions are often used in calculations involving three-dimensional +// rotations (https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation), +// as they provide greater mathematical robustness by avoiding the gimbal lock +// problems that can be encountered when using Euler angles +// (https://en.wikipedia.org/wiki/Gimbal_lock). +// +// Quaternions are generally represented in this form: +// +// w + xi + yj + zk +// +// where x, y, z, and w are real numbers, and i, j, and k are three imaginary +// numbers. +// +// Our naming choice `(x, y, z, w)` comes from the desire to avoid confusion for +// those interested in the geometric properties of the quaternion in the 3D +// Cartesian space. Other texts often use alternative names or subscripts, such +// as `(a, b, c, d)`, `(1, i, j, k)`, or `(0, 1, 2, 3)`, which are perhaps +// better suited for mathematical interpretations. +// +// To avoid any confusion, as well as to maintain compatibility with a large +// number of software libraries, the quaternions represented using the protocol +// buffer below *must* follow the Hamilton convention, which defines `ij = k` +// (i.e. a right-handed algebra), and therefore: +// +// i^2 = j^2 = k^2 = ijk = −1 +// ij = −ji = k +// jk = −kj = i +// ki = −ik = j +// +// Please DO NOT use this to represent quaternions that follow the JPL +// convention, or any of the other quaternion flavors out there. +// +// Definitions: +// +// - Quaternion norm (or magnitude): `sqrt(x^2 + y^2 + z^2 + w^2)`. +// - Unit (or normalized) quaternion: a quaternion whose norm is 1. +// - Pure quaternion: a quaternion whose scalar component (`w`) is 0. +// - Rotation quaternion: a unit quaternion used to represent rotation. +// - Orientation quaternion: a unit quaternion used to represent orientation. +// +// A quaternion can be normalized by dividing it by its norm. The resulting +// quaternion maintains the same direction, but has a norm of 1, i.e. it moves +// on the unit sphere. This is generally necessary for rotation and orientation +// quaternions, to avoid rounding errors: +// https://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions +// +// Note that `(x, y, z, w)` and `(-x, -y, -z, -w)` represent the same rotation, +// but normalization would be even more useful, e.g. for comparison purposes, if +// it would produce a unique representation. It is thus recommended that `w` be +// kept positive, which can be achieved by changing all the signs when `w` is +// negative. +// +message Quaternion { + // The x component. + double x = 1; + + // The y component. + double y = 2; + + // The z component. + double z = 3; + + // The scalar component. + double w = 4; +} diff --git a/go/protopace/schema/google/type/timeofday.proto b/go/protopace/schema/google/type/timeofday.proto new file mode 100644 index 000000000..3735745a4 --- /dev/null +++ b/go/protopace/schema/google/type/timeofday.proto @@ -0,0 +1,44 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/timeofday;timeofday"; +option java_multiple_files = true; +option java_outer_classname = "TimeOfDayProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a time of day. The date and time zone are either not significant +// or are specified elsewhere. An API may choose to allow leap seconds. Related +// types are [google.type.Date][google.type.Date] and +// `google.protobuf.Timestamp`. +message TimeOfDay { + // Hours of day in 24 hour format. Should be from 0 to 23. An API may choose + // to allow the value "24:00:00" for scenarios like business closing time. + int32 hours = 1; + + // Minutes of hour of day. Must be from 0 to 59. + int32 minutes = 2; + + // Seconds of minutes of the time. Must normally be from 0 to 59. An API may + // allow the value 60 if it allows leap-seconds. + int32 seconds = 3; + + // Fractions of seconds in nanoseconds. Must be from 0 to 999,999,999. + int32 nanos = 4; +} diff --git a/go/protopace/schema/google/type/type.yaml b/go/protopace/schema/google/type/type.yaml new file mode 100644 index 000000000..d5c71364d --- /dev/null +++ b/go/protopace/schema/google/type/type.yaml @@ -0,0 +1,40 @@ +type: google.api.Service +config_version: 3 +name: type.googleapis.com +title: Common Types + +types: +- name: google.type.Color +- name: google.type.Date +- name: google.type.DateTime +- name: google.type.Decimal +- name: google.type.Expr +- name: google.type.Fraction +- name: google.type.Interval +- name: google.type.LatLng +- name: google.type.LocalizedText +- name: google.type.Money +- name: google.type.PhoneNumber +- name: google.type.PostalAddress +- name: google.type.Quaternion +- name: google.type.TimeOfDay + +enums: +- name: google.type.CalendarPeriod +- name: google.type.DayOfWeek +- name: google.type.Month + +documentation: + summary: Defines common types for Google APIs. + overview: |- + # Google Common Types + + This package contains definitions of common types for Google APIs. + All types defined in this package are suitable for different APIs to + exchange data, and will never break binary compatibility. They should + have design quality comparable to major programming languages like + Java and C#. + + NOTE: Some common types are defined in the package `google.protobuf` + as they are directly supported by Protocol Buffers compiler and + runtime. Those types are called Well-Known Types. diff --git a/go/protopace/schema/google_types.go b/go/protopace/schema/google_types.go new file mode 100644 index 000000000..e81f5a533 --- /dev/null +++ b/go/protopace/schema/google_types.go @@ -0,0 +1,23 @@ +package schema + +import ( + "embed" + "io" + + "github.com/bufbuild/protocompile" +) + +//go:embed google/type/*.proto +var files embed.FS + +// WithGoogleTypeImports returns a new resolver that can provide the source code for google/types protos +func WithGoogleTypeImports(resolver protocompile.Resolver) protocompile.Resolver { + return protocompile.CompositeResolver{ + resolver, + &protocompile.SourceResolver{ + Accessor: func(path string) (io.ReadCloser, error) { + return files.Open(path) + }, + }, + } +} diff --git a/go/protopace/schema/resolver.go b/go/protopace/schema/resolver.go index 1d76c4f92..9ace3e55d 100644 --- a/go/protopace/schema/resolver.go +++ b/go/protopace/schema/resolver.go @@ -17,7 +17,7 @@ func NewSchemaResolver(schemas []Schema) protocompile.Resolver { schemasIndex[schema.Name] = schema } resolver := SchemaResolver{schemas: schemasIndex} - return protocompile.WithStandardImports(&resolver) + return WithGoogleTypeImports(protocompile.WithStandardImports(&resolver)) } func (s *SchemaResolver) AddSchema(schema Schema) { diff --git a/go/protopace/schema/schema.go b/go/protopace/schema/schema.go index 6762b0488..1a0bb822e 100644 --- a/go/protopace/schema/schema.go +++ b/go/protopace/schema/schema.go @@ -75,7 +75,7 @@ func (s Schema) CompileBufImage() (bufimage.Image, error) { } files[i] = file } - + image, err := bufimage.NewImage(files) return image, err } diff --git a/karapace/compatibility/protobuf/checks.py b/karapace/compatibility/protobuf/checks.py index 9d94425f9..04a599f00 100644 --- a/karapace/compatibility/protobuf/checks.py +++ b/karapace/compatibility/protobuf/checks.py @@ -3,8 +3,8 @@ See LICENSE for details """ from avro.compatibility import SchemaCompatibilityResult, SchemaCompatibilityType -from karapace.protobuf.compare_result import CompareResult, Modification -from karapace.protobuf.protopace import check_compatibility, IncompatibleError, Proto +from karapace.protobuf.compare_result import CompareResult +from karapace.protobuf.protopace import check_compatibility, IncompatibleError from karapace.protobuf.schema import ProtobufSchema @@ -12,27 +12,15 @@ def check_protobuf_schema_compatibility( reader: ProtobufSchema, writer: ProtobufSchema, use_protopace: bool = False ) -> SchemaCompatibilityResult: if use_protopace: - old_deps = [] - # TODO: get dependencies recursive - if reader.dependencies: - for _, val in reader.dependencies.items(): - old_deps.append(Proto(val.name, val.get_schema().schema_str)) - old_proto = Proto("test.proto", reader.to_schema(), old_deps) - - new_deps = [] - if writer.dependencies: - for _, val in writer.dependencies.items(): - new_deps.append(Proto(val.name, val.get_schema().schema_str)) - new_proto = Proto("test.proto", writer.to_schema(), new_deps) - + old_proto = writer.to_proto() + new_proto = reader.to_proto() try: check_compatibility(new_proto, old_proto) except IncompatibleError as err: return SchemaCompatibilityResult( compatibility=SchemaCompatibilityType.incompatible, - messages=set([str(err)]), + messages={str(err)}, ) - return SchemaCompatibilityResult(SchemaCompatibilityType.compatible) result = CompareResult() diff --git a/karapace/protobuf/protopace/bin/protopace-darwin-amd64.so b/karapace/protobuf/protopace/bin/protopace-darwin-amd64.so index 194362293..6b0c90dd0 100644 Binary files a/karapace/protobuf/protopace/bin/protopace-darwin-amd64.so and b/karapace/protobuf/protopace/bin/protopace-darwin-amd64.so differ diff --git a/karapace/protobuf/protopace/bin/protopace-darwin-arm64.so b/karapace/protobuf/protopace/bin/protopace-darwin-arm64.so index d6b215756..dde377d4f 100644 Binary files a/karapace/protobuf/protopace/bin/protopace-darwin-arm64.so and b/karapace/protobuf/protopace/bin/protopace-darwin-arm64.so differ diff --git a/karapace/protobuf/protopace/bin/protopace-linux-amd64.so b/karapace/protobuf/protopace/bin/protopace-linux-amd64.so index ed26e20e3..cd94c59d3 100644 Binary files a/karapace/protobuf/protopace/bin/protopace-linux-amd64.so and b/karapace/protobuf/protopace/bin/protopace-linux-amd64.so differ diff --git a/karapace/protobuf/protopace/bin/protopace-linux-arm64.so b/karapace/protobuf/protopace/bin/protopace-linux-arm64.so index 55c4943ef..2d29b1b41 100644 Binary files a/karapace/protobuf/protopace/bin/protopace-linux-arm64.so and b/karapace/protobuf/protopace/bin/protopace-linux-arm64.so differ diff --git a/karapace/protobuf/protopace/protopace.py b/karapace/protobuf/protopace/protopace.py index e3c74fe52..eb6b9d209 100644 --- a/karapace/protobuf/protopace/protopace.py +++ b/karapace/protobuf/protopace/protopace.py @@ -4,6 +4,8 @@ """ from dataclasses import dataclass, field +from functools import cached_property +from karapace.errors import InvalidSchema from typing import List import ctypes @@ -44,9 +46,14 @@ class Proto: schema: str dependencies: List["Proto"] = field(default_factory=list) - -class CompileError(Exception): - pass + @cached_property + def all_dependencies(self) -> List["Proto"]: + dependencies = {} + for dep in self.dependencies: + if dep.dependencies: + dependencies.update([(d.name, d) for d in dep.all_dependencies]) + dependencies[dep.name] = dep + return list(dependencies.values()) class IncompatibleError(Exception): @@ -54,9 +61,9 @@ class IncompatibleError(Exception): def format_proto(proto: Proto) -> str: - length = len(proto.dependencies) - c_dependencies = (ctypes.c_char_p * length)(*[d.schema.encode() for d in proto.dependencies]) - c_dependency_names = (ctypes.c_char_p * length)(*[d.name.encode() for d in proto.dependencies]) + length = len(proto.all_dependencies) + c_dependencies = (ctypes.c_char_p * length)(*[d.schema.encode() for d in proto.all_dependencies]) + c_dependency_names = (ctypes.c_char_p * length)(*[d.name.encode() for d in proto.all_dependencies]) res_ptr = lib.FormatSchema(proto.name.encode(), proto.schema.encode(), c_dependency_names, c_dependencies, length) res = FormatResult.from_address(res_ptr) @@ -65,7 +72,7 @@ def format_proto(proto: Proto) -> str: err = res.err msg = err.decode() lib.free(ctypes.c_void_p(res_ptr)) - raise CompileError(msg) + raise InvalidSchema(msg) result = res.res.decode() lib.free(ctypes.c_void_p(res_ptr)) @@ -73,13 +80,13 @@ def format_proto(proto: Proto) -> str: def check_compatibility(proto: Proto, prev_proto: Proto) -> None: - length = len(proto.dependencies) - c_dependencies = (ctypes.c_char_p * length)(*[d.schema.encode() for d in proto.dependencies]) - c_dependency_names = (ctypes.c_char_p * length)(*[d.name.encode() for d in proto.dependencies]) + length = len(proto.all_dependencies) + c_dependencies = (ctypes.c_char_p * length)(*[d.schema.encode() for d in proto.all_dependencies]) + c_dependency_names = (ctypes.c_char_p * length)(*[d.name.encode() for d in proto.all_dependencies]) - prev_length = len(prev_proto.dependencies) - prev_c_dependencies = (ctypes.c_char_p * prev_length)(*[d.schema.encode() for d in prev_proto.dependencies]) - prev_c_dependency_names = (ctypes.c_char_p * prev_length)(*[d.name.encode() for d in prev_proto.dependencies]) + prev_length = len(prev_proto.all_dependencies) + prev_c_dependencies = (ctypes.c_char_p * prev_length)(*[d.schema.encode() for d in prev_proto.all_dependencies]) + prev_c_dependency_names = (ctypes.c_char_p * prev_length)(*[d.name.encode() for d in prev_proto.all_dependencies]) err = lib.CheckCompatibility( proto.name.encode(), diff --git a/karapace/protobuf/schema.py b/karapace/protobuf/schema.py index 9c407bdcd..e15d070fb 100644 --- a/karapace/protobuf/schema.py +++ b/karapace/protobuf/schema.py @@ -21,6 +21,7 @@ from karapace.protobuf.option_element import OptionElement from karapace.protobuf.proto_file_element import ProtoFileElement from karapace.protobuf.proto_parser import ProtoParser +from karapace.protobuf.protopace import Proto from karapace.protobuf.serialization import deserialize, serialize from karapace.protobuf.type_element import TypeElement from karapace.protobuf.utils import append_documentation, append_indented @@ -267,10 +268,17 @@ def __init__( self.proto_file_element = deserialize(schema) except binascii.Error: # If not base64 formatted self.proto_file_element = ProtoParser.parse(DEFAULT_LOCATION, schema) - + self._schema_str = schema self.references = references self.dependencies = dependencies + def to_proto(self, name="noname.proto") -> Proto: + dependencies = [] + if self.dependencies: + for _, dep in self.dependencies.items(): + dependencies.append(dep.get_schema().to_proto(name=dep.name)) + return Proto(name, self._schema_str, dependencies) + def type_in_tree(self, tree: TypeTree, remaining_tokens: list[str]) -> TypeTree | None: if remaining_tokens: to_seek = remaining_tokens.pop() diff --git a/karapace/schema_models.py b/karapace/schema_models.py index d21917025..9f092ec5b 100644 --- a/karapace/schema_models.py +++ b/karapace/schema_models.py @@ -20,12 +20,13 @@ SchemaParseException as ProtobufSchemaParseException, ) from karapace.protobuf.proto_normalizations import NormalizedProtobufSchema +from karapace.protobuf.protopace import format_proto, Proto from karapace.protobuf.schema import ProtobufSchema from karapace.schema_references import Reference from karapace.schema_type import SchemaType from karapace.typing import JsonObject, SchemaId, Subject, Version, VersionTag from karapace.utils import assert_never, json_decode, json_encode, JSONDecodeError -from typing import Any, cast, Dict, Final, final, Mapping, Sequence +from typing import Any, cast, Dict, Final, Mapping, Sequence import hashlib import logging @@ -93,6 +94,7 @@ def __init__( schema: Draft7Validator | AvroSchema | ProtobufSchema | None = None, references: Sequence[Reference] | None = None, dependencies: Mapping[str, Dependency] | None = None, + use_protopace: bool = False, ) -> None: """Schema with type information @@ -105,9 +107,12 @@ def __init__( self.schema_type: Final = schema_type self.references: Final = references self.dependencies: Final = dependencies - self.schema_str: Final = TypedSchema.normalize_schema_str(schema_str, schema_type, schema) + self.schema_str: Final = schema_str self.max_id: SchemaId | None = None self._fingerprint_cached: str | None = None + self.use_protopace = use_protopace + self._schema = schema + self.normalize_schema_str() def to_dict(self) -> JsonObject: if self.schema_type is SchemaType.PROTOBUF: @@ -123,34 +128,37 @@ def fingerprint(self) -> str: self._fingerprint_cached = hashlib.sha1(fingerprint_str.encode("utf8")).hexdigest() return self._fingerprint_cached - # This is marked @final because __init__ references this statically, hence - # allowing overriding this in a subclass could lead to confusing bugs. - @staticmethod - @final - def normalize_schema_str( - schema_str: str, - schema_type: SchemaType, - schema: Draft7Validator | AvroSchema | ProtobufSchema | None = None, - ) -> str: - if schema_type is SchemaType.AVRO or schema_type is SchemaType.JSONSCHEMA: + def to_proto(self, name="noname.proto") -> Proto: + if self.schema_type is not SchemaType.PROTOBUF: + raise InvalidSchema("Only supported for Protobuf") + + dependencies = [] + if self.dependencies: + for _, dep in self.dependencies.items(): + dependencies.append(dep.get_schema().to_proto(name=dep.name)) + return Proto(name, self.schema_str, dependencies) + + def normalize_schema_str(self) -> None: + if self.use_protopace and self.schema_type is SchemaType.PROTOBUF: + self.schema_str = format_proto(self.to_proto()) + if self.schema_type is SchemaType.AVRO or self.schema_type is SchemaType.JSONSCHEMA: try: - schema_str = json_encode(json_decode(schema_str), compact=True, sort_keys=True) + self.schema_str = json_encode(json_decode(self.schema_str), compact=True, sort_keys=True) except JSONDecodeError as e: LOG.info("Schema is not valid JSON") raise e - elif schema_type == SchemaType.PROTOBUF: - if schema: - schema_str = str(schema) + elif self.schema_type == SchemaType.PROTOBUF: + if self._schema: + self.schema_str = str(self._schema) else: try: - schema_str = str(parse_protobuf_schema_definition(schema_str, None, None, False)) + self.schema_strschema_str = str(parse_protobuf_schema_definition(self.schema_str, None, None, False)) except InvalidSchema as e: LOG.info("Schema is not valid ProtoBuf definition") raise e else: - assert_never(schema_type) - return schema_str + assert_never(self.schema_type) def __str__(self) -> str: return self.schema_str @@ -188,6 +196,7 @@ def parse( references: Sequence[Reference] | None = None, dependencies: Mapping[str, Dependency] | None = None, normalize: bool = False, + use_protopace: bool = False, ) -> ParsedTypedSchema: if schema_type not in [SchemaType.AVRO, SchemaType.JSONSCHEMA, SchemaType.PROTOBUF]: raise InvalidSchema(f"Unknown parser {schema_type} for {schema_str}") @@ -235,6 +244,7 @@ def parse( schema=parsed_schema, references=references, dependencies=dependencies, + use_protopace=use_protopace, ) @@ -264,6 +274,7 @@ def __init__( schema: Draft7Validator | AvroSchema | ProtobufSchema, references: Sequence[Reference] | None = None, dependencies: Mapping[str, Dependency] | None = None, + use_protopace: bool = False, ) -> None: self._schema_cached: Draft7Validator | AvroSchema | ProtobufSchema | None = schema @@ -273,6 +284,7 @@ def __init__( references=references, dependencies=dependencies, schema=schema, + use_protopace=use_protopace, ) @staticmethod @@ -282,6 +294,7 @@ def parse( references: Sequence[Reference] | None = None, dependencies: Mapping[str, Dependency] | None = None, normalize: bool = False, + use_protopace: bool = False, ) -> ParsedTypedSchema: return parse( schema_type=schema_type, @@ -291,6 +304,7 @@ def parse( references=references, dependencies=dependencies, normalize=normalize, + use_protopace=use_protopace, ) def __str__(self) -> str: @@ -350,6 +364,7 @@ def __init__( schema: Draft7Validator | AvroSchema | ProtobufSchema, references: list[Reference] | None = None, dependencies: dict[str, Dependency] | None = None, + use_protopace: bool = False, ) -> None: super().__init__( schema_type=schema_type, @@ -357,6 +372,7 @@ def __init__( references=references, dependencies=dependencies, schema=schema, + use_protopace=use_protopace, ) @staticmethod @@ -366,6 +382,7 @@ def parse( references: Sequence[Reference] | None = None, dependencies: Mapping[str, Dependency] | None = None, normalize: bool = False, + use_protopace: bool = False, ) -> ValidatedTypedSchema: parsed_schema = parse( schema_type=schema_type, @@ -375,6 +392,7 @@ def parse( references=references, dependencies=dependencies, normalize=normalize, + use_protopace=use_protopace, ) return cast(ValidatedTypedSchema, parsed_schema) diff --git a/karapace/schema_reader.py b/karapace/schema_reader.py index 493019233..21c310247 100644 --- a/karapace/schema_reader.py +++ b/karapace/schema_reader.py @@ -133,6 +133,7 @@ def __init__( self.timeout_s = MESSAGE_CONSUME_TIMEOUT_SECONDS self.max_messages_to_process = MAX_MESSAGES_TO_CONSUME_ON_STARTUP self.config = config + self.use_protopace = config["use_protopace"] self.database = database self.admin_client: KafkaAdminClient | None = None @@ -544,6 +545,7 @@ def _handle_msg_schema(self, key: dict, value: dict | None) -> None: normalize=False, ) schema_str = str(parsed_schema) + except InvalidSchema: LOG.exception("Schema is not valid ProtoBuf definition") return @@ -558,6 +560,7 @@ def _handle_msg_schema(self, key: dict, value: dict | None) -> None: references=resolved_references, dependencies=resolved_dependencies, schema=parsed_schema, + use_protopace=self.use_protopace, ) except (InvalidSchema, JSONDecodeError): return diff --git a/karapace/schema_registry_apis.py b/karapace/schema_registry_apis.py index 575bb7ad6..7ebcdeb58 100644 --- a/karapace/schema_registry_apis.py +++ b/karapace/schema_registry_apis.py @@ -452,7 +452,7 @@ async def compatibility_check( use_protopace=self.config["use_protopace"], ) if is_incompatible(result): - self.log.info(f'incompatible: {result.messages}') + self.log.info("incompatible: %s", result.messages) self.r({"is_compatible": False}, content_type) self.r({"is_compatible": True}, content_type) @@ -1123,6 +1123,7 @@ async def subjects_schema_post( references=references, dependencies=new_schema_dependencies, normalize=normalize, + use_protopace=self.config["use_protopace"], ) except InvalidSchema: self.log.warning("Invalid schema: %r", schema_str) @@ -1155,6 +1156,7 @@ async def subjects_schema_post( references=other_references, dependencies=other_dependencies, normalize=normalize, + use_protopace=self.config["use_protopace"], ) except InvalidSchema as e: failed_schema_id = schema_version.schema_id @@ -1224,6 +1226,7 @@ async def subject_post( references=references, dependencies=resolved_dependencies, normalize=normalize, + use_protopace=self.config["use_protopace"], ) except (InvalidReferences, InvalidSchema, InvalidSchemaType) as e: self.log.warning("Invalid schema: %r", body["schema"], exc_info=True) diff --git a/tests/integration/test_schema_protobuf.py b/tests/integration/test_schema_protobuf.py index 10df70637..febbea601 100644 --- a/tests/integration/test_schema_protobuf.py +++ b/tests/integration/test_schema_protobuf.py @@ -126,7 +126,8 @@ async def test_protobuf_schema_normalization(registry_async_client: Client, trai |message TestMessage { | message Value { | string str2 = 1; - | Enu x = 2; + | int32 x = 2; + | Enu enu = 3; | } | string test = 1; | .a1.TestMessage.Value val = 2; @@ -236,7 +237,11 @@ async def test_protobuf_schema_references(registry_async_client: Client) -> None |syntax = "proto3"; |package a1; |import "Customer.proto"; + |import "google/protobuf/descriptor.proto"; |message TestMessage { + | extend google.protobuf.OneofOptions { + | bool my_option = 50002; + | } | enum Enum { | HIGH = 0; | MIDDLE = 1; @@ -404,7 +409,11 @@ async def test_protobuf_schema_verifier(registry_async_client: Client) -> None: |syntax = "proto3"; |package a1; |import "Customer.proto"; + |import "google/protobuf/descriptor.proto"; |message TestMessage { + | extend google.protobuf.OneofOptions { + | bool my_option = 50002; + | } | enum Enum { | HIGH = 0; | MIDDLE = 1;