def _mutator(key, val): nonlocal drefs, rrefs if isrref(val): rrefs.append(RRef(val)) elif isdref(val): drefs.append(DRef(val)) return val
def _cfgpathof(s) -> Path: if isrref(s): return store_cfgpath(rref2dref(RRef(s))) elif isdref(s): return store_cfgpath(DRef(s)) else: return store_cfgpath(instantiate(s).dref)
def shell(r: Union[Build, RRef, DRef, Path, str, None] = None) -> None: """ Open the Unix Shell in the directory associated with the argument passed. Path to the shell executable is read from the `SHELL` environment variable, defaulting to `/bin/sh`. If `r` is None, open the shell in the root of the Pylightnix storage. The function is expected to be run in REPL Python shells like IPython. """ cwd: str if r is None: import pylightnix.core cwd = pylightnix.core.PYLIGHTNIX_STORE elif isrref(r): cwd = store_rref2path(RRef(r)) elif isdref(r): cwd = store_dref2path(DRef(r)) elif isinstance(r, Build): assert len(r.outgroups) > 0, ( "Shell function requires at least one build output path to be defined" ) cwd = r.outgroups[0][Tag('out')] elif isdir(r): cwd = str(r) elif isfile(r): cwd = dirname(str(r)) else: assert False, ( f"Expecting `RRef`, `DRef`, a directory or file path (either a string or " f"a `Path`), or None. Got {r}") Popen([environ.get('SHELL', '/bin/sh')], shell=False, cwd=cwd).wait()
def dref(self)->DRef: """ Check that the current value of Lens is a `DRef` and return it """ r=lens_repr(self,'dref') v=traverse(self, r) if isdref(v): return DRef(v) elif isrref(v): return rref2dref(v) else: assert False, f"Lens {r} expected a DRef-like object, got '{v}'"
def lsref(r: Union[RRef, DRef]) -> List[str]: """ List the contents of `r`. For [DRefs](#pylightnix.types.DRef), return realization hashes. For [RRefs](#pylightnix.types.RRef), list artifact files. """ if isrref(r): return list(lsrref(RRef(r))) elif isdref(r): return list(lsdref_(DRef(r))) else: assert False, f"Invalid reference {r}"
def store_config(r: Union[DRef, RRef], S=None) -> RConfig: """ Read the [Config](#pylightnix.types.Config) of the derivation and [resolve](#pylightnix.core.config_substitutePromises) it from promises and claims. """ assert isrref(r) or isdref(r), ( f"Invalid reference '{r}'. Expected either RRef or DRef.") if isrref(r): dref = rref2dref(RRef(r)) else: dref = DRef(r) return config_substitutePromises(store_config_(dref, S), dref)
def path2dref(p: Path) -> Optional[DRef]: """ Takes either a system path of some realization in the Pylightnix storage or a symlink pointing to such path. Return a `DRef` which corresponds to this path. Note: `path2dref` operates on `p` symbolically. It doesn't actually check the presence of such an object in storage """ if islink(p): p = Path(readlink(p)) _, dref_part = split(p) dref = DRef('dref:' + dref_part) return dref if isdref(dref) else None
def rmref(r: Union[RRef, DRef]) -> None: """ Forcebly remove a reference from the storage. Removing [DRefs](#pylightnix.types.DRef) also removes all their realizations. Currently Pylightnix makes no attempts to synchronize an access to the storage. In scenarious involving parallelization, users are expected to take care of possible race conditions. """ if isrref(r): dirrm(store_rref2path(RRef(r))) elif isdref(r): dirrm(store_dref2path(DRef(r))) else: assert False, f"Invalid reference {r}"
def path2rref(p: Path) -> Optional[RRef]: """ Takes either a system path of some realization in the Pylightnix storage or a symlink pointing to such path. Return `RRef` which corresponds to this path. Note: `path2rref` operates on `p` symbolically. It doesn't actually check the presence of such an object in storage """ if islink(p): p = Path(readlink(p)) head, h1 = split(p) _, dref_part = split(head) dref = DRef('dref:' + dref_part) if not isdref(dref): return None h2, nm = undref(dref) return mkrref(HashPart(h1), HashPart(h2), mkname(nm))
def val2rref(v:Any, ctx:LensContext)->RRef: S=ctx.storage if isdref(v): dref=DRef(v) context=ctx.context if context is not None: if dref in context: rgs=context_deref(context, dref, S) assert len(rgs)==1, "Lens doesn't support multirealization dependencies" return rgs[0][Tag('out')] else: assert False, f"Can't convert {dref} into RRef because it is not in context" else: assert False, f"Lens couldn't resolve '{dref}' without a context" elif isinstance(v,Closure): return val2rref(v.dref, ctx) else: assert isrref(v), f"Lens expected RRef, but got '{v}'" return RRef(v)
def val2dict(v:Any, ctx:LensContext)->Optional[dict]: """ Return the `dict` representation of the Lens value, if possible. Getting the dictionary allows for creating new lenses """ S:SPath=ctx.storage if isdref(v): return config_dict(store_config(DRef(v), S)) elif isrref(v): return config_dict(store_config(rref2dref(RRef(v)),S)) elif isrefpath(v): j=tryreadjson(val2path(v, ctx)) assert j is not None, f"RefPath {v} doesn't belong to a valid JSON file" assert isinstance(j, dict), f"A file with RefPath {v} doesn't contain valid JSON dict" return j elif isinstance(v,Build): return config_dict(build_config(v)) elif isinstance(v,dict): return v elif isinstance(v,Closure): return val2dict(v.dref, ctx) else: return None
def val2path(v:Any, ctx:LensContext)->Path: """ Resolve the current value of Lens into system path. Assert if it is not possible or if the result is associated with multiple paths.""" S:SPath=ctx.storage if isdref(v): dref=DRef(v) context=ctx.context if context is not None: if dref in context: rgs=context_deref(context, dref) assert len(rgs)==1, "Lens doesn't support multirealization dependencies" return Path(store_rref2path(rgs[0][tag_out()])) return store_dref2path(dref) elif isrref(v): return store_rref2path(RRef(v),S) elif isrefpath(v): refpath=list(v) # RefPath is list bpath=ctx.build_path context=ctx.context if context is not None: if refpath[0] in context: rgs=context_deref(context,refpath[0],S) assert len(rgs)==1, "Lens doesn't support multirealization dependencies" return Path(join(store_rref2path(rgs[0][Tag('out')],S), *refpath[1:])) else: if bpath is not None: # FIXME: should we assert on refpath[0]==build.dref ? return Path(join(bpath, *refpath[1:])) else: assert False, f"Can't dereference refpath {refpath}" else: assert False, f"Lens couldn't resolve '{refpath}' without a context" elif isinstance(v, Closure): return val2path(v.dref, ctx) elif isinstance(v, Build): assert ctx.build_path is not None, f"Lens can't access build path of '{v}'" return ctx.build_path else: assert False, f"Lens doesn't know how to resolve '{v}'"
def _mut(k: Any, val: Any): if ispromise(val) or isclaim(val): return [DRef(r)] + val[1:] else: return val
def mkdref(dhash: HashPart, refname: Name) -> DRef: assert_valid_hashpart(dhash) assert_valid_name(refname) return DRef('dref:' + dhash + '-' + refname)