Porting edencli config.py

Summary: Fixed the code that was complaining while running "eden clone". There is still more work to get everything working, like we need to implement the config file locking (replacement for flock on Windows).

Reviewed By: chadaustin

Differential Revision: D15996454

fbshipit-source-id: 6ba51eb04b6ca1fddbd2016a88b86c7aca7acf0b
This commit is contained in:
Puneet Kaushik 2019-07-01 15:41:03 -07:00 committed by Facebook Github Bot
parent 3986ddb614
commit 1ced314647

View File

@ -9,7 +9,6 @@ import binascii
import collections import collections
import datetime import datetime
import errno import errno
import fcntl
import json import json
import os import os
import shutil import shutil
@ -28,6 +27,12 @@ from . import configinterpolator, configutil, util
from .util import EdenStartError, HealthStatus, print_stderr, readlink_retry_estale from .util import EdenStartError, HealthStatus, print_stderr, readlink_retry_estale
# On Linux we import fcntl for flock. The Windows LockFileEx is not semantically
# same as flock. We will need to make some changes for LockFileEx to work.
if os.name != "nt":
import fcntl
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from eden.cli.redirect import RedirectionType # noqa: F401 from eden.cli.redirect import RedirectionType # noqa: F401
@ -181,12 +186,20 @@ class EdenInstance:
@property @property
def _config_variables(self) -> Dict[str, str]: def _config_variables(self) -> Dict[str, str]:
if os.name == "nt":
# We don't have user ids on Windows right now.
# We should update this code if and when we add user id support.
user_id = 0
user_name = "USERNAME"
else:
user_id = os.getuid()
user_name = "USER"
return ( return (
self._interpolate_dict self._interpolate_dict
if self._interpolate_dict is not None if self._interpolate_dict is not None
else { else {
"USER": os.environ.get("USER", ""), "USER": os.environ.get(user_name, ""),
"USER_ID": str(os.getuid()), "USER_ID": str(user_id),
"HOME": str(self._home_dir), "HOME": str(self._home_dir),
} }
) )
@ -449,6 +462,7 @@ Do you want to run `eden mount %s` instead?"""
if help_contents is not None: if help_contents is not None:
with help_path.open("w") as f: with help_path.open("w") as f:
f.write(help_contents) f.write(help_contents)
if os.name != "nt":
os.fchmod(f.fileno(), 0o444) os.fchmod(f.fileno(), 0o444)
def _create_client_dir_for_path(self, clients_dir: Path, path: str) -> Path: def _create_client_dir_for_path(self, clients_dir: Path, path: str) -> Path:
@ -850,6 +864,14 @@ class ConfigUpdater(object):
self.config[key] = value self.config[key] = value
def _acquire_lock(self) -> None: def _acquire_lock(self) -> None:
# Skipping locks on Windows for two reasons:
# First, locking the config file is not a strict requirement even on
# POSIX. Plus we don't have a similar flock implementation on Windows.
# We could make a locking scheme with LockFileEx(), but it would
# have different symentics than flock (For one, we can't unlink a
# locked file).
if os.name == "nt":
return
while True: while True:
self._lock_file = typing.cast(typing.TextIO, open(self._lock_path, "w+")) self._lock_file = typing.cast(typing.TextIO, open(self._lock_path, "w+"))
fcntl.flock(self._lock_file.fileno(), fcntl.LOCK_EX) fcntl.flock(self._lock_file.fileno(), fcntl.LOCK_EX)
@ -869,6 +891,8 @@ class ConfigUpdater(object):
continue continue
def _unlock(self) -> None: def _unlock(self) -> None:
if os.name == "nt":
return
assert self._lock_file is not None assert self._lock_file is not None
# Remove the file on disk before we unlock it. # Remove the file on disk before we unlock it.
# This way processes currently waiting in _acquire_lock() that already # This way processes currently waiting in _acquire_lock() that already