|
1 | | -""" |
2 | | -Check `Plugin Writer's Guide`_ for more details. |
3 | | -
|
4 | | -.. _Plugin Writer's Guide: |
5 | | - https://pulpproject.org/pulpcore/docs/dev/ |
6 | | -""" |
7 | | - |
8 | 1 | from logging import getLogger |
9 | 2 |
|
10 | 3 | from django.db import models |
11 | 4 |
|
12 | 5 | from pulpcore.plugin.models import ( |
13 | 6 | Content, |
14 | | - ContentArtifact, |
15 | 7 | Remote, |
16 | 8 | Repository, |
17 | | - Publication, |
18 | 9 | Distribution, |
19 | 10 | ) |
20 | 11 | from pulpcore.plugin.util import get_domain_pk |
|
24 | 15 |
|
25 | 16 | class RustContent(Content): |
26 | 17 | """ |
27 | | - The "rust" content type. |
| 18 | + The "rust" content type representing a Cargo package version. |
| 19 | +
|
| 20 | + This model represents a single version of a Rust crate as defined in the |
| 21 | + Cargo registry index specification. Each instance corresponds to one line |
| 22 | + in a package's index file. |
| 23 | +
|
| 24 | + Fields: |
| 25 | + name: The package name (crate name) |
| 26 | + vers: The semantic version string (SemVer 2.0.0) |
| 27 | + cksum: SHA256 checksum of the .crate file (tarball) |
| 28 | + yanked: Whether this version has been yanked (removed from normal use) |
| 29 | + features: JSON object mapping feature names to their dependencies |
| 30 | + features2: JSON object with extended feature syntax support |
| 31 | + links: Value from Cargo.toml manifest 'links' field (for native library linking) |
| 32 | + rust_version: Minimum Rust version required to compile this package |
| 33 | + v: Schema version of the index format (integer) |
| 34 | + """ |
28 | 35 |
|
29 | | - Define fields you need for your new content type and |
30 | | - specify uniqueness constraint to identify unit of this type. |
| 36 | + TYPE = "rust" |
| 37 | + repo_key_fields = ("name", "vers") |
31 | 38 |
|
32 | | - For example:: |
| 39 | + # Package name - alphanumeric characters, hyphens, and underscores allowed |
| 40 | + name = models.CharField(max_length=255, blank=False, null=False, db_index=True) |
33 | 41 |
|
34 | | - field1 = models.TextField() |
35 | | - field2 = models.IntegerField() |
36 | | - field3 = models.CharField() |
| 42 | + # Semantic version string following SemVer 2.0.0 specification |
| 43 | + vers = models.CharField(max_length=64, blank=False, null=False) |
37 | 44 |
|
38 | | - class Meta: |
39 | | - default_related_name = "%(app_label)s_%(model_name)s" |
40 | | - unique_together = ("field1", "field2") |
41 | | - """ |
| 45 | + # SHA256 checksum (hex-encoded) of the .crate tarball file for verification |
| 46 | + cksum = models.CharField(max_length=64, blank=False, null=False) |
42 | 47 |
|
43 | | - TYPE = "rust" |
| 48 | + # Indicates if this version has been yanked (deprecated/removed from use) |
| 49 | + # Yanked versions can still be used by existing Cargo.lock files but won't be selected |
| 50 | + # for new builds |
| 51 | + yanked = models.BooleanField(default=False) |
| 52 | + |
| 53 | + # Feature flags and compatibility |
| 54 | + # Maps feature names to lists of features/dependencies they enable |
| 55 | + # Example: {"default": ["std"], "std": [], "serde": ["dep:serde"]} |
| 56 | + features = models.JSONField(default=dict, blank=True) |
| 57 | + |
| 58 | + # Extended feature syntax introduced in newer registry versions |
| 59 | + # Supports more complex feature dependency expressions |
| 60 | + features2 = models.JSONField(default=dict, blank=True, null=True) |
| 61 | + |
| 62 | + # Name of native library this package links to (from Cargo.toml 'links' field) |
| 63 | + # Used to prevent multiple packages from linking the same native library |
| 64 | + links = models.CharField(max_length=255, blank=True, null=True) |
| 65 | + |
| 66 | + # Minimum Rust compiler version required (MSRV - Minimum Supported Rust Version) |
| 67 | + # Example: "1.56.0" |
| 68 | + rust_version = models.CharField(max_length=32, blank=True, null=True) |
| 69 | + |
| 70 | + # Schema version of the index entry format |
| 71 | + # Allows for future format evolution while maintaining backward compatibility |
| 72 | + v = models.IntegerField(default=1) |
44 | 73 |
|
45 | | - name = models.CharField(blank=False, null=False) |
46 | 74 | _pulp_domain = models.ForeignKey("core.Domain", default=get_domain_pk, on_delete=models.PROTECT) |
47 | 75 |
|
48 | 76 | class Meta: |
49 | 77 | default_related_name = "%(app_label)s_%(model_name)s" |
50 | | - unique_together = ("name", "_pulp_domain") |
| 78 | + unique_together = (("name", "vers", "_pulp_domain"),) |
51 | 79 |
|
52 | 80 |
|
53 | | -class RustPublication(Publication): |
| 81 | +class RustDependency(models.Model): |
54 | 82 | """ |
55 | | - A Publication for RustContent. |
56 | | -
|
57 | | - Define any additional fields for your new publication if needed. |
| 83 | + Represents a dependency of a Cargo package version. |
| 84 | +
|
| 85 | + Each RustContent (package version) can have multiple dependencies. |
| 86 | + Dependencies are stored as separate records to enable efficient querying |
| 87 | + and relationship tracking. |
| 88 | +
|
| 89 | + Fields: |
| 90 | + content: The package version that has this dependency |
| 91 | + name: The dependency name as used in code (may be renamed via 'package') |
| 92 | + req: Version requirement string (e.g., "^1.0", ">=0.2.3,<0.3") |
| 93 | + features: List of feature flags to enable for this dependency |
| 94 | + optional: Whether this is an optional dependency |
| 95 | + default_features: Whether to enable the dependency's default features |
| 96 | + target: Platform-specific conditional compilation target (e.g., "cfg(unix)") |
| 97 | + kind: Dependency type - "normal", "dev", or "build" |
| 98 | + registry: Alternative registry URL if dependency is from a different registry |
| 99 | + package: Original package name if dependency was renamed in Cargo.toml |
58 | 100 | """ |
59 | 101 |
|
60 | | - TYPE = "rust" |
| 102 | + # The package version that declares this dependency |
| 103 | + content = models.ForeignKey(RustContent, on_delete=models.CASCADE, related_name="dependencies") |
| 104 | + |
| 105 | + # Name of the dependency as used in the code (may differ from package name if renamed) |
| 106 | + name = models.CharField(max_length=255, blank=False, null=False) |
| 107 | + |
| 108 | + # Version requirement string using Cargo's version requirement syntax |
| 109 | + # Examples: "1.0", "^1.2.3", ">=1.0.0,<2.0.0", "*" |
| 110 | + req = models.CharField(max_length=255, blank=False, null=False) |
| 111 | + |
| 112 | + # List of feature flags to enable for this dependency |
| 113 | + # Example: ["serde", "std"] |
| 114 | + features = models.JSONField(default=list, blank=True) |
| 115 | + |
| 116 | + # If true, this dependency is only included when explicitly requested via features |
| 117 | + # Optional dependencies can be enabled as features themselves |
| 118 | + optional = models.BooleanField(default=False) |
| 119 | + |
| 120 | + # Whether to enable the dependency's default feature set |
| 121 | + # Setting to false allows for minimal builds |
| 122 | + default_features = models.BooleanField(default=True) |
| 123 | + |
| 124 | + # Platform-specific target configuration (cfg expression) |
| 125 | + # Example: "cfg(windows)", "cfg(target_arch = \"x86_64\")" |
| 126 | + # If set, dependency only applies when the target matches |
| 127 | + target = models.CharField(max_length=255, blank=True, null=True) |
| 128 | + |
| 129 | + # Type of dependency - determines when it's required during the build process |
| 130 | + kind = models.CharField( |
| 131 | + max_length=16, |
| 132 | + choices=[ |
| 133 | + ("normal", "Normal"), # Regular runtime dependency |
| 134 | + ("dev", "Development"), # Development/test-only dependency |
| 135 | + ("build", "Build"), # Build script dependency |
| 136 | + ], |
| 137 | + default="normal", |
| 138 | + ) |
| 139 | + |
| 140 | + # @TODO: I suspect this isn't needed |
| 141 | + # URL of alternative registry if dependency comes from a non-default registry |
| 142 | + # Null means the dependency is from the same registry as the parent package |
| 143 | + registry = models.CharField(max_length=512, blank=True, null=True) |
| 144 | + |
| 145 | + # Original crate name if the dependency was renamed |
| 146 | + # Example: if 'use foo' but package is 'bar', name='foo', package='bar' |
| 147 | + package = models.CharField(max_length=255, blank=True, null=True) |
61 | 148 |
|
62 | 149 | class Meta: |
63 | 150 | default_related_name = "%(app_label)s_%(model_name)s" |
| 151 | + verbose_name_plural = "rust dependencies" |
| 152 | + indexes = [ |
| 153 | + models.Index(fields=["content", "kind"]), |
| 154 | + models.Index(fields=["name"]), |
| 155 | + ] |
64 | 156 |
|
65 | 157 |
|
66 | 158 | class RustRemote(Remote): |
@@ -100,5 +192,7 @@ class RustDistribution(Distribution): |
100 | 192 |
|
101 | 193 | TYPE = "rust" |
102 | 194 |
|
| 195 | + allow_uploads = models.BooleanField(default=True) |
| 196 | + |
103 | 197 | class Meta: |
104 | 198 | default_related_name = "%(app_label)s_%(model_name)s" |
0 commit comments