From 4ec155d70d810ee4cb0d6a825fdae4eb1515ff40 Mon Sep 17 00:00:00 2001 From: Filipp Date: Tue, 28 Mar 2023 11:00:26 +0300 Subject: [PATCH 1/5] WIP fixing relative links check the FIXMEs --- src/generator/lib/util.py | 28 +++++++++++++++++++++ src/generator/templates/api/lib/rbuild.mako | 6 ++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/generator/lib/util.py b/src/generator/lib/util.py index 0ddc7616b1..bcc5b193d7 100644 --- a/src/generator/lib/util.py +++ b/src/generator/lib/util.py @@ -1,6 +1,7 @@ import os import re import subprocess +import urllib import inflect from dataclasses import dataclass @@ -1173,6 +1174,33 @@ def string_impl(p): "string": lambda x: x }.get(p.get("format", p["type"]), lambda x: f"{x}.to_string()") +MD_LINKS_CAPTURE = re.compile(r''' + \[ # Opening bracket for the "name" part of the url + ([^]]+?) # Some amount of non-closing bracket `]` symbols, + # Captured in a group + \] # Close the name part + \s* # maybe a whitespace + \( # Opening a paren for the url part + ([^)]+?) # Url, captured in a group + \) # closing paren +''', re.VERBOSE) + +# FIXME: combine with links handling in .docs +def fix_relative_links(url_base): + url_parsed = urllib.parse.urlparse(url_base) + url_base = f"{url_parsed.scheme}://{url_parsed.netloc}" + def replace_url(url_match: re.match): + original_url = url_match.group(0) + name = url_match.group(1) + url = url_match.group(2) + if url.startswith('/'): + return f"[{name}]({url_base}{url})" + return original_url + + def fixer(docs): + # FIXME: replace with proper markdown parser and documentationLink value + return MD_LINKS_CAPTURE.sub(replace_url, docs) + return fixer if __name__ == '__main__': raise AssertionError('For import only') diff --git a/src/generator/templates/api/lib/rbuild.mako b/src/generator/templates/api/lib/rbuild.mako index 696f3e6b66..037a08beab 100644 --- a/src/generator/templates/api/lib/rbuild.mako +++ b/src/generator/templates/api/lib/rbuild.mako @@ -6,7 +6,7 @@ rust_copy_value_s, organize_params, REQUEST_VALUE_PROPERTY_NAME, build_all_params, rb_type_params_s, hub_type_params_s, mb_type_params_s, mb_additional_type_params, struct_type_bounds_s, METHODS_RESOURCE, SPACES_PER_TAB, prefix_all_but_first_with, - METHODS_BUILDER_MARKER_TRAIT, remove_empty_lines, method_default_scope, rust_doc_sanitize) + METHODS_BUILDER_MARKER_TRAIT, remove_empty_lines, method_default_scope, rust_doc_sanitize, fix_relative_links) %>\ <%namespace name="util" file="../../../lib/util.mako"/>\ <%namespace name="lib" file="lib.mako"/>\ @@ -80,7 +80,7 @@ impl${rb_params} ${ThisType} { % if 'description' in m: /// Create a builder to help you perform the following task: /// - ${m.description | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)} + ${m.description | fix_relative_links(documentationLink), rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)} % endif % if required_props: /// @@ -91,7 +91,7 @@ impl${rb_params} ${ThisType} { arg_prefix = "/// * `" + p.name + "` - " %>\ ${arg_prefix}${p.get('description', "No description provided.") - | remove_empty_lines, prefix_all_but_first_with(' ' * SPACES_PER_TAB + '///' + ' ' * (len(arg_prefix) - len('///')))} + | fix_relative_links(documentationLink), remove_empty_lines, prefix_all_but_first_with(' ' * SPACES_PER_TAB + '///' + ' ' * (len(arg_prefix) - len('///')))} % endfor % endif pub fn ${mangle_ident(a)}${type_params}(&self${method_args}) -> ${RType}${mb_tparams} { From 8461619b540596665f9fd0e3620bbbed682fc861 Mon Sep 17 00:00:00 2001 From: Filipp Date: Tue, 28 Mar 2023 16:29:53 +0300 Subject: [PATCH 2/5] `make clean-all-api gen-all-api` --- gen/acceleratedmobilepageurl1/src/api.rs | 2 +- gen/adsense2/src/api.rs | 2 +- gen/androiddeviceprovisioning1/src/api.rs | 6 +++--- gen/cloudresourcemanager1/src/api.rs | 2 +- gen/cloudresourcemanager1_beta1/src/api.rs | 4 ++-- gen/compute1/src/api.rs | 4 ++-- gen/datacatalog1/src/api.rs | 2 +- gen/displayvideo1/src/api.rs | 2 +- gen/domains1/src/api.rs | 2 +- gen/domains1_beta1/src/api.rs | 2 +- gen/people1/src/api.rs | 6 +++--- gen/realtimebidding1/src/api.rs | 4 ++-- gen/runtimeconfig1_beta1/src/api.rs | 4 ++-- gen/searchconsole1/src/api.rs | 2 +- gen/sheets4/src/api.rs | 12 ++++++------ gen/speech1_beta1/src/api.rs | 3 +-- gen/sqladmin1_beta4/src/api.rs | 2 +- 17 files changed, 30 insertions(+), 31 deletions(-) diff --git a/gen/acceleratedmobilepageurl1/src/api.rs b/gen/acceleratedmobilepageurl1/src/api.rs index 28ce49335a..28f60fed7c 100644 --- a/gen/acceleratedmobilepageurl1/src/api.rs +++ b/gen/acceleratedmobilepageurl1/src/api.rs @@ -289,7 +289,7 @@ impl<'a, S> AmpUrlMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Returns AMP URL(s) and equivalent [AMP Cache URL(s)](/amp/cache/overview#amp-cache-url-format). + /// Returns AMP URL(s) and equivalent [AMP Cache URL(s)](https://developers.google.com/amp/cache/overview#amp-cache-url-format). /// /// # Arguments /// diff --git a/gen/adsense2/src/api.rs b/gen/adsense2/src/api.rs index ea9d9d7337..0d801fb263 100644 --- a/gen/adsense2/src/api.rs +++ b/gen/adsense2/src/api.rs @@ -1092,7 +1092,7 @@ impl<'a, S> AccountMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Creates an ad unit. This method can only be used by projects enabled for the [AdSense for Platforms](https://developers.google.com/adsense/platforms/) product. Note that ad units can only be created for ad clients with an "AFC" product code. For more info see the [AdClient resource](/adsense/management/reference/rest/v2/accounts.adclients). For now, this method can only be used to create `DISPLAY` ad units. See: https://support.google.com/adsense/answer/9183566 + /// Creates an ad unit. This method can only be used by projects enabled for the [AdSense for Platforms](https://developers.google.com/adsense/platforms/) product. Note that ad units can only be created for ad clients with an "AFC" product code. For more info see the [AdClient resource](https://developers.google.com/adsense/management/reference/rest/v2/accounts.adclients). For now, this method can only be used to create `DISPLAY` ad units. See: https://support.google.com/adsense/answer/9183566 /// /// # Arguments /// diff --git a/gen/androiddeviceprovisioning1/src/api.rs b/gen/androiddeviceprovisioning1/src/api.rs index 42a227128a..79ba1005eb 100644 --- a/gen/androiddeviceprovisioning1/src/api.rs +++ b/gen/androiddeviceprovisioning1/src/api.rs @@ -1604,7 +1604,7 @@ impl<'a, S> PartnerMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Claims a batch of devices for a customer asynchronously. Adds the devices to zero-touch enrollment. To learn more, read [Long‑running batch operations](/zero-touch/guides/how-it-works#operations). + /// Claims a batch of devices for a customer asynchronously. Adds the devices to zero-touch enrollment. To learn more, read [Long‑running batch operations](https://developers.google.com/zero-touch/guides/how-it-works#operations). /// /// # Arguments /// @@ -1712,7 +1712,7 @@ impl<'a, S> PartnerMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Unclaims a batch of devices for a customer asynchronously. Removes the devices from zero-touch enrollment. To learn more, read [Long‑running batch operations](/zero-touch/guides/how-it-works#operations). + /// Unclaims a batch of devices for a customer asynchronously. Removes the devices from zero-touch enrollment. To learn more, read [Long‑running batch operations](https://developers.google.com/zero-touch/guides/how-it-works#operations). /// /// # Arguments /// @@ -1730,7 +1730,7 @@ impl<'a, S> PartnerMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Updates the reseller metadata attached to a batch of devices. This method updates devices asynchronously and returns an `Operation` that can be used to track progress. Read [Long‑running batch operations](/zero-touch/guides/how-it-works#operations). Android Devices only. + /// Updates the reseller metadata attached to a batch of devices. This method updates devices asynchronously and returns an `Operation` that can be used to track progress. Read [Long‑running batch operations](https://developers.google.com/zero-touch/guides/how-it-works#operations). Android Devices only. /// /// # Arguments /// diff --git a/gen/cloudresourcemanager1/src/api.rs b/gen/cloudresourcemanager1/src/api.rs index 76f497fb2d..bcd382db48 100644 --- a/gen/cloudresourcemanager1/src/api.rs +++ b/gen/cloudresourcemanager1/src/api.rs @@ -1830,7 +1830,7 @@ impl<'a, S> ProjectMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Request that a new Project be created. The result is an Operation which can be used to track the creation process. This process usually takes a few seconds, but can sometimes take much longer. The tracking Operation is automatically deleted after a few hours, so there is no need to call DeleteOperation. Authorization requires the Google IAM permission `resourcemanager.projects.create` on the specified parent for the new project. The parent is identified by a specified ResourceId, which must include both an ID and a type, such as organization. This method does not associate the new project with a billing account. You can set or update the billing account associated with a project using the [`projects.updateBillingInfo`] (/billing/reference/rest/v1/projects/updateBillingInfo) method. + /// Request that a new Project be created. The result is an Operation which can be used to track the creation process. This process usually takes a few seconds, but can sometimes take much longer. The tracking Operation is automatically deleted after a few hours, so there is no need to call DeleteOperation. Authorization requires the Google IAM permission `resourcemanager.projects.create` on the specified parent for the new project. The parent is identified by a specified ResourceId, which must include both an ID and a type, such as organization. This method does not associate the new project with a billing account. You can set or update the billing account associated with a project using the [`projects.updateBillingInfo`](https://cloud.google.com/billing/reference/rest/v1/projects/updateBillingInfo) method. /// /// # Arguments /// diff --git a/gen/cloudresourcemanager1_beta1/src/api.rs b/gen/cloudresourcemanager1_beta1/src/api.rs index a6a00dd258..7dfefdfb14 100644 --- a/gen/cloudresourcemanager1_beta1/src/api.rs +++ b/gen/cloudresourcemanager1_beta1/src/api.rs @@ -853,7 +853,7 @@ impl<'a, S> ProjectMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Creates a Project resource. Initially, the Project resource is owned by its creator exclusively. The creator can later grant permission to others to read or update the Project. Several APIs are activated automatically for the Project, including Google Cloud Storage. The parent is identified by a specified ResourceId, which must include both an ID and a type, such as project, folder, or organization. This method does not associate the new project with a billing account. You can set or update the billing account associated with a project using the [`projects.updateBillingInfo`] (/billing/reference/rest/v1/projects/updateBillingInfo) method. + /// Creates a Project resource. Initially, the Project resource is owned by its creator exclusively. The creator can later grant permission to others to read or update the Project. Several APIs are activated automatically for the Project, including Google Cloud Storage. The parent is identified by a specified ResourceId, which must include both an ID and a type, such as project, folder, or organization. This method does not associate the new project with a billing account. You can set or update the billing account associated with a project using the [`projects.updateBillingInfo`](https://cloud.google.com/billing/reference/rest/v1/projects/updateBillingInfo) method. /// /// # Arguments /// @@ -924,7 +924,7 @@ impl<'a, S> ProjectMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Returns the IAM access control policy for the specified Project. Permission is denied if the policy or the resource does not exist. For additional information about resource structure and identification, see [Resource Names](/apis/design/resource_names). + /// Returns the IAM access control policy for the specified Project. Permission is denied if the policy or the resource does not exist. For additional information about resource structure and identification, see [Resource Names](https://cloud.google.com/apis/design/resource_names). /// /// # Arguments /// diff --git a/gen/compute1/src/api.rs b/gen/compute1/src/api.rs index 8db9076cd0..e8e903068f 100644 --- a/gen/compute1/src/api.rs +++ b/gen/compute1/src/api.rs @@ -38336,7 +38336,7 @@ impl<'a, S> ProjectMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Moves an instance and its attached persistent disks from one zone to another. *Note*: Moving VMs or disks by using this method might cause unexpected behavior. For more information, see the [known issue](/compute/docs/troubleshooting/known-issues#moving_vms_or_disks_using_the_moveinstance_api_or_the_causes_unexpected_behavior). + /// Moves an instance and its attached persistent disks from one zone to another. *Note*: Moving VMs or disks by using this method might cause unexpected behavior. For more information, see the [known issue](https://cloud.google.com/compute/docs/troubleshooting/known-issues#moving_vms_or_disks_using_the_moveinstance_api_or_the_causes_unexpected_behavior). /// /// # Arguments /// @@ -46862,7 +46862,7 @@ impl<'a, S> UrlMapMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Initiates a cache invalidation operation, invalidating the specified path, scoped to the specified UrlMap. For more information, see [Invalidating cached content](/cdn/docs/invalidating-cached-content). + /// Initiates a cache invalidation operation, invalidating the specified path, scoped to the specified UrlMap. For more information, see [Invalidating cached content](https://cloud.google.com/cdn/docs/invalidating-cached-content). /// /// # Arguments /// diff --git a/gen/datacatalog1/src/api.rs b/gen/datacatalog1/src/api.rs index ddf254b09e..7dcf5c96ce 100644 --- a/gen/datacatalog1/src/api.rs +++ b/gen/datacatalog1/src/api.rs @@ -2992,7 +2992,7 @@ impl<'a, S> ProjectMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Creates an entry group. An entry group contains logically related entries together with [Cloud Identity and Access Management](/data-catalog/docs/concepts/iam) policies. These policies specify users who can create, edit, and view entries within entry groups. Data Catalog automatically creates entry groups with names that start with the `@` symbol for the following resources: * BigQuery entries (`@bigquery`) * Pub/Sub topics (`@pubsub`) * Dataproc Metastore services (`@dataproc_metastore_{SERVICE_NAME_HASH}`) You can create your own entry groups for Cloud Storage fileset entries and custom entries together with the corresponding IAM policies. User-created entry groups can't contain the `@` symbol, it is reserved for automatically created groups. Entry groups, like entries, can be searched. A maximum of 10,000 entry groups may be created per organization across all locations. You must enable the Data Catalog API in the project identified by the `parent` parameter. For more information, see [Data Catalog resource project](https://cloud.google.com/data-catalog/docs/concepts/resource-project). + /// Creates an entry group. An entry group contains logically related entries together with [Cloud Identity and Access Management](https://cloud.google.com/data-catalog/docs/concepts/iam) policies. These policies specify users who can create, edit, and view entries within entry groups. Data Catalog automatically creates entry groups with names that start with the `@` symbol for the following resources: * BigQuery entries (`@bigquery`) * Pub/Sub topics (`@pubsub`) * Dataproc Metastore services (`@dataproc_metastore_{SERVICE_NAME_HASH}`) You can create your own entry groups for Cloud Storage fileset entries and custom entries together with the corresponding IAM policies. User-created entry groups can't contain the `@` symbol, it is reserved for automatically created groups. Entry groups, like entries, can be searched. A maximum of 10,000 entry groups may be created per organization across all locations. You must enable the Data Catalog API in the project identified by the `parent` parameter. For more information, see [Data Catalog resource project](https://cloud.google.com/data-catalog/docs/concepts/resource-project). /// /// # Arguments /// diff --git a/gen/displayvideo1/src/api.rs b/gen/displayvideo1/src/api.rs index c412fe7021..31831ac2cf 100644 --- a/gen/displayvideo1/src/api.rs +++ b/gen/displayvideo1/src/api.rs @@ -8157,7 +8157,7 @@ impl<'a, S> AdvertiserMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Uploads an asset. Returns the ID of the newly uploaded asset if successful. The asset file size should be no more than 10 MB for images, 200 MB for ZIP files, and 1 GB for videos. Must be used within the [multipart media upload process](/display-video/api/guides/how-tos/upload#multipart). Examples using provided client libraries can be found in our [Creating Creatives guide](/display-video/api/guides/creating-creatives/overview#upload_an_asset). + /// Uploads an asset. Returns the ID of the newly uploaded asset if successful. The asset file size should be no more than 10 MB for images, 200 MB for ZIP files, and 1 GB for videos. Must be used within the [multipart media upload process](https://developers.google.com/display-video/api/guides/how-tos/upload#multipart). Examples using provided client libraries can be found in our [Creating Creatives guide](https://developers.google.com/display-video/api/guides/creating-creatives/overview#upload_an_asset). /// /// # Arguments /// diff --git a/gen/domains1/src/api.rs b/gen/domains1/src/api.rs index 3fef7c9376..aaf50a25bb 100644 --- a/gen/domains1/src/api.rs +++ b/gen/domains1/src/api.rs @@ -1407,7 +1407,7 @@ impl<'a, S> ProjectMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Deletes a `Registration` resource. This method works on any `Registration` resource using [Subscription or Commitment billing](/domains/pricing#billing-models), provided that the resource was created at least 1 day in the past. For `Registration` resources using [Monthly billing](/domains/pricing#billing-models), this method works if: * `state` is `EXPORTED` with `expire_time` in the past * `state` is `REGISTRATION_FAILED` * `state` is `TRANSFER_FAILED` When an active registration is successfully deleted, you can continue to use the domain in [Google Domains](https://domains.google/) until it expires. The calling user becomes the domain's sole owner in Google Domains, and permissions for the domain are subsequently managed there. The domain does not renew automatically unless the new owner sets up billing in Google Domains. + /// Deletes a `Registration` resource. This method works on any `Registration` resource using [Subscription or Commitment billing](https://cloud.google.com/domains/pricing#billing-models), provided that the resource was created at least 1 day in the past. For `Registration` resources using [Monthly billing](https://cloud.google.com/domains/pricing#billing-models), this method works if: * `state` is `EXPORTED` with `expire_time` in the past * `state` is `REGISTRATION_FAILED` * `state` is `TRANSFER_FAILED` When an active registration is successfully deleted, you can continue to use the domain in [Google Domains](https://domains.google/) until it expires. The calling user becomes the domain's sole owner in Google Domains, and permissions for the domain are subsequently managed there. The domain does not renew automatically unless the new owner sets up billing in Google Domains. /// /// # Arguments /// diff --git a/gen/domains1_beta1/src/api.rs b/gen/domains1_beta1/src/api.rs index 5960b0a7e0..9084ca6336 100644 --- a/gen/domains1_beta1/src/api.rs +++ b/gen/domains1_beta1/src/api.rs @@ -1407,7 +1407,7 @@ impl<'a, S> ProjectMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Deletes a `Registration` resource. This method works on any `Registration` resource using [Subscription or Commitment billing](/domains/pricing#billing-models), provided that the resource was created at least 1 day in the past. For `Registration` resources using [Monthly billing](/domains/pricing#billing-models), this method works if: * `state` is `EXPORTED` with `expire_time` in the past * `state` is `REGISTRATION_FAILED` * `state` is `TRANSFER_FAILED` When an active registration is successfully deleted, you can continue to use the domain in [Google Domains](https://domains.google/) until it expires. The calling user becomes the domain's sole owner in Google Domains, and permissions for the domain are subsequently managed there. The domain does not renew automatically unless the new owner sets up billing in Google Domains. + /// Deletes a `Registration` resource. This method works on any `Registration` resource using [Subscription or Commitment billing](https://cloud.google.com/domains/pricing#billing-models), provided that the resource was created at least 1 day in the past. For `Registration` resources using [Monthly billing](https://cloud.google.com/domains/pricing#billing-models), this method works if: * `state` is `EXPORTED` with `expire_time` in the past * `state` is `REGISTRATION_FAILED` * `state` is `TRANSFER_FAILED` When an active registration is successfully deleted, you can continue to use the domain in [Google Domains](https://domains.google/) until it expires. The calling user becomes the domain's sole owner in Google Domains, and permissions for the domain are subsequently managed there. The domain does not renew automatically unless the new owner sets up billing in Google Domains. /// /// # Arguments /// diff --git a/gen/people1/src/api.rs b/gen/people1/src/api.rs index fcdd54f657..2575c175f5 100644 --- a/gen/people1/src/api.rs +++ b/gen/people1/src/api.rs @@ -2426,7 +2426,7 @@ impl<'a, S> OtherContactMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// List all "Other contacts", that is contacts that are not in a contact group. "Other contacts" are typically auto created contacts from interactions. Sync tokens expire 7 days after the full sync. A request with an expired sync token will get an error with an [google.rpc.ErrorInfo](https://cloud.google.com/apis/design/errors#error_info) with reason "EXPIRED_SYNC_TOKEN". In the case of such an error clients should make a full sync request without a `sync_token`. The first page of a full sync request has an additional quota. If the quota is exceeded, a 429 error will be returned. This quota is fixed and can not be increased. When the `sync_token` is specified, resources deleted since the last sync will be returned as a person with `PersonMetadata.deleted` set to true. When the `page_token` or `sync_token` is specified, all other request parameters must match the first call. Writes may have a propagation delay of several minutes for sync requests. Incremental syncs are not intended for read-after-write use cases. See example usage at [List the user's other contacts that have changed](/people/v1/other-contacts#list_the_users_other_contacts_that_have_changed). + /// List all "Other contacts", that is contacts that are not in a contact group. "Other contacts" are typically auto created contacts from interactions. Sync tokens expire 7 days after the full sync. A request with an expired sync token will get an error with an [google.rpc.ErrorInfo](https://cloud.google.com/apis/design/errors#error_info) with reason "EXPIRED_SYNC_TOKEN". In the case of such an error clients should make a full sync request without a `sync_token`. The first page of a full sync request has an additional quota. If the quota is exceeded, a 429 error will be returned. This quota is fixed and can not be increased. When the `sync_token` is specified, resources deleted since the last sync will be returned as a person with `PersonMetadata.deleted` set to true. When the `page_token` or `sync_token` is specified, all other request parameters must match the first call. Writes may have a propagation delay of several minutes for sync requests. Incremental syncs are not intended for read-after-write use cases. See example usage at [List the user's other contacts that have changed](https://developers.google.com/people/v1/other-contacts#list_the_users_other_contacts_that_have_changed). pub fn list(&self) -> OtherContactListCall<'a, S> { OtherContactListCall { hub: self.hub, @@ -2500,7 +2500,7 @@ impl<'a, S> PersonMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Provides a list of the authenticated user's contacts. Sync tokens expire 7 days after the full sync. A request with an expired sync token will get an error with an [google.rpc.ErrorInfo](https://cloud.google.com/apis/design/errors#error_info) with reason "EXPIRED_SYNC_TOKEN". In the case of such an error clients should make a full sync request without a `sync_token`. The first page of a full sync request has an additional quota. If the quota is exceeded, a 429 error will be returned. This quota is fixed and can not be increased. When the `sync_token` is specified, resources deleted since the last sync will be returned as a person with `PersonMetadata.deleted` set to true. When the `page_token` or `sync_token` is specified, all other request parameters must match the first call. Writes may have a propagation delay of several minutes for sync requests. Incremental syncs are not intended for read-after-write use cases. See example usage at [List the user's contacts that have changed](/people/v1/contacts#list_the_users_contacts_that_have_changed). + /// Provides a list of the authenticated user's contacts. Sync tokens expire 7 days after the full sync. A request with an expired sync token will get an error with an [google.rpc.ErrorInfo](https://cloud.google.com/apis/design/errors#error_info) with reason "EXPIRED_SYNC_TOKEN". In the case of such an error clients should make a full sync request without a `sync_token`. The first page of a full sync request has an additional quota. If the quota is exceeded, a 429 error will be returned. This quota is fixed and can not be increased. When the `sync_token` is specified, resources deleted since the last sync will be returned as a person with `PersonMetadata.deleted` set to true. When the `page_token` or `sync_token` is specified, all other request parameters must match the first call. Writes may have a propagation delay of several minutes for sync requests. Incremental syncs are not intended for read-after-write use cases. See example usage at [List the user's contacts that have changed](https://developers.google.com/people/v1/contacts#list_the_users_contacts_that_have_changed). /// /// # Arguments /// @@ -2667,7 +2667,7 @@ impl<'a, S> PersonMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Provides a list of domain profiles and domain contacts in the authenticated user's domain directory. When the `sync_token` is specified, resources deleted since the last sync will be returned as a person with `PersonMetadata.deleted` set to true. When the `page_token` or `sync_token` is specified, all other request parameters must match the first call. Writes may have a propagation delay of several minutes for sync requests. Incremental syncs are not intended for read-after-write use cases. See example usage at [List the directory people that have changed](/people/v1/directory#list_the_directory_people_that_have_changed). + /// Provides a list of domain profiles and domain contacts in the authenticated user's domain directory. When the `sync_token` is specified, resources deleted since the last sync will be returned as a person with `PersonMetadata.deleted` set to true. When the `page_token` or `sync_token` is specified, all other request parameters must match the first call. Writes may have a propagation delay of several minutes for sync requests. Incremental syncs are not intended for read-after-write use cases. See example usage at [List the directory people that have changed](https://developers.google.com/people/v1/directory#list_the_directory_people_that_have_changed). pub fn list_directory_people(&self) -> PersonListDirectoryPersonCall<'a, S> { PersonListDirectoryPersonCall { hub: self.hub, diff --git a/gen/realtimebidding1/src/api.rs b/gen/realtimebidding1/src/api.rs index 2114ef59bd..e4617d232d 100644 --- a/gen/realtimebidding1/src/api.rs +++ b/gen/realtimebidding1/src/api.rs @@ -1914,7 +1914,7 @@ impl<'a, S> BidderMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Lists creatives as they are at the time of the initial request. This call may take multiple hours to complete. For large, paginated requests, this method returns a snapshot of creatives at the time of request for the first page. `lastStatusUpdate` and `creativeServingDecision` may be outdated for creatives on sequential pages. We recommend [Google Cloud Pub/Sub](//cloud.google.com/pubsub/docs/overview) to view the latest status. + /// Lists creatives as they are at the time of the initial request. This call may take multiple hours to complete. For large, paginated requests, this method returns a snapshot of creatives at the time of request for the first page. `lastStatusUpdate` and `creativeServingDecision` may be outdated for creatives on sequential pages. We recommend [Google Cloud Pub/Sub](https://developers.google.com//cloud.google.com/pubsub/docs/overview) to view the latest status. /// /// # Arguments /// @@ -2439,7 +2439,7 @@ impl<'a, S> BuyerMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Lists creatives as they are at the time of the initial request. This call may take multiple hours to complete. For large, paginated requests, this method returns a snapshot of creatives at the time of request for the first page. `lastStatusUpdate` and `creativeServingDecision` may be outdated for creatives on sequential pages. We recommend [Google Cloud Pub/Sub](//cloud.google.com/pubsub/docs/overview) to view the latest status. + /// Lists creatives as they are at the time of the initial request. This call may take multiple hours to complete. For large, paginated requests, this method returns a snapshot of creatives at the time of request for the first page. `lastStatusUpdate` and `creativeServingDecision` may be outdated for creatives on sequential pages. We recommend [Google Cloud Pub/Sub](https://developers.google.com//cloud.google.com/pubsub/docs/overview) to view the latest status. /// /// # Arguments /// diff --git a/gen/runtimeconfig1_beta1/src/api.rs b/gen/runtimeconfig1_beta1/src/api.rs index d2cbec4eb4..85be38b2f2 100644 --- a/gen/runtimeconfig1_beta1/src/api.rs +++ b/gen/runtimeconfig1_beta1/src/api.rs @@ -693,7 +693,7 @@ impl<'a, S> ProjectMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Creates a variable within the given configuration. You cannot create a variable with a name that is a prefix of an existing variable name, or a name that has an existing variable name as a prefix. To learn more about creating a variable, read the [Setting and Getting Data](/deployment-manager/runtime-configurator/set-and-get-variables) documentation. + /// Creates a variable within the given configuration. You cannot create a variable with a name that is a prefix of an existing variable name, or a name that has an existing variable name as a prefix. To learn more about creating a variable, read the [Setting and Getting Data](https://cloud.google.com/deployment-manager/runtime-configurator/set-and-get-variables) documentation. /// /// # Arguments /// @@ -807,7 +807,7 @@ impl<'a, S> ProjectMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Watches a specific variable and waits for a change in the variable's value. When there is a change, this method returns the new value or times out. If a variable is deleted while being watched, the `variableState` state is set to `DELETED` and the method returns the last known variable `value`. If you set the deadline for watching to a larger value than internal timeout (60 seconds), the current variable value is returned and the `variableState` will be `VARIABLE_STATE_UNSPECIFIED`. To learn more about creating a watcher, read the [Watching a Variable for Changes](/deployment-manager/runtime-configurator/watching-a-variable) documentation. + /// Watches a specific variable and waits for a change in the variable's value. When there is a change, this method returns the new value or times out. If a variable is deleted while being watched, the `variableState` state is set to `DELETED` and the method returns the last known variable `value`. If you set the deadline for watching to a larger value than internal timeout (60 seconds), the current variable value is returned and the `variableState` will be `VARIABLE_STATE_UNSPECIFIED`. To learn more about creating a watcher, read the [Watching a Variable for Changes](https://cloud.google.com/deployment-manager/runtime-configurator/watching-a-variable) documentation. /// /// # Arguments /// diff --git a/gen/searchconsole1/src/api.rs b/gen/searchconsole1/src/api.rs index cf1edf613e..956de91872 100644 --- a/gen/searchconsole1/src/api.rs +++ b/gen/searchconsole1/src/api.rs @@ -1067,7 +1067,7 @@ impl<'a, S> SitemapMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Lists the [sitemaps-entries](/webmaster-tools/v3/sitemaps) submitted for this site, or included in the sitemap index file (if `sitemapIndex` is specified in the request). + /// Lists the [sitemaps-entries](https://developers.google.com/webmaster-tools/v3/sitemaps) submitted for this site, or included in the sitemap index file (if `sitemapIndex` is specified in the request). /// /// # Arguments /// diff --git a/gen/sheets4/src/api.rs b/gen/sheets4/src/api.rs index 779b62d1ad..a5e4817e24 100644 --- a/gen/sheets4/src/api.rs +++ b/gen/sheets4/src/api.rs @@ -6683,13 +6683,13 @@ impl<'a, S> SpreadsheetMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Appends values to a spreadsheet. The input range is used to search for existing data and find a "table" within that range. Values will be appended to the next row of the table, starting with the first column of the table. See the [guide](/sheets/api/guides/values#appending_values) and [sample code](/sheets/api/samples/writing#append_values) for specific details of how tables are detected and data is appended. The caller must specify the spreadsheet ID, range, and a valueInputOption. The `valueInputOption` only controls how the input data will be added to the sheet (column-wise or row-wise), it does not influence what cell the data starts being written to. + /// Appends values to a spreadsheet. The input range is used to search for existing data and find a "table" within that range. Values will be appended to the next row of the table, starting with the first column of the table. See the [guide](https://developers.google.com/sheets/api/guides/values#appending_values) and [sample code](https://developers.google.com/sheets/api/samples/writing#append_values) for specific details of how tables are detected and data is appended. The caller must specify the spreadsheet ID, range, and a valueInputOption. The `valueInputOption` only controls how the input data will be added to the sheet (column-wise or row-wise), it does not influence what cell the data starts being written to. /// /// # Arguments /// /// * `request` - No description provided. /// * `spreadsheetId` - The ID of the spreadsheet to update. - /// * `range` - The [A1 notation](/sheets/api/guides/concepts#cell) of a range to search for a logical table of data. Values are appended after the last row of the table. + /// * `range` - The [A1 notation](https://developers.google.com/sheets/api/guides/concepts#cell) of a range to search for a logical table of data. Values are appended after the last row of the table. pub fn values_append(&self, request: ValueRange, spreadsheet_id: &str, range: &str) -> SpreadsheetValueAppendCall<'a, S> { SpreadsheetValueAppendCall { hub: self.hub, @@ -6831,7 +6831,7 @@ impl<'a, S> SpreadsheetMethods<'a, S> { /// /// * `request` - No description provided. /// * `spreadsheetId` - The ID of the spreadsheet to update. - /// * `range` - The [A1 notation or R1C1 notation](/sheets/api/guides/concepts#cell) of the values to clear. + /// * `range` - The [A1 notation or R1C1 notation](https://developers.google.com/sheets/api/guides/concepts#cell) of the values to clear. pub fn values_clear(&self, request: ClearValuesRequest, spreadsheet_id: &str, range: &str) -> SpreadsheetValueClearCall<'a, S> { SpreadsheetValueClearCall { hub: self.hub, @@ -6851,7 +6851,7 @@ impl<'a, S> SpreadsheetMethods<'a, S> { /// # Arguments /// /// * `spreadsheetId` - The ID of the spreadsheet to retrieve data from. - /// * `range` - The [A1 notation or R1C1 notation](/sheets/api/guides/concepts#cell) of the range to retrieve values from. + /// * `range` - The [A1 notation or R1C1 notation](https://developers.google.com/sheets/api/guides/concepts#cell) of the range to retrieve values from. pub fn values_get(&self, spreadsheet_id: &str, range: &str) -> SpreadsheetValueGetCall<'a, S> { SpreadsheetValueGetCall { hub: self.hub, @@ -6874,7 +6874,7 @@ impl<'a, S> SpreadsheetMethods<'a, S> { /// /// * `request` - No description provided. /// * `spreadsheetId` - The ID of the spreadsheet to update. - /// * `range` - The [A1 notation](/sheets/api/guides/concepts#cell) of the values to update. + /// * `range` - The [A1 notation](https://developers.google.com/sheets/api/guides/concepts#cell) of the values to update. pub fn values_update(&self, request: ValueRange, spreadsheet_id: &str, range: &str) -> SpreadsheetValueUpdateCall<'a, S> { SpreadsheetValueUpdateCall { hub: self.hub, @@ -6929,7 +6929,7 @@ impl<'a, S> SpreadsheetMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Returns the spreadsheet at the given ID. The caller must specify the spreadsheet ID. By default, data within grids is not returned. You can include grid data in one of 2 ways: * Specify a [field mask](https://developers.google.com/sheets/api/guides/field-masks) listing your desired fields using the `fields` URL parameter in HTTP * Set the includeGridData URL parameter to true. If a field mask is set, the `includeGridData` parameter is ignored For large spreadsheets, as a best practice, retrieve only the specific spreadsheet fields that you want. To retrieve only subsets of spreadsheet data, use the ranges URL parameter. Ranges are specified using [A1 notation](/sheets/api/guides/concepts#cell). You can define a single cell (for example, `A1`) or multiple cells (for example, `A1:D5`). You can also get cells from other sheets within the same spreadsheet (for example, `Sheet2!A1:C4`) or retrieve multiple ranges at once (for example, `?ranges=A1:D5&ranges=Sheet2!A1:C4`). Limiting the range returns only the portions of the spreadsheet that intersect the requested ranges. + /// Returns the spreadsheet at the given ID. The caller must specify the spreadsheet ID. By default, data within grids is not returned. You can include grid data in one of 2 ways: * Specify a [field mask](https://developers.google.com/sheets/api/guides/field-masks) listing your desired fields using the `fields` URL parameter in HTTP * Set the includeGridData URL parameter to true. If a field mask is set, the `includeGridData` parameter is ignored For large spreadsheets, as a best practice, retrieve only the specific spreadsheet fields that you want. To retrieve only subsets of spreadsheet data, use the ranges URL parameter. Ranges are specified using [A1 notation](https://developers.google.com/sheets/api/guides/concepts#cell). You can define a single cell (for example, `A1`) or multiple cells (for example, `A1:D5`). You can also get cells from other sheets within the same spreadsheet (for example, `Sheet2!A1:C4`) or retrieve multiple ranges at once (for example, `?ranges=A1:D5&ranges=Sheet2!A1:C4`). Limiting the range returns only the portions of the spreadsheet that intersect the requested ranges. /// /// # Arguments /// diff --git a/gen/speech1_beta1/src/api.rs b/gen/speech1_beta1/src/api.rs index 4f0d75bbf0..e94eee9f38 100644 --- a/gen/speech1_beta1/src/api.rs +++ b/gen/speech1_beta1/src/api.rs @@ -657,8 +657,7 @@ impl<'a, S> SpeechMethods<'a, S> { /// Create a builder to help you perform the following task: /// /// Performs asynchronous speech recognition: receive results via the - /// [google.longrunning.Operations] - /// (/speech/reference/rest/v1beta1/operations#Operation) + /// [google.longrunning.Operations](https://cloud.google.com/speech/reference/rest/v1beta1/operations#Operation) /// interface. Returns either an /// `Operation.error` or an `Operation.response` which contains /// an `AsyncRecognizeResponse` message. diff --git a/gen/sqladmin1_beta4/src/api.rs b/gen/sqladmin1_beta4/src/api.rs index 185af820a8..aed0e94d8f 100644 --- a/gen/sqladmin1_beta4/src/api.rs +++ b/gen/sqladmin1_beta4/src/api.rs @@ -4229,7 +4229,7 @@ impl<'a, S> TierMethods<'a, S> { /// Create a builder to help you perform the following task: /// - /// Lists all available machine types (tiers) for Cloud SQL, for example, `db-custom-1-3840`. For related information, see [Pricing](/sql/pricing). + /// Lists all available machine types (tiers) for Cloud SQL, for example, `db-custom-1-3840`. For related information, see [Pricing](https://developers.google.com/sql/pricing). /// /// # Arguments /// From de51978c696f961e850d13a2db323db045125567 Mon Sep 17 00:00:00 2001 From: Filipp Samoilov Date: Sun, 16 Apr 2023 17:50:13 +0300 Subject: [PATCH 3/5] WIP --- src/generator/lib/util.py | 60 +++++++++------------ src/generator/templates/api/lib/lib.mako | 2 +- src/generator/templates/api/lib/mbuild.mako | 10 ++-- src/generator/templates/api/lib/rbuild.mako | 6 +-- src/generator/templates/api/lib/schema.mako | 6 +-- src/rust/preproc/src/main.rs | 27 +++++++++- 6 files changed, 62 insertions(+), 49 deletions(-) diff --git a/src/generator/lib/util.py b/src/generator/lib/util.py index bcc5b193d7..7be208b5a9 100644 --- a/src/generator/lib/util.py +++ b/src/generator/lib/util.py @@ -18,6 +18,7 @@ re_desc_parts = re.compile( flags=re.IGNORECASE | re.MULTILINE) re_find_replacements = re.compile(r"\{[/\+]?\w+\*?\}") +re_relative_links = re.compile(r"\]\s*\([^h]") HTTP_METHODS = set(("OPTIONS", "GET", "POST", "PUT", "DELETE", "HEAD", "TRACE", "CONNECT", "PATCH")) @@ -133,19 +134,34 @@ def rust_doc_comment(s): def has_markdown_codeblock_with_indentation(s): return re_spaces_after_newline.search(s) != None - -def preprocess(s): - p = subprocess.Popen([os.environ['PREPROC']], close_fds=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) +def preprocess(base_url, s): + if base_url is None: + printl(f"WARNING {s} has no base_url") + p = subprocess.Popen( + [os.environ['PREPROC']], + close_fds=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + env={"URL_BASE": base_url or ""} + ) + res = p.communicate(s.encode('utf-8')) + exitcode = p.wait(timeout=1) + if exitcode != 0: + raise ValueError(f"Child process exited with non-zero code {exitcode}") return res[0].decode('utf-8') +def has_relative_links(s): + return re_relative_links.search(s) is not None # runs the preprocessor in case there is evidence for code blocks using indentation -def rust_doc_sanitize(s): - if has_markdown_codeblock_with_indentation(s): - return preprocess(s) - else: - return s +def rust_doc_sanitize(base_url): + def fixer(s): + if has_markdown_codeblock_with_indentation(s) or has_relative_links(s): + return preprocess(base_url, s) + else: + return s + return fixer # rust comment filter @@ -1174,33 +1190,5 @@ def string_impl(p): "string": lambda x: x }.get(p.get("format", p["type"]), lambda x: f"{x}.to_string()") -MD_LINKS_CAPTURE = re.compile(r''' - \[ # Opening bracket for the "name" part of the url - ([^]]+?) # Some amount of non-closing bracket `]` symbols, - # Captured in a group - \] # Close the name part - \s* # maybe a whitespace - \( # Opening a paren for the url part - ([^)]+?) # Url, captured in a group - \) # closing paren -''', re.VERBOSE) - -# FIXME: combine with links handling in .docs -def fix_relative_links(url_base): - url_parsed = urllib.parse.urlparse(url_base) - url_base = f"{url_parsed.scheme}://{url_parsed.netloc}" - def replace_url(url_match: re.match): - original_url = url_match.group(0) - name = url_match.group(1) - url = url_match.group(2) - if url.startswith('/'): - return f"[{name}]({url_base}{url})" - return original_url - - def fixer(docs): - # FIXME: replace with proper markdown parser and documentationLink value - return MD_LINKS_CAPTURE.sub(replace_url, docs) - return fixer - if __name__ == '__main__': raise AssertionError('For import only') diff --git a/src/generator/templates/api/lib/lib.mako b/src/generator/templates/api/lib/lib.mako index ee82edb98c..bd9290683b 100644 --- a/src/generator/templates/api/lib/lib.mako +++ b/src/generator/templates/api/lib/lib.mako @@ -334,7 +334,7 @@ You can read the full text at the repository's [license file][repo-license]. #[derive(PartialEq, Eq, Hash)] pub enum Scope { % for url, scope in auth.oauth2.scopes.items(): - ${scope.description | rust_doc_sanitize, rust_doc_comment} + ${scope.description | rust_doc_sanitize(documentationLink), rust_doc_comment} ${scope_url_to_variant(name, url, fully_qualified=False)}, % if not loop.last: diff --git a/src/generator/templates/api/lib/mbuild.mako b/src/generator/templates/api/lib/mbuild.mako index f6fd75d157..23e3c8d4db 100644 --- a/src/generator/templates/api/lib/mbuild.mako +++ b/src/generator/templates/api/lib/mbuild.mako @@ -66,7 +66,7 @@ parts = get_parts(part_prop) %>\ % if 'description' in m: -${m.description | rust_doc_sanitize, rust_doc_comment} +${m.description | rust_doc_sanitize(documentationLink), rust_doc_comment} /// % endif % if m.get('supportsMediaDownload', False): @@ -90,7 +90,7 @@ ${m.description | rust_doc_sanitize, rust_doc_comment} /// It is not used directly, but through a [`${rb_type(resource)}`] instance. /// % if part_desc: -${part_desc | rust_doc_sanitize, rust_doc_comment} +${part_desc | rust_doc_sanitize(documentationLink), rust_doc_comment} /// % if m.get('scopes'): /// # Scopes @@ -248,7 +248,7 @@ ${self._setter_fn(resource, method, m, p, part_prop, ThisType, c)}\ # end part description %>\ % if 'description' in p: - ${p.description | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)} + ${p.description | rust_doc_sanitize(documentationLink), rust_doc_comment, indent_all_but_first_by(1)} % endif % if is_repeated_property(p): /// @@ -272,7 +272,7 @@ ${self._setter_fn(resource, method, m, p, part_prop, ThisType, c)}\ % endif % if part_desc: /// - ${part_desc | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)} + ${part_desc | rust_doc_sanitize(documentationLink), rust_doc_comment, indent_all_but_first_by(1)} % endif pub fn ${mangle_ident(setter_fn_name(p))}(mut self, ${value_name}: ${InType}) -> ${ThisType} { % if p.get('repeated', False): @@ -898,7 +898,7 @@ if enable_resource_parsing \ } % for p in media_params: - ${p.description | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)} + ${p.description | rust_doc_sanitize(documentationLink), rust_doc_comment, indent_all_but_first_by(1)} /// % for item_name, item in p.info.items(): /// * *${split_camelcase_s(item_name)}*: ${isinstance(item, (list, tuple)) and put_and(enclose_in("'", item)) or str(item)} diff --git a/src/generator/templates/api/lib/rbuild.mako b/src/generator/templates/api/lib/rbuild.mako index 037a08beab..bd13253981 100644 --- a/src/generator/templates/api/lib/rbuild.mako +++ b/src/generator/templates/api/lib/rbuild.mako @@ -6,7 +6,7 @@ rust_copy_value_s, organize_params, REQUEST_VALUE_PROPERTY_NAME, build_all_params, rb_type_params_s, hub_type_params_s, mb_type_params_s, mb_additional_type_params, struct_type_bounds_s, METHODS_RESOURCE, SPACES_PER_TAB, prefix_all_but_first_with, - METHODS_BUILDER_MARKER_TRAIT, remove_empty_lines, method_default_scope, rust_doc_sanitize, fix_relative_links) + METHODS_BUILDER_MARKER_TRAIT, remove_empty_lines, method_default_scope, rust_doc_sanitize) %>\ <%namespace name="util" file="../../../lib/util.mako"/>\ <%namespace name="lib" file="lib.mako"/>\ @@ -80,7 +80,7 @@ impl${rb_params} ${ThisType} { % if 'description' in m: /// Create a builder to help you perform the following task: /// - ${m.description | fix_relative_links(documentationLink), rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)} + ${m.description | rust_doc_sanitize(documentationLink), rust_doc_comment, indent_all_but_first_by(1)} % endif % if required_props: /// @@ -91,7 +91,7 @@ impl${rb_params} ${ThisType} { arg_prefix = "/// * `" + p.name + "` - " %>\ ${arg_prefix}${p.get('description', "No description provided.") - | fix_relative_links(documentationLink), remove_empty_lines, prefix_all_but_first_with(' ' * SPACES_PER_TAB + '///' + ' ' * (len(arg_prefix) - len('///')))} + | rust_doc_sanitize(documentationLink), remove_empty_lines, prefix_all_but_first_with(' ' * SPACES_PER_TAB + '///' + ' ' * (len(arg_prefix) - len('///')))} % endfor % endif pub fn ${mangle_ident(a)}${type_params}(&self${method_args}) -> ${RType}${mb_tparams} { diff --git a/src/generator/templates/api/lib/schema.mako b/src/generator/templates/api/lib/schema.mako index 55e2c5fdcf..7673938e5b 100644 --- a/src/generator/templates/api/lib/schema.mako +++ b/src/generator/templates/api/lib/schema.mako @@ -13,7 +13,7 @@ % if properties: ${struct} { % for pn, p in items(properties): - ${p.get('description', 'no description provided') | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)} + ${p.get('description', 'no description provided') | rust_doc_sanitize(documentationLink), rust_doc_comment, indent_all_but_first_by(1)} % if pn != mangle_ident(pn): #[serde(rename="${pn}")] % endif @@ -36,7 +36,7 @@ ${struct}(pub ${to_rust_type(schemas, s.id, NESTED_TYPE_SUFFIX, s, allow_optiona %>\ pub enum ${et} { % for p in s.variant.map: - ${p.get('description', 'no description provided') | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)} + ${p.get('description', 'no description provided') | rust_doc_sanitize(documentationLink), rust_doc_comment, indent_all_but_first_by(1)} % if variant_type(p) != p.type_value: #[serde(rename="${p.type_value}")] % endif @@ -80,7 +80,7 @@ ${struct} { _never_set: Option } s_type = s.id %>\ -<%block filter="rust_doc_sanitize, rust_doc_comment">\ +<%block filter="rust_doc_sanitize(documentationLink), rust_doc_comment">\ ${doc(s, c)}\ #[serde_with::serde_as(crate = "::client::serde_with")] diff --git a/src/rust/preproc/src/main.rs b/src/rust/preproc/src/main.rs index 251388994e..2a1e4f8b1a 100644 --- a/src/rust/preproc/src/main.rs +++ b/src/rust/preproc/src/main.rs @@ -1,7 +1,7 @@ extern crate pulldown_cmark; extern crate pulldown_cmark_to_cmark; -use pulldown_cmark::Parser; +use pulldown_cmark::{CowStr, Parser, Tag}; use pulldown_cmark_to_cmark::fmt::cmark; use std::io::{self, Read, Write}; @@ -13,6 +13,23 @@ fn main() { }; let mut output = String::with_capacity(2048); + let url_base = std::env::var("URL_BASE").unwrap_or(String::new()); + // FIXME: for urls starting with /, use only the netloc + let url_base = url_base + .strip_suffix("/") + .map(String::from) + .unwrap_or(url_base); + + fn fix_url<'a>(base: &str, url: CowStr<'a>) -> CowStr<'a> { + if url.starts_with("/") { + format!("{base}{url}").into() + } else if url.starts_with("..") { + format!("{base}/{url}").into() + } else { + url + } + } + cmark( Parser::new_ext(&md, pulldown_cmark::Options::all()).map(|e| { use pulldown_cmark::Event::*; @@ -21,9 +38,17 @@ fn main() { use pulldown_cmark::Tag::*; match tag { CodeBlock(code) => Start(CodeBlock(format!("text{}", code).into())), + Link(lt, url, title) => Start(Link( + lt.clone(), + fix_url(&url_base, url.clone()), + title.clone(), + )), _ => e, } } + End(Tag::Link(lt, url, title)) => { + End(Tag::Link(lt, fix_url(&url_base, url), title)) + } _ => e, } }), From fc1754fbfa78157719bbe51af286cd4f714fbd88 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 17 Apr 2023 15:13:27 +0200 Subject: [PATCH 4/5] thanks clippy --- src/rust/preproc/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rust/preproc/src/main.rs b/src/rust/preproc/src/main.rs index 46f660d1c1..37a4194281 100644 --- a/src/rust/preproc/src/main.rs +++ b/src/rust/preproc/src/main.rs @@ -13,15 +13,15 @@ fn main() { }; let mut output = String::with_capacity(2048); - let url_base = std::env::var("URL_BASE").unwrap_or(String::new()); + let url_base = std::env::var("URL_BASE").unwrap_or_default(); // FIXME: for urls starting with /, use only the netloc let url_base = url_base - .strip_suffix("/") + .strip_suffix('/') .map(String::from) .unwrap_or(url_base); fn fix_url<'a>(base: &str, url: CowStr<'a>) -> CowStr<'a> { - if url.starts_with("/") { + if url.starts_with('/') { format!("{base}{url}").into() } else if url.starts_with("..") { format!("{base}/{url}").into() From 5cccc5ba8305b1f6d0b47a66e96380041f3151b0 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 8 May 2023 07:53:14 +0200 Subject: [PATCH 5/5] Manually integrate changes from c43aa69e2b4f87a0c76eb8fd37c221042014d3c1 This was a force-pushed commit that probably doesn't exist for long before beign collected. Co-authored-by: Filipp --- src/generator/lib/util.py | 2 +- src/rust/preproc/Cargo.toml | 1 + src/rust/preproc/src/main.rs | 26 +++++++++++++++++++------- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/generator/lib/util.py b/src/generator/lib/util.py index 7be208b5a9..1c93035c5b 100644 --- a/src/generator/lib/util.py +++ b/src/generator/lib/util.py @@ -136,7 +136,7 @@ def has_markdown_codeblock_with_indentation(s): def preprocess(base_url, s): if base_url is None: - printl(f"WARNING {s} has no base_url") + print(f"WARNING {s} has no base_url") p = subprocess.Popen( [os.environ['PREPROC']], close_fds=True, diff --git a/src/rust/preproc/Cargo.toml b/src/rust/preproc/Cargo.toml index 81ce97c34c..34aa4713a3 100644 --- a/src/rust/preproc/Cargo.toml +++ b/src/rust/preproc/Cargo.toml @@ -16,3 +16,4 @@ test = false [dependencies] pulldown-cmark-to-cmark = "10.0.0" pulldown-cmark = "0.9.0" +url = "2.3.1" diff --git a/src/rust/preproc/src/main.rs b/src/rust/preproc/src/main.rs index 37a4194281..f59132f2e7 100644 --- a/src/rust/preproc/src/main.rs +++ b/src/rust/preproc/src/main.rs @@ -14,15 +14,25 @@ fn main() { let mut output = String::with_capacity(2048); let url_base = std::env::var("URL_BASE").unwrap_or_default(); - // FIXME: for urls starting with /, use only the netloc + let url_base = url_base .strip_suffix('/') .map(String::from) .unwrap_or(url_base); - fn fix_url<'a>(base: &str, url: CowStr<'a>) -> CowStr<'a> { + let url_root = if url_base.is_empty() { + String::new() + } else { + let parsed = url::Url::parse(&url_base).unwrap(); + let scheme = parsed.scheme(); + let host = parsed.host_str().unwrap_or_default(); + let port = parsed.port().map(|p| format!(":{p}")).unwrap_or_default(); + format!("{scheme}://{host}{port}") + }; + + fn fix_url<'a>(root: &str, base: &str, url: CowStr<'a>) -> CowStr<'a> { if url.starts_with('/') { - format!("{base}{url}").into() + format!("{root}{url}").into() } else if url.starts_with("..") { format!("{base}/{url}").into() } else { @@ -40,14 +50,16 @@ fn main() { CodeBlock(pulldown_cmark::CodeBlockKind::Indented) => Start(CodeBlock( pulldown_cmark::CodeBlockKind::Fenced("text".into()), )), - Link(lt, url, title) => { - Start(Link(*lt, fix_url(&url_base, url.clone()), title.clone())) - } + Link(lt, url, title) => Start(Link( + *lt, + fix_url(&url_root, &url_base, url.clone()), + title.clone(), + )), _ => e, } } End(Tag::Link(lt, url, title)) => { - End(Tag::Link(lt, fix_url(&url_base, url), title)) + End(Tag::Link(lt, fix_url(&url_root, &url_base, url), title)) } _ => e, }