blob: e6dcdd9b93ad85d367acf8d2b5ed49a9178c688f [file] [log] [blame]
# Copyright 2021 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Python Types that are shared across different parts of the assembly types
"""
from dataclasses import dataclass
from functools import total_ordering
import os
import shutil
from typing import Dict, Iterable, TextIO, Union
from os import PathLike
import serialization
__all__ = ["FileEntry", "FilePath", "fast_copy"]
FilePath = Union[str, os.PathLike]
# TODO(fxb/89571) Move to python module at //build/python/modules/file_entry
@total_ordering
@dataclass
@serialization.serialize_dict
class FileEntry:
"""FileEntry Class
This is a source_path=destination_path mapping type
"""
# TODO(fxbug.dev/98573) Mark these fields to `kw_only=True` after switching
# to python 3.10 or later.
source: FilePath
destination: FilePath
def get_destination(self) -> str:
"""Destination accessor method
"""
return str(self.destination)
def __hash__(self):
return hash((self.destination, self.source))
def __eq__(self, other) -> bool:
if isinstance(other, self.__class__):
return self.source == other.source and self.destination == other.destination
else:
return False
def __lt__(self, other) -> bool:
if not isinstance(other, FileEntry):
raise ValueError("other is not a FileEntry")
return (self.source,
self.destination) < (other.source, other.destination)
def __repr__(self) -> str:
result = "FileEntry{{ source: {}, destination: {} }}".format(
self.source, self.destination)
return result
# TODO(fxb/89571) Move to python module at //build/python/modules/fini_manfest
@staticmethod
def write_fini_manifest(
entries: Iterable['FileEntry'], file: TextIO) -> None:
"""Write out the FileEntry instances into a FINI manifest.
The fini manifest is in the format of::
dest_path=source_path
If the `rebase` path is supplied, all destination paths are made relative to it.
"""
for entry in sorted(entries):
dst = entry.destination
src = entry.source
file.write("{}={}\n".format(dst, src))
def fast_copy(src: FilePath, dst: FilePath, **kwargs) -> None:
"""A wrapper around os and os.path fns to correctly copy a file using a
hardlink.
"""
real_src_path = os.path.realpath(src)
try:
os.link(real_src_path, dst, **kwargs)
except OSError:
shutil.copy2(real_src_path, dst, **kwargs)