diff --git a/source/dub/commandline.d b/source/dub/commandline.d index 4d1b44e..6980076 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -39,14 +39,14 @@ int runDubCommandLine(string[] args) { logDiagnostic("DUB version %s", getDUBVersion()); - + version(Windows){ // rdmd uses $TEMP to compute a temporary path. since cygwin substitutes backslashes // with slashes, this causes OPTLINK to fail (it thinks path segments are options) // we substitute the other way around here to fix this. environment["TEMP"] = environment["TEMP"].replace("/", "\\"); } - + // split application arguments from DUB arguments string[] app_args; auto app_args_idx = args.countUntil("--"); @@ -55,14 +55,14 @@ args = args[0 .. app_args_idx]; } args = args[1 .. $]; // strip the application name - + // parse general options bool verbose, vverbose, quiet, vquiet; bool help, annotate; LogLevel loglevel = LogLevel.info; string[] registry_urls; string root_path = getcwd(); - + auto common_args = new CommandArgs(args); try { common_args.getopt("h|help", &help, ["Display general or command specific help"]); @@ -74,7 +74,7 @@ common_args.getopt("q|quiet", &quiet, ["Only print warnings and errors"]); common_args.getopt("vquiet", &vquiet, ["Print no messages"]); common_args.getopt("cache", &defaultPlacementLocation, ["Puts any fetched packages in the specified location [local|system|user]."]); - + if( vverbose ) loglevel = LogLevel.debug_; else if( verbose ) loglevel = LogLevel.diagnostic; else if( vquiet ) loglevel = LogLevel.none; @@ -86,41 +86,41 @@ logInfo("Run 'dub help' for usage information."); return 1; } - + // create the list of all supported commands - + CommandGroup[] commands = [ CommandGroup("Package creation", - new InitCommand - ), + new InitCommand + ), CommandGroup("Build, test and run", - new RunCommand, - new BuildCommand, - new TestCommand, - new GenerateCommand, - new DescribeCommand, - new CleanCommand, - new DustmiteCommand - ), + new RunCommand, + new BuildCommand, + new TestCommand, + new GenerateCommand, + new DescribeCommand, + new CleanCommand, + new DustmiteCommand + ), CommandGroup("Package management", - new FetchCommand, - new InstallCommand, - new RemoveCommand, - new UninstallCommand, - new UpgradeCommand, - new AddPathCommand, - new RemovePathCommand, - new AddLocalCommand, - new RemoveLocalCommand, - new ListCommand, - new ListInstalledCommand, - new AddOverrideCommand, - new RemoveOverrideCommand, - new ListOverridesCommand, - new CleanCachesCommand, - ) + new FetchCommand, + new InstallCommand, + new RemoveCommand, + new UninstallCommand, + new UpgradeCommand, + new AddPathCommand, + new RemovePathCommand, + new AddLocalCommand, + new RemoveLocalCommand, + new ListCommand, + new ListInstalledCommand, + new AddOverrideCommand, + new RemoveOverrideCommand, + new ListOverridesCommand, + new CleanCachesCommand, + ) ]; - + // extract the command string cmdname; args = common_args.extractRemainingArgs(); @@ -135,28 +135,28 @@ cmdname = "run"; } auto command_args = new CommandArgs(args); - + if (cmdname == "help") { showHelp(commands, common_args); return 0; } - + // find the selected command Command cmd; foreach (grp; commands) foreach (c; grp.commands) - if (c.name == cmdname) { - cmd = c; - break; - } - + if (c.name == cmdname) { + cmd = c; + break; + } + if (!cmd) { logError("Unknown command: %s", cmdname); writeln(); showHelp(commands, common_args); return 1; } - + // process command line options for the selected command try { cmd.prepare(command_args); @@ -167,34 +167,34 @@ logInfo("Run 'dub help' for usage information."); return 1; } - + if (help) { showCommandHelp(cmd, command_args, common_args); return 0; } - + auto remaining_args = command_args.extractRemainingArgs(); if (remaining_args.any!(a => a.startsWith("-"))) { logError("Unknown command line flags: %s", remaining_args.filter!(a => a.startsWith("-")).array.join(" ")); logError(`Type "dub %s -h" to get a list of all supported flags.`, cmdname); return 1; } - + Dub dub; - + // initialize the root package if (!cmd.skipDubInitialization) { // initialize DUB auto package_suppliers = registry_urls.map!(url => cast(PackageSupplier)new RegistryPackageSupplier(URL(url))).array; dub = new Dub(package_suppliers, root_path); dub.dryRun = annotate; - + // make the CWD package available so that for example sub packages can reference their // parent package. try dub.packageManager.getOrLoadPackage(Path(root_path)); catch (Exception e) { logDiagnostic("No package found in current working directory."); } } - + // execute the command int rc; try { @@ -212,7 +212,7 @@ logDebug("Full exception: %s", e.toString().sanitize); return 2; } - + if (!cmd.skipDubInitialization) dub.shutdown(); return rc; @@ -229,22 +229,22 @@ string[] m_args; Arg[] m_recognizedArgs; } - + this(string[] args) { m_args = "dummy" ~ args; } - + @property const(Arg)[] recognizedArgs() { return m_recognizedArgs; } - + void getopt(T)(string names, T* var, string[] help_text = null) { foreach (ref arg; m_recognizedArgs) - if (names == arg.names) { - assert(help_text is null); - *var = arg.value.get!T; - return; - } + if (names == arg.names) { + assert(help_text is null); + *var = arg.value.get!T; + return; + } assert(help_text.length > 0); Arg arg; arg.defaultValue = *var; @@ -254,12 +254,12 @@ arg.value = *var; m_recognizedArgs ~= arg; } - + void dropAllArgs() { m_args = null; } - + string[] extractRemainingArgs() { auto ret = m_args[1 .. $]; @@ -276,7 +276,7 @@ bool acceptsAppArgs; bool hidden = false; // used for deprecated commands bool skipDubInitialization = false; - + abstract void prepare(scope CommandArgs args); abstract int execute(Dub dub, string[] free_args, string[] app_args); } @@ -284,7 +284,7 @@ struct CommandGroup { string caption; Command[] commands; - + this(string caption, Command[] commands...) { this.caption = caption; @@ -298,10 +298,13 @@ /******************************************************************************/ class InitCommand : Command { + private{ + string m_buildType; + } this() { this.name = "init"; - this.argumentsPattern = "[ []]"; + this.argumentsPattern = "[ [...] [--type=]]"; this.description = "Initializes an empty package skeleton"; this.helpText = [ "Initializes an empty package of the specified type in the given directory. By default, the current working dirctory is used. Available types:", @@ -311,19 +314,23 @@ "deimos - standard skeleton for a static C binding library" ]; } - + override void prepare(scope CommandArgs args) { + args.getopt("t|type", &m_buildType, ["Set the type of project to generate. [minimal (default) | vibe.d | deimos"]); } - + override int execute(Dub dub, string[] free_args, string[] app_args) { string dir, type = "minimal"; enforceUsage(app_args.empty, "Unexpected application arguments."); - enforceUsage(free_args.length <= 2, "Too many arguments."); - if (free_args.length >= 1) dir = free_args[0]; - if (free_args.length >= 2) type = free_args[1]; - dub.createEmptyPackage(Path(dir), type); + if(m_buildType.length == 0) + m_buildType = "minimal"; + dir = free_args[0]; + if (free_args.length == 1) + dub.createEmptyPackage(Path(dir), [], m_buildType); + else + dub.createEmptyPackage(Path(dir), free_args[1..$], m_buildType); return 0; } } @@ -349,7 +356,7 @@ bool m_forceRemove = false; bool m_disableBuildOption = false; } - + override void prepare(scope CommandArgs args) { if (!m_disableBuildOption) { @@ -385,16 +392,16 @@ " separate (default), allAtOnce, singleFile" ]); } - + protected void setupPackage(Dub dub, string package_name) { m_compiler = getCompiler(m_compilerName); m_buildPlatform = m_compiler.determinePlatform(m_buildSettings, m_compilerName, m_arch); m_buildSettings.addDebugVersions(m_debugVersions); - + m_defaultConfig = null; enforce (loadSpecificPackage(dub, package_name), "Failed to load package."); - + if (m_buildConfig.length != 0 && !dub.configurations.canFind(m_buildConfig)) { string msg = "Unknown build configuration: "~m_buildConfig; @@ -403,15 +410,15 @@ msg ~= ". Did you mean '" ~ match ~ "'?"; enforce(0, msg); } - + if (m_buildType.length == 0) { if (environment.get("DFLAGS")) m_buildType = "$DFLAGS"; else m_buildType = "debug"; } - + if (!m_nodeps) { // TODO: only upgrade(select) if necessary, only upgrade(upgrade) every now and then - + // retrieve missing packages logDiagnostic("Checking for missing dependencies."); dub.upgrade(UpgradeOptions.select); @@ -419,10 +426,10 @@ logDiagnostic("Checking for upgrades."); dub.upgrade(UpgradeOptions.upgrade|UpgradeOptions.printUpgradesOnly|UpgradeOptions.useCachedResult); } - + dub.project.validate(); } - + private bool loadSpecificPackage(Dub dub, string package_name) { Package pack; @@ -440,17 +447,17 @@ if (!loadCwdPackage(dub, pack, true)) return false; return true; } - + private bool loadCwdPackage(Dub dub, Package pack, bool warn_missing_package) { if (warn_missing_package) { bool found = existsFile(dub.rootPath ~ "source/app.d"); if (!found) foreach (f; packageInfoFiles) - if (existsFile(dub.rootPath ~ f.filename)) { - found = true; - break; - } + if (existsFile(dub.rootPath ~ f.filename)) { + found = true; + break; + } if (!found) { logInfo(""); logInfo("Neither a package description file, nor source/app.d was found in"); @@ -461,10 +468,10 @@ return false; } } - + if (pack) dub.loadPackage(pack); else dub.loadPackageFromCwd(); - + return true; } } @@ -479,7 +486,7 @@ bool m_combined = false; bool m_printPlatform, m_printBuilds, m_printConfigs; } - + this() { this.name = "generate"; @@ -494,15 +501,15 @@ "An optional package name can be given to generate a different package than the root/CWD package." ]; } - + override void prepare(scope CommandArgs args) { super.prepare(args); - + args.getopt("combined", &m_combined, [ "Tries to build the whole project in a single compiler run." ]); - + args.getopt("print-builds", &m_printBuilds, [ "Prints the list of available build types" ]); @@ -513,7 +520,7 @@ "Prints the identifiers for the current build platform as used for the build fields in dub.json" ]); } - + override int execute(Dub dub, string[] free_args, string[] app_args) { string package_name; @@ -525,16 +532,16 @@ enforceUsage(free_args.length <= 1, "Expected one or zero arguments."); if (free_args.length >= 1) package_name = free_args[0]; } - + setupPackage(dub, package_name); - + if (m_printBuilds) { // FIXME: use actual package data logInfo("Available build types:"); foreach (tp; ["debug", "release", "unittest", "profile"]) logInfo(" %s", tp); logInfo(""); } - + m_defaultConfig = dub.project.getDefaultConfiguration(m_buildPlatform); if (m_printConfigs) { logInfo("Available configurations:"); @@ -542,7 +549,7 @@ logInfo(" %s%s", tp, tp == m_defaultConfig ? " [default]" : null); logInfo(""); } - + GeneratorSettings gensettings; gensettings.platform = m_buildPlatform; gensettings.config = m_buildConfig.length ? m_buildConfig : m_defaultConfig; @@ -556,7 +563,7 @@ gensettings.force = m_force; gensettings.rdmd = m_rdmd; gensettings.tempBuild = m_tempBuild; - + logDiagnostic("Generating using %s", m_generator); if (m_generator == "visuald-combined") { gensettings.combined = true; @@ -579,20 +586,20 @@ "Builds a package (uses the main package in the current working directory by default)" ]; } - + override void prepare(scope CommandArgs args) { args.getopt("rdmd", &m_rdmd, [ "Use rdmd instead of directly invoking the compiler" ]); - + args.getopt("f|force", &m_force, [ "Forces a recompilation even if the target is up to date" ]); super.prepare(args); m_generator = "build"; } - + override int execute(Dub dub, string[] free_args, string[] app_args) { return super.execute(dub, free_args, app_args); @@ -610,17 +617,17 @@ ]; this.acceptsAppArgs = true; } - + override void prepare(scope CommandArgs args) { args.getopt("temp-build", &m_tempBuild, [ "Builds the project in the temp folder if possible." ]); - + super.prepare(args); m_run = true; } - + override int execute(Dub dub, string[] free_args, string[] app_args) { return super.execute(dub, free_args, app_args); @@ -633,7 +640,7 @@ bool m_combined = false; bool m_force = false; } - + this() { this.name = "test"; @@ -659,11 +666,11 @@ `run the unit tests.` ]; this.acceptsAppArgs = true; - + m_buildType = "unittest"; m_disableBuildOption = true; } - + override void prepare(scope CommandArgs args) { args.getopt("main-file", &m_mainFile, [ @@ -680,18 +687,18 @@ "Enables code coverage statistics to be generated." ]); if (coverage) m_buildType = "unittest-cov"; - + super.prepare(args); } - + override int execute(Dub dub, string[] free_args, string[] app_args) { string package_name; enforceUsage(free_args.length <= 1, "Expected one or zero arguments."); if (free_args.length >= 1) package_name = free_args[0]; - + setupPackage(dub, package_name); - + GeneratorSettings settings; settings.platform = m_buildPlatform; settings.compiler = getCompiler(m_buildPlatform.compilerBinary); @@ -702,7 +709,7 @@ settings.force = m_force; settings.run = true; settings.runArgs = app_args; - + dub.testProject(settings, m_buildConfig, Path(m_mainFile)); return 0; } @@ -719,26 +726,26 @@ "All usual options that are also used for build/run/generate apply." ]; } - + override void prepare(scope CommandArgs args) { super.prepare(args); } - + override int execute(Dub dub, string[] free_args, string[] app_args) { // disable all log output and use "writeln" to output the JSON description auto ll = getLogLevel(); setLogLevel(LogLevel.none); scope (exit) setLogLevel(ll); - + string package_name; enforceUsage(free_args.length <= 1, "Expected one or zero arguments."); if (free_args.length >= 1) package_name = free_args[0]; setupPackage(dub, package_name); - + m_defaultConfig = dub.project.getDefaultConfiguration(m_buildPlatform); - + dub.describeProject(m_buildPlatform, m_buildConfig.length ? m_buildConfig : m_defaultConfig); return 0; } @@ -748,7 +755,7 @@ private { bool m_allPackages; } - + this() { this.name = "clean"; @@ -759,29 +766,29 @@ "Without arguments, the package in the current working directory will be cleaned." ]; } - + override void prepare(scope CommandArgs args) { args.getopt("all-packages", &m_allPackages, [ "Cleans up *all* known packages (dub list)" ]); } - + override int execute(Dub dub, string[] free_args, string[] app_args) { enforceUsage(free_args.length <= 1, "Expected one or zero arguments."); enforceUsage(app_args.length == 0, "Application arguments are not supported for the clean command."); enforceUsage(!m_allPackages || !free_args.length, "The --all-packages flag may not be used together with an explicit package name."); - + enforce(free_args.length == 0, "Cleaning a specific package isn't possible right now."); - + if (m_allPackages) { foreach (p; dub.packageManager.getPackageIterator()) dub.cleanPackage(p.path); } else { dub.cleanPackage(dub.rootPath); } - + return 0; } } @@ -798,7 +805,7 @@ bool m_missingOnly = false; bool m_verify = false; } - + this() { this.name = "upgrade"; @@ -812,7 +819,7 @@ "If a package specified, (only) that package will be upgraded. Otherwise all direct and indirect dependencies of the current package will get upgraded." ]; } - + override void prepare(scope CommandArgs args) { args.getopt("prerelease", &m_prerelease, [ @@ -828,7 +835,7 @@ "Performs an upgrade only for dependencies that don't yet have a version selected. This is also done automatically before each build." ]); } - + override int execute(Dub dub, string[] free_args, string[] app_args) { enforceUsage(free_args.length <= 1, "Unexpected arguments."); @@ -853,21 +860,21 @@ bool m_system = false; bool m_local = false; } - + override void prepare(scope CommandArgs args) { args.getopt("version", &m_version, [ "Use the specified version/branch instead of the latest available match", "The remove command also accepts \"*\" here as a wildcard to remove all versions of the package from the specified location" ]); - + args.getopt("system", &m_system, ["Deprecated: Puts the package into the system wide package cache instead of the user local one."]); args.getopt("local", &m_local, ["Deprecated: Puts the package into a sub folder of the current working directory. Cannot be mixed with --system."]); args.getopt("force-remove", &m_forceRemove, [ "Force deletion of fetched packages with untracked files" ]); } - + abstract override int execute(Dub dub, string[] free_args, string[] app_args); } @@ -894,18 +901,18 @@ "Note: DUB does not do a system installation of packages. Packages are instead only registered within DUB's internal ecosystem. Generation of native system packages/installers may be added later as a separate feature." ]; } - + override void prepare(scope CommandArgs args) { super.prepare(args); } - + override int execute(Dub dub, string[] free_args, string[] app_args) { enforceUsage(!m_local || !m_system, "--local and --system are exclusive to each other."); enforceUsage(free_args.length == 1, "Expecting exactly one argument."); enforceUsage(app_args.length == 0, "Unexpected application arguments."); - + auto location = defaultPlacementLocation; if (m_local) { @@ -917,9 +924,9 @@ logWarn("--system is deprecated. Use --cache=system instead."); location = PlacementLocation.system; } - + auto name = free_args[0]; - + FetchOptions fetchOpts; fetchOpts |= FetchOptions.forceBranchUpgrade; fetchOpts |= m_forceRemove ? FetchOptions.forceRemove : FetchOptions.none; @@ -962,17 +969,17 @@ "Removes a package that is cached on the local system." ]; } - + override void prepare(scope CommandArgs args) { super.prepare(args); } - + override int execute(Dub dub, string[] free_args, string[] app_args) { enforceUsage(free_args.length == 1, "Expecting exactly one argument."); enforceUsage(app_args.length == 0, "Unexpected application arguments."); - + auto package_id = free_args[0]; auto location = defaultPlacementLocation; if (m_local) @@ -985,7 +992,7 @@ logWarn("--system is deprecated. Use --cache=system instead."); location = PlacementLocation.system; } - + dub.remove(package_id, m_version, location, m_forceRemove); return 0; } @@ -1010,14 +1017,14 @@ private { bool m_system; } - + override void prepare(scope CommandArgs args) { args.getopt("system", &m_system, [ "Register system-wide instead of user-wide" ]); } - + abstract override int execute(Dub dub, string[] free_args, string[] app_args); } @@ -1029,7 +1036,7 @@ this.description = "Adds a default package search path"; this.helpText = ["Adds a default package search path"]; } - + override int execute(Dub dub, string[] free_args, string[] app_args) { enforceUsage(free_args.length == 1, "Missing search path."); @@ -1046,7 +1053,7 @@ this.description = "Removes a package search path"; this.helpText = ["Removes a package search path"]; } - + override int execute(Dub dub, string[] free_args, string[] app_args) { enforceUsage(free_args.length == 1, "Expected one argument."); @@ -1063,7 +1070,7 @@ this.description = "Adds a local package directory (e.g. a git repository)"; this.helpText = ["Adds a local package directory (e.g. a git repository)"]; } - + override int execute(Dub dub, string[] free_args, string[] app_args) { enforceUsage(free_args.length == 1 || free_args.length == 2, "Expecting one or two arguments."); @@ -1081,7 +1088,7 @@ this.description = "Removes a local package directory"; this.helpText = ["Removes a local package directory"]; } - + override int execute(Dub dub, string[] free_args, string[] app_args) { enforceUsage(free_args.length == 1, "Missing path to package."); @@ -1130,7 +1137,7 @@ private { bool m_system = false; } - + this() { this.name = "add-override"; @@ -1139,14 +1146,14 @@ this.helpText = [ ]; } - + override void prepare(scope CommandArgs args) { args.getopt("system", &m_system, [ "Register system-wide instead of user-wide" ]); } - + override int execute(Dub dub, string[] free_args, string[] app_args) { enforceUsage(app_args.length == 0, "Unexpected application arguments."); @@ -1171,7 +1178,7 @@ private { bool m_system = false; } - + this() { this.name = "remove-override"; @@ -1180,14 +1187,14 @@ this.helpText = [ ]; } - + override void prepare(scope CommandArgs args) { args.getopt("system", &m_system, [ "Register system-wide instead of user-wide" ]); } - + override int execute(Dub dub, string[] free_args, string[] app_args) { enforceUsage(app_args.length == 0, "Unexpected application arguments."); @@ -1240,9 +1247,9 @@ "This command removes any cached metadata like the list of available packages and their latest version." ]; } - + override void prepare(scope CommandArgs args) {} - + override int execute(Dub dub, string[] free_args, string[] app_args) { dub.cleanCaches(); @@ -1265,7 +1272,7 @@ string m_testPackage; bool m_combined; } - + this() { this.name = "dustmite"; @@ -1280,7 +1287,7 @@ "Determining the desired error condition is done by checking the compiler/linker status code, as well as their output (stdout and stderr combined). If --program-status or --program-regex is given and the generated binary is an executable, it will be executed and its output will also be incorporated into the final decision." ]; } - + override void prepare(scope CommandArgs args) { args.getopt("compiler-status", &m_compilerStatusCode, ["The expected status code of the compiler run"]); @@ -1292,19 +1299,19 @@ args.getopt("test-package", &m_testPackage, ["Perform a test run - usually only used internally"]); args.getopt("combined", &m_combined, ["Builds multiple packages with one compiler run"]); super.prepare(args); - + // speed up loading when in test mode if (m_testPackage.length) skipDubInitialization = true; } - + override int execute(Dub dub, string[] free_args, string[] app_args) { if (m_testPackage.length) { dub = new Dub(Path(getcwd())); - + setupPackage(dub, m_testPackage); m_defaultConfig = dub.project.getDefaultConfiguration(m_buildPlatform); - + GeneratorSettings gensettings; gensettings.platform = m_buildPlatform; gensettings.config = m_buildConfig.length ? m_buildConfig : m_defaultConfig; @@ -1334,12 +1341,12 @@ enforceUsage(path.length > 0, "Destination path must not be empty."); if (!path.absolute) path = Path(getcwd()) ~ path; enforceUsage(!path.startsWith(dub.rootPath), "Destination path must not be a sub directory of the tested package!"); - + setupPackage(dub, null); auto prj = dub.project; if (m_buildConfig.empty) m_buildConfig = prj.getDefaultConfiguration(m_buildPlatform); - + void copyFolderRec(Path folder, Path dstfolder) { mkdirRecurse(dstfolder.toNativeString()); @@ -1357,7 +1364,7 @@ } } } - + bool[string] visited; foreach (pack_; prj.getTopologicalPackageList()) { auto pack = pack_.basePackage; @@ -1381,38 +1388,38 @@ } return 0; } - + void delegate(int, string) check(int code_match, string regex_match) { return (code, output) { import std.encoding; import std.regex; - + if (code_match != int.min && code != code_match) { logInfo("Exit code %s doesn't match expected value %s", code, code_match); throw new DustmiteMismatchException; } - + if (regex_match.length > 0 && !match(output.sanitize, regex_match)) { logInfo("Output doesn't match regex:"); logInfo("%s", output); throw new DustmiteMismatchException; } - + if (code != 0 && code_match != int.min || regex_match.length > 0) { logInfo("Tool failed, but matched either exit code or output - counting as match."); throw new DustmiteMatchException; } }; } - + static class DustmiteMismatchException : Exception { this(string message = "", string file = __FILE__, int line = __LINE__, Throwable next = null) { super(message, file, line, next); } } - + static class DustmiteMatchException : Exception { this(string message = "", string file = __FILE__, int line = __LINE__, Throwable next = null) { @@ -1436,7 +1443,7 @@ private void showHelp(in CommandGroup[] commands, CommandArgs common_args) { writeln( -`USAGE: dub [] [] [-- []] + `USAGE: dub [] [] [-- []] Manages the DUB project in the current directory. If the command is omitted, DUB will default to "run". When running an application, "--" can be used to @@ -1450,7 +1457,7 @@ Available commands ==================`); - + foreach (grp; commands) { writeln(); writeWS(shortArgColumn); @@ -1488,7 +1495,7 @@ writeln(); foreach (ln; cmd.helpText) ln.writeWrapped(); - + if (args.recognizedArgs.length) { writeln(); writeln(); @@ -1497,7 +1504,7 @@ writeln(); writeOptions(args); } - + writeln(); writeln(); writeln("Common options"); diff --git a/source/dub/dub.d b/source/dub/dub.d index 5226a79..fb163f3 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -74,14 +74,14 @@ Project m_project; Path m_overrideSearchPath; } - + /// Initiales the package manager for the vibe application /// under root. this(PackageSupplier[] additional_package_suppliers = null, string root_path = ".") { m_rootPath = Path(root_path); if (!m_rootPath.absolute) m_rootPath = Path(getcwd()) ~ m_rootPath; - + version(Windows){ m_systemDubPath = Path(environment.get("ProgramData")) ~ "dub/"; m_userDubPath = Path(environment.get("APPDATA")) ~ "dub/"; @@ -93,10 +93,10 @@ m_userDubPath = Path(getcwd()) ~ m_userDubPath; m_tempPath = Path("/tmp"); } - + m_userConfig = jsonFromFile(m_userDubPath ~ "settings.json", true); m_systemConfig = jsonFromFile(m_systemDubPath ~ "settings.json", true); - + PackageSupplier[] ps = additional_package_suppliers; if (auto pp = "registryUrls" in m_userConfig) ps ~= deserializeJson!(string[])(*pp) @@ -107,16 +107,16 @@ .map!(url => cast(PackageSupplier)new RegistryPackageSupplier(URL(url))) .array; ps ~= defaultPackageSuppliers(); - + auto cacheDir = m_userDubPath ~ "cache/"; foreach (p; ps) p.cacheOp(cacheDir, CacheOp.load); - + m_packageSuppliers = ps; m_packageManager = new PackageManager(m_userDubPath, m_systemDubPath); updatePackageSearchPath(); } - + /// Initializes DUB with only a single search path this(Path override_path) { @@ -124,7 +124,7 @@ m_packageManager = new PackageManager(Path(), Path(), false); updatePackageSearchPath(); } - + /// Perform cleanup and persist caches to disk void shutdown() { @@ -132,7 +132,7 @@ foreach (p; m_packageSuppliers) p.cacheOp(cacheDir, CacheOp.store); } - + /// cleans all metadata caches void cleanCaches() { @@ -140,9 +140,9 @@ foreach (p; m_packageSuppliers) p.cacheOp(cacheDir, CacheOp.clean); } - + @property void dryRun(bool v) { m_dryRun = v; } - + /** Returns the root path (usually the current working directory). */ @property Path rootPath() const { return m_rootPath; } @@ -152,26 +152,26 @@ m_rootPath = root_path; if (!m_rootPath.absolute) m_rootPath = Path(getcwd()) ~ m_rootPath; } - + /// Returns the name listed in the dub.json of the current /// application. @property string projectName() const { return m_project.name; } - + @property Path projectPath() const { return m_projectPath; } - + @property string[] configurations() const { return m_project.configurations; } - + @property inout(PackageManager) packageManager() inout { return m_packageManager; } - + @property inout(Project) project() inout { return m_project; } - + /// Loads the package from the current working directory as the main /// project package. void loadPackageFromCwd() { loadPackage(m_rootPath); } - + /// Loads the package from the specified path as the main project package. void loadPackage(Path path) { @@ -179,7 +179,7 @@ updatePackageSearchPath(); m_project = new Project(m_packageManager, m_projectPath); } - + /// Loads a specific package as the main project package (can be a sub package) void loadPackage(Package pack) { @@ -187,21 +187,21 @@ updatePackageSearchPath(); m_project = new Project(m_packageManager, pack); } - + void overrideSearchPath(Path path) { if (!path.absolute) path = Path(getcwd()) ~ path; m_overrideSearchPath = path; updatePackageSearchPath(); } - + string getDefaultConfiguration(BuildPlatform platform, bool allow_non_library_configs = true) const { return m_project.getDefaultConfiguration(platform, allow_non_library_configs); } - + void upgrade(UpgradeOptions options) { // clear non-existent version selections if (!(options & UpgradeOptions.upgrade)) { - next_pack: + next_pack: foreach (p; m_project.selections.selectedPackages) { auto dep = m_project.selections.getSelectedVersion(p); if (!dep.path.empty) { @@ -219,12 +219,12 @@ } } } - + logWarn("Selected package %s %s doesn't exist. Using latest matching version instead.", p, dep); m_project.selections.deselectVersion(p); } } - + Dependency[string] versions; if ((options & UpgradeOptions.useCachedResult) && m_project.isUpgradeCacheUpToDate()) { logDiagnostic("Using cached upgrade results..."); @@ -237,20 +237,20 @@ m_project.setUpgradeCache(versions); } } - + if (options & UpgradeOptions.printUpgradesOnly) { bool any = false; string rootbasename = getBasePackageName(m_project.rootPackage.name); - + foreach (p, ver; versions) { if (!ver.path.empty) continue; - + auto basename = getBasePackageName(p); if (basename == rootbasename) continue; - + if (!m_project.selections.hasSelectedVersion(basename)) { logInfo("Package %s can be installed with version %s.", - basename, ver); + basename, ver); any = true; continue; } @@ -258,13 +258,13 @@ if (!sver.path.empty) continue; if (ver.version_ <= sver.version_) continue; logInfo("Package %s can be upgraded from %s to %s.", - basename, sver, ver); + basename, sver, ver); any = true; } if (any) logInfo("Use \"dub upgrade\" to perform those changes."); return; } - + foreach (p, ver; versions) { assert(!p.canFind(":"), "Resolved packages contain a sub package!?: "~p); Package pack; @@ -272,7 +272,7 @@ else { pack = m_packageManager.getBestPackage(p, ver); if (pack && m_packageManager.isManagedPackage(pack) - && ver.version_.isBranch && (options & UpgradeOptions.upgrade) != 0) + && ver.version_.isBranch && (options & UpgradeOptions.upgrade) != 0) { // TODO: only re-install if there is actually a new commit available logInfo("Re-installing branch based dependency %s %s", p, ver.toString()); @@ -280,7 +280,7 @@ pack = null; } } - + FetchOptions fetchOpts; fetchOpts |= (options & UpgradeOptions.preRelease) != 0 ? FetchOptions.usePrerelease : FetchOptions.none; fetchOpts |= (options & UpgradeOptions.forceRemove) != 0 ? FetchOptions.forceRemove : FetchOptions.none; @@ -288,13 +288,13 @@ if ((options & UpgradeOptions.select) && ver.path.empty && p != m_project.rootPackage.name) m_project.selections.selectVersion(p, ver.version_); } - + m_project.reinit(); - + if (options & UpgradeOptions.select) m_project.saveSelections(); } - + /// Generate project files for a specified IDE. /// Any existing project files will be overridden. void generateProject(string ide, GeneratorSettings settings) { @@ -302,13 +302,13 @@ if (m_dryRun) return; // TODO: pass m_dryRun to the generator generator.generate(settings); } - + /// Executes tests on the current project. Throws an exception, if /// unittests failed. void testProject(GeneratorSettings settings, string config, Path custom_main_file) { if (custom_main_file.length && !custom_main_file.absolute) custom_main_file = getWorkingDirectory() ~ custom_main_file; - + if (config.length == 0) { // if a custom main file was given, favor the first library configuration, so that it can be applied if (custom_main_file.length) config = m_project.getDefaultConfiguration(settings.platform, false); @@ -319,18 +319,18 @@ // if still nothing found, use the first executable configuration if (!config.length) config = m_project.getDefaultConfiguration(settings.platform, true); } - + auto generator = createProjectGenerator("build", m_project); - + auto test_config = format("__test__%s__", config); - + BuildSettings lbuildsettings = settings.buildSettings; m_project.addBuildSettings(lbuildsettings, settings.platform, config, null, true); if (lbuildsettings.targetType == TargetType.none) { logInfo(`Configuration '%s' has target type "none". Skipping test.`, config); return; } - + if (lbuildsettings.targetType == TargetType.executable) { if (config == "unittest") logInfo("Running custom 'unittest' configuration.", config); else logInfo(`Configuration '%s' does not output a library. Falling back to "dub -b unittest -c %s".`, config, config); @@ -342,7 +342,7 @@ settings.config = m_project.getDefaultConfiguration(settings.platform); } else { logInfo(`Generating test runner configuration '%s' for '%s' (%s).`, test_config, config, lbuildsettings.targetType); - + BuildSettingsTemplate tcinfo = m_project.rootPackage.info.getConfiguration(config).buildSettings; tcinfo.targetType = TargetType.executable; tcinfo.targetName = test_config; @@ -354,13 +354,13 @@ tcinfo.importPaths[""] ~= custom_main_file.parentPath.toNativeString(); custommodname = custom_main_file.head.toString().baseName(".d"); } - + string[] import_modules; foreach (file; lbuildsettings.sourceFiles) { if (file.endsWith(".d") && Path(file).head.toString() != "package.d") import_modules ~= lbuildsettings.determineModuleName(Path(file), m_project.rootPackage.path); } - + // generate main file Path mainfile = getTempDir() ~ "dub_test_root.d"; tcinfo.sourceFiles[""] ~= mainfile.toNativeString(); @@ -383,7 +383,7 @@ fil.write(q{ import std.stdio; import core.runtime; - + void main() { writeln("All unit tests have been run successfully."); } shared static this() { version (Have_tested) { @@ -400,13 +400,13 @@ } m_project.rootPackage.info.configurations ~= ConfigurationInfo(test_config, tcinfo); m_project = new Project(m_packageManager, m_project.rootPackage); - + settings.config = test_config; } - + generator.generate(settings); } - + /// Outputs a JSON description of the project, including its dependencies. void describeProject(BuildPlatform platform, string config) { @@ -415,29 +415,29 @@ dst.compiler = platform.compiler; dst.architecture = platform.architecture.serializeToJson(); dst.platform = platform.platform.serializeToJson(); - + m_project.describe(dst, platform, config); - + import std.stdio; write(dst.toPrettyString()); } - + /// Cleans intermediate/cache files of the given package void cleanPackage(Path path) { logInfo("Cleaning package at %s...", path.toNativeString()); enforce(!Package.findPackageFile(path).empty, "No package found.", path.toNativeString()); - + // TODO: clear target files and copy files - + if (existsFile(path ~ ".dub/build")) rmdirRecurse((path ~ ".dub/build").toNativeString()); if (existsFile(path ~ ".dub/obj")) rmdirRecurse((path ~ ".dub/obj").toNativeString()); } - - + + /// Returns all cached packages as a "packageId" = "version" associative array string[string] cachedPackages() const { return m_project.cachedPackagesIDs(); } - + /// Fetches the package matching the dependency and places it in the specified location. Package fetch(string packageId, const Dependency dep, PlacementLocation location, FetchOptions options, string reason = "") { @@ -455,14 +455,14 @@ } enforce(pinfo.type != Json.Type.undefined, "No package "~packageId~" was found matching the dependency "~dep.toString()); string ver = pinfo["version"].get!string; - + Path placement; final switch (location) { case PlacementLocation.local: placement = m_rootPath; break; case PlacementLocation.user: placement = m_userDubPath ~ "packages/"; break; case PlacementLocation.system: placement = m_systemDubPath ~ "packages/"; break; } - + // always upgrade branch based versions - TODO: actually check if there is a new commit available Package existing; try existing = m_packageManager.getPackage(packageId, ver, placement); @@ -470,30 +470,30 @@ logWarn("Failed to load existing package %s: %s", ver, e.msg); logDiagnostic("Full error: %s", e.toString().sanitize); } - + if (options & FetchOptions.printOnly) { if (existing && existing.vers != ver) logInfo("A new version for %s is available (%s -> %s). Run \"dub upgrade %s\" to switch.", - packageId, existing.vers, ver, packageId); + packageId, existing.vers, ver, packageId); return null; } - + if (existing) { if (!ver.startsWith("~") || !(options & FetchOptions.forceBranchUpgrade) || location == PlacementLocation.local) { // TODO: support git working trees by performing a "git pull" instead of this logDiagnostic("Package %s %s (%s) is already present with the latest version, skipping upgrade.", - packageId, ver, placement); + packageId, ver, placement); return existing; } else { logInfo("Removing %s %s to prepare replacement with a new version.", packageId, ver); if (!m_dryRun) m_packageManager.remove(existing, (options & FetchOptions.forceRemove) != 0); } } - + if (reason.length) logInfo("Fetching %s %s (%s)...", packageId, ver, reason); else logInfo("Fetching %s %s...", packageId, ver); if (m_dryRun) return null; - + logDiagnostic("Acquiring package zip file"); auto dload = m_projectPath ~ ".dub/temp/downloads"; auto tempfname = packageId ~ "-" ~ (ver.startsWith('~') ? ver[1 .. $] : ver) ~ ".zip"; @@ -502,15 +502,15 @@ if (exists(sTempFile)) std.file.remove(sTempFile); supplier.retrievePackage(tempFile, packageId, dep, (options & FetchOptions.usePrerelease) != 0); // Q: continue on fail? scope(exit) std.file.remove(sTempFile); - + logInfo("Placing %s %s to %s...", packageId, ver, placement.toNativeString()); auto clean_package_version = ver[ver.startsWith("~") ? 1 : 0 .. $]; clean_package_version = clean_package_version.replace("+", "_"); // + has special meaning for Optlink Path dstpath = placement ~ (packageId ~ "-" ~ clean_package_version); - + return m_packageManager.storeFetchedPackage(tempFile, pinfo, dstpath); } - + /// Removes a given package from the list of present/cached modules. /// @removeFromApplication: if true, this will also remove an entry in the /// list of dependencies in the application's dub.json @@ -519,10 +519,10 @@ logInfo("Removing %s in %s", pack.name, pack.path.toNativeString()); if (!m_dryRun) m_packageManager.remove(pack, force_remove); } - + /// @see remove(string, string, RemoveLocation) enum RemoveVersionWildcard = "*"; - + /// This will remove a given package with a specified version from the /// location. /// It will remove at most one package, unless @param version_ is @@ -539,34 +539,34 @@ enforce(!package_id.empty); if (location_ == PlacementLocation.local) { logInfo("To remove a locally placed package, make sure you don't have any data" - ~ "\nleft in it's directory and then simply remove the whole directory."); + ~ "\nleft in it's directory and then simply remove the whole directory."); throw new Exception("dub cannot remove locally installed packages."); } - + Package[] packages; const bool wildcardOrEmpty = version_ == RemoveVersionWildcard || version_.empty; - + // Retrieve packages to be removed. foreach(pack; m_packageManager.getPackageIterator(package_id)) if( wildcardOrEmpty || pack.vers == version_ ) packages ~= pack; - + // Check validity of packages to be removed. if(packages.empty) { throw new Exception("Cannot find package to remove. (" - ~ "id: '" ~ package_id ~ "', version: '" ~ version_ ~ "', location: '" ~ to!string(location_) ~ "'" - ~ ")"); + ~ "id: '" ~ package_id ~ "', version: '" ~ version_ ~ "', location: '" ~ to!string(location_) ~ "'" + ~ ")"); } if(version_.empty && packages.length > 1) { logError("Cannot remove package '" ~ package_id ~ "', there are multiple possibilities at location\n" - ~ "'" ~ to!string(location_) ~ "'."); + ~ "'" ~ to!string(location_) ~ "'."); logError("Available versions:"); foreach(pack; packages) logError(" %s", pack.vers); throw new Exception("Please specify a individual version using --version=... or use the" - ~ " wildcard --version=" ~ RemoveVersionWildcard ~ " to remove all versions."); + ~ " wildcard --version=" ~ RemoveVersionWildcard ~ " to remove all versions."); } - + logDebug("Removing %s packages.", packages.length); foreach(pack; packages) { try { @@ -578,81 +578,91 @@ } } } - + void addLocalPackage(string path, string ver, bool system) { if (m_dryRun) return; m_packageManager.addLocalPackage(makeAbsolute(path), ver, system ? LocalPackageType.system : LocalPackageType.user); } - + void removeLocalPackage(string path, bool system) { if (m_dryRun) return; m_packageManager.removeLocalPackage(makeAbsolute(path), system ? LocalPackageType.system : LocalPackageType.user); } - + void addSearchPath(string path, bool system) { if (m_dryRun) return; m_packageManager.addSearchPath(makeAbsolute(path), system ? LocalPackageType.system : LocalPackageType.user); } - + void removeSearchPath(string path, bool system) { if (m_dryRun) return; m_packageManager.removeSearchPath(makeAbsolute(path), system ? LocalPackageType.system : LocalPackageType.user); } - - void createEmptyPackage(Path path, string type) + + void createEmptyPackage(Path path, string[] deps, string type) { if( !path.absolute() ) path = m_rootPath ~ path; path.normalize(); - + if (m_dryRun) return; - - initPackage(path, type); - + string[string] depVers; + foreach(ps; this.m_packageSuppliers){ + foreach(dep; deps){ + try{ + auto versionStrings = ps.getVersions(dep); + depVers[dep] = versionStrings[$-1].toString; + } catch(Exception e){ + logError("Error, no package %s found. Ignoring...", dep); + } + } + } + initPackage(path, depVers, type); + //Act smug to the user. logInfo("Successfully created an empty project in '%s'.", path.toNativeString()); } - + void runDdox(bool run) { if (m_dryRun) return; - + auto ddox_pack = m_packageManager.getBestPackage("ddox", ">=0.0.0"); if (!ddox_pack) ddox_pack = m_packageManager.getBestPackage("ddox", "~master"); if (!ddox_pack) { logInfo("DDOX is not present, getting it and storing user wide"); ddox_pack = fetch("ddox", Dependency(">=0.0.0"), defaultPlacementLocation, FetchOptions.none); } - + version(Windows) auto ddox_exe = "ddox.exe"; else auto ddox_exe = "ddox"; - + if( !existsFile(ddox_pack.path~ddox_exe) ){ logInfo("DDOX in %s is not built, performing build now.", ddox_pack.path.toNativeString()); - + auto ddox_dub = new Dub(m_packageSuppliers); ddox_dub.loadPackage(ddox_pack.path); ddox_dub.upgrade(UpgradeOptions.select); - + auto compiler_binary = "dmd"; - + GeneratorSettings settings; settings.config = "application"; settings.compiler = getCompiler(compiler_binary); settings.platform = settings.compiler.determinePlatform(settings.buildSettings, compiler_binary); settings.buildType = "debug"; ddox_dub.generateProject("build", settings); - + //runCommands(["cd "~ddox_pack.path.toNativeString()~" && dub build -v"]); } - + auto p = ddox_pack.path; p.endsWithSlash = true; auto dub_path = p.toNativeString(); - + string[] commands; string[] filterargs = m_project.rootPackage.info.ddoxFilterArgs.dup; if (filterargs.empty) filterargs = ["--min-protection=Protected", "--only-documented"]; @@ -663,14 +673,14 @@ else commands ~= "cp -ru \""~dub_path~"public\"/* docs/"; } runCommands(commands); - + if (run) { auto proc = spawnProcess([dub_path~"ddox", "serve-html", "--navigation-type=ModuleTree", "docs.json", "--web-file-dir="~dub_path~"public"]); browse("http://127.0.0.1:8080/"); wait(proc); } } - + private void updatePackageSearchPath() { if (m_overrideSearchPath.length) { @@ -679,7 +689,7 @@ } else { auto p = environment.get("DUBPATH"); Path[] paths; - + version(Windows) enum pathsep = ";"; else enum pathsep = ":"; if (p.length) paths ~= p.split(pathsep).map!(p => Path(p))().array(); @@ -687,7 +697,7 @@ m_packageManager.searchPath = paths; } } - + private Path makeAbsolute(Path p) const { return p.absolute ? p : m_rootPath ~ p; } private Path makeAbsolute(string p) const { return makeAbsolute(Path(p)); } } @@ -696,7 +706,7 @@ { assert(base_path.absolute); if (!file.absolute) file = base_path ~ file; - + size_t path_skip = 0; foreach (ipath; settings.importPaths.map!(p => Path(p))) { if (!ipath.absolute) ipath = base_path ~ ipath; @@ -704,18 +714,18 @@ if (file.startsWith(ipath) && ipath.length > path_skip) path_skip = ipath.length; } - + enforce(path_skip > 0, - format("Source file '%s' not found in any import path.", file.toNativeString())); - + format("Source file '%s' not found in any import path.", file.toNativeString())); + auto mpath = file[path_skip .. file.length]; auto ret = appender!string; - + //search for module keyword in file string moduleName = getModuleNameFromFile(file.to!string); - + if(moduleName.length) return moduleName; - + //create module name from path foreach (i; 0 .. mpath.length) { import std.path; @@ -725,7 +735,7 @@ if (i+1 < mpath.length) ret ~= p; else ret ~= p.baseName(".d"); } - + return ret.data; } @@ -734,21 +744,21 @@ */ string getModuleNameFromContent(string content) { import std.regex; - + static bool regex_initialized = false; static Regex!char comments_pattern, module_pattern; - + if (!regex_initialized) { comments_pattern = regex(`(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|(//.*)`, "g"); module_pattern = regex(`module\s+([\w\.]+)\s*;`, "g"); regex_initialized = true; } - + content = replaceAll(content, comments_pattern, ""); string moduleName = matchFirst(content, module_pattern).front; - + if (moduleName.length >= 7) moduleName = moduleName[7..$-1]; - + return moduleName; } @@ -757,18 +767,18 @@ //test simple name string name = getModuleNameFromContent("module myPackage.myModule;"); assert(name == "myPackage.myModule", "can't parse module name"); - + //test if it can ignore module inside comments name = getModuleNameFromContent("/** module fakePackage.fakeModule; */ module myPackage.myModule;"); - + assert(name == "myPackage.myModule", "can't parse module name"); - + name = getModuleNameFromContent("//module fakePackage.fakeModule; module myPackage.myModule;"); - + assert(name == "myPackage.myModule", "can't parse module name"); } @@ -777,7 +787,7 @@ */ string getModuleNameFromFile(string filePath) { string fileContent = filePath.readText; - + return getModuleNameFromContent(fileContent); } @@ -801,38 +811,38 @@ SelectedVersions m_selectedVersions; Package m_rootPackage; } - - + + this(Dub dub, UpgradeOptions options) { m_dub = dub; m_options = options; } - + Dependency[string] resolve(Package root, SelectedVersions selected_versions) { m_rootPackage = root; m_selectedVersions = selected_versions; return super.resolve(TreeNode(root.name, Dependency(root.ver)), (m_options & UpgradeOptions.printUpgradesOnly) == 0); } - + protected override Dependency[] getAllConfigs(string pack) { if (auto pvers = pack in m_packageVersions) return *pvers; - + if (!(m_options & UpgradeOptions.upgrade) && m_selectedVersions.hasSelectedVersion(pack)) { auto ret = [m_selectedVersions.getSelectedVersion(pack)]; logDiagnostic("Using fixed selection %s %s", pack, ret[0]); m_packageVersions[pack] = ret; return ret; } - + logDiagnostic("Search for versions of %s (%s package suppliers)", pack, m_dub.m_packageSuppliers.length); Version[] versions; foreach (p; m_dub.packageManager.getPackageIterator(pack)) versions ~= p.ver; - + foreach (ps; m_dub.m_packageSuppliers) { try { auto vers = ps.getVersions(pack); @@ -841,7 +851,7 @@ logDiagnostic("No versions for %s for %s", pack, ps.description); continue; } - + versions ~= vers; break; } catch (Exception e) { @@ -849,28 +859,28 @@ logDebug("Full error: %s", e.toString().sanitize); } } - + // sort by version, descending, and remove duplicates versions = versions.sort!"a>b".uniq.array; - + // move pre-release versions to the back of the list if no preRelease flag is given if (!(m_options & UpgradeOptions.preRelease)) versions = versions.filter!(v => !v.isPreRelease).array ~ versions.filter!(v => v.isPreRelease).array; - + if (!versions.length) logDiagnostic("Nothing found for %s", pack); - + auto ret = versions.map!(v => Dependency(v)).array; m_packageVersions[pack] = ret; return ret; } - + protected override Dependency[] getSpecificConfigs(TreeNodes nodes) { if (!nodes.configs.path.empty) return [nodes.configs]; else return null; } - - + + protected override TreeNodes[] getChildren(TreeNode node) { auto ret = appender!(TreeNodes[]); @@ -881,10 +891,10 @@ return null; } auto basepack = pack.basePackage; - + foreach (dname, dspec; pack.dependencies) { auto dbasename = getBasePackageName(dname); - + // detect dependencies to the root package (or sub packages thereof) if (dbasename == basepack.name) { auto absdeppath = dspec.mapToPath(pack.path).path; @@ -892,13 +902,13 @@ if (subpack) { auto desireddeppath = dname == dbasename ? basepack.path : subpack.path; enforce(dspec.path.empty || absdeppath == desireddeppath, - format("Dependency from %s to root package references wrong path: %s vs. %s", - node.pack, absdeppath.toNativeString(), desireddeppath.toNativeString())); + format("Dependency from %s to root package references wrong path: %s vs. %s", + node.pack, absdeppath.toNativeString(), desireddeppath.toNativeString())); } ret ~= TreeNodes(dname, node.config); continue; } - + if (dspec.optional && !m_dub.packageManager.getFirstPackage(dname)) continue; if (m_options & UpgradeOptions.upgrade || !m_selectedVersions || !m_selectedVersions.hasSelectedVersion(dbasename)) @@ -907,17 +917,17 @@ } return ret.data; } - + protected override bool matches(Dependency configs, Dependency config) { if (!configs.path.empty) return configs.path == config.path; return configs.merge(config).valid; } - + private Package getPackage(string name, Dependency dep) { auto basename = getBasePackageName(name); - + // for sub packages, first try to get them from the base package if (basename != name) { auto subname = getSubPackageName(name); @@ -936,23 +946,23 @@ return null; } } - + if (!dep.path.empty) { auto ret = m_dub.packageManager.getOrLoadPackage(dep.path); if (dep.matches(ret.ver)) return ret; } - + if (auto ret = m_dub.m_packageManager.getBestPackage(name, dep)) return ret; - + auto key = name ~ ":" ~ dep.version_.toString(); if (auto ret = key in m_remotePackages) return *ret; - + auto prerelease = (m_options & UpgradeOptions.preRelease) != 0; - + auto rootpack = name.split(":")[0]; - + foreach (ps; m_dub.m_packageSuppliers) { if (rootpack == name) { try { @@ -984,9 +994,9 @@ } } } - + m_remotePackages[key] = null; - + logWarn("Package %s %s could not be loaded either locally, or from the configured package registries.", name, dep); return null; } diff --git a/source/dub/init.d b/source/dub/init.d index 877851d..6ba1b2e 100644 --- a/source/dub/init.d +++ b/source/dub/init.d @@ -19,81 +19,84 @@ import std.string; -void initPackage(Path root_path, string type) +void initPackage(Path root_path, string[string] deps, string type) { void enforceDoesNotExist(string filename) { enforce(!existsFile(root_path ~ filename), "The target directory already contains a '"~filename~"' file. Aborting."); } - + //Check to see if a target directory needs to be created if( !root_path.empty ){ if( !existsFile(root_path) ) createDirectory(root_path); } - + //Make sure we do not overwrite anything accidentally foreach (fil; packageInfoFiles) enforceDoesNotExist(fil.filename); - + auto files = ["source/", "views/", "public/", "dub.json", ".gitignore"]; foreach (fil; files) enforceDoesNotExist(fil); - + switch (type) { default: throw new Exception("Unknown package init type: "~type); - case "minimal": initMinimalPackage(root_path); break; - case "vibe.d": initVibeDPackage(root_path); break; - case "deimos": initDeimosPackage(root_path); break; + case "minimal": initMinimalPackage(root_path, deps); break; + case "vibe.d": initVibeDPackage(root_path, deps); break; + case "deimos": initDeimosPackage(root_path, deps); break; } writeGitignore(root_path); } -void initMinimalPackage(Path root_path) +void initMinimalPackage(Path root_path, string[string] deps) { - writePackageJson(root_path, "A minimal D application."); + writePackageJson(root_path, "A minimal D application.", deps); createDirectory(root_path ~ "source"); write((root_path ~ "source/app.d").toNativeString(), -q{import std.stdio; - -void main() -{ - writeln("Edit source/app.d to start your project."); -} -}); + q{import std.stdio; + + void main() + { + writeln("Edit source/app.d to start your project."); + } + }); } -void initVibeDPackage(Path root_path) +void initVibeDPackage(Path root_path, string[string] deps) { + if("vibe-d" !in deps) + deps["vibe-d"] = "~>0.7.19"; + writePackageJson(root_path, "A simple vibe.d server application.", - ["vibe-d": "~>0.7.19"], ["versions": `["VibeDefaultMain"]`]); + deps, ["versions": `["VibeDefaultMain"]`]); createDirectory(root_path ~ "source"); createDirectory(root_path ~ "views"); createDirectory(root_path ~ "public"); write((root_path ~ "source/app.d").toNativeString(), -q{import vibe.d; - -shared static this() -{ - auto settings = new HTTPServerSettings; - settings.port = 8080; - settings.bindAddresses = ["::1", "127.0.0.1"]; - listenHTTP(settings, &hello); - - logInfo("Please open http://127.0.0.1:8080/ in your browser."); + q{import vibe.d; + + shared static this() + { + auto settings = new HTTPServerSettings; + settings.port = 8080; + settings.bindAddresses = ["::1", "127.0.0.1"]; + listenHTTP(settings, &hello); + + logInfo("Please open http://127.0.0.1:8080/ in your browser."); + } + + void hello(HTTPServerRequest req, HTTPServerResponse res) + { + res.writeBody("Hello, World!"); + } + }); } -void hello(HTTPServerRequest req, HTTPServerResponse res) -{ - res.writeBody("Hello, World!"); -} -}); -} - -void initDeimosPackage(Path root_path) +void initDeimosPackage(Path root_path, string[string] deps) { auto name = root_path.head.toString().toLower(); writePackageJson(root_path, "Deimos Bindings for "~name~".", - null, ["targetType": `"sourceLibrary"`, "importPaths": `["."]`]); + deps, ["targetType": `"sourceLibrary"`, "importPaths": `["."]`]); createDirectory(root_path ~ "C"); createDirectory(root_path ~ "deimos"); } @@ -101,16 +104,16 @@ void writePackageJson(Path root_path, string description, string[string] dependencies = null, string[string] addFields = null) { import std.algorithm : map; - + assert(!root_path.empty); - + string username; version (Windows) username = environment.get("USERNAME", "Peter Parker"); else username = environment.get("USER", "Peter Parker"); - + auto fil = openFile(root_path ~ defaultPackageFilename(), FileMode.Append); scope(exit) fil.close(); - + fil.formattedWrite("{\n\t\"name\": \"%s\",\n", root_path.head.toString().toLower()); fil.formattedWrite("\t\"description\": \"%s\",\n", description); fil.formattedWrite("\t\"copyright\": \"Copyright © %s, %s\",\n", Clock.currTime().year, username); @@ -125,5 +128,5 @@ void writeGitignore(Path root_path) { write((root_path ~ ".gitignore").toNativeString(), - ".dub\ndocs.json\n__dummy.html\n*.o\n*.obj\n"); + ".dub\ndocs.json\n__dummy.html\n*.o\n*.obj\n"); }