def test_subclass_equality(self): class FPStrategyA(DefaultFingerprintStrategy): pass class FPStrategyB(DefaultFingerprintStrategy): pass self.assertNotEqual(FPStrategyA(), DefaultFingerprintStrategy()) self.assertNotEqual(FPStrategyA(), FPStrategyB()) self.assertEqual(FPStrategyA(), FPStrategyA()) self.assertNotEqual(hash(FPStrategyA()), hash(DefaultFingerprintStrategy())) self.assertNotEqual(hash(FPStrategyA()), hash(FPStrategyB())) self.assertEqual(hash(FPStrategyA()), hash(FPStrategyA()))
def execute(self): dist_targets = self.context.targets(is_local_python_dist) build_graph = self.context.build_graph if dist_targets: with self.invalidated(dist_targets, fingerprint_strategy=DefaultFingerprintStrategy(), invalidate_dependents=True) as invalidation_check: for vt in invalidation_check.invalid_vts: if vt.target.dependencies: raise TargetDefinitionException( vt.target, 'The `dependencies` field is disallowed on `python_dist` targets. ' 'List any 3rd party requirements in the install_requirements argument ' 'of your setup function.' ) self._create_dist(vt.target, vt.results_dir) for vt in invalidation_check.all_vts: dist = self._get_whl_from_dir(os.path.join(vt.results_dir, 'dist')) req_lib_addr = Address.parse('{}__req_lib'.format(vt.target.address.spec)) self._inject_synthetic_dist_requirements(dist, req_lib_addr) # Make any target that depends on the dist depend on the synthetic req_lib, # for downstream consumption. for dependent in build_graph.dependents_of(vt.target.address): build_graph.inject_dependency(dependent, req_lib_addr)
def transitive_invalidation_hash(self, fingerprint_strategy=None): """ :param FingerprintStrategy fingerprint_strategy: optional fingerprint strategy to use to compute the fingerprint of a target :return: A fingerprint representing this target and all of its dependencies. The return value can be `None`, indicating that this target and all of its transitive dependencies did not contribute to the fingerprint, according to the provided FingerprintStrategy. :rtype: string """ fingerprint_strategy = fingerprint_strategy or DefaultFingerprintStrategy( ) if fingerprint_strategy not in self._cached_transitive_fingerprint_map: hasher = sha1() def dep_hash_iter(): for dep in self.dependencies: dep_hash = dep.transitive_invalidation_hash( fingerprint_strategy) if dep_hash is not None: yield dep_hash dep_hashes = sorted(list(dep_hash_iter())) for dep_hash in dep_hashes: hasher.update(dep_hash) target_hash = self.invalidation_hash(fingerprint_strategy) if target_hash is None and not dep_hashes: return None dependencies_hash = hasher.hexdigest()[:12] combined_hash = '{target_hash}.{deps_hash}'.format( target_hash=target_hash, deps_hash=dependencies_hash) self._cached_transitive_fingerprint_map[ fingerprint_strategy] = combined_hash return self._cached_transitive_fingerprint_map[fingerprint_strategy]
def transitive_invalidation_hash(self, fingerprint_strategy=None, depth=0): """ :API: public :param FingerprintStrategy fingerprint_strategy: optional fingerprint strategy to use to compute the fingerprint of a target :return: A fingerprint representing this target and all of its dependencies. The return value can be `None`, indicating that this target and all of its transitive dependencies did not contribute to the fingerprint, according to the provided FingerprintStrategy. :rtype: string """ if depth > self._MAX_RECURSION_DEPTH: # NB(zundel) without this catch, we'll eventually hit the python stack limit # RuntimeError: maximum recursion depth exceeded while calling a Python object raise self.RecursiveDepthError( "Max depth of {} exceeded.".format(self._MAX_RECURSION_DEPTH) ) fingerprint_strategy = fingerprint_strategy or DefaultFingerprintStrategy() direct = depth == 0 and fingerprint_strategy.direct(self) if direct: fingerprint_map = self._cached_direct_transitive_fingerprint_map else: fingerprint_map = self._cached_all_transitive_fingerprint_map if fingerprint_strategy not in fingerprint_map: hasher = sha1() def dep_hash_iter(): dep_list = fingerprint_strategy.dependencies(self) if direct else self.dependencies for dep in dep_list: try: if direct: dep_hash = dep.invalidation_hash(fingerprint_strategy) else: dep_hash = dep.transitive_invalidation_hash( fingerprint_strategy, depth=depth + 1 ) if dep_hash is not None: yield dep_hash except self.RecursiveDepthError as e: raise self.RecursiveDepthError( "{message}\n referenced from {spec}".format( message=e, spec=dep.address.spec ) ) dep_hashes = sorted(list(dep_hash_iter())) for dep_hash in dep_hashes: hasher.update(dep_hash.encode()) target_hash = self.invalidation_hash(fingerprint_strategy) if target_hash is None and not dep_hashes: return None dependencies_hash = hasher.hexdigest()[:12] combined_hash = "{target_hash}.{deps_hash}".format( target_hash=target_hash, deps_hash=dependencies_hash ) fingerprint_map[fingerprint_strategy] = combined_hash return fingerprint_map[fingerprint_strategy]
def execute(self): dist_targets = self.context.targets(self.filter_target) if dist_targets: with self.invalidated(dist_targets, fingerprint_strategy=DefaultFingerprintStrategy(), invalidate_dependents=True) as invalidation_check: interpreter = self.context.products.get_data(PythonInterpreter) for vt in invalidation_check.invalid_vts: if vt.target.dependencies: raise TargetDefinitionException( vt.target, 'The `dependencies` field is disallowed on `python_dist` targets. ' 'List any 3rd party requirements in the install_requirements argument ' 'of your setup function.' ) setup_req_dir = os.path.join(vt.results_dir, 'setup_requires_site') pythonpath = self._ensure_setup_requires_site_dir(dist_targets, interpreter, setup_req_dir) self._create_dist(vt.target, vt.results_dir, interpreter, pythonpath) local_wheel_products = self.context.products.get('local_wheels') for vt in invalidation_check.all_vts: dist = self._get_whl_from_dir(os.path.join(vt.results_dir, 'dist')) req_lib_addr = Address.parse('{}__req_lib'.format(vt.target.address.spec)) self._inject_synthetic_dist_requirements(dist, req_lib_addr) # Make any target that depends on the dist depend on the synthetic req_lib, # for downstream consumption. for dependent in self.context.build_graph.dependents_of(vt.target.address): self.context.build_graph.inject_dependency(dependent, req_lib_addr) local_wheel_products.add(vt.target, os.path.dirname(dist)).append(os.path.basename(dist))
def execute(self): dist_targets = self.context.targets(is_local_python_dist) built_dists = set() if dist_targets: with self.invalidated( dist_targets, fingerprint_strategy=DefaultFingerprintStrategy(), invalidate_dependents=True) as invalidation_check: for vt in invalidation_check.all_vts: if vt.valid: built_dists.add( self._get_whl_from_dir( os.path.join(vt.results_dir, 'dist'))) else: if vt.target.dependencies: raise TargetDefinitionException( vt.target, 'The `dependencies` field is disallowed on `python_dist` targets. List any 3rd ' 'party requirements in the install_requirements argument of your setup function.' ) built_dists.add( self._create_dist(vt.target, vt.results_dir)) self.context.products.register_data(self.PYTHON_DISTS, built_dists)
def invalidation_hash(self, fingerprint_strategy=None): fingerprint_strategy = fingerprint_strategy or DefaultFingerprintStrategy( ) fp_name = fingerprint_strategy.name() if fp_name not in self._cached_fingerprint_map: self._cached_fingerprint_map[ fp_name] = self.compute_invalidation_hash(fingerprint_strategy) return self._cached_fingerprint_map[fp_name]
def invalidation_hash(self, fingerprint_strategy=None): """ :API: public """ fingerprint_strategy = fingerprint_strategy or DefaultFingerprintStrategy() if fingerprint_strategy not in self._cached_fingerprint_map: self._cached_fingerprint_map[fingerprint_strategy] = self.compute_invalidation_hash(fingerprint_strategy) return self._cached_fingerprint_map[fingerprint_strategy]
def compute_invalidation_hash(self, fingerprint_strategy=None): """ :param FingerprintStrategy fingerprint_strategy: optional fingerprint strategy to use to compute the fingerprint of a target :return: a fingerprint representing this target (no dependencies) :rtype: string """ fingerprint_strategy = fingerprint_strategy or DefaultFingerprintStrategy() return fingerprint_strategy.fingerprint_target(self)
def transitive_invalidation_hash(self, fingerprint_strategy=None): fingerprint_strategy = fingerprint_strategy or DefaultFingerprintStrategy( ) fp_name = fingerprint_strategy.name() if fp_name not in self._cached_transitive_fingerprint_map: hasher = sha1() direct_deps = sorted(self.dependencies) for dep in direct_deps: hasher.update( dep.transitive_invalidation_hash(fingerprint_strategy)) target_hash = self.invalidation_hash(fingerprint_strategy) dependencies_hash = hasher.hexdigest()[:12] combined_hash = '{target_hash}.{deps_hash}'.format( target_hash=target_hash, deps_hash=dependencies_hash) self._cached_transitive_fingerprint_map[fp_name] = combined_hash return self._cached_transitive_fingerprint_map[fp_name]
def transitive_invalidation_hash(self, fingerprint_strategy=None): """ :param FingerprintStrategy fingerprint_strategy: optional fingerprint strategy to use to compute the fingerprint of a target :return: a fingerprint representing this target and all of its dependencies :rtype: string """ fingerprint_strategy = fingerprint_strategy or DefaultFingerprintStrategy( ) if fingerprint_strategy not in self._cached_transitive_fingerprint_map: hasher = sha1() direct_deps = sorted(self.dependencies) for dep in direct_deps: hasher.update( dep.transitive_invalidation_hash(fingerprint_strategy)) target_hash = self.invalidation_hash(fingerprint_strategy) dependencies_hash = hasher.hexdigest()[:12] combined_hash = '{target_hash}.{deps_hash}'.format( target_hash=target_hash, deps_hash=dependencies_hash) self._cached_transitive_fingerprint_map[ fingerprint_strategy] = combined_hash return self._cached_transitive_fingerprint_map[fingerprint_strategy]
def compute_invalidation_hash(self, fingerprint_strategy=None): fingerprint_strategy = fingerprint_strategy or DefaultFingerprintStrategy( ) return fingerprint_strategy.fingerprint_target(self)