wrap: Initialize subprojects that are git submodules

This will benefit projects such as GNOME Recipes that prefer using
submodules over wraps because it's easier to maintain since git is
aware of it, and because it integrates with their existing
workflow. Without this, these projects have to manually initialize
the submodules which is completely unnecessary.

Closes https://github.com/mesonbuild/meson/issues/1449
pull/1516/head
Nirbheek Chauhan 8 years ago
parent fb809e79e5
commit a60d688973
  1. 12
      mesonbuild/interpreter.py
  2. 50
      mesonbuild/wrap/wrap.py

@ -1498,11 +1498,13 @@ class Interpreter(InterpreterBase):
raise InvalidCode('Recursive include of subprojects: %s.' % incpath) raise InvalidCode('Recursive include of subprojects: %s.' % incpath)
if dirname in self.subprojects: if dirname in self.subprojects:
return self.subprojects[dirname] return self.subprojects[dirname]
r = wrap.Resolver(os.path.join(self.build.environment.get_source_dir(), self.subproject_dir)) subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir)
resolved = r.resolve(dirname) r = wrap.Resolver(subproject_dir_abs)
if resolved is None: try:
msg = 'Subproject directory {!r} does not exist and cannot be downloaded.' resolved = r.resolve(dirname)
raise InterpreterException(msg.format(os.path.join(self.subproject_dir, dirname))) except RuntimeError as e:
msg = 'Subproject directory {!r} does not exist and cannot be downloaded:\n{}'
raise InterpreterException(msg.format(os.path.join(self.subproject_dir, dirname), e))
subdir = os.path.join(self.subproject_dir, resolved) subdir = os.path.join(self.subproject_dir, resolved)
os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True) os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True)
self.args_frozen = True self.args_frozen = True

@ -37,6 +37,13 @@ def build_ssl_context():
ctx.load_default_certs() ctx.load_default_certs()
return ctx return ctx
def quiet_git(cmd):
pc = subprocess.Popen(['git'] + cmd, stdout=subprocess.PIPE)
out, err = pc.communicate()
if pc.returncode != 0:
return False, err
return True, out
def open_wrapdburl(urlstring): def open_wrapdburl(urlstring):
global ssl_warning_printed global ssl_warning_printed
if has_ssl: if has_ssl:
@ -94,24 +101,31 @@ class Resolver:
def resolve(self, packagename): def resolve(self, packagename):
# Check if the directory is already resolved # Check if the directory is already resolved
dirname = Path(os.path.join(self.subdir_root, packagename)) dirname = Path(os.path.join(self.subdir_root, packagename))
subprojdir = os.path.join(*dirname.parts[-2:])
if dirname.is_dir(): if dirname.is_dir():
if (dirname / 'meson.build').is_file(): if (dirname / 'meson.build').is_file():
# The directory is there and has meson.build? Great, use it. # The directory is there and has meson.build? Great, use it.
return packagename return packagename
# Is the dir not empty and also not a git submodule dir that is # Is the dir not empty and also not a git submodule dir that is
# not checkout properly? Can't do anything, exception! # not checkout properly? Can't do anything, exception!
elif next(dirname.iterdir(), None) and not (dirname / '.git').is_file(): elif next(dirname.iterdir(), None) and not (dirname / '.git').is_file():
m = '{!r} is not empty and has no meson.build files' m = '{!r} is not empty and has no meson.build files'
raise RuntimeError(m.format(dirname)) raise RuntimeError(m.format(subprojdir))
elif dirname.exists(): elif dirname.exists():
m = '{!r} is not a directory, can not use as subproject' m = '{!r} already exists and is not a dir; cannot use as subproject'
raise RuntimeError(m.format(dirname)) raise RuntimeError(m.format(subprojdir))
dirname = str(dirname)
# Check if the subproject is a git submodule
if self.resolve_git_submodule(dirname):
return packagename
# Check if there's a .wrap file for this subproject # Check if there's a .wrap file for this subproject
fname = os.path.join(self.subdir_root, packagename + '.wrap') fname = os.path.join(self.subdir_root, packagename + '.wrap')
if not os.path.isfile(fname): if not os.path.isfile(fname):
# No wrap file with this name? Give up. # No wrap file with this name? Give up.
return None m = 'No {}.wrap found for {!r}'
raise RuntimeError(m.format(packagename, subprojdir))
p = PackageDefinition(fname) p = PackageDefinition(fname)
if p.type == 'file': if p.type == 'file':
if not os.path.isdir(self.cachedir): if not os.path.isdir(self.cachedir):
@ -123,9 +137,31 @@ class Resolver:
elif p.type == "hg": elif p.type == "hg":
self.get_hg(p) self.get_hg(p)
else: else:
raise RuntimeError('Unreachable code.') raise AssertionError('Unreachable code.')
return p.get('directory') return p.get('directory')
def resolve_git_submodule(self, dirname):
# Are we in a git repository?
ret, out = quiet_git(['rev-parse'])
if not ret:
return False
# Is `dirname` a submodule?
ret, out = quiet_git(['submodule', 'status', dirname])
if not ret:
return False
# Submodule has not been added, add it
if out.startswith(b'-'):
if subprocess.call(['git', 'submodule', 'update', dirname]) != 0:
return False
# Submodule was added already, but it wasn't populated. Do a checkout.
elif out.startswith(b' '):
if subprocess.call(['git', 'checkout', '.'], cwd=dirname):
return True
else:
m = 'Unknown git submodule output: {!r}'
raise AssertionError(m.format(out))
return True
def get_git(self, p): def get_git(self, p):
checkoutdir = os.path.join(self.subdir_root, p.get('directory')) checkoutdir = os.path.join(self.subdir_root, p.get('directory'))
revno = p.get('revision') revno = p.get('revision')

Loading…
Cancel
Save