Skip to content

Commit

Permalink
add env + config for package + settings locations
Browse files Browse the repository at this point in the history
fix #229
  • Loading branch information
WebFreak001 committed Aug 22, 2022
1 parent 83c4029 commit b8aa9a4
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 2 deletions.
41 changes: 41 additions & 0 deletions changelog/dpath.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
DUB settings & packages directory placement overhauled

You can now configure where DUB places its downloaded packages and where the user configuration is stored through environment variables or through the dub configuration. You need to use an environment variable or the system-wide dub configuration to specify where the user configuration is stored.

By default DUB stores the packages on
- Windows: `%APPDATA%/dub/settings.json` + `%LOCALAPPDATA%/dub/packages/`
- Posix: `$HOME/.dub/{packages/,settings.json}`

now if the `DUB_HOME` environment variable is set it instead stores the packages (and other config) in
- `$DUB_HOME/{packages/,settings.json}`

alternatively if `DUB_HOME` isn't set, but `DPATH` is set, the following path is used:
- `$DPATH/dub/{packages/,settings.json}`

The `DPATH` environment variable is intended to be used by all D tooling related things doing user-space installation of things. It can be used to avoid cluttering the home folder.

Additionally to environment variables it is possible to configure the package placement path + settings.json path through DUB's settings.json file. To configure where the user-editable settings.json is placed you need to adjust the system-wide dub configuration.

In the settings.json you can set the following fields:

```json
{
"dubHome": "/path/to/dub", // sets both package store and config location

// OR

"userSettings": "/path/to/dub/settings/folder",
"localRepository": "/path/to/dub/repository/folder"
}
```

Additionally, these config paths will have environment variables using the `$VARIABLE` syntax resolved.

The following list describes which path is going to be picked, from top to bottom, stopping whenever one is found:

- `$DUB_HOME` environment variable
- `$DPATH` environment variable
- system-wide settings.json: `"userSettings"` property
- system-wide settings.json: `"dubHome"` property (only for userSettings)
- through all settings.json: `"localRepository"` property
- through all settings.json: `"dubHome"` property (only for localRepository)
122 changes: 120 additions & 2 deletions source/dub/dub.d
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,120 @@ class Dub {
assert(dub.computePkgSuppliers(null, SkipPackageSuppliers.none, null).length == 1);
assert(dub.computePkgSuppliers(null, SkipPackageSuppliers.configured, null).length == 0);
assert(dub.computePkgSuppliers(null, SkipPackageSuppliers.standard, null).length == 0);

assert(dub.computePkgSuppliers(null, SkipPackageSuppliers.standard, "http://example.com/")
.length == 1);
.length == 1);

dub.m_config.skipRegistry = typeof(dub.m_config.skipRegistry)(SkipPackageSuppliers.configured);
assert(dub.getPackageSuppliers(null).length == 0);

dub.m_config.skipRegistry = typeof(dub.m_config.skipRegistry)(SkipPackageSuppliers.standard);
assert(dub.getPackageSuppliers(null).length == 0);

environment["DUB_REGISTRY"] = "http://example.com/";
assert(dub.getPackageSuppliers(null).length == 1);
}

/** Initializes the instance with a single package search path, without
loading a package.
This constructor corresponds to the "--bare" option of the command line
interface. Use
*/
this(NativePath override_path)
{
init(NativePath());
m_overrideSearchPath = override_path;
m_packageManager = new PackageManager(override_path);
}

private void loadConfigAndSetDirs(NativePath root_path)
{
import configy.Read;

this.m_dirs = SpecialDirs.make();

void readSettingsFile (NativePath path_)
{
const path = path_.toNativeString();
if (path.exists)
this.m_config = this.m_config.merge(
parseConfigFile!UserConfiguration(CLIArgs(path)));
}

const dubFolderPath = NativePath(thisExePath).parentPath;

// override default userSettings + localRepository if a $DPATH or
// $DUB_HOME environment variable is set.
bool overrideUserSettings;
bool overrideLocalRepository;
{
string dpathOverride = environment.get("DUB_HOME");
if (!dpathOverride.length) {
dpathOverride = environment.get("DPATH");
if (dpathOverride.length)
dpathOverride = (NativePath(dpathOverride) ~ "dub/").toNativeString();

}
if (dpathOverride.length) {
overrideUserSettings = true;
overrideLocalRepository = true;

m_dirs.userSettings = NativePath(dpathOverride);
m_dirs.localRepository = m_dirs.userSettings;
}
}

// load system-wide configs:
readSettingsFile(m_dirs.systemSettings ~ "settings.json");
readSettingsFile(dubFolderPath ~ "../etc/dub/settings.json");
version (Posix) {
if (dubFolderPath.absolute && dubFolderPath.startsWith(NativePath("usr")))
readSettingsFile(NativePath("/etc/dub/settings.json"));
}

// Override user + local package path from /etc/dub/settings.json
// Then continues loading local settings from these folders. (keeping
// global /etc/dub/settings.json settings intact)
//
// Don't use it if either $DPATH or $DUB_HOME are set.
if (!overrideUserSettings) {
if (this.userSettingsOverride.length) {
m_dirs.userSettings = NativePath(this.userSettingsOverride.expandEnvironmentVariables);

overrideUserSettings = true;
} else if (this.dubHome.length) {
m_dirs.userSettings = NativePath(this.dubHome.expandEnvironmentVariables);

overrideUserSettings = true;
}
}

// load user config:
readSettingsFile(m_dirs.userSettings ~ "settings.json");

// load per-package config:
if (!root_path.empty)
readSettingsFile(root_path ~ "dub.settings.json");

// resolve directories from config
if (!overrideLocalRepository) {
if (this.localRepository.length) {
m_dirs.localRepository = NativePath(this.localRepository.expandEnvironmentVariables);

overrideLocalRepository = true;
} else if (this.dubHome.length) {
m_dirs.localRepository = NativePath(this.dubHome.expandEnvironmentVariables);

overrideLocalRepository = true;
}
}
}

private void init(NativePath root_path)
{
loadConfigAndSetDirs(root_path);

determineDefaultCompiler();
}

@property bool dryRun() const { return m_dryRun; }
Expand Down Expand Up @@ -369,6 +480,10 @@ class Dub {
@property const(string[string]) defaultPreRunEnvironments() const { return this.m_config.defaultPreRunEnvironments; }
@property const(string[string]) defaultPostRunEnvironments() const { return this.m_config.defaultPostRunEnvironments; }

private @property const(string) dubHome() const { return this.m_config.dubHome; }
private @property const(string) userSettingsOverride() const { return this.m_config.userSettings; }
private @property const(string) localRepository() const { return this.m_config.localRepository; }

/** Loads the package that resides within the configured `rootPath`.
*/
void loadPackage()
Expand Down Expand Up @@ -1828,6 +1943,9 @@ private struct UserConfiguration {
SetInfo!(string[string]) defaultPostBuildEnvironments;
SetInfo!(string[string]) defaultPreRunEnvironments;
SetInfo!(string[string]) defaultPostRunEnvironments;
SetInfo!(string) dubHome;
SetInfo!(string) userSettings;
SetInfo!(string) localRepository;

/// Merge a lower priority config (`this`) with a `higher` priority config
public UserConfiguration merge(UserConfiguration higher)
Expand Down
8 changes: 8 additions & 0 deletions source/dub/project.d
Original file line number Diff line number Diff line change
Expand Up @@ -1433,6 +1433,7 @@ private string[] processVarsWithGlob(Project, Package)(string var, in Project pr
.filter!(name => globMatch(name, res))
.array;
}

/// Expand variables using `$VAR_NAME` or `${VAR_NAME}` syntax.
/// `$$` escapes itself and is expanded to a single `$`.
private string expandVars(alias expandVar)(string s)
Expand Down Expand Up @@ -1518,6 +1519,13 @@ unittest
assert(expandVars!expandVar("$${DUB_EXE:-dub}") == "${DUB_EXE:-dub}");
}

string expandEnvironmentVariables(string s)
{
import std.process : environment;

return expandVars!(v => environment.get(v))(s);
}

// Keep the following list up-to-date if adding more build settings variables.
/// List of variables that can be used in build settings
package(dub) immutable buildSettingsVars = [
Expand Down
11 changes: 11 additions & 0 deletions test/dpath-variable.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash

. $(dirname "${BASH_SOURCE[0]}")/common.sh
export DPATH="${CURR_DIR}/dpath-variable/dpath"
rm -rf "$DPATH"
cd ${CURR_DIR}/dpath-variable
${DUB} upgrade

if [[ ! -f "$DPATH/dub/packages/gitcompatibledubpackage-1.0.1/gitcompatibledubpackage/dub.json" ]]; then
die $LINENO 'Did not get dependencies installed into $DPATH.'
fi
1 change: 1 addition & 0 deletions test/dpath-variable/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dpath
6 changes: 6 additions & 0 deletions test/dpath-variable/dub.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "dpath-variable",
"dependencies": {
"gitcompatibledubpackage": "1.0.1"
}
}
3 changes: 3 additions & 0 deletions test/dpath-variable/source/app.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
void main()
{
}

0 comments on commit b8aa9a4

Please sign in to comment.