rename ghstack.eden_shell to ghstack.sapling_shell

Reviewed By: muirdm

Differential Revision: D40707034

fbshipit-source-id: 824b43da89442c16730b4802c578b1165d3fdffa
This commit is contained in:
Michael Bolin 2022-10-26 16:53:42 -07:00 committed by Facebook GitHub Bot
parent f141c18eeb
commit e768bf69b5
11 changed files with 62 additions and 59 deletions

View File

@ -19,10 +19,10 @@ import ghstack
import ghstack.action
import ghstack.checkout
import ghstack.config
import ghstack.eden_shell
import ghstack.github_real
import ghstack.land
import ghstack.logs
import ghstack.sapling_shell
import ghstack.submit
import ghstack.unlink
@ -217,7 +217,7 @@ def _create_ghstack_context(ui):
ghstack.logs.rotate()
conf = ghstack.config.read_config()
sh = ghstack.eden_shell.EdenShell(conf=conf, sapling_cli=cli)
sh = ghstack.sapling_shell.SaplingShell(conf=conf, sapling_cli=cli)
github = ghstack.github_real.RealGitHubEndpoint(
oauth_token=conf.github_oauth,
proxy=conf.proxy,

View File

@ -1,3 +1,3 @@
# Because this is a fork, it is not clear what an appropriate "version" is, but
# it should at least be something distinct from the official "0.6.0" version.
__version__ = "0.6.0.eden"
__version__ = "0.6.0.sapling"

View File

@ -139,14 +139,19 @@ def create_shell(conf: ghstack.config.Config) -> ghstack.shell.Shell:
import pathlib
cwd = pathlib.Path(os.getcwd())
candidates = [cwd] + list(pathlib.Path(os.getcwd()).parents)
sapling_dotdir_candidates = [
# @fb-only
'.sl',
]
for c in candidates:
git_dir = c.joinpath('.git')
if git_dir.is_dir():
break
eden_dir = c.joinpath('.hg')
if eden_dir.is_dir():
import ghstack.eden_shell
return ghstack.eden_shell.EdenShell(conf=conf)
for dotdir in sapling_dotdir_candidates:
sapling_dir = c.joinpath(dotdir)
if sapling_dir.is_dir():
import ghstack.sapling_shell
return ghstack.sapling_shell.SaplingShell(conf=conf)
import ghstack.shell
return ghstack.shell.Shell()

View File

@ -1,9 +1,9 @@
import logging
import re
import ghstack.eden_shell
import ghstack.github
import ghstack.github_utils
import ghstack.sapling_shell
import ghstack.shell
@ -32,14 +32,14 @@ def main(pull_request: str,
# TODO: Handle remotes correctly too (so this subsumes hub)
if isinstance(sh, ghstack.eden_shell.EdenShell):
if isinstance(sh, ghstack.sapling_shell.SaplingShell):
repo_id = repository["id"]
oid = ghstack.github_utils.get_commit_and_tree_for_ref(
github=github,
repo_id=repo_id,
ref=orig_ref,
)['commit']
sh.run_eden_command("update", oid)
sh.run_sapling_command("update", oid)
else:
sh.git("fetch", "--prune", remote_name)
sh.git("checkout", remote_name + "/" + orig_ref)

View File

@ -1,6 +0,0 @@
import ghstack.eden_shell
import ghstack.shell
def is_eden_working_copy(sh: ghstack.shell.Shell) -> bool:
return isinstance(sh, ghstack.eden_shell.EdenShell)

View File

@ -1,10 +1,9 @@
import re
import ghstack.eden
import ghstack.eden_shell
import ghstack.git
import ghstack.github
import ghstack.github_utils
import ghstack.sapling_shell
import ghstack.shell
from ghstack.ghs_types import GitCommitHash
@ -15,9 +14,9 @@ def main(pull_request: str,
sh: ghstack.shell.Shell,
github_url: str) -> None:
import ghstack
if isinstance(sh, ghstack.eden_shell.EdenShell):
import ghstack.eden_land
return ghstack.eden_land.main(pull_request, remote_name, github, sh, github_url)
if isinstance(sh, ghstack.sapling_shell.SaplingShell):
import ghstack.sapling_land
return ghstack.sapling_land.main(pull_request, remote_name, github, sh, github_url)
# We land the entire stack pointed to by a URL.
# Local state is ignored; PR is source of truth

View File

@ -1,16 +1,16 @@
import json
import re
import ghstack.eden_shell
import ghstack.github
import ghstack.github_utils
import ghstack.sapling_shell
from ghstack.ghs_types import GitCommitHash
def main(pull_request: str,
remote_name: str,
github: ghstack.github.GitHubEndpoint,
sh: ghstack.eden_shell.EdenShell,
sh: ghstack.sapling_shell.SaplingShell,
github_url: str) -> None:
"""The general approach to land is:
@ -47,9 +47,9 @@ def main(pull_request: str,
)['commit']
# Do a `pull` so we have the latest commit for the default branch locally.
sh.run_eden_command("pull")
default_branch_oid = sh.run_eden_command("log", "-T", "{node}", "-r", default_branch, "--limit", "1")
base = sh.run_eden_command("log", "-T", "{node}", "-r", f"ancestor({orig_oid}, {default_branch_oid})")
sh.run_sapling_command("pull")
default_branch_oid = sh.run_sapling_command("log", "-T", "{node}", "-r", default_branch, "--limit", "1")
base = sh.run_sapling_command("log", "-T", "{node}", "-r", f"ancestor({orig_oid}, {default_branch_oid})")
stack = ghstack.git.parse_header(
# pyre-ignore[6]
@ -74,7 +74,7 @@ def main(pull_request: str,
# Rebase each commit in the stack onto the default branch.
rebase_base = default_branch_oid
for s in stack:
stdout = sh.run_eden_command("rebase", "--keep", "-s", s.oid, "-d", rebase_base, "-q", "-T", "{nodechanges|json}")
stdout = sh.run_sapling_command("rebase", "--keep", "-s", s.oid, "-d", rebase_base, "-q", "-T", "{nodechanges|json}")
# If there is no output, it appears that '""' is returned as opposed
# to '{}', which is a little weird...
if not stdout or stdout == '""':
@ -107,7 +107,7 @@ def main(pull_request: str,
ghstack.github_utils.update_ref(github=github, repo_id=repo_id, ref=base_ref, target_ref=head_ref)
# All good! Push!
sh.run_eden_command("push", "--rev", rebase_base, "--to", default_branch)
sh.run_sapling_command("push", "--rev", rebase_base, "--to", default_branch)
# Delete the branches
for orig_ref in stack_orig_refs:

View File

@ -9,7 +9,7 @@ from ghstack.shell import _SHELL_RET
WILDCARD_ARG = {}
class EdenShell(ghstack.shell.Shell):
class SaplingShell(ghstack.shell.Shell):
def __init__(self,
conf: ghstack.config.Config,
quiet: bool = False,
@ -20,13 +20,21 @@ class EdenShell(ghstack.shell.Shell):
self.conf = conf
self.sapling_cli = sapling_cli
self.git_dir = self._run_eden_command([
self.git_dir = self._run_sapling_command([
'debugshell',
'-c',
'print(repo.svfs.join(repo.svfs.readutf8("gitdir")))',
])
logging.debug(f"--git-dir set to: {self.git_dir}")
def is_git(self) -> bool:
"""Whether this shell corresponds to a Git working copy."""
return False
def is_sapling(self) -> bool:
"""Whether this shell corresponds to a Sapling working copy."""
return True
def git(self, *_args: str, **kwargs: Any # noqa: F811
) -> _SHELL_RET:
args = list(_args)
@ -34,7 +42,7 @@ class EdenShell(ghstack.shell.Shell):
if match_args(["remote", "get-url", remote_name], args):
return self._get_origin()
elif match_args(["fetch", "--prune"], args):
raise ValueError(f"unexpected use of `git fetch` in EdenShell: {' '.join(args)}")
raise ValueError(f"unexpected use of `git fetch` in SaplingShell: {' '.join(args)}")
elif match_args(["merge-base", WILDCARD_ARG, "HEAD"], args):
# remote is probably "origin/main", which we need to convert to
# "main" to use with the `log` subcommand.
@ -42,13 +50,13 @@ class EdenShell(ghstack.shell.Shell):
index = remote.rfind('/')
if index != -1:
remote = remote[(index+1):]
return self._run_eden_command(["log", "-T", "{node}", "-r", f"ancestor(., {remote})"])
return self._run_sapling_command(["log", "-T", "{node}", "-r", f"ancestor(., {remote})"])
elif match_args(["push", remote_name], args):
if len(args) == 2:
raise ValueError(f"expected more args: {args}")
args[1] = self._get_origin()
elif match_args(["reset"], args):
raise ValueError(f"unexpected use of `git reset` in EdenShell: {' '.join(args)}")
raise ValueError(f"unexpected use of `git reset` in SaplingShell: {' '.join(args)}")
git_args = self._rewrite_args(args)
full_args = ["--git-dir", self.git_dir] + git_args
@ -61,7 +69,7 @@ class EdenShell(ghstack.shell.Shell):
# not be able to resolve arguments like HEAD, so we must resolve those
# to a full hash before running Git.
if 'HEAD' in args:
top = self._run_eden_command(['log', '-r', 'max(descendants(.))', '-T', '{node}'])
top = self._run_sapling_command(['log', '-r', 'max(descendants(.))', '-T', '{node}'])
for index, arg in enumerate(args):
if arg == 'HEAD':
args[index] = top
@ -70,12 +78,12 @@ class EdenShell(ghstack.shell.Shell):
def _get_origin(self):
# This should be good enough, right???
return self._run_eden_command(["config", "paths.default"])
return self._run_sapling_command(["config", "paths.default"])
def run_eden_command(self, *args: str) -> str:
return self._run_eden_command(list(args))
def run_sapling_command(self, *args: str) -> str:
return self._run_sapling_command(list(args))
def _run_eden_command(self, args: List[str]) -> str:
def _run_sapling_command(self, args: List[str]) -> str:
env = dict(os.environ)
env["SL_AUTOMATION"] = "true"
full_args = [self.sapling_cli] + args
@ -85,7 +93,7 @@ class EdenShell(ghstack.shell.Shell):
return self._maybe_rstrip(stdout)
def rewrite_commit_message(self, rev: str, commit_msg: str) -> Dict[str, str]:
stdout = self.run_eden_command(
stdout = self.run_sapling_command(
"metaedit", "-q", "-T", "{nodechanges|json}", "-r", rev, "-m", commit_msg)
# Note that updates will look something like:
#

View File

@ -82,6 +82,14 @@ class Shell(object):
self.testing = testing
self.testing_time = 1112911993
def is_git(self) -> bool:
"""Whether this shell corresponds to a Git working copy."""
return True
def is_sapling(self) -> bool:
"""Whether this shell corresponds to a Sapling working copy."""
return False
def sh(self, *args: str, # noqa: C901
env: Optional[Dict[str, str]] = None,
stderr: _HANDLE = None,

View File

@ -6,7 +6,6 @@ from typing import Final, List, NamedTuple, Optional, Set, Tuple
import ghstack
import ghstack.diff
import ghstack.eden
import ghstack.git
import ghstack.github
import ghstack.github_utils
@ -158,8 +157,7 @@ def main(*,
repo_id = repo["id"]
default_branch = repo["default_branch"]
is_eden = ghstack.eden.is_eden_working_copy(sh)
if not is_eden:
if sh.is_git():
sh.git("fetch", "--prune", remote_name)
base = GitCommitHash(sh.git("merge-base", f"{remote_name}/{default_branch}", "HEAD"))
@ -197,8 +195,7 @@ def main(*,
draft=draft,
stack=list(reversed(stack)),
github_url=github_url,
remote_name=remote_name,
is_eden=is_eden)
remote_name=remote_name)
submitter.prepare_updates()
submitter.push_updates()
@ -313,9 +310,6 @@ class Submitter(object):
# Name of the upstream remote (normally origin)
remote_name: str
# True if ghstack is operating in an Eden checkout.
is_eden: bool
def __init__(
self,
github: ghstack.github.GitHubEndpoint,
@ -336,8 +330,7 @@ class Submitter(object):
no_skip: bool,
draft: bool,
github_url: str,
remote_name: str,
is_eden: bool):
remote_name: str):
self.github = github
self.sh = sh
self.username = username
@ -361,7 +354,6 @@ class Submitter(object):
self.draft = draft
self.github_url = github_url
self.remote_name = remote_name
self.is_eden = is_eden
def _default_title_and_body(self, commit: ghstack.diff.Diff,
old_pr_body: Optional[str]
@ -666,7 +658,7 @@ Since we cannot proceed, ghstack will abort now.
"""
Process a diff that has an existing upload to GitHub.
"""
# TODO: Special-case is_eden.
# TODO: Special-case Sapling.
commit = elab_commit.diff
username = elab_commit.username
@ -897,7 +889,7 @@ Since we cannot proceed, ghstack will abort now.
ancestors are unaffected and no surgery needs to be done on `self.stack`.
In this case, the `stack_index` argument is ignored.
"""
if isinstance(self.sh, ghstack.eden_shell.EdenShell):
if isinstance(self.sh, ghstack.sapling_shell.SaplingShell):
commit = self.stack[stack_index]
# In Eden, update the commit message for the user's existing commit,
# but avoid creating a local head for the corresponding /orig
@ -986,7 +978,7 @@ Since we cannot proceed, ghstack will abort now.
# In Eden, updates should happen via `hg metaedit` without doing
# `hg update`, so there should be no reason to run something like
# `git reset --soft`.
if not self.is_eden:
if self.sh.is_git():
# fix the HEAD pointer
self.sh.git("reset", "--soft", self.base_orig)
@ -1108,7 +1100,7 @@ Since we cannot proceed, ghstack will abort now.
def run_pre_ghstack_hook(sh: ghstack.shell.Shell, base_commit: str, top_commit: str) -> None:
"""If a `pre-ghstack` git hook is configured, run it."""
if isinstance(sh, ghstack.eden_shell.EdenShell):
if isinstance(sh, ghstack.sapling_shell.SaplingShell):
hooks_path = os.path.join(sh.git_dir, 'hooks')
else:
default_hooks_path = os.path.join(sh.git("rev-parse", "--show-toplevel"), ".git/hooks")

View File

@ -4,7 +4,6 @@ import textwrap
from dataclasses import dataclass
from typing import List, Optional, Set
import ghstack.eden
import ghstack.diff
import ghstack.git
import ghstack.github
@ -76,8 +75,6 @@ def main(*,
"current stack; these commits are not:\n{}"
.format("\n".join(invalid_commits)))
is_eden = ghstack.eden.is_eden_working_copy(sh)
# Run the interactive rebase. Don't start rewriting until we
# hit the first commit that needs it.
head = base
@ -102,7 +99,7 @@ def main(*,
logging.debug("-- edited commit_msg:\n{}".format(
textwrap.indent(commit_msg, ' ')))
if isinstance(sh, ghstack.eden_shell.EdenShell):
if isinstance(sh, ghstack.sapling_shell.SaplingShell):
# After rewriting the commit message via metaedit, update the
# hashes for the desecendant commits.
mappings = sh.rewrite_commit_message(commit_id, commit_msg)
@ -138,7 +135,7 @@ def main(*,
"-p", head,
input=commit_msg))
if not is_eden:
if sh.is_git():
sh.git('reset', '--soft', head)
logging.info("""