1# Copyright 2022 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# 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, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Serializes an Environment into a JSON file.""" 15 16import ntpath 17import os 18import posixpath 19import re 20 21 22class GNIVisitor: 23 """Serializes portions of an Environment into a gni file. 24 25 Example gni file: 26 27 declare_args() { 28 pw_env_setup_CIPD_ARM = "//<ENVIRONMENT_DIR>/cipd/packages/arm" 29 pw_env_setup_CIPD_BAZEL = "//<ENVIRONMENT_DIR>/cipd/packages/bazel" 30 pw_env_setup_CIPD_DEFAULT = "//<ENVIRONMENT_DIR>/cipd/packages/default" 31 pw_env_setup_CIPD_LUCI = "//<ENVIRONMENT_DIR>/cipd/packages/luci" 32 pw_env_setup_CIPD_PIGWEED = "//<ENVIRONMENT_DIR>/cipd/packages/pigweed" 33 pw_env_setup_CIPD_PYTHON = "//<ENVIRONMENT_DIR>/cipd/packages/python" 34 pw_env_setup_VIRTUAL_ENV = "//<ENVIRONMENT_DIR>/pigweed-venv" 35 } 36 """ 37 38 def __init__(self, project_root, gni_file, *args, **kwargs): 39 super().__init__(*args, **kwargs) 40 self._project_root = project_root 41 self._gni_file = gni_file 42 self._variables = {} # Dict of variables to set. 43 44 def _gn_variables(self, env): 45 self._variables.clear() 46 env.accept(self) 47 variables = dict(self._variables) 48 self._variables.clear() 49 return variables 50 51 def serialize(self, env, outs): 52 """Write a gni file based on the given environment. 53 54 Args: 55 env (environment.Environment): Environment variables to use. 56 outs (file): GNI file to write. 57 """ 58 59 print( 60 """ 61# This file is automatically generated by Pigweed's environment setup. Do not 62# edit it manually or check it in. 63 64# Relative paths are interpreted with respect to this file, which helps 65# determine the correct path even if the source root changes. 66 """.strip(), 67 file=outs, 68 ) 69 70 print('declare_args() {', file=outs) 71 for name, value in sorted(self._gn_variables(env).items()): 72 print(' {} = {}'.format(name, value), file=outs) 73 print('}', file=outs) 74 75 def _abspath_to_gn_path(self, path): 76 gn_dir = os.path.join( 77 self._project_root, os.path.dirname(self._gni_file) 78 ) 79 # Use relative paths within the project root: 80 if path.startswith(self._project_root + os.sep): 81 gn_path = os.path.relpath(path, start=gn_dir) 82 else: 83 gn_path = path 84 if os.name == 'nt': 85 # GN paths are posix-style, so convert to posix. This 86 # find-and-replace is a little crude, but python 2.7 doesn't support 87 # pathlib. 88 gn_path = gn_path.replace(ntpath.sep, posixpath.sep) 89 return 'get_path_info("{}", "abspath")'.format(gn_path) 90 91 def visit_set(self, set): # pylint: disable=redefined-builtin 92 match = re.search(r'PW_(.*)_CIPD_INSTALL_DIR', set.name) 93 name = None 94 95 if match: 96 name = 'pw_env_setup_CIPD_{}'.format(match.group(1)) 97 if set.name == 'VIRTUAL_ENV': 98 name = 'pw_env_setup_VIRTUAL_ENV' 99 if set.name == 'PW_PACKAGE_ROOT': 100 name = 'pw_env_setup_PACKAGE_ROOT' 101 102 if name: 103 self._variables[name] = self._abspath_to_gn_path(set.value) 104 105 def visit_clear(self, clear): 106 pass 107 108 def visit_remove(self, remove): 109 pass 110 111 def visit_prepend(self, prepend): 112 pass 113 114 def visit_append(self, append): 115 pass 116 117 def visit_echo(self, echo): 118 pass 119 120 def visit_comment(self, comment): 121 pass 122 123 def visit_command(self, command): 124 pass 125 126 def visit_doctor(self, doctor): 127 pass 128 129 def visit_blank_line(self, blank_line): 130 pass 131 132 def visit_function(self, function): 133 pass 134 135 def visit_hash(self, hash): # pylint: disable=redefined-builtin 136 pass 137