Skip to content
Snippets Groups Projects
Commit aedfc80f authored by Franck Bret's avatar Franck Bret Committed by Phabricator Migration user
Browse files

crates: Loader implements incremental mode

Add incremental support based on sha256 EXTID
Manage release date for each versions of a package
Adapt test dataset and add incremental test cases

Related T4104
parent a13e3e6f
No related tags found
1 merge request!427crates: Loader implements incremental mode
Pipeline #4416 failed
Showing
with 585 additions and 351 deletions
...@@ -67,13 +67,13 @@ Here is an overview of the fields (+ internal version name + branch name) used b ...@@ -67,13 +67,13 @@ Here is an overview of the fields (+ internal version name + branch name) used b
- metadata is intrinsic - metadata is intrinsic
* - crates * - crates
- ``p_info.​version`` - ``p_info.​version``
- ``release_name(​version, filename) + "\n\n" + i_metadata.description + "\n"`` - ``release_name(​version)``
- =version - =version
- Synthetic release for Crate source package {p_info.name} version {p_info.version} {description} - Synthetic release for Crate source package {p_info.name} version {p_info.version}
- true - true
- from int metadata - from intrinsic metadata
- from ext metadata - from extrinsic metadata
- ``i_metadata`` for intrinsic metadata, ``e_metadata`` for extrinsic metadata - ""
* - debian * - debian
- =``version`` - =``version``
- ``release_name(​version)`` - ``release_name(​version)``
......
...@@ -3,139 +3,35 @@ ...@@ -3,139 +3,35 @@
# License: GNU General Public License version 3, or any later version # License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information # See top-level LICENSE file for more information
from distutils.version import StrictVersion from datetime import datetime
import json import json
from pathlib import Path from pathlib import Path
import string
from typing import Any, Dict, Iterator, List, Optional, Sequence, Tuple from typing import Any, Dict, Iterator, List, Optional, Sequence, Tuple
from urllib.parse import urlparse from urllib.parse import urlparse
import attr import attr
from packaging.version import parse as parse_version
import toml import toml
from typing_extensions import TypedDict
from swh.loader.package.loader import BasePackageInfo, PackageLoader from swh.loader.package.loader import (
from swh.loader.package.utils import cached_method, get_url_body, release_name BasePackageInfo,
from swh.model.model import ObjectType, Person, Release, Sha1Git, TimestampWithTimezone PackageLoader,
RawExtrinsicMetadataCore,
)
from swh.loader.package.utils import EMPTY_AUTHOR, release_name
from swh.model.model import (
MetadataAuthority,
MetadataAuthorityType,
ObjectType,
Person,
Release,
Sha1Git,
TimestampWithTimezone,
)
from swh.storage.interface import StorageInterface from swh.storage.interface import StorageInterface
class ExtrinsicPackageMetadata(TypedDict):
"""Data structure for package extrinsic metadata pulled from http api endpoint.
We set only the keys we need according to what is available when querying
https://crates.io/api/v1/crates/<name>, where `name` is the name of the crate
package (see JSON response example at https://crates.io/api/v1/crates/hg-core).
Usage example:
.. code-block:: python
e_metadata = ExtrinsicPackageMetadata(**self.info())
""" # noqa
categories: List[Dict[Any, Any]]
"""Related categories"""
crate: Dict[Any, Any]
"""Crate project information"""
keywords: List[Any]
"""Keywords"""
versions: List[Dict[Any, Any]]
"""A list of released versions for a crate"""
class ExtrinsicVersionPackageMetadata(TypedDict):
"""Data structure for specific package version extrinsic metadata, pulled
from http api endpoint.
Similar to `ExtrinsicPackageMetadata` in its usage, but we flatten the data
related to a specific version.
"""
crate: str
"""The package name"""
crate_size: int
"""The package size"""
created_at: str
"""First released at"""
downloads: str
"""Number of downloads"""
license: str
"""Package license"""
num: str
"""Package version"""
published_by: Dict[Any, Any]
"""Publishers information"""
updated_at: str
"""Last update"""
yanked: bool
"""Is that version yanked? (yanked means release-level deprecation)"""
class IntrinsicPackageMetadata(TypedDict):
"""Data structure for specific package version intrinsic metadata.
Data is extracted from the crate package's .toml file. Then the data of the
'package' entry is flattened.
Cargo.toml file content example:
.. code-block:: toml
[package]
name = "hg-core"
version = "0.0.1"
authors = ["Georges Racinet <georges.racinet@octobus.net>"]
description = "Mercurial pure Rust core library, with no assumption on
Python bindings (FFI)"
homepage = "https://mercurial-scm.org"
license = "GPL-2.0-or-later"
repository = "https://www.mercurial-scm.org/repo/hg"
[lib]
name = "hg"
[dev-dependencies.rand]
version = "~0.6"
[dev-dependencies.rand_pcg]
version = "~0.1"
:param toml: toml object
"""
name: str
"""The package name"""
version: str
"""Package version"""
authors: List[str]
"""Authors"""
description: str
"""Package and release description"""
homepage: str
"""Homepage of the project"""
license: str
"""Package license"""
repository: str
"""Source code repository"""
@attr.s @attr.s
class CratesPackageInfo(BasePackageInfo): class CratesPackageInfo(BasePackageInfo):
...@@ -145,16 +41,20 @@ class CratesPackageInfo(BasePackageInfo): ...@@ -145,16 +41,20 @@ class CratesPackageInfo(BasePackageInfo):
version = attr.ib(type=str) version = attr.ib(type=str)
"""Current version""" """Current version"""
e_metadata: Dict[str, Any] = attr.ib(factory=ExtrinsicPackageMetadata) sha256 = attr.ib(type=str)
"""Extrinsic package metadata, common to all versions""" """Extid as sha256"""
e_metadata_version: Dict[str, Any] = attr.ib( last_update = attr.ib(type=datetime)
factory=ExtrinsicVersionPackageMetadata """Last update as release date"""
)
"""Extrinsic package metadata specific to a version"""
i_metadata: Dict[str, Any] = attr.ib(factory=IntrinsicPackageMetadata) yanked = attr.ib(type=bool)
"""Intrinsic metadata of the current package version""" """Whether the package is yanked or not"""
MANIFEST_FORMAT = string.Template(
"name $name\nshasum $sha256\nurl $url\nversion $version\nlast_update $last_update"
)
EXTID_TYPE = "crates-manifest-sha256"
EXTID_VERSION = 0
def extract_intrinsic_metadata(dir_path: Path) -> Dict[str, Any]: def extract_intrinsic_metadata(dir_path: Path) -> Dict[str, Any]:
...@@ -171,35 +71,6 @@ def extract_intrinsic_metadata(dir_path: Path) -> Dict[str, Any]: ...@@ -171,35 +71,6 @@ def extract_intrinsic_metadata(dir_path: Path) -> Dict[str, Any]:
return toml.load(dir_path / "Cargo.toml") return toml.load(dir_path / "Cargo.toml")
def extract_author(p_info: CratesPackageInfo) -> Person:
"""Extract package author from intrinsic metadata and return it as a
`Person` model.
Args:
p_info: CratesPackageInfo that should contains i_metadata entries
Returns:
Only one author (Person) of the package. Currently limited by internal detail
of the swh stack (see T3887).
"""
authors = p_info.i_metadata["authors"]
fullname = authors[0] # TODO: here we have a list of author, see T3887
return Person.from_fullname(fullname.encode())
def extract_description(p_info: CratesPackageInfo) -> str:
"""Extract package description from intrinsic metadata and return it as a
string.
Args:
p_info: CratesPackageInfo that should contains i_metadata and entries
Returns:
Package description from metadata.
"""
return p_info.i_metadata["description"]
class CratesLoader(PackageLoader[CratesPackageInfo]): class CratesLoader(PackageLoader[CratesPackageInfo]):
"""Load Crates package origins into swh archive.""" """Load Crates package origins into swh archive."""
...@@ -210,6 +81,7 @@ class CratesLoader(PackageLoader[CratesPackageInfo]): ...@@ -210,6 +81,7 @@ class CratesLoader(PackageLoader[CratesPackageInfo]):
storage: StorageInterface, storage: StorageInterface,
url: str, url: str,
artifacts: List[Dict[str, Any]], artifacts: List[Dict[str, Any]],
crates_metadata: List[Dict[str, Any]],
**kwargs, **kwargs,
): ):
"""Constructor """Constructor
...@@ -223,8 +95,8 @@ class CratesLoader(PackageLoader[CratesPackageInfo]): ...@@ -223,8 +95,8 @@ class CratesLoader(PackageLoader[CratesPackageInfo]):
A list of dict listing all existing released versions for a A list of dict listing all existing released versions for a
package (Usually set with crates lister `extra_loader_arguments`). package (Usually set with crates lister `extra_loader_arguments`).
Each line is a dict that should have an `url` Each line is a dict that should have an `url`
(where to download package specific version) and a `version` entry. (where to download package specific version), a `version`, a
`filename` and a `checksums['sha256']` entry.
Example:: Example::
...@@ -232,29 +104,34 @@ class CratesLoader(PackageLoader[CratesPackageInfo]): ...@@ -232,29 +104,34 @@ class CratesLoader(PackageLoader[CratesPackageInfo]):
{ {
"version": <version>, "version": <version>,
"url": "https://static.crates.io/crates/<package_name>/<package_name>-<version>.crate", "url": "https://static.crates.io/crates/<package_name>/<package_name>-<version>.crate",
"filename": "<package_name>-<version>.crate",
"checksums": {
"sha256": "<sha256>",
},
} }
] ]
crates_metadata:
Same as previously but for Crates metadata.
For now it only has one boolean key `yanked`.
Example::
[
{
"version": "<version>",
"yanked": <yanked>,
},
]
""" # noqa """ # noqa
super().__init__(storage=storage, url=url, **kwargs) super().__init__(storage=storage, url=url, **kwargs)
self.url = url self.url = url
self.artifacts: Dict[str, Dict] = { self.artifacts: Dict[str, Dict] = {
artifact["version"]: artifact for artifact in artifacts artifact["version"]: artifact for artifact in artifacts
} }
self.crates_metadata: Dict[str, Dict] = {
@cached_method data["version"]: data for data in crates_metadata
def _raw_info(self) -> bytes: }
"""Get crate metadata (fetched from http api endpoint set as self.url)
Returns:
Content response as bytes. Content response is a json document.
"""
return get_url_body(self.url)
@cached_method
def info(self) -> Dict:
"""Parse http api json response and return the crate metadata information
as a Dict."""
return json.loads(self._raw_info())
def get_versions(self) -> Sequence[str]: def get_versions(self) -> Sequence[str]:
"""Get all released versions of a crate """Get all released versions of a crate
...@@ -267,7 +144,7 @@ class CratesLoader(PackageLoader[CratesPackageInfo]): ...@@ -267,7 +144,7 @@ class CratesLoader(PackageLoader[CratesPackageInfo]):
["0.1.1", "0.10.2"] ["0.1.1", "0.10.2"]
""" """
versions = list(self.artifacts.keys()) versions = list(self.artifacts.keys())
versions.sort(key=StrictVersion) versions.sort(key=parse_version)
return versions return versions
def get_default_version(self) -> str: def get_default_version(self) -> str:
...@@ -282,6 +159,12 @@ class CratesLoader(PackageLoader[CratesPackageInfo]): ...@@ -282,6 +159,12 @@ class CratesLoader(PackageLoader[CratesPackageInfo]):
""" """
return self.get_versions()[-1] return self.get_versions()[-1]
def get_metadata_authority(self):
return MetadataAuthority(
type=MetadataAuthorityType.FORGE,
url="https://crates.io/",
)
def get_package_info(self, version: str) -> Iterator[Tuple[str, CratesPackageInfo]]: def get_package_info(self, version: str) -> Iterator[Tuple[str, CratesPackageInfo]]:
"""Get release name and package information from version """Get release name and package information from version
...@@ -291,62 +174,63 @@ class CratesLoader(PackageLoader[CratesPackageInfo]): ...@@ -291,62 +174,63 @@ class CratesLoader(PackageLoader[CratesPackageInfo]):
Returns: Returns:
Iterator of tuple (release_name, p_info) Iterator of tuple (release_name, p_info)
""" """
artifact = self.artifacts[version] artifact = self.artifacts[version].copy()
filename = artifact["filename"] filename = artifact["filename"]
assert artifact["checksums"]["sha256"]
sha256 = artifact["checksums"]["sha256"]
package_name = urlparse(self.url).path.split("/")[-1] package_name = urlparse(self.url).path.split("/")[-1]
url = artifact["url"] url = artifact["url"]
# Get extrinsic metadata from http api crate_metadata = self.crates_metadata[version].copy()
e_metadata = ExtrinsicPackageMetadata(**self.info()) # type: ignore[misc] yanked = crate_metadata["yanked"]
last_update = datetime.fromisoformat(crate_metadata["last_update"])
# Extract crate info for current version (One .crate file for a given version) # Remove "version" from artifact to follow "original-artifacts-json" extrinsic
(crate_version,) = [ # metadata format specifications
crate for crate in e_metadata["versions"] if crate["num"] == version # See https://docs.softwareheritage.org/devel/swh-storage/extrinsic-metadata-specification.html#extrinsic-metadata-formats # noqa: B950
] del artifact["version"]
e_metadata_version = ExtrinsicVersionPackageMetadata( # type: ignore[misc]
**crate_version
)
p_info = CratesPackageInfo( p_info = CratesPackageInfo(
name=package_name, name=package_name,
filename=filename, filename=filename,
url=url, url=url,
version=version, version=version,
e_metadata=e_metadata, sha256=sha256,
e_metadata_version=e_metadata_version, checksums={"sha256": sha256},
yanked=yanked,
last_update=last_update,
directory_extrinsic_metadata=[
RawExtrinsicMetadataCore(
format="crates-package-json",
metadata=json.dumps([crate_metadata]).encode(),
),
],
) )
yield release_name(version, filename), p_info yield release_name(version, filename), p_info
def build_release( def build_release(
self, p_info: CratesPackageInfo, uncompressed_path: str, directory: Sha1Git self, p_info: CratesPackageInfo, uncompressed_path: str, directory: Sha1Git
) -> Optional[Release]: ) -> Optional[Release]:
# Extract intrinsic metadata from dir_path/Cargo.toml # Extract intrinsic metadata from dir_path/Cargo.toml
name = p_info.name dir_path = Path(uncompressed_path, f"{p_info.name}-{p_info.version}")
version = p_info.version i_metadata = extract_intrinsic_metadata(dir_path)
dir_path = Path(uncompressed_path, f"{name}-{version}")
i_metadata_raw = extract_intrinsic_metadata(dir_path) author = EMPTY_AUTHOR
# Get only corresponding key of IntrinsicPackageMetadata authors = i_metadata.get("package", {}).get("authors")
i_metadata_keys = [k for k in IntrinsicPackageMetadata.__annotations__.keys()] if authors and isinstance(authors, list):
# We use data only from "package" entry # TODO: here we have a list of author, see T3887
i_metadata = { author = Person.from_fullname(authors[0].encode())
k: v for k, v in i_metadata_raw["package"].items() if k in i_metadata_keys
}
p_info.i_metadata = IntrinsicPackageMetadata(**i_metadata) # type: ignore[misc]
author = extract_author(p_info)
description = extract_description(p_info)
message = ( message = (
f"Synthetic release for Crate source package {p_info.name} " f"Synthetic release for Crate source package {p_info.name} "
f"version {p_info.version}\n\n" f"version {p_info.version}\n"
f"{description}\n"
) )
# The only way to get a value for updated_at is through extrinsic metadata
updated_at = p_info.e_metadata_version.get("updated_at")
return Release( return Release(
name=version.encode(), name=p_info.version.encode(),
date=TimestampWithTimezone.from_datetime(p_info.last_update),
author=author, author=author,
date=TimestampWithTimezone.from_iso8601(updated_at),
message=message.encode(), message=message.encode(),
target_type=ObjectType.DIRECTORY, target_type=ObjectType.DIRECTORY,
target=directory, target=directory,
......
[
{
"url": "https://crates.io/api/v1/crates/hg-core",
"artifacts": [
{
"version": "0.0.1",
"checksums": {
"sha256": "233409cca39eccab8075d3414884a2e9096aa3f7ceb4139685134c9f2561e734"
},
"filename": "hg-core-0.0.1.crate",
"url": "https://static.crates.io/crates/hg-core/hg-core-0.0.1.crate"
}
],
"crates_metadata": [
{
"version": "0.0.1",
"yanked": false,
"last_update": "2019-04-16T18:48:11.404457+00:00"
}
]
},
{
"url": "https://crates.io/api/v1/crates/micro-timer",
"artifacts": [
{
"version": "0.1.0",
"checksums": {
"sha256": "837c3955f0dfbd1a95f4388e06acb2f1a8030e28d251867e603b6be7b93da783"
},
"filename": "micro-timer-0.1.0.crate",
"url": "https://static.crates.io/crates/micro-timer/micro-timer-0.1.0.crate"
},
{
"version": "0.1.1",
"checksums": {
"sha256": "bfb0e972e961d6bfd8d344ccf05c29ae39b7d817ced30568204495aee4bab519"
},
"filename": "micro-timer-0.1.1.crate",
"url": "https://static.crates.io/crates/micro-timer/micro-timer-0.1.1.crate"
},
{
"version": "0.1.2",
"checksums": {
"sha256": "53251c2ab69c97447b4d6bfb327f7608ba0f7108e4aa3d4f559934d6cd088d11"
},
"filename": "micro-timer-0.1.2.crate",
"url": "https://static.crates.io/crates/micro-timer/micro-timer-0.1.2.crate"
},
{
"version": "0.2.0",
"checksums": {
"sha256": "d5a39e92178f6f0c8acb1111258327eab2447e2ab574e5868e2770ed28940d70"
},
"filename": "micro-timer-0.2.0.crate",
"url": "https://static.crates.io/crates/micro-timer/micro-timer-0.2.0.crate"
},
{
"version": "0.2.1",
"checksums": {
"sha256": "7889cfebb345bd706ecb93e7b67e7e6af1d68ce16e3f0c109bf8b7bcb79e55af"
},
"filename": "micro-timer-0.2.1.crate",
"url": "https://static.crates.io/crates/micro-timer/micro-timer-0.2.1.crate"
},
{
"version": "0.3.0",
"checksums": {
"sha256": "d92b84c26f807891fd492ceecc11ca2bdaf73583665275080ead1c127ed861a4"
},
"filename": "micro-timer-0.3.0.crate",
"url": "https://static.crates.io/crates/micro-timer/micro-timer-0.3.0.crate"
},
{
"version": "0.3.1",
"checksums": {
"sha256": "740acae0cfa83cf78207aab16ba4a41dce7101bca774c63eac8c41fd5ce382a5"
},
"filename": "micro-timer-0.3.1.crate",
"url": "https://static.crates.io/crates/micro-timer/micro-timer-0.3.1.crate"
},
{
"version": "0.4.0",
"checksums": {
"sha256": "475222c2def55b7166390398a0c033ceb9a1cdfe008ff6ebd22773fb2029a60f"
},
"filename": "micro-timer-0.4.0.crate",
"url": "https://static.crates.io/crates/micro-timer/micro-timer-0.4.0.crate"
}
],
"crates_metadata": [
{
"version": "0.1.0",
"yanked": false,
"last_update": "2020-02-27T14:31:49.131258+00:00"
},
{
"version": "0.1.1",
"yanked": false,
"last_update": "2020-02-27T15:17:53.486346+00:00"
},
{
"version": "0.1.2",
"yanked": false,
"last_update": "2020-02-27T23:35:41.872176+00:00"
},
{
"version": "0.2.0",
"yanked": false,
"last_update": "2020-03-23T10:57:04.418462+00:00"
},
{
"version": "0.2.1",
"yanked": false,
"last_update": "2020-03-23T11:22:26.288804+00:00"
},
{
"version": "0.3.0",
"yanked": false,
"last_update": "2020-06-02T11:38:33.047581+00:00"
},
{
"version": "0.3.1",
"yanked": false,
"last_update": "2020-06-22T16:40:06.754009+00:00"
},
{
"version": "0.4.0",
"yanked": false,
"last_update": "2020-09-28T13:40:49.593030+00:00"
}
]
}
]
#!/usr/bin/env bash #!/usr/bin/env bash
# Script to generate fake crates files and fake http api response. # Script to generate fake crates files.
set -euo pipefail set -euo pipefail
...@@ -45,7 +45,7 @@ echo -e '''[package] ...@@ -45,7 +45,7 @@ echo -e '''[package]
edition = "2018" edition = "2018"
name = "micro-timer" name = "micro-timer"
version = "0.1.0" version = "0.1.0"
authors = ["Raphaël Gomès <rgomes@octobus.net>"] # authors = ["Raphaël Gomès <rgomes@octobus.net>"] # commented for testing empty authors
description = "Dumb tiny logging timer" description = "Dumb tiny logging timer"
homepage = "https://heptapod.octobus.net/Alphare/micro-timer" homepage = "https://heptapod.octobus.net/Alphare/micro-timer"
readme = "README.md" readme = "README.md"
...@@ -243,17 +243,6 @@ cp micro-timer-0.3.0.crate ../../https_static.crates.io/crates_micro-timer_micro ...@@ -243,17 +243,6 @@ cp micro-timer-0.3.0.crate ../../https_static.crates.io/crates_micro-timer_micro
cp micro-timer-0.3.1.crate ../../https_static.crates.io/crates_micro-timer_micro-timer-0.3.1.crate cp micro-timer-0.3.1.crate ../../https_static.crates.io/crates_micro-timer_micro-timer-0.3.1.crate
cp micro-timer-0.4.0.crate ../../https_static.crates.io/crates_micro-timer_micro-timer-0.4.0.crate cp micro-timer-0.4.0.crate ../../https_static.crates.io/crates_micro-timer_micro-timer-0.4.0.crate
# Creates some http file response for test purposes.
mkdir ../../https_crates.io
# hg-core, https://crates.io/api/v1/crates/hg-core
echo -e '''{"categories":[],"crate":{"badges":[],"categories":[],"created_at":"2019-04-16T18:48:11.404457+00:00","description":"Mercurial pure Rust core library, with no assumption on Python bindings (FFI)","documentation":null,"downloads":442,"exact_match":false,"homepage":"https://mercurial-scm.org","id":"hg-core","keywords":[],"links":{"owner_team":"/api/v1/crates/hg-core/owner_team","owner_user":"/api/v1/crates/hg-core/owner_user","owners":"/api/v1/crates/hg-core/owners","reverse_dependencies":"/api/v1/crates/hg-core/reverse_dependencies","version_downloads":"/api/v1/crates/hg-core/downloads","versions":null},"max_stable_version":"0.0.1","max_version":"0.0.1","name":"hg-core","newest_version":"0.0.1","recent_downloads":40,"repository":"https://www.mercurial-scm.org/repo/hg","updated_at":"2019-04-16T18:48:11.404457+00:00","versions":[145309]},"keywords":[],"versions":[{"audit_actions":[],"crate":"hg-core","crate_size":21344,"created_at":"2019-04-16T18:48:11.404457+00:00","dl_path":"/api/v1/crates/hg-core/0.0.1/download","downloads":442,"features":{},"id":145309,"license":"GPL-2.0-or-later","links":{"authors":"/api/v1/crates/hg-core/0.0.1/authors","dependencies":"/api/v1/crates/hg-core/0.0.1/dependencies","version_downloads":"/api/v1/crates/hg-core/0.0.1/downloads"},"num":"0.0.1","published_by":{"avatar":"https://avatars0.githubusercontent.com/u/474220?v=4","id":45544,"login":"gracinet","name":"Georges Racinet","url":"https://github.com/gracinet"},"readme_path":"/api/v1/crates/hg-core/0.0.1/readme","updated_at":"2019-04-16T18:48:11.404457+00:00","yanked":false}]}
''' > ../../https_crates.io/api_v1_crates_hg-core
# micro-timer, https://crates.io/api/v1/crates/micro-timer
echo -e '''{"categories":[],"crate":{"badges":[],"categories":[],"created_at":"2020-02-27T14:31:49.131258+00:00","description":"Dumb tiny logging timer","documentation":null,"downloads":44245,"exact_match":false,"homepage":"https://foss.heptapod.net/octobus/rust/micro-timer","id":"micro-timer","keywords":[],"links":{"owner_team":"/api/v1/crates/micro-timer/owner_team","owner_user":"/api/v1/crates/micro-timer/owner_user","owners":"/api/v1/crates/micro-timer/owners","reverse_dependencies":"/api/v1/crates/micro-timer/reverse_dependencies","version_downloads":"/api/v1/crates/micro-timer/downloads","versions":null},"max_stable_version":"0.4.0","max_version":"0.4.0","name":"micro-timer","newest_version":"0.4.0","recent_downloads":3910,"repository":"https://foss.heptapod.net/octobus/rust/micro-timer","updated_at":"2020-09-28T13:40:49.593030+00:00","versions":[288167,254896,248120,223660,223652,216405,216156,216139]},"keywords":[],"versions":[{"audit_actions":[{"action":"publish","time":"2020-09-28T13:40:49.593030+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":3513,"created_at":"2020-09-28T13:40:49.593030+00:00","dl_path":"/api/v1/crates/micro-timer/0.4.0/download","downloads":337,"features":{},"id":288167,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.4.0/authors","dependencies":"/api/v1/crates/micro-timer/0.4.0/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.4.0/downloads"},"num":"0.4.0","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.4.0/readme","updated_at":"2020-09-28T13:40:49.593030+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-06-22T16:40:06.754009+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":3357,"created_at":"2020-06-22T16:40:06.754009+00:00","dl_path":"/api/v1/crates/micro-timer/0.3.1/download","downloads":37853,"features":{},"id":254896,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.3.1/authors","dependencies":"/api/v1/crates/micro-timer/0.3.1/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.3.1/downloads"},"num":"0.3.1","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.3.1/readme","updated_at":"2020-06-22T16:40:06.754009+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-06-02T11:38:33.047581+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":3306,"created_at":"2020-06-02T11:38:33.047581+00:00","dl_path":"/api/v1/crates/micro-timer/0.3.0/download","downloads":4163,"features":{},"id":248120,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.3.0/authors","dependencies":"/api/v1/crates/micro-timer/0.3.0/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.3.0/downloads"},"num":"0.3.0","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.3.0/readme","updated_at":"2020-06-02T11:38:33.047581+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-03-23T11:22:26.288804+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":2937,"created_at":"2020-03-23T11:22:26.288804+00:00","dl_path":"/api/v1/crates/micro-timer/0.2.1/download","downloads":1301,"features":{},"id":223660,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.2.1/authors","dependencies":"/api/v1/crates/micro-timer/0.2.1/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.2.1/downloads"},"num":"0.2.1","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.2.1/readme","updated_at":"2020-03-23T11:22:26.288804+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-03-23T10:57:04.418462+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":2941,"created_at":"2020-03-23T10:57:04.418462+00:00","dl_path":"/api/v1/crates/micro-timer/0.2.0/download","downloads":104,"features":{},"id":223652,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.2.0/authors","dependencies":"/api/v1/crates/micro-timer/0.2.0/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.2.0/downloads"},"num":"0.2.0","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.2.0/readme","updated_at":"2020-03-23T10:57:04.418462+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-02-27T23:35:41.872176+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":4927,"created_at":"2020-02-27T23:35:41.872176+00:00","dl_path":"/api/v1/crates/micro-timer/0.1.2/download","downloads":258,"features":{},"id":216405,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.1.2/authors","dependencies":"/api/v1/crates/micro-timer/0.1.2/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.1.2/downloads"},"num":"0.1.2","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.1.2/readme","updated_at":"2020-02-27T23:35:41.872176+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-02-27T15:17:53.486346+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":2916,"created_at":"2020-02-27T15:17:53.486346+00:00","dl_path":"/api/v1/crates/micro-timer/0.1.1/download","downloads":111,"features":{},"id":216156,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.1.1/authors","dependencies":"/api/v1/crates/micro-timer/0.1.1/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.1.1/downloads"},"num":"0.1.1","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.1.1/readme","updated_at":"2020-02-27T15:17:53.486346+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-02-27T14:31:49.131258+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":2902,"created_at":"2020-02-27T14:31:49.131258+00:00","dl_path":"/api/v1/crates/micro-timer/0.1.0/download","downloads":118,"features":{},"id":216139,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.1.0/authors","dependencies":"/api/v1/crates/micro-timer/0.1.0/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.1.0/downloads"},"num":"0.1.0","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.1.0/readme","updated_at":"2020-02-27T14:31:49.131258+00:00","yanked":false}]}
''' > ../../https_crates.io/api_v1_crates_micro-timer
# Clean up removing tmp_dir # Clean up removing tmp_dir
cd ../../ cd ../../
rm -r tmp_dir/ rm -r tmp_dir/
{"categories":[],"crate":{"badges":[],"categories":[],"created_at":"2019-04-16T18:48:11.404457+00:00","description":"Mercurial pure Rust core library, with no assumption on Python bindings (FFI)","documentation":null,"downloads":442,"exact_match":false,"homepage":"https://mercurial-scm.org","id":"hg-core","keywords":[],"links":{"owner_team":"/api/v1/crates/hg-core/owner_team","owner_user":"/api/v1/crates/hg-core/owner_user","owners":"/api/v1/crates/hg-core/owners","reverse_dependencies":"/api/v1/crates/hg-core/reverse_dependencies","version_downloads":"/api/v1/crates/hg-core/downloads","versions":null},"max_stable_version":"0.0.1","max_version":"0.0.1","name":"hg-core","newest_version":"0.0.1","recent_downloads":40,"repository":"https://www.mercurial-scm.org/repo/hg","updated_at":"2019-04-16T18:48:11.404457+00:00","versions":[145309]},"keywords":[],"versions":[{"audit_actions":[],"crate":"hg-core","crate_size":21344,"created_at":"2019-04-16T18:48:11.404457+00:00","dl_path":"/api/v1/crates/hg-core/0.0.1/download","downloads":442,"features":{},"id":145309,"license":"GPL-2.0-or-later","links":{"authors":"/api/v1/crates/hg-core/0.0.1/authors","dependencies":"/api/v1/crates/hg-core/0.0.1/dependencies","version_downloads":"/api/v1/crates/hg-core/0.0.1/downloads"},"num":"0.0.1","published_by":{"avatar":"https://avatars0.githubusercontent.com/u/474220?v=4","id":45544,"login":"gracinet","name":"Georges Racinet","url":"https://github.com/gracinet"},"readme_path":"/api/v1/crates/hg-core/0.0.1/readme","updated_at":"2019-04-16T18:48:11.404457+00:00","yanked":false}]}
{"categories":[],"crate":{"badges":[],"categories":[],"created_at":"2020-02-27T14:31:49.131258+00:00","description":"Dumb tiny logging timer","documentation":null,"downloads":44245,"exact_match":false,"homepage":"https://foss.heptapod.net/octobus/rust/micro-timer","id":"micro-timer","keywords":[],"links":{"owner_team":"/api/v1/crates/micro-timer/owner_team","owner_user":"/api/v1/crates/micro-timer/owner_user","owners":"/api/v1/crates/micro-timer/owners","reverse_dependencies":"/api/v1/crates/micro-timer/reverse_dependencies","version_downloads":"/api/v1/crates/micro-timer/downloads","versions":null},"max_stable_version":"0.4.0","max_version":"0.4.0","name":"micro-timer","newest_version":"0.4.0","recent_downloads":3910,"repository":"https://foss.heptapod.net/octobus/rust/micro-timer","updated_at":"2020-09-28T13:40:49.593030+00:00","versions":[288167,254896,248120,223660,223652,216405,216156,216139]},"keywords":[],"versions":[{"audit_actions":[{"action":"publish","time":"2020-09-28T13:40:49.593030+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":3513,"created_at":"2020-09-28T13:40:49.593030+00:00","dl_path":"/api/v1/crates/micro-timer/0.4.0/download","downloads":337,"features":{},"id":288167,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.4.0/authors","dependencies":"/api/v1/crates/micro-timer/0.4.0/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.4.0/downloads"},"num":"0.4.0","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.4.0/readme","updated_at":"2020-09-28T13:40:49.593030+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-06-22T16:40:06.754009+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":3357,"created_at":"2020-06-22T16:40:06.754009+00:00","dl_path":"/api/v1/crates/micro-timer/0.3.1/download","downloads":37853,"features":{},"id":254896,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.3.1/authors","dependencies":"/api/v1/crates/micro-timer/0.3.1/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.3.1/downloads"},"num":"0.3.1","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.3.1/readme","updated_at":"2020-06-22T16:40:06.754009+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-06-02T11:38:33.047581+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":3306,"created_at":"2020-06-02T11:38:33.047581+00:00","dl_path":"/api/v1/crates/micro-timer/0.3.0/download","downloads":4163,"features":{},"id":248120,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.3.0/authors","dependencies":"/api/v1/crates/micro-timer/0.3.0/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.3.0/downloads"},"num":"0.3.0","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.3.0/readme","updated_at":"2020-06-02T11:38:33.047581+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-03-23T11:22:26.288804+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":2937,"created_at":"2020-03-23T11:22:26.288804+00:00","dl_path":"/api/v1/crates/micro-timer/0.2.1/download","downloads":1301,"features":{},"id":223660,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.2.1/authors","dependencies":"/api/v1/crates/micro-timer/0.2.1/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.2.1/downloads"},"num":"0.2.1","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.2.1/readme","updated_at":"2020-03-23T11:22:26.288804+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-03-23T10:57:04.418462+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":2941,"created_at":"2020-03-23T10:57:04.418462+00:00","dl_path":"/api/v1/crates/micro-timer/0.2.0/download","downloads":104,"features":{},"id":223652,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.2.0/authors","dependencies":"/api/v1/crates/micro-timer/0.2.0/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.2.0/downloads"},"num":"0.2.0","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.2.0/readme","updated_at":"2020-03-23T10:57:04.418462+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-02-27T23:35:41.872176+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":4927,"created_at":"2020-02-27T23:35:41.872176+00:00","dl_path":"/api/v1/crates/micro-timer/0.1.2/download","downloads":258,"features":{},"id":216405,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.1.2/authors","dependencies":"/api/v1/crates/micro-timer/0.1.2/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.1.2/downloads"},"num":"0.1.2","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.1.2/readme","updated_at":"2020-02-27T23:35:41.872176+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-02-27T15:17:53.486346+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":2916,"created_at":"2020-02-27T15:17:53.486346+00:00","dl_path":"/api/v1/crates/micro-timer/0.1.1/download","downloads":111,"features":{},"id":216156,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.1.1/authors","dependencies":"/api/v1/crates/micro-timer/0.1.1/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.1.1/downloads"},"num":"0.1.1","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.1.1/readme","updated_at":"2020-02-27T15:17:53.486346+00:00","yanked":false},{"audit_actions":[{"action":"publish","time":"2020-02-27T14:31:49.131258+00:00","user":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"}}],"crate":"micro-timer","crate_size":2902,"created_at":"2020-02-27T14:31:49.131258+00:00","dl_path":"/api/v1/crates/micro-timer/0.1.0/download","downloads":118,"features":{},"id":216139,"license":"non-standard","links":{"authors":"/api/v1/crates/micro-timer/0.1.0/authors","dependencies":"/api/v1/crates/micro-timer/0.1.0/dependencies","version_downloads":"/api/v1/crates/micro-timer/0.1.0/downloads"},"num":"0.1.0","published_by":{"avatar":"https://avatars.githubusercontent.com/u/9445758?v=4","id":79957,"login":"Alphare","name":"Raphaël Gomès","url":"https://github.com/Alphare"},"readme_path":"/api/v1/crates/micro-timer/0.1.0/readme","updated_at":"2020-02-27T14:31:49.131258+00:00","yanked":false}]}
No preview for this file type
This diff is collapsed.
...@@ -24,7 +24,23 @@ def crates_listed_origin(crates_lister): ...@@ -24,7 +24,23 @@ def crates_listed_origin(crates_lister):
url="some-url/api/v1/crates/some-package", url="some-url/api/v1/crates/some-package",
visit_type="crates", visit_type="crates",
extra_loader_arguments={ extra_loader_arguments={
"artifacts": [{"version": "0.0.1", "url": "some-package-0.0.1.crate"}], "artifacts": [
{
"version": "0.0.1",
"filename": "some-package-0.0.1.crate",
"url": "https://somewhere/some-package-0.0.1.crate",
"checksums": {
"sha256": "5de32cb59a062672560d6f0842c4aa7714727457b9fe2daf8987d995a176a405", # noqa: B950
},
},
],
"crates_metadata": [
{
"version": "0.0.1",
"yanked": True,
"last_update": "1970-01-01T00:00:00.000000+00:00",
},
],
}, },
) )
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment