Skip to content

Commit

Permalink
PackageManager: Store packages hierarchically, by version
Browse files Browse the repository at this point in the history
As explained in the changelog, this hierarchy makes much more sense
than the current one, and will make it possible to read the version
from the directory name.
  • Loading branch information
Geod24 committed Mar 2, 2023
1 parent 8d99f17 commit 230834c
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 26 deletions.
14 changes: 14 additions & 0 deletions changelog/hierarchy.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
The way packages are stored internally has changed

Previous versions of dub stored packages in the following format:
`$CACHE_PATH/$PACKAGE_NAME-$PACKAGE_VERSION/$PACKAGE_NAME/`
Starting from this version, the format will be:
`$CACHE_PATH/$PACKAGE_NAME/$PACKAGE_VERSION/$PACKAGE_NAME`.

Introducing a new level will help users quickly list what packages
they actually have installed, and reduce visibility of packages that
might update frequently. It will render various commands (e.g. `du`)
more useful, and pave the way for a package GC function.
More importantly, it will allow future version of dub to infer the
version from the path to the package, removing the need to read (or edit)
the recipe file on every dub invocation.
61 changes: 35 additions & 26 deletions source/dub/packagemanager.d
Original file line number Diff line number Diff line change
Expand Up @@ -1298,29 +1298,8 @@ private struct Location {
if (!path.existsDirectory())
return;

logDebug("iterating dir %s", path.toNativeString());
try foreach (pdir; iterateDirectory(path)) {
logDebug("iterating dir %s entry %s", path.toNativeString(), pdir.name);
if (!pdir.isDirectory) continue;

// Old / flat directory structure, used in non-standard path
// Packages are stored in $ROOT/$SOMETHING/`
auto pack_path = path ~ (pdir.name ~ "/");
auto packageFile = Package.findPackageFile(pack_path);

// New (since 2015) managed structure:
// $ROOT/$NAME-$VERSION/$NAME
// This is the most common code path
if (mgr.isManagedPath(path) && packageFile.empty) {
foreach (subdir; iterateDirectory(path ~ (pdir.name ~ "/")))
if (subdir.isDirectory && pdir.name.startsWith(subdir.name)) {
pack_path ~= subdir.name ~ "/";
packageFile = Package.findPackageFile(pack_path);
break;
}
}

if (packageFile.empty) continue;
void loadInternal (NativePath pack_path, NativePath packageFile)
{
Package p;
try {
foreach (pp; existing_packages)
Expand All @@ -1338,6 +1317,38 @@ private struct Location {
logDiagnostic("Full error: %s", e.toString().sanitize());
}
}

logDebug("iterating dir %s", path.toNativeString());
try foreach (pdir; iterateDirectory(path)) {
logDebug("iterating dir %s entry %s", path.toNativeString(), pdir.name);
if (!pdir.isDirectory) continue;

// Old / flat directory structure, used in non-standard path
// Packages are stored in $ROOT/$SOMETHING/`
const pack_path = path ~ (pdir.name ~ "/");
auto packageFile = Package.findPackageFile(pack_path);
if (!packageFile.empty) {
// Deprecated unmanaged directory structure
logWarn("Package at path '%s' should be under '%s'",
pack_path.toNativeString().color(Mode.bold),
(pack_path ~ "$VERSION" ~ pdir.name).toNativeString().color(Mode.bold));
logWarn("The package will no longer be detected starting from v1.42.0");
loadInternal(pack_path, packageFile);
}

// Managed structure: $ROOT/$NAME/$VERSION/$NAME
// This is the most common code path
if (mgr.isManagedPath(path) && packageFile.empty) {
// Iterate over versions of a package
foreach (versdir; iterateDirectory(pack_path)) {
if (!versdir.isDirectory) continue;
auto vers_path = pack_path ~ versdir.name ~ (pdir.name ~ "/");
if (!vers_path.existsDirectory()) continue;
packageFile = Package.findPackageFile(vers_path);
loadInternal(vers_path, packageFile);
}
}
}
catch (Exception e)
logDiagnostic("Failed to enumerate %s packages: %s", path.toNativeString(), e.toString());
}
Expand Down Expand Up @@ -1417,9 +1428,7 @@ private struct Location {
*/
private NativePath getPackagePath (string name, string vers)
{
// + has special meaning for Optlink
string clean_vers = vers.chompPrefix("~").replace("+", "_");
NativePath result = this.packagePath ~ (name ~ "-" ~ clean_vers);
NativePath result = this.packagePath ~ name ~ vers;
result.endsWithSlash = true;
return result;
}
Expand Down

0 comments on commit 230834c

Please sign in to comment.