Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce PackageName, to fully type a package name #2801

Merged
merged 1 commit into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions source/dub/commandline.d
Original file line number Diff line number Diff line change
Expand Up @@ -1557,7 +1557,7 @@ class BuildCommand : GenerateCommand {
if (packageParts.name.startsWith(":"))
return 0;

const baseName = getBasePackageName(packageParts.name);
const baseName = PackageName(packageParts.name).main;
// Found locally
if (dub.packageManager.getBestPackage(baseName, packageParts.range))
return 0;
Expand Down Expand Up @@ -2788,7 +2788,7 @@ class DustmiteCommand : PackageBuildCommand {
static void fixPathDependency(string pack, ref Dependency dep) {
dep.visit!(
(NativePath path) {
auto mainpack = getBasePackageName(pack);
auto mainpack = PackageName(pack).main;
dep = Dependency(NativePath("../") ~ mainpack);
},
(any) { /* Nothing to do */ },
Expand Down
69 changes: 68 additions & 1 deletion source/dub/dependency.d
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,79 @@ import std.array;
import std.exception;
import std.string;

/// Represents a fully-qualified package name
public struct PackageName
{
/// The underlying full name of the package
private string fullName;
/// Where the separator lies, if any
private size_t separator;

/// For compatibility in `PackageDependency`
alias toString this;

/// Creates a new instance of this struct
public this(string fn) @safe pure
{
this.fullName = fn;
if (auto idx = fn.indexOf(':'))
this.separator = idx > 0 ? idx : fn.length;
else // We were given `:foo`
assert(0, "Argument to PackageName constructor needs to be " ~
"a fully qualified string");
}

/// Private constructor to have nothrow / @nogc
private this(string fn, size_t sep) @safe pure nothrow @nogc
{
this.fullName = fn;
this.separator = sep;
}

/// The base package name in which the subpackages may live
public PackageName main () const return @safe pure nothrow @nogc
{
return PackageName(this.fullName[0 .. this.separator], this.separator);
}

/// The subpackage name, or an empty string if there isn't
public string sub () const return @safe pure nothrow @nogc
{
// Return `null` instead of an empty string so that
// it can be used in a boolean context, e.g.
// `if (name.sub)` would be true with empty string
return this.separator < this.fullName.length
? this.fullName[this.separator + 1 .. $]
: null;
}

/// Human readable representation
public string toString () const return scope @safe pure nothrow @nogc
{
return this.fullName;
}
}

/** Encapsulates the name of a package along with its dependency specification.
*/
struct PackageDependency {
/// Backward compatibility
deprecated("Use the constructor that accepts a `PackageName` as first argument")
this(string n, Dependency s = Dependency.init) @safe pure
{
this.name = PackageName(n);
this.spec = s;
}

// Remove once deprecated overload is gone
this(PackageName n, Dependency s = Dependency.init) @safe pure nothrow @nogc
{
this.name = n;
this.spec = s;
}

/// Name of the referenced package.
string name;
PackageName name;

/// Dependency specification used to select a particular version of the package.
Dependency spec;
Expand Down
35 changes: 18 additions & 17 deletions source/dub/dub.d
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,8 @@ class Dub {
recipe_content = recipe_content[idx+1 .. $];
auto recipe_default_package_name = path.toString.baseName.stripExtension.strip;

auto recipe = parsePackageRecipe(recipe_content, recipe_filename, null, recipe_default_package_name);
const PackageName empty;
auto recipe = parsePackageRecipe(recipe_content, recipe_filename, empty, recipe_default_package_name);
enforce(recipe.buildSettings.sourceFiles.length == 0, "Single-file packages are not allowed to specify source files.");
enforce(recipe.buildSettings.sourcePaths.length == 0, "Single-file packages are not allowed to specify source paths.");
enforce(recipe.buildSettings.cSourcePaths.length == 0, "Single-file packages are not allowed to specify C source paths.");
Expand Down Expand Up @@ -637,7 +638,7 @@ class Dub {
try if (m_packageManager.getOrLoadPackage(path)) continue;
catch (Exception e) { logDebug("Failed to load path based selection: %s", e.toString().sanitize); }
} else if (!dep.repository.empty) {
if (m_packageManager.loadSCMPackage(getBasePackageName(p), dep.repository))
if (m_packageManager.loadSCMPackage(PackageName(p).main, dep.repository))
continue;
} else {
if (m_packageManager.getPackage(p, dep.version_)) continue;
Expand All @@ -664,12 +665,12 @@ class Dub {

if (options & UpgradeOptions.dryRun) {
bool any = false;
string rootbasename = getBasePackageName(m_project.rootPackage.name);
string rootbasename = PackageName(m_project.rootPackage.name).main;

foreach (p, ver; versions) {
if (!ver.path.empty || !ver.repository.empty) continue;

auto basename = getBasePackageName(p);
auto basename = PackageName(p).main;
if (basename == rootbasename) continue;

if (!m_project.selections.hasSelectedVersion(basename)) {
Expand Down Expand Up @@ -907,7 +908,7 @@ class Dub {
/// Ditto
Package fetch(string packageId, in VersionRange range, PlacementLocation location, FetchOptions options, string reason = "")
{
auto basePackageName = getBasePackageName(packageId);
auto basePackageName = PackageName(packageId).main;
Json pinfo;
PackageSupplier supplier;
foreach(ps; m_packageSuppliers){
Expand Down Expand Up @@ -1229,7 +1230,7 @@ class Dub {
Version[] listPackageVersions(string name)
{
Version[] versions;
auto basePackageName = getBasePackageName(name);
auto basePackageName = PackageName(name).main;
foreach (ps; this.m_packageSuppliers) {
try versions ~= ps.getVersions(basePackageName);
catch (Exception e) {
Expand Down Expand Up @@ -1719,7 +1720,7 @@ private class DependencyVersionResolver : DependencyResolver!(Dependency, Depend

// filter out invalid/unreachable dependency specs
versions = versions.filter!((v) {
bool valid = getPackage(pack, Dependency(v)) !is null;
bool valid = getPackage(PackageName(pack), Dependency(v)) !is null;
if (!valid) logDiagnostic("Excluding invalid dependency specification %s %s from dependency resolution process.", pack, v);
return valid;
}).array;
Expand All @@ -1735,7 +1736,7 @@ private class DependencyVersionResolver : DependencyResolver!(Dependency, Depend
protected override Dependency[] getSpecificConfigs(string pack, TreeNodes nodes)
{
if (!nodes.configs.path.empty || !nodes.configs.repository.empty) {
if (getPackage(nodes.pack, nodes.configs)) return [nodes.configs];
if (getPackage(PackageName(nodes.pack), nodes.configs)) return [nodes.configs];
else return null;
}
else return null;
Expand All @@ -1755,7 +1756,7 @@ private class DependencyVersionResolver : DependencyResolver!(Dependency, Depend
{
import std.array : appender;
auto ret = appender!(TreeNodes[]);
auto pack = getPackage(node.pack, node.config);
auto pack = getPackage(PackageName(node.pack), node.config);
if (!pack) {
// this can happen when the package description contains syntax errors
logDebug("Invalid package in dependency tree: %s %s", node.pack, node.config);
Expand All @@ -1764,13 +1765,13 @@ private class DependencyVersionResolver : DependencyResolver!(Dependency, Depend
auto basepack = pack.basePackage;

foreach (d; pack.getAllDependenciesRange()) {
auto dbasename = getBasePackageName(d.name);
auto dbasename = PackageName(d.name).main;

// detect dependencies to the root package (or sub packages thereof)
if (dbasename == basepack.name) {
auto absdeppath = d.spec.mapToPath(pack.path).path;
absdeppath.endsWithSlash = true;
auto subpack = m_dub.m_packageManager.getSubPackage(basepack, getSubPackageName(d.name), true);
auto subpack = m_dub.m_packageManager.getSubPackage(basepack, PackageName(d.name).sub, true);
if (subpack) {
auto desireddeppath = basepack.path;
desireddeppath.endsWithSlash = true;
Expand Down Expand Up @@ -1821,7 +1822,7 @@ private class DependencyVersionResolver : DependencyResolver!(Dependency, Depend
return configs.merge(config).valid;
}

private Package getPackage(string name, Dependency dep)
private Package getPackage(PackageName name, Dependency dep)
{
auto key = PackageDependency(name, dep);
if (auto pp = key in m_packages)
Expand All @@ -1831,16 +1832,16 @@ private class DependencyVersionResolver : DependencyResolver!(Dependency, Depend
return p;
}

private Package getPackageRaw(string name, Dependency dep)
private Package getPackageRaw(PackageName name, Dependency dep)
{
import dub.recipe.json;

auto basename = getBasePackageName(name);
auto basename = name.main;

// for sub packages, first try to get them from the base package
if (basename != name) {
auto subname = getSubPackageName(name);
auto basepack = getPackage(basename, dep);
auto subname = name.sub;
auto basepack = getPackage(name.main, dep);
if (!basepack) return null;
if (auto sp = m_dub.m_packageManager.getSubPackage(basepack, subname, true)) {
return sp;
Expand Down Expand Up @@ -1895,7 +1896,7 @@ private class DependencyVersionResolver : DependencyResolver!(Dependency, Depend
if (desc.type == Json.Type.null_)
continue;
PackageRecipe recipe;
parseJson(recipe, desc, null);
parseJson(recipe, desc);
auto ret = new Package(recipe);
m_remotePackages[key] = ret;
return ret;
Expand Down
14 changes: 8 additions & 6 deletions source/dub/packagemanager.d
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ class PackageManager {
* Returns:
* A `Package` if one was found, `null` if none exists.
*/
protected Package lookup (string name, Version vers) {
protected Package lookup (PackageName name, Version vers) {
if (!this.m_initialized)
this.refresh();

Expand Down Expand Up @@ -240,7 +240,7 @@ class PackageManager {
}
}

return this.lookup(name, ver);
return this.lookup(PackageName(name), ver);
}

/// ditto
Expand Down Expand Up @@ -268,7 +268,7 @@ class PackageManager {
// Bare mode
if (loc >= this.m_repositories.length)
return null;
return this.m_repositories[loc].load(name, ver, this);
return this.m_repositories[loc].load(PackageName(name), ver, this);
}

/// ditto
Expand Down Expand Up @@ -374,7 +374,9 @@ class PackageManager {
.format(path.toNativeString(),
packageInfoFiles.map!(f => cast(string)f.filename).join("/")));

auto content = readPackageRecipe(recipe, parent ? parent.name : null, mode);
const PackageName pname = parent
? PackageName(parent.name) : PackageName.init;
auto content = readPackageRecipe(recipe, pname, mode);
auto ret = new Package(content, path, parent, version_);
ret.m_infoFile = recipe;
return ret;
Expand Down Expand Up @@ -1433,13 +1435,13 @@ package struct Location {
* Returns:
* A `Package` if one was found, `null` if none exists.
*/
Package load (string name, Version vers, PackageManager mgr)
Package load (PackageName name, Version vers, PackageManager mgr)
{
if (auto pkg = this.lookup(name, vers))
return pkg;

string versStr = vers.toString();
const lookupName = getBasePackageName(name);
const lookupName = name.main;
const path = this.getPackagePath(lookupName, versStr) ~ (lookupName ~ "/");
if (!path.existsDirectory())
return null;
Expand Down
6 changes: 3 additions & 3 deletions source/dub/project.d
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ class Project {
pack.simpleLint();

foreach (d; pack.getAllDependencies()) {
auto basename = getBasePackageName(d.name);
auto basename = d.name.main;
d.spec.visit!(
(NativePath path) { /* Valid */ },
(Repository repo) { /* Valid */ },
Expand Down Expand Up @@ -517,8 +517,8 @@ class Project {
Dependency vspec = dep.spec;
Package p;

auto basename = getBasePackageName(dep.name);
auto subname = getSubPackageName(dep.name);
auto basename = dep.name.main;
auto subname = dep.name.sub;

// non-optional and optional-default dependencies (if no selections file exists)
// need to be satisfied
Expand Down
Loading
Loading