Exemple #1
0
    def _make(b: Build) -> None:
        c = build_cattrs(b)
        o = build_outpath(b)

        download_dir = o if force_download else tmpfetchdir
        partpath = join(download_dir, filename_ + '.tmp')

        try:
            p = Popen(
                [CURL(), "--continue-at", "-", "--output", partpath, url],
                cwd=download_dir)
            p.wait()
            assert p.returncode == 0, f"Download failed, errcode '{p.returncode}'"
            assert isfile(partpath), f"Can't find output file '{partpath}'"

            with open(partpath, "rb") as f:
                if sha256 is not None:
                    realhash = sha256sum(f.read()).hexdigest()
                    assert realhash == c.sha256, (
                        f"Expected sha256 checksum '{c.sha256}', "
                        f"but got '{realhash}'")
                if sha1 is not None:
                    realhash = sha1sum(f.read()).hexdigest()
                    assert realhash == c.sha1, (
                        f"Expected sha1 checksum '{c.sha1}', "
                        f"but got '{realhash}'")
            fullpath = join(o, filename_)
            rename(partpath, fullpath)

        except Exception as e:
            error(f"Download failed: {e}")
            error(f"Keeping temporary directory {o}")
            raise
Exemple #2
0
    def _realize(b: Build) -> None:
        c = build_cattrs(b)
        o = build_outpath(b)

        try:
            assert path_ is not None
            partpath = join(o, fname) + '.tmp'
            fullpath = join(o, fname)

            copyfile(path_, partpath)
            assert isfile(partpath), f"Can't copy '{path_}' to '{partpath}'"

            with open(partpath, "rb") as f:
                realhash = sha256sum(f.read()).hexdigest()
                assert realhash == c.sha256, (
                    f"Expected sha256 checksum '{c.sha256}', "
                    f"but got '{realhash}'")
            rename(partpath, fullpath)

            if 'unpack' in c.mode:
                _unpack_inplace(o, fullpath, 'remove' in c.mode)

        except Exception as e:
            error(f"Copying failed: {e}")
            error(f"Keeping temporary directory {o}")
            raise
Exemple #3
0
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()
Exemple #4
0
def dirrw(o: Path) -> None:
    for root, dirs, files in walk(o):
        for d in dirs:
            mode = stat(join(root, d))[ST_MODE]
            chmod(join(root, d), mode | (S_IWRITE))
        for f in files:
            if isfile(f):
                filerw(Path(join(root, f)))
            if islink(f):
                warning(
                    f"Pylightnix doesn't guarantee the consistency of symlink '{f}'"
                )
    chmod(o, stat(o)[ST_MODE] | (S_IWRITE | S_IWGRP | S_IWOTH))
Exemple #5
0
    def _realize(b: Build) -> None:
        c = build_cattrs(b)
        o = build_outpath(b)

        download_dir = o if force_download else tmpfetchdir

        try:
            partpath = join(download_dir, fname + '.tmp')
            p = Popen(
                [WGET(), "--continue", '--output-document', partpath, c.url],
                cwd=download_dir)
            p.wait()

            assert p.returncode == 0, f"Download failed, errcode '{p.returncode}'"
            assert isfile(partpath), f"Can't find output file '{partpath}'"

            with open(partpath, "rb") as f:
                if sha256 is not None:
                    realhash = sha256sum(f.read()).hexdigest()
                    assert realhash == c.sha256, (
                        f"Expected sha256 checksum '{c.sha256}', "
                        f"but got '{realhash}'")
                elif sha1 is not None:
                    realhash = sha1sum(f.read()).hexdigest()
                    assert realhash == c.sha1, (
                        f"Expected sha1 checksum '{c.sha1}', "
                        f"but got '{realhash}'")
                else:
                    assert False, 'Either sha256 or sha1 arguments should be set'

            fullpath = join(o, fname)
            rename(partpath, fullpath)

            if 'unpack' in c.mode:
                _unpack_inplace(o, fullpath, 'remove' in c.mode)

        except Exception as e:
            error(f"Download failed: {e}")
            error(f"Keeping temporary directory {o}")
            raise
Exemple #6
0
def filero(f: Path) -> None:
    assert isfile(f), f"'{f}' is not a file"
    chmod(f, stat(f)[ST_MODE] & ~(S_IWRITE | S_IWGRP | S_IWOTH))
Exemple #7
0
def filerw(f: Path) -> None:
    assert isfile(f), f"'{f}' is not a file"
    chmod(f, stat(f)[ST_MODE] | (S_IWRITE))
Exemple #8
0
def filehash(path: Path) -> Hash:
    assert isfile(path), f"filehash() expects a file path, not '{path}'"
    with open(path, 'rb') as f:
        return datahash([(path, f.read())])
Exemple #9
0
def fetchurl2(m: Manager,
              url: str,
              sha256: Optional[str] = None,
              sha1: Optional[str] = None,
              name: Optional[str] = None,
              filename: Optional[str] = None,
              force_download: bool = False,
              **kwargs) -> DRef:
    """ Download file given it's URL addess.

  Downloading is done by calling `wget` application. Optional unpacking is
  performed with the `aunpack` script from `atool` package. `sha256` defines the
  expected SHA-256 hashsum of the stored data. `mode` allows to tweak the
  stage's behavior: adding word 'unpack' instructs fetchurl to unpack the
  package, adding 'remove' instructs it to remove the archive after unpacking.

  If 'unpack' is not expected, then the promise named 'out_path' is created.

  Agruments:
  - `m:Manager` the dependency resolution [Manager](#pylightnix.types.Manager).
  - `url:str` URL to download from. Should point to a single file.
  - `sha256:str` SHA-256 hash sum of the file.
  - `model:str='unpack,remove'` Additional options. Format: `[unpack[,remove]]`.
  - `name:Optional[str]`: Name of the Derivation. The stage will attempt to
    deduce the name if not specified.
  - `filename:Optional[str]=None` Name of the filename on disk after downloading.
    Stage will attempt to deduced it if not specified.
  - `force_download:bool=False` If False, resume the last download if
    possible.
  - `check_promises:bool=True` Passed to `mkdrv` as-is.

  Example:
  ```python
  def hello_src(m:Manager)->DRef:
    hello_version = '2.10'
    return fetchurl2(
      m,
      name='hello-src',
      url=f'http://ftp.gnu.org/gnu/hello/hello-{hello_version}.tar.gz',
      sha256='31e066137a962676e89f69d1b65382de95a7ef7d914b8cb956f41ea72e0f516b')

  rref:RRef=realize(instantiate(hello_src))
  print(store_rref2path(rref))
  ```
  """

    import pylightnix.core
    tmpfetchdir = join(pylightnix.core.PYLIGHTNIX_TMP, 'fetchurl2')
    assert isabs(tmpfetchdir), (f"Expect absolute PYLIGHTNIX_TMP path, "
                                f"got {tmpfetchdir}")

    filename_ = filename or basename(urlparse(url).path)
    assert len(filename_) > 0, ("Downloadable filename shouldn't be empty. "
                                "Try specifying a valid `filename` argument")
    assert CURL() is not None
    makedirs(tmpfetchdir, exist_ok=True)

    if name is None:
        name = 'fetchurl2'

    if sha256 is None and sha1 is None:
        if isfile(url):
            sha256 = filehash(Path(url))
            url = f'file://{url}'
        else:
            assert False, (
                "Either `sha256` or `sha1` arguments should be specified "
                "for URLs")

    def _config() -> dict:
        args: dict = {'name': name}
        if sha1 is not None:
            args.update({'sha1': sha1})
        if sha256 is not None:
            args.update({'sha256': sha256})
        args.update({'out': [promise, filename_]})
        args.update(**kwargs)
        return args

    def _make(b: Build) -> None:
        c = build_cattrs(b)
        o = build_outpath(b)

        download_dir = o if force_download else tmpfetchdir
        partpath = join(download_dir, filename_ + '.tmp')

        try:
            p = Popen(
                [CURL(), "--continue-at", "-", "--output", partpath, url],
                cwd=download_dir)
            p.wait()
            assert p.returncode == 0, f"Download failed, errcode '{p.returncode}'"
            assert isfile(partpath), f"Can't find output file '{partpath}'"

            with open(partpath, "rb") as f:
                if sha256 is not None:
                    realhash = sha256sum(f.read()).hexdigest()
                    assert realhash == c.sha256, (
                        f"Expected sha256 checksum '{c.sha256}', "
                        f"but got '{realhash}'")
                if sha1 is not None:
                    realhash = sha1sum(f.read()).hexdigest()
                    assert realhash == c.sha1, (
                        f"Expected sha1 checksum '{c.sha1}', "
                        f"but got '{realhash}'")
            fullpath = join(o, filename_)
            rename(partpath, fullpath)

        except Exception as e:
            error(f"Download failed: {e}")
            error(f"Keeping temporary directory {o}")
            raise

    return mkdrv(m, mkconfig(_config()), match_only(), build_wrapper(_make))
Exemple #10
0
def assert_promise_fulfilled(k: str, p: PromisePath, o: Path) -> None:
    ppath = join(o, *p[1:])
    assert isfile(ppath) or isdir(ppath) or islink(ppath), (
        f"Promise '{k}' of {p[0]} is not fulfilled. "
        f"{ppath} is expected to be a file or a directory.")
Exemple #11
0
def mkrealization(dref: DRef,
                  l: Context,
                  o: Path,
                  leader: Optional[Tuple[Tag, RRef]] = None,
                  S=None) -> RRef:
    """ Create the [Realization](#pylightnix.types.RRef) object in the storage
  `S`. Return new Realization reference.

  Parameters:
  - `dref:DRef`: Derivation reference to create the realization of.
  - `l:Context`: Context which stores dependency information.
  - `o:Path`: Path to temporal (build) folder which contains artifacts,
    prepared by the [Realizer](#pylightnix.types.Realizer).
  - `leader`: Tag name and Group identifier of the Group leader. By default,
    we use name `out` and derivation's own rref.

  FIXME: Assert or handle possible but improbable hash collision[*]
  FIXME: Consider(not sure) writing group.json for all realizations[**]
  """
    c = store_config(dref, S)
    assert_valid_config(c)
    (dhash, nm) = undref(dref)

    assert isdir(o), (
        f"While realizing {dref}: Outpath is expected to be a path to existing "
        f"directory, but got {o}")

    for fn in PYLIGHTNIX_RESERVED:
        assert not isfile(join(o, fn)), (
            f"While realizing {dref}: output folder '{o}' contains file '{fn}'. "
            f"This name is reserved, please use another name. List of reserved "
            f"names: {PYLIGHTNIX_RESERVED}")

    with open(reserved(o, 'context.json'), 'w') as f:
        f.write(context_serialize(l))

    if leader is not None:  # [**]
        tag, group_rref = leader
        with open(reserved(o, 'group.json'), 'w') as f:
            json_dump({'tag': tag, 'group': group_rref}, f)

    rhash = dirhash(o)
    rref = mkrref(trimhash(rhash), dhash, nm)
    rrefpath = store_rref2path(rref, S)
    rreftmp = Path(rrefpath + '.tmp')

    replace(o, rreftmp)
    dirchmod(rreftmp, 'ro')

    try:
        replace(rreftmp, rrefpath)
    except OSError as err:
        if err.errno == ENOTEMPTY:
            # Folder name contain the hash of the content, so getting here
            # probably[*] means that we already have this object in storage so we
            # just remove temp folder.
            dirrm(rreftmp, ignore_not_found=False)
        else:
            # Attempt to roll-back
            dirchmod(rreftmp, 'rw')
            replace(rreftmp, o)
            raise
    return rref