sapling/eden/fs/cli/hg_util.py
generatedunixname89002005307016 1e1a7fa10d suppress errors in eden - batch 1
Differential Revision: D25562362

fbshipit-source-id: ec62c64396f61335f6cfe8f355ba977bfd1da031
2020-12-15 15:22:22 -08:00

118 lines
3.8 KiB
Python

#!/usr/bin/env python3
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2.
# pyre-strict
import binascii
import typing
from pathlib import Path
from typing import BinaryIO, Dict, Tuple
import eden.dirstate
from .config import EdenCheckout
_DEFAULT_EXTRA_HGRC_CONTENTS: str = """\
[extensions]
eden =
share =
[ui]
portablefilenames = ignore
"""
def setup_hg_dir(checkout: EdenCheckout, commit_id: str) -> None:
checkout_hg_dir = checkout.path / ".hg"
try:
checkout_hg_dir.mkdir()
except FileExistsError:
raise Exception(f"{checkout_hg_dir} directory already exists")
# hgrc
hgrc_data = get_hgrc_data(checkout)
(checkout_hg_dir / "hgrc").write_text(hgrc_data)
# requires
requires_data = get_requires_data(checkout)
(checkout_hg_dir / "requires").write_text(requires_data)
# Create the shared and sharedpath files, which tell mercurial where it should
# really look for most of the mercurial state, and that bookmarks should also be
# shared.
#
# Note that the sharedpath file intentionally does not include a trailing newline.
# This matches how it is generated by mercurial.
backing_hg_dir = get_backing_hg_dir(checkout)
(checkout_hg_dir / "sharedpath").write_bytes(bytes(backing_hg_dir))
(checkout_hg_dir / "shared").write_text("bookmarks\n")
# Create an empty bookmarks file
(checkout_hg_dir / "bookmarks").touch()
# Create a branch file with the contents "default\n". Even though we do not
# use branches, we have seen some users with a function in their .bashrc
# that categorically reads the .hg/branch file to include in their prompt.
(checkout_hg_dir / "branch").write_text("default\n")
# Write the parents to the dirstate file.
with typing.cast(BinaryIO, (checkout_hg_dir / "dirstate").open("wb")) as f:
parents = (binascii.unhexlify(commit_id), b"\x00" * 20)
tuples_dict: Dict[str, Tuple[str, int, int]] = {}
copymap: Dict[str, str] = {}
eden.dirstate.write(f, parents, tuples_dict, copymap)
def get_backing_hg_dir(checkout: EdenCheckout) -> Path:
"""Given an EdenCheckout object, return the path to the actual .hg/ directory that
contains the mercurial data store.
This is the path that .hg/sharedpath should point to.
"""
return checkout.get_config().backing_repo / ".hg"
def get_hgrc_data(checkout: EdenCheckout) -> str:
backing_hg_dir = get_backing_hg_dir(checkout)
extra_hgrc = checkout.instance.get_config_value(
"hg.extra_hgrc", default=_DEFAULT_EXTRA_HGRC_CONTENTS
)
if extra_hgrc and extra_hgrc[-1] != "\n":
extra_hgrc += "\n"
try:
orig_hgrc = (backing_hg_dir / "hgrc").read_text()
except FileNotFoundError:
# Repositories aren't required to have an .hgrc file
# Make sure the .hg directory itself exists though, to confirm
# we weren't called with incorrect arguments.
if not backing_hg_dir.is_dir():
raise Exception(f"backing repository does not exist: {backing_hg_dir}")
orig_hgrc = ""
return orig_hgrc + "\n" + extra_hgrc
def get_requires_data(checkout: EdenCheckout) -> str:
backing_hg_dir = get_backing_hg_dir(checkout)
try:
orig_requires_data = (backing_hg_dir / "requires").read_text()
requires = set(orig_requires_data.splitlines())
except FileNotFoundError:
requires = set()
# Add eden as a requirement
requires.add("eden")
# Drop other dirstate-related requirements that are specific to
# the backing repository's dirstate.
requires.discard("sqldirstate")
requires.discard("treedirstate")
return "\n".join(sorted(requires)) + "\n"