xref: /aosp_15_r20/external/google-cloud-java/owl-bot-postprocessor/synthtool/gcp/samples.py (revision 55e87721aa1bc457b326496a7ca40f3ea1a63287)
1# Copyright 2020 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import glob
16import re
17import os
18import yaml
19from typing import List, Dict
20from synthtool.log import logger
21
22
23def _read_sample_metadata_comment(sample_file: str) -> Dict:
24    """Additional meta-information can be provided through embedded comments:
25
26    // sample-metadata:
27    //   title: ACL (Access Control)
28    //   description: Demonstrates setting access control rules.
29    //   usage: node iam.js --help
30    """
31    sample_metadata = {}  # type: Dict[str, str]
32    with open(sample_file) as f:
33        contents = f.read()
34        match = re.search(
35            r"(?P<metadata>// *sample-metadata:([^\n]+|\n//)+)", contents, re.DOTALL
36        )
37        if match:
38            # the metadata yaml is stored in a comments, remove the
39            # prefix so that we can parse the yaml contained.
40            sample_metadata_string = re.sub(r"((#|//) ?)", "", match.group("metadata"))
41            try:
42                sample_metadata = yaml.load(
43                    sample_metadata_string, Loader=yaml.SafeLoader
44                )["sample-metadata"]
45            except yaml.scanner.ScannerError:
46                # warn and continue on bad metadata
47                logger.warning(f"bad metadata detected in {sample_file}")
48    return sample_metadata
49
50
51def _sample_metadata(file: str) -> Dict[str, str]:
52    metadata = {
53        "title": _decamelize(os.path.splitext(os.path.basename(file))[0]),
54        "file": file,
55    }
56    return {**metadata, **_read_sample_metadata_comment(file)}
57
58
59def all_samples(sample_globs: List[str]) -> List[Dict[str, str]]:
60    """Walks samples directory and builds up samples data-structure
61
62    Args:
63        sample_globs: (List[str]): List of path globs to search for samples
64
65    Returns:
66        A list of sample metadata in the format:
67        {
68            "title": "Requester Pays",
69            "file": "samples/requesterPays.js"
70        }
71        The file path is the relative path from the repository root.
72    """
73    files = []
74    for sample_glob in sample_globs:
75        for file in glob.glob(sample_glob, recursive=True):
76            files.append(file)
77    return [_sample_metadata(file) for file in sorted(files)]
78
79
80def _decamelize(value: str):
81    """Parser to convert fooBar.js to Foo Bar."""
82    if not value:
83        return ""
84    str_decamelize = re.sub("^.", value[0].upper(), value)  # apple -> Apple.
85    str_decamelize = re.sub(
86        "([A-Z]+)([A-Z])([a-z0-9])", r"\1 \2\3", str_decamelize
87    )  # ACLBatman -> ACL Batman.
88    return re.sub("([a-z0-9])([A-Z])", r"\1 \2", str_decamelize)  # FooBar -> Foo Bar.
89