kopia lustrzana https://github.com/jupyterhub/repo2docker
Mercurial optional
rodzic
96914545e1
commit
5bb586931b
|
@ -1,8 +1,39 @@
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import os
|
||||||
|
from distutils.util import strtobool
|
||||||
|
|
||||||
from .base import ContentProvider, ContentProviderException
|
from .base import ContentProvider, ContentProviderException
|
||||||
from ..utils import execute_cmd
|
from ..utils import execute_cmd
|
||||||
|
|
||||||
|
HG_EVOLVE_REQUIRED = strtobool(
|
||||||
|
os.environ.get("REPO2DOCKER_HG_EVOLVE_REQUIRED", "False")
|
||||||
|
)
|
||||||
|
|
||||||
|
if HG_EVOLVE_REQUIRED:
|
||||||
|
if "REPO2DOCKER_HG_REQUIRED" in os.environ:
|
||||||
|
HG_REQUIRED = strtobool(os.environ["REPO2DOCKER_HG_REQUIRED"])
|
||||||
|
if not HG_REQUIRED:
|
||||||
|
raise ValueError(
|
||||||
|
"Incompatible values for environment variables "
|
||||||
|
"REPO2DOCKER_HG_EVOLVE_REQUIRED=1 and REPO2DOCKER_HG_REQUIRED=0"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
HG_REQUIRED = True
|
||||||
|
else:
|
||||||
|
HG_REQUIRED = strtobool(os.environ.get("REPO2DOCKER_HG_REQUIRED", "False"))
|
||||||
|
|
||||||
|
|
||||||
|
def is_mercurial_available():
|
||||||
|
try:
|
||||||
|
subprocess.check_output(["hg", "version"])
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
if HG_REQUIRED and not is_mercurial_available():
|
||||||
|
raise RuntimeError("REPO2DOCKER_HG_REQUIRED but the command `hg` is not available")
|
||||||
|
|
||||||
|
|
||||||
class Mercurial(ContentProvider):
|
class Mercurial(ContentProvider):
|
||||||
"""Provide contents of a remote Mercurial repository."""
|
"""Provide contents of a remote Mercurial repository."""
|
||||||
|
@ -16,6 +47,8 @@ class Mercurial(ContentProvider):
|
||||||
stderr=subprocess.DEVNULL,
|
stderr=subprocess.DEVNULL,
|
||||||
)
|
)
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
|
# warning: if hg is not installed and `not HG_REQUIRED`,
|
||||||
|
# we return None even for a hg repo
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return {"repo": source, "ref": ref}
|
return {"repo": source, "ref": ref}
|
||||||
|
@ -26,7 +59,14 @@ class Mercurial(ContentProvider):
|
||||||
|
|
||||||
# make a clone of the remote repository
|
# make a clone of the remote repository
|
||||||
try:
|
try:
|
||||||
cmd = ["hg", "clone", repo, output_dir]
|
cmd = [
|
||||||
|
"hg",
|
||||||
|
"clone",
|
||||||
|
repo,
|
||||||
|
output_dir,
|
||||||
|
"--config",
|
||||||
|
"phases.publish=False",
|
||||||
|
]
|
||||||
if ref is not None:
|
if ref is not None:
|
||||||
# don't update so the clone will include an empty working
|
# don't update so the clone will include an empty working
|
||||||
# directory, the given ref will be updated out later
|
# directory, the given ref will be updated out later
|
||||||
|
@ -35,9 +75,9 @@ class Mercurial(ContentProvider):
|
||||||
yield line
|
yield line
|
||||||
|
|
||||||
except subprocess.CalledProcessError as error:
|
except subprocess.CalledProcessError as error:
|
||||||
msg = "Failed to clone repository from {repo}".format(repo=repo)
|
msg = f"Failed to clone repository from {repo}"
|
||||||
if ref is not None:
|
if ref is not None:
|
||||||
msg += " (ref {ref})".format(ref=ref)
|
msg += f" (ref {ref})"
|
||||||
msg += "."
|
msg += "."
|
||||||
raise ContentProviderException(msg) from error
|
raise ContentProviderException(msg) from error
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,29 @@ from tempfile import TemporaryDirectory
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from repo2docker.contentproviders import Mercurial
|
from repo2docker.contentproviders import Mercurial
|
||||||
|
from repo2docker.contentproviders.mercurial import (
|
||||||
|
HG_REQUIRED,
|
||||||
|
HG_EVOLVE_REQUIRED,
|
||||||
|
is_mercurial_available,
|
||||||
|
)
|
||||||
|
|
||||||
|
skip_if_no_hg = pytest.mark.skipif(
|
||||||
|
not HG_REQUIRED and not is_mercurial_available(),
|
||||||
|
reason="not HG_REQUIRED and Mercurial not available",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def is_evolve_available():
|
||||||
|
if not is_mercurial_available():
|
||||||
|
return False
|
||||||
|
output = subprocess.getoutput("hg version -v")
|
||||||
|
return " evolve " in output
|
||||||
|
|
||||||
|
|
||||||
|
EVOLVE_AVAILABLE = is_evolve_available()
|
||||||
|
|
||||||
|
if HG_EVOLVE_REQUIRED and not EVOLVE_AVAILABLE:
|
||||||
|
raise RuntimeError("HG_EVOLVE_REQUIRED and not EVOLVE_AVAILABLE")
|
||||||
|
|
||||||
|
|
||||||
def _add_content_to_hg(repo_dir):
|
def _add_content_to_hg(repo_dir):
|
||||||
|
@ -16,6 +39,14 @@ def _add_content_to_hg(repo_dir):
|
||||||
subprocess.check_call(["hg", "add", "test"], cwd=repo_dir)
|
subprocess.check_call(["hg", "add", "test"], cwd=repo_dir)
|
||||||
subprocess.check_call(["hg", "commit", "-m", "Test commit"], cwd=repo_dir)
|
subprocess.check_call(["hg", "commit", "-m", "Test commit"], cwd=repo_dir)
|
||||||
|
|
||||||
|
if EVOLVE_AVAILABLE:
|
||||||
|
subprocess.check_call(["hg", "topic", "test-topic"], cwd=repo_dir)
|
||||||
|
subprocess.check_call(
|
||||||
|
["hg", "commit", "-m", "Test commit in topic test-topic"],
|
||||||
|
cwd=repo_dir,
|
||||||
|
)
|
||||||
|
subprocess.check_call(["hg", "up", "default"], cwd=repo_dir)
|
||||||
|
|
||||||
|
|
||||||
def _get_node_id(repo_dir):
|
def _get_node_id(repo_dir):
|
||||||
"""Get repository's current commit node ID (currently SHA1)."""
|
"""Get repository's current commit node ID (currently SHA1)."""
|
||||||
|
@ -46,6 +77,7 @@ def hg_repo_with_content(hg_repo):
|
||||||
yield hg_repo, node_id
|
yield hg_repo, node_id
|
||||||
|
|
||||||
|
|
||||||
|
@skip_if_no_hg
|
||||||
def test_detect_mercurial(hg_repo_with_content, repo_with_content):
|
def test_detect_mercurial(hg_repo_with_content, repo_with_content):
|
||||||
mercurial = Mercurial()
|
mercurial = Mercurial()
|
||||||
assert mercurial.detect("this-is-not-a-directory") is None
|
assert mercurial.detect("this-is-not-a-directory") is None
|
||||||
|
@ -58,6 +90,7 @@ def test_detect_mercurial(hg_repo_with_content, repo_with_content):
|
||||||
assert mercurial.detect(hg_repo) == {"repo": hg_repo, "ref": None}
|
assert mercurial.detect(hg_repo) == {"repo": hg_repo, "ref": None}
|
||||||
|
|
||||||
|
|
||||||
|
@skip_if_no_hg
|
||||||
def test_clone(hg_repo_with_content):
|
def test_clone(hg_repo_with_content):
|
||||||
"""Test simple hg clone to a target dir"""
|
"""Test simple hg clone to a target dir"""
|
||||||
upstream, node_id = hg_repo_with_content
|
upstream, node_id = hg_repo_with_content
|
||||||
|
@ -72,9 +105,10 @@ def test_clone(hg_repo_with_content):
|
||||||
assert mercurial.content_id == node_id
|
assert mercurial.content_id == node_id
|
||||||
|
|
||||||
|
|
||||||
|
@skip_if_no_hg
|
||||||
def test_bad_ref(hg_repo_with_content):
|
def test_bad_ref(hg_repo_with_content):
|
||||||
"""
|
"""
|
||||||
Test trying to checkout a ref that doesn't exist
|
Test trying to update to a ref that doesn't exist
|
||||||
"""
|
"""
|
||||||
upstream, node_id = hg_repo_with_content
|
upstream, node_id = hg_repo_with_content
|
||||||
with TemporaryDirectory() as clone_dir:
|
with TemporaryDirectory() as clone_dir:
|
||||||
|
@ -82,3 +116,30 @@ def test_bad_ref(hg_repo_with_content):
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
for _ in Mercurial().fetch(spec, clone_dir):
|
for _ in Mercurial().fetch(spec, clone_dir):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
not HG_EVOLVE_REQUIRED and not EVOLVE_AVAILABLE,
|
||||||
|
reason="not HG_EVOLVE_REQUIRED and hg-evolve not available",
|
||||||
|
)
|
||||||
|
@skip_if_no_hg
|
||||||
|
def test_ref_topic(hg_repo_with_content):
|
||||||
|
"""
|
||||||
|
Test trying to update to a topic
|
||||||
|
"""
|
||||||
|
upstream, node_id = hg_repo_with_content
|
||||||
|
node_id = subprocess.Popen(
|
||||||
|
["hg", "identify", "-i", "-r", "topic(test-topic)"],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
cwd=upstream,
|
||||||
|
)
|
||||||
|
node_id = node_id.stdout.read().decode().strip()
|
||||||
|
|
||||||
|
with TemporaryDirectory() as clone_dir:
|
||||||
|
spec = {"repo": upstream, "ref": "test-topic"}
|
||||||
|
mercurial = Mercurial()
|
||||||
|
for _ in mercurial.fetch(spec, clone_dir):
|
||||||
|
pass
|
||||||
|
assert (Path(clone_dir) / "test").exists()
|
||||||
|
|
||||||
|
assert mercurial.content_id == node_id
|
||||||
|
|
Ładowanie…
Reference in New Issue