def try_nixpkgs(topmost_name): ''' Try to instantiate python3?Packages.<name>. While we're at it, find and also return all the dependencies. ''' try: assert sys.version_info.major == 3 # Instantiate python3Packages.<name> # Returns a list of store paths where the first one is the module path module_name = topmost_name attr_path = "python3%sPackages.%s" % ( sys.version_info.minor, module_name ) store_paths = nix.eval(""" with import <nixpkgs> {}; let getClosure = drv: let propagated = if (lib.hasAttr "propagatedBuildInputs" drv) then (builtins.filter (x: x != null) drv.propagatedBuildInputs) else []; in lib.foldl (acc: v: acc ++ getClosure v) [ drv ] propagated; in builtins.map (drv: "${drv}") (lib.unique (getClosure %s)) """ % attr_path) # Build/download path if not os.path.exists(store_paths[0]): # Abuse IFD to realise store path # Try to import a file that will never exist dummy_file = hashlib.sha1(attr_path.encode()).hexdigest() try: nix.eval(""" with import <nixpkgs> {}; import "${%s}/%s.nix" """ % (attr_path, dummy_file)) except nix.NixError as ex: # This is expected. # What really matters now is whether the store path exists. # If it does, the realization was a success. # Otherwise, it's likely a missing/misspelt derivation name if not os.path.exists(store_paths[0]): raise ex # Guess sys.path-usable subpaths from them (and flatten the list) return sum(( glob.glob(os.path.join(p, 'lib', 'py*', '*-packages')) for p in store_paths ), []) except Exception as e: raise ImportError(e)
def instantiate(packages: List[Attribute], nixpkgs: str) -> Dict[Drvpath, Attribute]: # 1. Attempt to evaluate each package attribute, and if it's # not broken or disabled get the drvpath for it. kv = nix.eval( """ let pkgs = import nixpkgsPath { config = { checkMeta = true; allowUnfree = true; }; }; getPkg = n: (pkgs.lib.getAttrFromPath (pkgs.lib.splitString "." n) pkgs); getDrvPath = pkg: let maybe = builtins.tryEval pkg.drvPath; in if maybe.success then maybe.value else null; in pkgs.lib.genAttrs maybePackages (n: getDrvPath (getPkg n)) """, vars=dict(nixpkgsPath=nixpkgs, maybePackages=packages), ) answer = {drvpath: attrib for attrib, drvpath in kv.items() if drvpath is not None} # 2. Instantiate all of the non-broken drvpaths in the nix store. expr2 = "with import %(nixpkgs)s { }; [%(attribs)s]" % dict( nixpkgs=nixpkgs, attribs=" ".join(answer.values()) ) cmd2 = [find_executable("nix-instantiate"), "-E", expr2] run(cmd2, check=True, shell=False) return answer
def init_module(): """ Initialise module This creates completions with docstrings for all derivations in the python package set """ attr_path = "python3%sPackages" % sys.version_info.minor expr = """ with import <nixpkgs> {}; let drvAttrs = lib.filterAttrs (k: v: (builtins.tryEval v).success && builtins.typeOf v == "set") %s; meta = builtins.mapAttrs (k: v: if builtins.hasAttr "meta" v then v.meta else {}) drvAttrs; in builtins.mapAttrs (k: v: if builtins.hasAttr "description" v then v.description else "") meta """ % attr_path g = globals() for attr, desc in nix.eval(expr).items(): if attr not in g: g[attr] = NixPackage(attr, doc=desc)
def test_string(self): self.assertEqual(nix.eval("a", vars=dict(a="foo")), "foo")
def test_dict(self): val = dict(a=1) self.assertEqual(nix.eval("a", vars=dict(a=val)), val)
def test_none(self): self.assertEqual(nix.eval("a", vars=dict(a=None)), None)
def test_bool(self): self.assertEqual(nix.eval("a", vars=dict(a=True)), True)
def main(): args = docopt(__doc__) system = eval("builtins.currentSystem") expr = args["EXPR"] nix_path = environ["NIX_PATH"] = expanduser(args["-I"] or environ["NIX_PATH"]) new_version = args["VERSION"] new_hash = args["HASH"] force = args['--force'] no_build = args['--no-build'] setLOL(args['--lol']) log.info(f"This system: {system}") log.debug(f"NIX_PATH: {nix_path}") try: nv = neval(f"builtins.parseDrvName {expr}.name") name, version = nv['name'], parse_version(nv['version'].split('-')[-1]) loc, locline = neval(f"{expr}.meta.position").split(":") locline = int(locline) log.info(f"File for {name}-{version} is {loc}:{locline}") hash_algo = neval(f"{expr}.src.drvAttrs.outputHashAlgo") hash = neval(f"{expr}.src.drvAttrs.outputHash") is_git = neval(f"builtins.hasAttr ''rev'' {expr}.src.drvAttrs") # TODO: resolve mirrors if not is_git: urls = neval(f"{expr}.src.drvAttrs.urls") else: log.debug("Using url instead of urls in drvAttrs") urls = [neval(f"{expr}.src.drvAttrs.url")] log.info(f"for urls {urls}") log.info(f"Hash {hash_algo} with {hash}") # log.info(f"new hash for input: {fetchedHash}") except Exception as e: log.error(f"Unable to find expression {expr}") log.error(e) sys.exit(1) if not new_version: log.info(f"Trying to guess new version for {name}") try: new_version = guessNewVersion(name, version, urls, force) except Exception as e: log.error(e) sys.exit(1) log.info( f"Found newer version for {name}: {new_version} (> {version})") matcher = re.compile(f'(version|rev)\s*=\s*"{version}";\s*(#.*)?$') replaceLast(loc, locline, version, new_version, matcher) attrs = neval(f"{expr}.src.drvAttrs") if is_git: new_hash = fetchGit(attrs) else: new_hash = fetchUrl(attrs) log.info(f"new hash for {expr} is {new_hash}") # TODO: not sure if hash_algo always matches matcher = re.compile(f'({hash_algo})\s*=\s*"{hash}";$\s*(#.*)?') replaceLast(loc, locline, hash, new_hash, matcher) if not no_build: log.info(f"trying to build changed expression {expr}") try: buildExpression(expr) except CalledProcessError: log.error( f"Unable to build {expr}, go ahead and follow the white rabbit" ) sys.exit(1) else: log.info(f"Build of {expr} skipped") log.info("Finished") sys.exit(0)
def neval(expr): """ eval with nixpkgs loaded """ return eval(f"with import <nixpkgs> {{}};{expr}")
def main(): args = docopt(__doc__) name = args["NAME"] nix_path = environ["NIX_PATH"] = expanduser(args["-I"] or environ["NIX_PATH"]) force = args['--force'] typ = args['TYPE'] extraBuild = args['--build'] or "" extraCheck = args['--check'] or "" maintainer = args['--maintainer'] or "" setLOL(args['--lol']) base_dir = eval("builtins.toString <nixpkgs>") log.info(base_dir) if typ.lower() == 'pypi': info = getPypiInfo(name) url = info["home_page"] license = args["--license"] or info["license"] or "PLACEHOLDER_LICENSE" version = args["--version"] or info["version"] # extra == tests build = [ req.split()[0].lower().replace('.','-').replace(';','') for req in info.get("requires_dist",[]) ] + extraBuild.split() check = extraCheck.split() if extraCheck else [] description = info["summary"] hjoin = lambda lst: '\n, '.join(lst) njoin = lambda lst: '\n '.join(lst) sha256 = fetchUrl({ "urls": [f"mirror://pypi/{name[0]}/{name}/{name}-{version}.tar.gz"],"postFetch":False}) print( f"""{{ lib, fetchPypi, buildPythonPackage # buildInputs , {hjoin(build)} # checkInputs , {hjoin(check)} }}: # {name} = callPackage ../development/python-modules/{name} {{}}; buildPythonPackage rec {{ pname = "{name}"; version = "{version}"; src = fetchPypi {{ inherit pname version; sha256 = "{sha256}"; }}; propagatedBuildInputs = [ {njoin(build)} ]; checkInputs = [ {njoin(check)} ]; meta = with lib; {{ description = "{description}"; homepage = "{url}"; # TODO License license = licenses."{license}"; maintainers = with maintainers; [ {maintainer} ]; }}; }}""") else: log.error(f"unsupported type {typ}") sys.exit(1) sys.exit(0)