def prefix_lock(self, spec): """Get a lock on a particular spec's installation directory. NOTE: The installation directory **does not** need to exist. Prefix lock is a byte range lock on the nth byte of a file. The lock file is ``spack.store.db.prefix_lock`` -- the DB tells us what to call it and it lives alongside the install DB. n is the sys.maxsize-bit prefix of the DAG hash. This makes likelihood of collision is very low AND it gives us readers-writer lock semantics with just a single lockfile, so no cleanup required. """ prefix = spec.prefix if prefix not in self._prefix_locks: self._prefix_locks[prefix] = Lock( self.prefix_lock_path, spec.dag_hash_bit_prefix(bit_length(sys.maxsize)), 1) return self._prefix_locks[prefix]
def __init__(self, spec): if not spec.concrete: raise ValueError("Can only build concrete specs!") # concrete spec that we are building self.spec = spec # dependencies that we still need to build self.deps = set(d.name for d in spec.dependencies()) # dictionary of read locks on dependencies self.dep_locks = {} # last checked time (note: None is less than everything) self.check_time = None # one-byte lock (in the single file) associated with the concrete spec. self.lock = Lock( LOCK_PATH, start=spec.dag_hash_bit_prefix(bit_length(sys.maxsize)), length=1, default_timeout=LOCK_TIMEOUT, )
def __init__(self, url_or_fetch_strategy, name=None, mirror_paths=None, keep=False, path=None, lock=True, search_fn=None): """Create a stage object. Parameters: url_or_fetch_strategy URL of the archive to be downloaded into this stage, OR a valid FetchStrategy. name If a name is provided, then this stage is a named stage and will persist between runs (or if you construct another stage object later). If name is not provided, then this stage will be given a unique name automatically. mirror_paths If provided, Stage will search Spack's mirrors for this archive at each of the provided relative mirror paths before using the default fetch strategy. keep By default, when used as a context manager, the Stage is deleted on exit when no exceptions are raised. Pass True to keep the stage intact even if no exceptions are raised. path If provided, the stage path to use for associated builds. lock True if the stage directory file lock is to be used, False otherwise. search_fn The search function that provides the fetch strategy instance. """ # TODO: fetch/stage coupling needs to be reworked -- the logic # TODO: here is convoluted and not modular enough. if isinstance(url_or_fetch_strategy, string_types): self.fetcher = fs.from_url_scheme(url_or_fetch_strategy) elif isinstance(url_or_fetch_strategy, fs.FetchStrategy): self.fetcher = url_or_fetch_strategy else: raise ValueError( "Can't construct Stage without url or fetch strategy") self.fetcher.set_stage(self) # self.fetcher can change with mirrors. self.default_fetcher = self.fetcher self.search_fn = search_fn # used for mirrored archives of repositories. self.skip_checksum_for_mirror = True self.srcdir = None # TODO: This uses a protected member of tempfile, but seemed the only # TODO: way to get a temporary name. It won't be the same as the # TODO: temporary stage area in _stage_root. self.name = name if name is None: self.name = stage_prefix + next(tempfile._get_candidate_names()) self.mirror_paths = mirror_paths # Use the provided path or construct an optionally named stage path. if path is not None: self.path = path else: self.path = os.path.join(get_stage_root(), self.name) # Flag to decide whether to delete the stage folder on exit or not self.keep = keep # File lock for the stage directory. We use one file for all # stage locks. See spack.database.Database.prefix_lock for # details on this approach. self._lock = None if lock: if self.name not in Stage.stage_locks: sha1 = hashlib.sha1(self.name.encode('utf-8')).digest() lock_id = prefix_bits(sha1, bit_length(sys.maxsize)) stage_lock_path = os.path.join(get_stage_root(), '.lock') Stage.stage_locks[self.name] = spack.util.lock.Lock( stage_lock_path, lock_id, 1) self._lock = Stage.stage_locks[self.name] # When stages are reused, we need to know whether to re-create # it. This marks whether it has been created/destroyed. self.created = False
def __init__( self, url_or_fetch_strategy, name=None, mirror_path=None, keep=False, path=None, lock=True, search_fn=None): """Create a stage object. Parameters: url_or_fetch_strategy URL of the archive to be downloaded into this stage, OR a valid FetchStrategy. name If a name is provided, then this stage is a named stage and will persist between runs (or if you construct another stage object later). If name is not provided, then this stage will be given a unique name automatically. mirror_path If provided, Stage will search Spack's mirrors for this archive at the mirror_path, before using the default fetch strategy. keep By default, when used as a context manager, the Stage is deleted on exit when no exceptions are raised. Pass True to keep the stage intact even if no exceptions are raised. """ # TODO: fetch/stage coupling needs to be reworked -- the logic # TODO: here is convoluted and not modular enough. if isinstance(url_or_fetch_strategy, string_types): self.fetcher = fs.from_url(url_or_fetch_strategy) elif isinstance(url_or_fetch_strategy, fs.FetchStrategy): self.fetcher = url_or_fetch_strategy else: raise ValueError( "Can't construct Stage without url or fetch strategy") self.fetcher.set_stage(self) # self.fetcher can change with mirrors. self.default_fetcher = self.fetcher self.search_fn = search_fn # used for mirrored archives of repositories. self.skip_checksum_for_mirror = True # TODO : this uses a protected member of tempfile, but seemed the only # TODO : way to get a temporary name besides, the temporary link name # TODO : won't be the same as the temporary stage area in tmp_root self.name = name if name is None: self.name = _stage_prefix + next(tempfile._get_candidate_names()) self.mirror_path = mirror_path # Try to construct here a temporary name for the stage directory # If this is a named stage, then construct a named path. if path is not None: self.path = path else: self.path = os.path.join(spack.paths.stage_path, self.name) # Flag to decide whether to delete the stage folder on exit or not self.keep = keep # File lock for the stage directory. We use one file for all # stage locks. See spack.database.Database.prefix_lock for # details on this approach. self._lock = None if lock: if self.name not in Stage.stage_locks: sha1 = hashlib.sha1(self.name.encode('utf-8')).digest() lock_id = prefix_bits(sha1, bit_length(sys.maxsize)) stage_lock_path = os.path.join(spack.paths.stage_path, '.lock') Stage.stage_locks[self.name] = spack.util.lock.Lock( stage_lock_path, lock_id, 1) self._lock = Stage.stage_locks[self.name] # When stages are reused, we need to know whether to re-create # it. This marks whether it has been created/destroyed. self.created = False
def __init__(self, url_or_fetch_strategy, name=None, mirror_path=None, keep=False, path=None, lock=True): """Create a stage object. Parameters: url_or_fetch_strategy URL of the archive to be downloaded into this stage, OR a valid FetchStrategy. name If a name is provided, then this stage is a named stage and will persist between runs (or if you construct another stage object later). If name is not provided, then this stage will be given a unique name automatically. mirror_path If provided, Stage will search Spack's mirrors for this archive at the mirror_path, before using the default fetch strategy. keep By default, when used as a context manager, the Stage is deleted on exit when no exceptions are raised. Pass True to keep the stage intact even if no exceptions are raised. """ # TODO: fetch/stage coupling needs to be reworked -- the logic # TODO: here is convoluted and not modular enough. if isinstance(url_or_fetch_strategy, basestring): self.fetcher = fs.from_url(url_or_fetch_strategy) elif isinstance(url_or_fetch_strategy, fs.FetchStrategy): self.fetcher = url_or_fetch_strategy else: raise ValueError( "Can't construct Stage without url or fetch strategy") self.fetcher.set_stage(self) # self.fetcher can change with mirrors. self.default_fetcher = self.fetcher # used for mirrored archives of repositories. self.skip_checksum_for_mirror = True # TODO : this uses a protected member of tempfile, but seemed the only # TODO : way to get a temporary name besides, the temporary link name # TODO : won't be the same as the temporary stage area in tmp_root self.name = name if name is None: self.name = _stage_prefix + next(tempfile._get_candidate_names()) self.mirror_path = mirror_path # Try to construct here a temporary name for the stage directory # If this is a named stage, then construct a named path. if path is not None: self.path = path else: self.path = join_path(spack.stage_path, self.name) # Flag to decide whether to delete the stage folder on exit or not self.keep = keep # File lock for the stage directory. We use one file for all # stage locks. See Spec.prefix_lock for details on this approach. self._lock = None if lock: if self.name not in Stage.stage_locks: sha1 = hashlib.sha1(self.name).digest() lock_id = prefix_bits(sha1, bit_length(sys.maxsize)) stage_lock_path = join_path(spack.stage_path, '.lock') Stage.stage_locks[self.name] = llnl.util.lock.Lock( stage_lock_path, lock_id, 1) self._lock = Stage.stage_locks[self.name]