| #!/usr/bin/env python3 |
| |
| ############################################################################### |
| ## BSD 3-Clause License |
| ## |
| ## Copyright (c) 2022, The Regents of the University of California |
| ## All rights reserved. |
| ## |
| ## Redistribution and use in source and binary forms, with or without |
| ## modification, are permitted provided that the following conditions are met: |
| ## |
| ## * Redistributions of source code must retain the above copyright notice, this |
| ## list of conditions and the following disclaimer. |
| ## |
| ## * Redistributions in binary form must reproduce the above copyright notice, |
| ## this list of conditions and the following disclaimer in the documentation |
| ## and/or other materials provided with the distribution. |
| ## |
| ## * Neither the name of the copyright holder nor the names of its |
| ## contributors may be used to endorse or promote products derived from |
| ## this software without specific prior written permission. |
| ## |
| ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| ## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| ## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| ## ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| ## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| ## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| ## POSSIBILITY OF SUCH DAMAGE. |
| |
| # The purpose of this script is to build a symbolic link farm from a |
| # source PDK according to a JSON mapping file. This is to adapt a PDK |
| # from a vendor into the form expected by OpenLane without actually |
| # modifying the source PDK. This is in opposition to the open_pdks |
| # approach which modifies the vendor PDK to fit. |
| |
| # This is a transitional tool. Eventually OpenLane scripts will use |
| # the mapping file to directly access the files without needing the |
| # link farm. This will free OL from any dependency on PDK organization. |
| |
| import argparse |
| import glob |
| import json |
| import os |
| |
| parser = argparse.ArgumentParser( |
| description="""Builds a link farm from <source> in <dest> according to <mappings>""" |
| ) |
| parser.add_argument("-s", "--source", required=True) |
| parser.add_argument("-d", "--destination", required=True) |
| parser.add_argument("-m", "--mappings", required=True) |
| parser.add_argument("-v", "--verbose", action="store_true") |
| |
| args = parser.parse_args() |
| |
| |
| def link_files(source_path, destination_path): |
| """Create a link from source_path to destination path unless |
| one already exists. If it exists but is different then the |
| arguments imply an exception is raised.""" |
| |
| destination_dir = os.path.dirname(destination_path) |
| if not os.path.isdir(destination_dir): |
| os.makedirs(destination_dir) |
| if os.path.exists(destination_path): |
| if ( |
| os.path.islink(destination_path) |
| and os.path.realpath(destination_path) == source_path |
| ): |
| if args.verbose: |
| print(f" Skip {source_path} -> {destination_path}") |
| return |
| else: |
| raise Exception(f"File {destination_path} already exists") |
| os.symlink(source_path, destination_path) |
| if args.verbose: |
| print(f" Link {source_path} -> {destination_path}") |
| |
| |
| with open(args.mappings) as f: |
| mappings = json.load(f) |
| |
| if not os.path.isdir(args.source): |
| raise Exception(f"{args.source} is not a directory") |
| |
| source = os.path.abspath(f"{args.source}") |
| destination = os.path.abspath(f"{args.destination}") |
| |
| for category, mapping in mappings.items(): |
| print(f"Linking {category}") |
| pdk = mapping["pdk"] |
| openlane = mapping["openlane"] |
| for pattern in mapping["files"]: |
| pattern = f"{source}/{pdk}/{pattern}" |
| paths = glob.glob(pattern) |
| if len(paths) == 0: |
| raise Exception(f"No matches for {pattern}") |
| for source_path in paths: |
| file_name = os.path.basename(source_path) |
| destination_path = f"{destination}/{openlane}/{file_name}" |
| link_files(source_path, destination_path) |