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