aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorEli Schwartz <eschwartz@archlinux.org>2023-06-21 01:27:11 -0400
committerEli Schwartz <eschwartz@archlinux.org>2023-06-25 10:08:15 -0400
commitb05764b73e2e3df612f64a4c81b669e65220863d (patch)
tree845ddc38af14dab00d9890b82769a596fa12d9a4 /mesonbuild
parenta146ee6946b4d5cde8b4cd6460260aedc5b438d2 (diff)
downloadmeson-b05764b73e2e3df612f64a4c81b669e65220863d.zip
meson-b05764b73e2e3df612f64a4c81b669e65220863d.tar.gz
meson-b05764b73e2e3df612f64a4c81b669e65220863d.tar.bz2
mdist: consolidate facts about the current dist using a dataclass
And avoid passing variables around several functions just to finally get where they need to be. These function signatures were kind of ugly... Also the use of dataclasses makes a big chunk of this file now typed properly.
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/mdist.py118
1 files changed, 67 insertions, 51 deletions
diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py
index 779faa6..26c2a43 100644
--- a/mesonbuild/mdist.py
+++ b/mesonbuild/mdist.py
@@ -26,6 +26,7 @@ import tempfile
import hashlib
import typing as T
+from dataclasses import dataclass
from glob import glob
from pathlib import Path
from mesonbuild.environment import detect_ninja
@@ -36,6 +37,9 @@ from mesonbuild.wrap import wrap
from mesonbuild import mlog, build, coredata
from .scripts.meson_exe import run_exe
+if T.TYPE_CHECKING:
+ from .mesonlib import ExecutableSerialisation
+
archive_choices = ['gztar', 'xztar', 'zip']
archive_extension = {'gztar': '.tar.gz',
@@ -85,20 +89,32 @@ def is_hg(src_root):
return os.path.isdir(os.path.join(src_root, '.hg'))
+@dataclass
class Dist:
- def run_dist_scripts(self, src_root, bld_root, dist_root, dist_scripts, subprojects):
- assert os.path.isabs(dist_root)
+ dist_name: str
+ src_root: str
+ bld_root: str
+ dist_scripts: T.List[ExecutableSerialisation]
+ subprojects: T.Dict[str, str]
+ options: argparse.Namespace
+
+ def __post_init__(self):
+ self.dist_sub = os.path.join(self.bld_root, 'meson-dist')
+ self.distdir = os.path.join(self.dist_sub, self.dist_name)
+
+ def run_dist_scripts(self):
+ assert os.path.isabs(self.distdir)
env = {}
- env['MESON_DIST_ROOT'] = dist_root
- env['MESON_SOURCE_ROOT'] = src_root
- env['MESON_BUILD_ROOT'] = bld_root
- for d in dist_scripts:
- if d.subproject and d.subproject not in subprojects:
+ env['MESON_DIST_ROOT'] = self.distdir
+ env['MESON_SOURCE_ROOT'] = self.src_root
+ env['MESON_BUILD_ROOT'] = self.bld_root
+ for d in self.dist_scripts:
+ if d.subproject and d.subproject not in self.subprojects:
continue
- subdir = subprojects.get(d.subproject, '')
- env['MESON_PROJECT_DIST_ROOT'] = os.path.join(dist_root, subdir)
- env['MESON_PROJECT_SOURCE_ROOT'] = os.path.join(src_root, subdir)
- env['MESON_PROJECT_BUILD_ROOT'] = os.path.join(bld_root, subdir)
+ subdir = self.subprojects.get(d.subproject, '')
+ env['MESON_PROJECT_DIST_ROOT'] = os.path.join(self.distdir, subdir)
+ env['MESON_PROJECT_SOURCE_ROOT'] = os.path.join(self.src_root, subdir)
+ env['MESON_PROJECT_BUILD_ROOT'] = os.path.join(self.bld_root, subdir)
name = ' '.join(d.cmd_args)
print(f'Running custom dist script {name!r}')
try:
@@ -111,18 +127,18 @@ class Dist:
class GitDist(Dist):
- def git_root(self, src_root):
+ def git_root(self, dir_):
# Cannot use --show-toplevel here because git in our CI prints cygwin paths
# that python cannot resolve. Workaround this by taking parent of src_root.
- prefix = quiet_git(['rev-parse', '--show-prefix'], src_root, check=True)[1].strip()
+ prefix = quiet_git(['rev-parse', '--show-prefix'], dir_, check=True)[1].strip()
if not prefix:
- return Path(src_root)
+ return Path(dir_)
prefix_level = len(Path(prefix).parents)
- return Path(src_root).parents[prefix_level - 1]
+ return Path(dir_).parents[prefix_level - 1]
- def have_dirty_index(self, src_root):
+ def have_dirty_index(self):
'''Check whether there are uncommitted changes in git'''
- ret = subprocess.call(['git', '-C', src_root, 'diff-index', '--quiet', 'HEAD'])
+ ret = subprocess.call(['git', '-C', self.src_root, 'diff-index', '--quiet', 'HEAD'])
return ret == 1
def copy_git(self, src, distdir, revision='HEAD', prefix=None, subdir=None):
@@ -137,9 +153,9 @@ class GitDist(Dist):
t = tarfile.open(fileobj=f) # [ignore encoding]
t.extractall(path=distdir)
- def process_git_project(self, src_root, distdir, options):
- if self.have_dirty_index(src_root):
- handle_dirty_opt(msg_uncommitted_changes, options.allow_dirty)
+ def process_git_project(self, src_root, distdir):
+ if self.have_dirty_index():
+ handle_dirty_opt(msg_uncommitted_changes, self.options.allow_dirty)
if os.path.exists(distdir):
windows_proof_rmtree(distdir)
repo_root = self.git_root(src_root)
@@ -155,9 +171,9 @@ class GitDist(Dist):
self.copy_git(repo_root, tmp_distdir, subdir=str(subdir))
Path(tmp_distdir, subdir).rename(distdir)
windows_proof_rmtree(tmp_distdir)
- self.process_submodules(src_root, distdir, options)
+ self.process_submodules(src_root, distdir)
- def process_submodules(self, src, distdir, options):
+ def process_submodules(self, src, distdir):
module_file = os.path.join(src, '.gitmodules')
if not os.path.exists(module_file):
return
@@ -172,49 +188,48 @@ class GitDist(Dist):
mlog.warning(f'Submodule {subpath!r} is not checked out and cannot be added to the dist')
continue
elif status in {'+', 'U'}:
- handle_dirty_opt(f'Submodule {subpath!r} has uncommitted changes that will not be included in the dist tarball', options.allow_dirty)
+ handle_dirty_opt(f'Submodule {subpath!r} has uncommitted changes that will not be included in the dist tarball', self.options.allow_dirty)
self.copy_git(os.path.join(src, subpath), distdir, revision=sha1, prefix=subpath)
- def create_dist(self, dist_name, archives, src_root, bld_root, dist_sub, dist_scripts, subprojects, options):
- distdir = os.path.join(dist_sub, dist_name)
- self.process_git_project(src_root, distdir, options)
- for path in subprojects.values():
- sub_src_root = os.path.join(src_root, path)
- sub_distdir = os.path.join(distdir, path)
+ def create_dist(self, archives):
+ self.process_git_project(self.src_root, self.distdir)
+ for path in self.subprojects.values():
+ sub_src_root = os.path.join(self.src_root, path)
+ sub_distdir = os.path.join(self.distdir, path)
if os.path.exists(sub_distdir):
continue
if is_git(sub_src_root):
- self.process_git_project(sub_src_root, sub_distdir, options)
+ self.process_git_project(sub_src_root, sub_distdir)
else:
shutil.copytree(sub_src_root, sub_distdir)
- self.run_dist_scripts(src_root, bld_root, distdir, dist_scripts, subprojects)
+ self.run_dist_scripts()
output_names = []
for a in archives:
- compressed_name = distdir + archive_extension[a]
- shutil.make_archive(distdir, a, root_dir=dist_sub, base_dir=dist_name)
+ compressed_name = self.distdir + archive_extension[a]
+ shutil.make_archive(self.distdir, a, root_dir=self.dist_sub, base_dir=self.dist_name)
output_names.append(compressed_name)
- windows_proof_rmtree(distdir)
+ windows_proof_rmtree(self.distdir)
return output_names
class HgDist(Dist):
- def have_dirty_index(self, src_root):
+ def have_dirty_index(self):
'''Check whether there are uncommitted changes in hg'''
- out = subprocess.check_output(['hg', '-R', src_root, 'summary'])
+ out = subprocess.check_output(['hg', '-R', self.src_root, 'summary'])
return b'commit: (clean)' not in out
- def create_dist(self, dist_name, archives, src_root, bld_root, dist_sub, dist_scripts, options):
- if self.have_dirty_index(src_root):
- handle_dirty_opt(msg_uncommitted_changes, options.allow_dirty)
- if dist_scripts:
+ def create_dist(self, archives):
+ if self.have_dirty_index():
+ handle_dirty_opt(msg_uncommitted_changes, self.options.allow_dirty)
+ if self.dist_scripts:
mlog.warning('dist scripts are not supported in Mercurial projects')
- os.makedirs(dist_sub, exist_ok=True)
- tarname = os.path.join(dist_sub, dist_name + '.tar')
+ os.makedirs(self.dist_sub, exist_ok=True)
+ tarname = os.path.join(self.dist_sub, self.dist_name + '.tar')
xzname = tarname + '.xz'
gzname = tarname + '.gz'
- zipname = os.path.join(dist_sub, dist_name + '.zip')
+ zipname = os.path.join(self.dist_sub, self.dist_name + '.zip')
# Note that -X interprets relative paths using the current working
# directory, not the repository root, so this must be an absolute path:
# https://bz.mercurial-scm.org/show_bug.cgi?id=6267
@@ -223,8 +238,8 @@ class HgDist(Dist):
# be useful to link the tarball to the Mercurial revision for either
# manual inspection or in case any code interprets it for a --version or
# similar.
- subprocess.check_call(['hg', 'archive', '-R', src_root, '-S', '-t', 'tar',
- '-X', src_root + '/.hg[a-z]*', tarname])
+ subprocess.check_call(['hg', 'archive', '-R', self.src_root, '-S', '-t', 'tar',
+ '-X', self.src_root + '/.hg[a-z]*', tarname])
output_names = []
if 'xztar' in archives:
import lzma
@@ -237,7 +252,7 @@ class HgDist(Dist):
output_names.append(gzname)
os.unlink(tarname)
if 'zip' in archives:
- subprocess.check_call(['hg', 'archive', '-R', src_root, '-S', '-t', 'zip', zipname])
+ subprocess.check_call(['hg', 'archive', '-R', self.src_root, '-S', '-t', 'zip', zipname])
output_names.append(zipname)
return output_names
@@ -319,7 +334,6 @@ def run(options):
src_root = b.environment.source_dir
bld_root = b.environment.build_dir
priv_dir = os.path.join(bld_root, 'meson-private')
- dist_sub = os.path.join(bld_root, 'meson-dist')
dist_name = b.project_name + '-' + b.project_version
@@ -335,17 +349,19 @@ def run(options):
extra_meson_args.append('-Dwrap_mode=nodownload')
if is_git(src_root):
- project = GitDist()
- names = project.create_dist(dist_name, archives, src_root, bld_root, dist_sub, b.dist_scripts, subprojects, options)
+ cls = GitDist
elif is_hg(src_root):
if subprojects:
print('--include-subprojects option currently not supported with Mercurial')
return 1
- project = HgDist()
- names = project.create_dist(dist_name, archives, src_root, bld_root, dist_sub, b.dist_scripts, options)
+ cls = HgDist
else:
print('Dist currently only works with Git or Mercurial repos')
return 1
+
+ project = cls(dist_name, src_root, bld_root, b.dist_scripts, subprojects, options)
+ names = project.create_dist(archives)
+
if names is None:
return 1
rc = 0