# Copyright 2020 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 # # https://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. import glob import re import os import yaml from typing import List, Dict from synthtool.log import logger def _read_sample_metadata_comment(sample_file: str) -> Dict: """Additional meta-information can be provided through embedded comments: // sample-metadata: // title: ACL (Access Control) // description: Demonstrates setting access control rules. // usage: node iam.js --help """ sample_metadata = {} # type: Dict[str, str] with open(sample_file) as f: contents = f.read() match = re.search( r"(?P// *sample-metadata:([^\n]+|\n//)+)", contents, re.DOTALL ) if match: # the metadata yaml is stored in a comments, remove the # prefix so that we can parse the yaml contained. sample_metadata_string = re.sub(r"((#|//) ?)", "", match.group("metadata")) try: sample_metadata = yaml.load( sample_metadata_string, Loader=yaml.SafeLoader )["sample-metadata"] except yaml.scanner.ScannerError: # warn and continue on bad metadata logger.warning(f"bad metadata detected in {sample_file}") return sample_metadata def _sample_metadata(file: str) -> Dict[str, str]: metadata = { "title": _decamelize(os.path.splitext(os.path.basename(file))[0]), "file": file, } return {**metadata, **_read_sample_metadata_comment(file)} def all_samples(sample_globs: List[str]) -> List[Dict[str, str]]: """Walks samples directory and builds up samples data-structure Args: sample_globs: (List[str]): List of path globs to search for samples Returns: A list of sample metadata in the format: { "title": "Requester Pays", "file": "samples/requesterPays.js" } The file path is the relative path from the repository root. """ files = [] for sample_glob in sample_globs: for file in glob.glob(sample_glob, recursive=True): files.append(file) return [_sample_metadata(file) for file in sorted(files)] def _decamelize(value: str): """Parser to convert fooBar.js to Foo Bar.""" if not value: return "" str_decamelize = re.sub("^.", value[0].upper(), value) # apple -> Apple. str_decamelize = re.sub( "([A-Z]+)([A-Z])([a-z0-9])", r"\1 \2\3", str_decamelize ) # ACLBatman -> ACL Batman. return re.sub("([a-z0-9])([A-Z])", r"\1 \2", str_decamelize) # FooBar -> Foo Bar.