diff --git a/changelog/recipefile.dd b/changelog/recipefile.dd new file mode 100644 index 0000000..2941dbc --- /dev/null +++ b/changelog/recipefile.dd @@ -0,0 +1,15 @@ +Added `--recipe=` switch to DUB + +You can now override which file is used as recipe, instead of the default +`dub.sdl` and `dub.json`. This means you can define multiple dub.json files for +local development, for example for special local-machine-only operations, and +select which one to use over the CLI. + +``` +dub build --recipe=custom-dub.json +``` + +This can also be used to pick dub.sdl over dub.json, if both of them exist in +the same directory. Although this is discouraged for interoperability with other +DUB-supporting tools and general confusion for users. Both existing at the same +time may also become an error when this switch is not specified in the future. diff --git a/source/dub/commandline.d b/source/dub/commandline.d index 56edc9d..bcfbc2d 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -501,11 +501,13 @@ return 1; } - // initialize the root package - Dub dub = cmd.prepareDub(handler.options); + try { + // initialize the root package + Dub dub = cmd.prepareDub(handler.options); - // execute the command - try return cmd.execute(dub, remaining_args, command_args.appArgs); + // execute the command + return cmd.execute(dub, remaining_args, command_args.appArgs); + } catch (UsageException e) { // usage exceptions get thrown before any logging, so we are // making the errors more narrow to better fit on small screens. @@ -534,7 +536,7 @@ bool verbose, vverbose, quiet, vquiet, verror, version_; bool help, annotate, bare; string[] registry_urls; - string root_path; + string root_path, recipeFile; enum Color { automatic, on, off } Color colorMode = Color.automatic; SkipPackageSuppliers skipRegistry = SkipPackageSuppliers.none; @@ -568,6 +570,7 @@ { args.getopt("h|help", &help, ["Display general or command specific help"]); args.getopt("root", &root_path, ["Path to operate in instead of the current working dir"]); + args.getopt("recipe", &recipeFile, ["Loads a custom recipe path instead of dub.json/dub.sdl"]); args.getopt("registry", ®istry_urls, [ "Search the given registry URL first when resolving dependencies. Can be specified multiple times. Available registry types:", " DUB: URL to DUB registry (default)", @@ -836,11 +839,25 @@ dub = new Dub(options.root_path, package_suppliers, options.skipRegistry); dub.dryRun = options.annotate; dub.defaultPlacementLocation = options.placementLocation; - + dub.mainRecipePath = options.recipeFile; // make the CWD package available so that for example sub packages can reference their // parent package. - try dub.packageManager.getOrLoadPackage(NativePath(options.root_path), NativePath.init, false, StrictMode.Warn); - catch (Exception e) { logDiagnostic("No valid package found in current working directory: %s", e.msg); } + try dub.packageManager.getOrLoadPackage(NativePath(options.root_path), NativePath(options.recipeFile), false, StrictMode.Warn); + catch (Exception e) { + // by default we ignore CWD package load fails in prepareDUB, since + // they will fail again later when they are actually requested. This + // is done to provide custom options to the loading logic and should + // ideally be moved elsewhere. (This catch has been around since 10 + // years when it was first introduced in _app.d_) + logDiagnostic("No valid package found in current working directory: %s", e.msg); + + // for now, we work around not knowing if the package is needed or + // not, simply by trusting the user to only use `--recipe` when the + // recipe file actually exists, otherwise we throw the error. + bool loadMustSucceed = options.recipeFile.length > 0; + if (loadMustSucceed) + throw e; + } return dub; } @@ -1168,6 +1185,7 @@ return true; } + bool from_cwd = package_name.length == 0 || package_name.startsWith(":"); // load package in root_path to enable searching for sub packages if (loadCwdPackage(dub, from_cwd)) { @@ -1272,6 +1290,7 @@ if (!gensettings.config.length) gensettings.config = m_defaultConfig; gensettings.runArgs = app_args; + gensettings.recipeName = dub.mainRecipePath; // legacy compatibility, default working directory is always CWD gensettings.overrideToolWorkingDirectory = getWorkingDirectory(); diff --git a/source/dub/dub.d b/source/dub/dub.d index 87a78bc..b64a386 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -126,6 +126,7 @@ PackageManager m_packageManager; PackageSupplier[] m_packageSuppliers; NativePath m_rootPath; + string m_mainRecipePath; SpecialDirs m_dirs; Settings m_config; Project m_project; @@ -391,6 +392,14 @@ /// application. @property string projectName() const { return m_project.name; } + @property string mainRecipePath() const { return m_mainRecipePath; } + /// Whenever the switch --recipe= is supplied, this member will be populated. + @property string mainRecipePath(string recipePath) + { + return m_mainRecipePath = recipePath; + } + + @property NativePath projectPath() const { return this.m_project.rootPackage.path; } @property string[] configurations() const { return m_project.configurations; } diff --git a/source/dub/generators/build.d b/source/dub/generators/build.d index 73fe18b..707ba0d 100644 --- a/source/dub/generators/build.d +++ b/source/dub/generators/build.d @@ -46,8 +46,16 @@ addHash(settings.platform.architecture); addHash(settings.platform.compiler); addHash(settings.platform.compilerVersion); + if(settings.recipeName != "") + addHash(settings.recipeName); const hashstr = Base64URL.encode(hash.finish()[0 .. $ / 2]).stripRight("="); + if(settings.recipeName != "") + { + import std.path:stripExtension, baseName; + string recipeName = settings.recipeName.baseName.stripExtension; + return format("%s-%s-%s-%s", config, settings.buildType, recipeName, hashstr); + } return format("%s-%s-%s", config, settings.buildType, hashstr); } @@ -747,10 +755,9 @@ (cast(uint)(buildsettings.options & ~BuildOption.color)).to!string, // exclude color option from id settings.platform.compilerBinary, settings.platform.compiler, - settings.platform.compilerVersion, + settings.platform.compilerVersion ], ]; - return computeBuildName(config, settings, hashing); } diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index 5816058..20a301c 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -809,6 +809,7 @@ BuildPlatform platform; Compiler compiler; string config; + string recipeName; string buildType; BuildSettings buildSettings; BuildMode buildMode = BuildMode.separate; diff --git a/test/issue2684-recipe-file.sh b/test/issue2684-recipe-file.sh new file mode 100755 index 0000000..2567395 --- /dev/null +++ b/test/issue2684-recipe-file.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +cd ${CURR_DIR}/issue2684-recipe-file +${DUB} | grep -c "This was built using dub.json" > /dev/null +${DUB} --recipe=dubWithAnotherSource.json | grep -c "This was built using dubWithAnotherSource.json" > /dev/null \ No newline at end of file diff --git a/test/issue2684-recipe-file/.gitignore b/test/issue2684-recipe-file/.gitignore new file mode 100644 index 0000000..3de530e --- /dev/null +++ b/test/issue2684-recipe-file/.gitignore @@ -0,0 +1,16 @@ +.dub +docs.json +__dummy.html +docs/ +/issue2684-recipe-file +issue2684-recipe-file.so +issue2684-recipe-file.dylib +issue2684-recipe-file.dll +issue2684-recipe-file.a +issue2684-recipe-file.lib +issue2684-recipe-file-test-* +*.exe +*.pdb +*.o +*.obj +*.lst diff --git a/test/issue2684-recipe-file/anotherSource/app.d b/test/issue2684-recipe-file/anotherSource/app.d new file mode 100644 index 0000000..f28bb40 --- /dev/null +++ b/test/issue2684-recipe-file/anotherSource/app.d @@ -0,0 +1,7 @@ +module app; +import std.stdio; + +void main() +{ + writeln("This was built using dubWithAnotherSource.json"); +} \ No newline at end of file diff --git a/test/issue2684-recipe-file/dub.json b/test/issue2684-recipe-file/dub.json new file mode 100644 index 0000000..17ac6ce --- /dev/null +++ b/test/issue2684-recipe-file/dub.json @@ -0,0 +1,9 @@ +{ + "authors": [ + "Hipreme" + ], + "copyright": "Copyright © 2023, Hipreme", + "description": "A minimal D application.", + "license": "public domain", + "name": "issue2684-recipe-file" +} \ No newline at end of file diff --git a/test/issue2684-recipe-file/dubWithAnotherSource.json b/test/issue2684-recipe-file/dubWithAnotherSource.json new file mode 100644 index 0000000..0ef1676 --- /dev/null +++ b/test/issue2684-recipe-file/dubWithAnotherSource.json @@ -0,0 +1,10 @@ +{ + "authors": [ + "Hipreme" + ], + "copyright": "Copyright © 2023, Hipreme", + "description": "A minimal D application.", + "sourcePaths": ["anotherSource"], + "license": "public domain", + "name": "issue2684-recipe-file" +} \ No newline at end of file diff --git a/test/issue2684-recipe-file/source/app.d b/test/issue2684-recipe-file/source/app.d new file mode 100644 index 0000000..022b7ee --- /dev/null +++ b/test/issue2684-recipe-file/source/app.d @@ -0,0 +1,10 @@ +module app; +import std.stdio; + +void main() +{ + writeln("This was built using dub.json. +Try using the other configuration by calling dub with: +dub --recipe=dubWithAnotherSource.json +"); +}