Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support git insteadOf config entries during import #267

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions test/list_ssh.repos
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
repositories:
vcstool:
type: git
url: [email protected]:dirk-thomas/vcstool.git
version: heads/master
3 changes: 3 additions & 0 deletions test/remotes_insteadof.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
=== ./vcstool (git) ===
origin https://github.com/dirk-thomas/vcstool.git (fetch)
origin https://github.com/dirk-thomas/vcstool.git (push)
38 changes: 36 additions & 2 deletions test/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
REPOS_FILE = os.path.join(os.path.dirname(__file__), 'list.repos')
REPOS_FILE_URL = file_uri_scheme + REPOS_FILE
REPOS2_FILE = os.path.join(os.path.dirname(__file__), 'list2.repos')
REPOS_SSH_FILE = os.path.join(os.path.dirname(__file__), 'list_ssh.repos')
TEST_WORKSPACE = os.path.join(
os.path.dirname(os.path.dirname(__file__)), 'test_workspace')

Expand Down Expand Up @@ -315,6 +316,36 @@ def test_import_url(self):
finally:
rmtree(workdir)

def test_import_insteadof(self):
"""
Imports an ssh repo with a ssh->https indexOf rule. Checks if remote was changed
"""
workdir = os.path.join(TEST_WORKSPACE, 'import-insteadof')
os.makedirs(workdir)

try:
# git doesn't make it easy to change the location of the global .gitconfig
# It will look for HOME/.gitconfig, so I have to override HOME and
# put a new gitconfig there. The thought of overwriting the user's .gitconfig
# scares me, so check/write the file manually
gitconfig_file = os.path.join(workdir, '.gitconfig')
self.assertFalse(os.path.exists(gitconfig_file))
with open(gitconfig_file, 'w') as f:
f.write('[url "https://github.com/"]\n\tinsteadOf = [email protected]:\n')

run_command(
'import', ['--input', REPOS_SSH_FILE, '.'],
subfolder='import-insteadof', envs={'HOME': workdir})

# Need the raw output to see if the ssh url was changed to https
output = run_command('remotes', subfolder='import-insteadof',
envs={'HOME': workdir}, raw_output=True)

expected = get_expected_output('remotes_insteadof')
self.assertEqual(output, expected)
finally:
rmtree(workdir)

def test_validate(self):
output = run_command(
'validate', ['--input', REPOS_FILE])
Expand Down Expand Up @@ -352,20 +383,23 @@ def test_status(self):
self.assertEqual(output, expected)


def run_command(command, args=None, subfolder=None):
def run_command(command, args=None, subfolder=None, envs=None, raw_output=False):
repo_root = os.path.dirname(os.path.dirname(__file__))
script = os.path.join(repo_root, 'scripts', 'vcs-' + command)
env = dict(os.environ)
env.update(
LANG='en_US.UTF-8',
PYTHONPATH=repo_root + os.pathsep + env.get('PYTHONPATH', ''))
if envs is not None:
env.update(envs)

cwd = TEST_WORKSPACE
if subfolder:
cwd = os.path.join(cwd, subfolder)
output = subprocess.check_output(
[sys.executable, script] + (args or []),
stderr=subprocess.STDOUT, cwd=cwd, env=env)
return adapt_command_output(output, cwd)
return output if raw_output else adapt_command_output(output, cwd)


def adapt_command_output(output, cwd=None):
Expand Down
59 changes: 33 additions & 26 deletions vcstool/clients/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
from shutil import which
import subprocess

from vcstool.executor import USE_COLOR
from vcstool.executor import USE_COLOR, ansi

from .vcs_base import VcsClientBase
from ..util import rmtree


class GitClient(VcsClientBase):

type = 'git'
_executable = None
_git_version = None
Expand Down Expand Up @@ -69,7 +68,7 @@ def export(self, command):
result_branch = self._run_command(cmd_branch)
if result_branch['returncode']:
result_branch['output'] = 'Could not determine ref: ' + \
result_branch['output']
result_branch['output']
return result_branch
branch_name = result_branch['output']
exact = branch_name == 'HEAD' # is detached
Expand All @@ -82,7 +81,7 @@ def export(self, command):
result_remote = self._run_command(cmd_remote)
if result_remote['returncode']:
result_remote['output'] = 'Could not determine ref: ' + \
result_remote['output']
result_remote['output']
return result_remote
branch_with_remote = result_remote['output']

Expand Down Expand Up @@ -122,7 +121,7 @@ def export(self, command):
result_ref = self._run_command(cmd_ref)
if result_ref['returncode']:
result_ref['output'] = 'Could not determine ref: ' + \
result_ref['output']
result_ref['output']
return result_ref
ref = result_ref['output']

Expand All @@ -131,7 +130,7 @@ def export(self, command):
result_remotes = self._run_command(cmd_remotes)
if result_remotes['returncode']:
result_remotes['output'] = 'Could not determine remotes: ' + \
result_remotes['output']
result_remotes['output']
return result_remotes
remotes = result_remotes['output'].splitlines()

Expand Down Expand Up @@ -215,11 +214,11 @@ def export(self, command):

def _get_remote_url(self, remote):
cmd_url = [
GitClient._executable, 'config', '--get', 'remote.%s.url' % remote]
GitClient._executable, 'ls-remote', '--get-url', '%s' % remote]
result_url = self._run_command(cmd_url)
if result_url['returncode']:
result_url['output'] = 'Could not determine remote url: ' + \
result_url['output']
result_url['output'] = 'Could not resolve url for remote %s: ' % remote + \
result_url['output']
return result_url

def import_(self, command):
Expand All @@ -231,6 +230,14 @@ def import_(self, command):
'returncode': 1
}

# Check if the url will be modified by insteadOf
resolved_cmd_url = self._get_remote_url(command.url)
if resolved_cmd_url['returncode']:
return resolved_cmd_url

if resolved_cmd_url['output'] != command.url:
command.url = resolved_cmd_url['output']

self._check_executable()
if GitClient.is_repository(self.path):
# verify that existing repository is the same
Expand Down Expand Up @@ -480,7 +487,7 @@ def _get_remote_urls(self):
result_remote = self._run_command(cmd_remote)
if result_remote['returncode']:
result_remote['output'] = 'Could not determine remotes: ' + \
result_remote['output']
result_remote['output']
return result_remote
remote_urls = []
cmd = result_remote['cmd']
Expand Down Expand Up @@ -517,7 +524,7 @@ def _check_version_type(self, url, version):
result = self._run_command(cmd)
if result['returncode']:
result['output'] = 'Could not determine ref type of version: ' + \
result['output']
result['output']
return result, None
if not result['output']:
result['version_type'] = 'hash'
Expand All @@ -533,7 +540,7 @@ def _check_version_type(self, url, version):
if refs[tag_ref] != refs[branch_ref]:
result['returncode'] = 1
result['output'] = 'The version ref is a branch as well as ' \
'tag but with different hashes'
'tag but with different hashes'
return result, None
if tag_ref in refs:
result['version_type'] = 'tag'
Expand Down Expand Up @@ -596,7 +603,7 @@ def pull(self, _command):
result_rev_parse = self._run_command(cmd_rev_parse)
if result_rev_parse['returncode']:
result_rev_parse['output'] = 'Could not determine ref: ' + \
result_rev_parse['output']
result_rev_parse['output']
return result_rev_parse
detached = result_rev_parse['output'] == 'HEAD'

Expand Down Expand Up @@ -682,7 +689,7 @@ def validate(self, command):
branches = []

for hash_and_ref in self._get_hash_ref_tuples(
result_ls_remote['output']
result_ls_remote['output']
):
hashes.append(hash_and_ref[0])

Expand All @@ -699,26 +706,26 @@ def validate(self, command):
version_type = 'ref'
version_name = command.version
elif (
command.version.startswith('heads/') and
command.version[6:] in branches
command.version.startswith('heads/') and
command.version[6:] in branches
):
version_type = 'branch'
version_name = command.version[6:]
elif (
command.version.startswith('tags/') and
command.version[5:] in tags
command.version.startswith('tags/') and
command.version[5:] in tags
):
version_type = 'tag'
version_name = command.version[5:]
elif (
command.version in branches and
command.version not in tags
command.version in branches and
command.version not in tags
):
version_type = 'branch'
version_name = command.version
elif (
command.version in tags and
command.version not in branches
command.version in tags and
command.version not in branches
):
version_type = 'tag'
version_name = command.version
Expand All @@ -729,8 +736,8 @@ def validate(self, command):
else:
cmd = result_ls_remote['cmd']
output = "Found git repository '%s' but " % command.url + \
'unable to verify non-branch / non-tag ref ' + \
"'%s' without cloning the repo" % command.version
'unable to verify non-branch / non-tag ref ' + \
"'%s' without cloning the repo" % command.version

return {
'cmd': cmd,
Expand All @@ -741,11 +748,11 @@ def validate(self, command):

cmd = result_ls_remote['cmd']
output = "Found git repository '%s' with %s '%s'" % \
(command.url, version_type, version_name)
(command.url, version_type, version_name)
else:
cmd = result_ls_remote['cmd']
output = "Found git repository '%s' with default branch" % \
command.url
command.url

return {
'cmd': cmd,
Expand Down