def clone( self, checkout_config: CheckoutConfig, path: str, snapshot_id: str ) -> None: if path in self._get_directory_map(): raise Exception( """\ mount path %s is already configured (see `eden list`). \ Do you want to run `eden mount %s` instead?""" % (path, path) ) # Create the mount point directory self._create_mount_point_dir(path) # Create client directory clients_dir = self._get_clients_dir() clients_dir.mkdir(parents=True, exist_ok=True) client_dir = self._create_client_dir_for_path(clients_dir, path) # Store snapshot ID checkout = EdenCheckout(self, Path(path), Path(client_dir)) if snapshot_id: checkout.save_snapshot(snapshot_id) else: raise Exception("snapshot id not provided") checkout.save_config(checkout_config) # Prepare to mount mount_info = eden_ttypes.MountArgument( mountPoint=os.fsencode(path), edenClientPath=os.fsencode(client_dir), readOnly=False, ) with self.get_thrift_client_legacy() as client: client.mount(mount_info) self._post_clone_checkout_setup(checkout, snapshot_id) # Add mapping of mount path to client directory in config.json self._add_path_to_directory_map(Path(path), os.path.basename(client_dir))
def mount(self, path: Union[Path, str], read_only: bool) -> int: # Load the config info for this client, to make sure we # know about the client. path = Path(path).resolve(strict=False) client_dir = self._get_client_dir_for_mount_point(path) checkout = EdenCheckout(self, path, client_dir) # Call checkout.get_config() for the side-effect of it raising an # Exception if the config is in an invalid state. checkout.get_config() # Make sure the mount path exists path.mkdir(parents=True, exist_ok=True) # Check if it is already mounted. try: root = path / ".eden" / "root" target = readlink_retry_estale(root) if Path(target) == path: print_stderr( f"ERROR: Mount point in use! {path} is already mounted by Eden." ) return 1 else: # If we are here, MOUNT/.eden/root is a symlink, but it does not # point to MOUNT. This suggests `path` is a subdirectory of an # existing mount, though we should never reach this point # because _get_client_dir_for_mount_point() above should have # already thrown an exception. We return non-zero here just in # case. print_stderr( f"ERROR: Mount point in use! " f"{path} is already mounted by Eden as part of {root}.") return 1 except OSError as ex: # - ENOENT is expected if the mount is not mounted. # - We'll get ENOTCONN if the directory was not properly unmounted from a # previous EdenFS instance. Remounting over this directory is okay (even # though ideally we would unmount the old stale mount point to clean it # up). # - EINVAL can happen if .eden/root isn't a symlink. This isn't expected # in most circumstances, but it does mean that the directory isn't # currently an EdenFS checkout. err = ex.errno if err not in (errno.ENOENT, errno.ENOTCONN, errno.EINVAL): raise # Ask eden to mount the path mount_info = eden_ttypes.MountArgument( mountPoint=bytes(path), edenClientPath=bytes(client_dir), readOnly=read_only) try: with self.get_thrift_client_legacy() as client: client.mount(mount_info) except eden_ttypes.EdenError as ex: if "already mounted" in str(ex): print_stderr( f"ERROR: Mount point in use! {path} is already mounted by Eden." ) return 1 return 0