Skip to content

Commit 6d557b8

Browse files
author
ajohns
committed
Merge branch 'issue_323'
# Conflicts: # src/rez/utils/_version.py # src/rezplugins/package_repository/filesystem.py
2 parents 42db059 + b89dedc commit 6d557b8

File tree

6 files changed

+147
-9
lines changed

6 files changed

+147
-9
lines changed

src/rez/build_process_.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,13 +189,23 @@ def create_build_context(self, variant, build_type, build_path):
189189

190190
requests_str = ' '.join(map(str, request))
191191
self._print("Resolving build environment: %s", requests_str)
192+
192193
if build_type == BuildType.local:
193194
packages_path = self.package.config.packages_path
194195
else:
195196
packages_path = self.package.config.nonlocal_packages_path
196197

198+
if self.package.config.is_overridden("package_filter"):
199+
from rez.package_filter import PackageFilterList
200+
201+
data = self.package.config.package_filter
202+
package_filter = PackageFilterList.from_pod(data)
203+
else:
204+
package_filter = None
205+
197206
context = ResolvedContext(request,
198207
package_paths=packages_path,
208+
package_filter=package_filter,
199209
building=True)
200210
if self.verbose:
201211
context.print_info()

src/rez/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,9 @@ def override(self, key, value):
388388
self.overrides[key] = value
389389
self._uncache(key)
390390

391+
def is_overridden(self, key):
392+
return (key in self.overrides)
393+
391394
def remove_override(self, key):
392395
"""Remove a setting override, if one exists."""
393396
keys = key.split('.')

src/rez/package_repository.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,14 @@ def iter_variants(self, package_resource):
141141
"""
142142
raise NotImplementedError
143143

144+
def pre_variant_install(self, variant_resource):
145+
"""Called before a variant is installed.
146+
147+
If any directories are created on disk for the variant to install into,
148+
this is called before that happens.
149+
"""
150+
pass
151+
144152
def install_variant(self, variant_resource, dry_run=False, overrides=None):
145153
"""Install a variant into this repository.
146154

src/rez/utils/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22

33
# Update this value to version up Rez. Do not place anything else in this file.
4-
_rez_version = "2.1.0"
4+
_rez_version = "2.2.0"
55

66

77
# Copyright 2013-2016 Allan Johns.

src/rezplugins/build_process/local.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Builds packages on local host
33
"""
4+
from rez.package_repository import package_repository_manager
45
from rez.build_process_ import BuildProcessHelper, BuildType
56
from rez.release_hook import ReleaseHookEvent
67
from rez.exceptions import BuildError, ReleaseError
@@ -96,10 +97,16 @@ def _build_variant_base(self, variant, build_type, install_path=None,
9697
install_path = install_path or self.package.config.local_packages_path
9798
variant_install_path = self.get_package_install_path(install_path)
9899
variant_build_path = self.build_path
100+
99101
if variant.subpath:
100102
variant_build_path = os.path.join(variant_build_path, variant.subpath)
101103
variant_install_path = os.path.join(variant_install_path, variant.subpath)
102104

105+
# inform package repo that a variant is about to be built/installed
106+
pkg_repo = package_repository_manager.get_repository(install_path)
107+
pkg_repo.pre_variant_install(variant.resource)
108+
109+
# create directories (build, install)
103110
if clean and os.path.exists(variant_build_path):
104111
shutil.rmtree(variant_build_path)
105112
if not os.path.exists(variant_build_path):

src/rezplugins/package_repository/filesystem.py

Lines changed: 118 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ def iter_packages(self):
7474

7575
# versioned packages
7676
for version_str in self._repository._get_version_dirs(self.path):
77-
7877
if _settings.check_package_definition_files:
7978
path = os.path.join(self.path, version_str)
8079
if not self._repository._get_file(path)[0]:
@@ -85,6 +84,7 @@ def iter_packages(self):
8584
location=self.location,
8685
name=self.name,
8786
version=version_str)
87+
8888
yield package
8989

9090

@@ -177,8 +177,6 @@ def _load_old_formats(self):
177177
pass
178178
return data
179179

180-
# should be static or classmethod, since it's passed as an arg to
181-
# load_from_file, which is memcached
182180
@staticmethod
183181
def _update_changelog(file_format, data):
184182
# this is to deal with older package releases. They can contain long
@@ -404,6 +402,8 @@ class FileSystemPackageRepository(PackageRepository):
404402
"file_lock_dir": Or(None, str),
405403
"package_filenames": [basestring]}
406404

405+
building_prefix = ".building"
406+
407407
@classmethod
408408
def name(cls):
409409
return "filesystem"
@@ -489,6 +489,24 @@ def file_lock_dir(self):
489489

490490
return dirname
491491

492+
def pre_variant_install(self, variant_resource):
493+
if not variant_resource.version:
494+
return
495+
496+
# create 'building' tagfile, this makes sure that a resolve doesn't
497+
# pick up this package if it doesn't yet have a package.py created.
498+
path = self.location
499+
500+
family_path = os.path.join(path, variant_resource.name)
501+
if not os.path.isdir(family_path):
502+
os.makedirs(family_path)
503+
504+
filename = self.building_prefix + str(variant_resource.version)
505+
filepath = os.path.join(family_path, filename)
506+
507+
with open(filepath, 'w'): # create empty file
508+
pass
509+
492510
def install_variant(self, variant_resource, dry_run=False, overrides=None):
493511
if variant_resource._repository is self:
494512
return variant_resource
@@ -549,6 +567,7 @@ def _get_family_dirs(self):
549567
dirs = []
550568
if not os.path.isdir(self.location):
551569
return dirs
570+
552571
for name in os.listdir(self.location):
553572
path = os.path.join(self.location, name)
554573
if os.path.isdir(path):
@@ -558,6 +577,7 @@ def _get_family_dirs(self):
558577
name_, ext_ = os.path.splitext(name)
559578
if ext_ in (".py", ".yaml") and is_valid_package_name(name_):
560579
dirs.append((name_, ext_[1:]))
580+
561581
return dirs
562582

563583
def _get_version_dirs__key(self, root):
@@ -569,14 +589,59 @@ def _get_version_dirs__key(self, root):
569589
key=_get_version_dirs__key,
570590
debug=config.debug_memcache)
571591
def _get_version_dirs(self, root):
572-
dirs = []
592+
593+
# simpler case if this test is on
594+
#
595+
if _settings.check_package_definition_files:
596+
dirs = []
597+
598+
for name in os.listdir(root):
599+
if name.startswith('.'):
600+
continue
601+
602+
path = os.path.join(root, name)
603+
if os.path.isdir(path):
604+
if not self._is_valid_package_directory(path):
605+
continue
606+
607+
dirs.append(name)
608+
return dirs
609+
610+
# with test off, we have to check for 'building' dirs, these have to be
611+
# tested regardless. Failed releases may cause 'building files' to be
612+
# left behind, so we need to clear these out also
613+
#
614+
dirs = set()
615+
building_dirs = set()
616+
617+
# find dirs and dirs marked as 'building'
573618
for name in os.listdir(root):
574619
if name.startswith('.'):
575-
continue
620+
if not name.startswith(self.building_prefix):
621+
continue
622+
623+
ver_str = name[len(self.building_prefix):]
624+
building_dirs.add(ver_str)
625+
576626
path = os.path.join(root, name)
577627
if os.path.isdir(path):
578-
dirs.append(name)
579-
return dirs
628+
dirs.add(name)
629+
630+
# check 'building' dirs for validity
631+
for name in building_dirs:
632+
if name not in dirs:
633+
continue
634+
635+
path = os.path.join(root, name)
636+
if not self._is_valid_package_directory(path):
637+
# package probably still being built
638+
dirs.remove(name)
639+
640+
return list(dirs)
641+
642+
# True if `path` contains package.py or similar
643+
def _is_valid_package_directory(self, path):
644+
return bool(self._get_file(path, "package")[0])
580645

581646
def _get_families(self):
582647
families = []
@@ -593,6 +658,7 @@ def _get_families(self):
593658
name=name,
594659
ext=ext)
595660
families.append(family)
661+
596662
return families
597663

598664
def _get_family(self, name):
@@ -772,7 +838,7 @@ def _create_variant(self, variant, dry_run=False, overrides=None):
772838
package_data["config"] = parent_package._data.get("config")
773839
package_data.pop("base", None)
774840

775-
# create version dir and write out the new package definition file
841+
# create version dir if it doesn't already exist
776842
family_path = os.path.join(self.location, variant.name)
777843
if variant.version:
778844
path = os.path.join(family_path, str(variant.version))
@@ -792,9 +858,27 @@ def _create_variant(self, variant, dry_run=False, overrides=None):
792858

793859
package_file = ".".join([package_filename, package_extension])
794860
filepath = os.path.join(path, package_file)
861+
795862
with open_file_for_write(filepath) as f:
796863
dump_package_data(package_data, buf=f, format_=package_format)
797864

865+
# delete the tmp 'building' file.
866+
if variant.version:
867+
filename = self.building_prefix + str(variant.version)
868+
filepath = os.path.join(family_path, filename)
869+
if os.path.exists(filepath):
870+
try:
871+
os.remove(filepath)
872+
except:
873+
pass
874+
875+
# delete other stale building files; previous failed releases may have
876+
# left some around
877+
try:
878+
self._delete_stale_build_tagfiles(family_path)
879+
except:
880+
pass
881+
798882
# touch the family dir, this keeps memcached resolves updated properly
799883
os.utime(family_path, None)
800884

@@ -816,6 +900,32 @@ def _create_variant(self, variant, dry_run=False, overrides=None):
816900
raise RezSystemError("Internal failure - expected installed variant")
817901
return new_variant
818902

903+
def _delete_stale_build_tagfiles(self, family_path):
904+
now = time.time()
905+
906+
for name in os.listdir(family_path):
907+
if not name.startswith(self.building_prefix):
908+
continue
909+
910+
tagfilepath = os.path.join(family_path, name)
911+
ver_str = name[len(self.building_prefix):]
912+
pkg_path = os.path.join(family_path, ver_str)
913+
914+
if os.path.exists(pkg_path):
915+
# build tagfile not needed if package is valid
916+
if self._is_valid_package_directory(pkg_path):
917+
os.remove(tagfilepath)
918+
continue
919+
else:
920+
# remove tagfile if pkg is gone. Delete only tagfiles over a certain
921+
# age, otherwise might delete a tagfile another process has created
922+
# just before it created the package directory.
923+
st = os.stat(tagfilepath)
924+
age = now - st.st_mtime
925+
926+
if age > 3600:
927+
os.remove(tagfilepath)
928+
819929

820930
def register_plugin():
821931
return FileSystemPackageRepository

0 commit comments

Comments
 (0)