diff --git a/source/app.d b/source/app.d index 3388fef..12e05a0 100644 --- a/source/app.d +++ b/source/app.d @@ -54,6 +54,7 @@ string install_version; string[] registry_urls; string[] debug_versions; + string[] app_args; string root_path = getcwd(); getopt(args, "v|verbose", &verbose, @@ -92,7 +93,11 @@ } else cmd = "run"; // contrary to the documentation, getopt does not remove -- - if( args.length >= 2 && args[1] == "--" ) args = args[0] ~ args[2 .. $]; + auto app_args_idx = args.countUntil("--"); + if (app_args_idx >= 0) { + app_args = args[app_args_idx+1 .. $]; + args = args[0 .. app_args_idx]; + } // display help if requested (obsolete) if( help ){ @@ -113,12 +118,13 @@ logInfo(""); } - Dub dub = new Dub(registry_urls.map!(url => cast(PackageSupplier)new RegistryPackageSupplier(Url(url))).array, root_path); + auto package_suppliers = registry_urls.map!(url => cast(PackageSupplier)new RegistryPackageSupplier(Url(url))).array; + Dub dub = new Dub(package_suppliers, root_path); string def_config; - bool loadCwdPackage() + bool loadCwdPackage(Package pack) { - if( !existsFile(dub.rootPath~"package.json") && !existsFile(dub.rootPath~"source/app.d") ){ + if (!existsFile(dub.rootPath~"package.json") && !existsFile(dub.rootPath~"source/app.d")) { logInfo(""); logInfo("Neither package.json, nor source/app.d was found in the current directory."); logInfo("Please run dub from the root directory of an existing package, or create a new"); @@ -128,10 +134,11 @@ return false; } - dub.loadPackageFromCwd(); + if (pack) dub.loadPackage(pack); + else dub.loadPackageFromCwd(); def_config = dub.getDefaultConfiguration(build_platform); - if( !build_config.length ) build_config = def_config; + if (!build_config.length) build_config = def_config; return true; } @@ -207,18 +214,32 @@ case "run": case "build": case "generate": - if (!loadCwdPackage()) return 1; - string generator; - if( cmd == "run" || cmd == "build" ) generator = rdmd ? "rdmd" : "build"; - else { - if( args.length >= 2 ) generator = args[1]; + string package_name; + if( cmd == "run" || cmd == "build" ) { + generator = rdmd ? "rdmd" : "build"; + if (args.length >= 2) package_name = args[1]; + } else { + if (args.length >= 2) generator = args[1]; + if (args.length >= 3) package_name = args[2]; if(generator.empty) { - logInfo("Usage: dub generate "); + logInfo("Usage: dub generate []"); return 1; } } + Package pack; + if (!package_name.empty) { + // load package in root_path to enable searching for sub packages + loadCwdPackage(null); + pack = dub.packageManager.getFirstPackage(package_name); + enforce(pack, "Failed to find a package named '"~package_name~"'."); + logInfo("Building package %s in %s", pack.name, pack.path.toNativeString()); + root_path = pack.path.toNativeString(); + dub = new Dub(package_suppliers, root_path); + } + if (!loadCwdPackage(pack)) return 1; + if( print_builds ){ logInfo("Available build types:"); foreach( tp; ["debug", "release", "unittest", "profile"] ) @@ -252,14 +273,14 @@ gensettings.compiler = compiler; gensettings.buildSettings = build_settings; gensettings.run = cmd == "run"; - gensettings.runArgs = args[1 .. $]; + gensettings.runArgs = app_args; logDiagnostic("Generating using %s", generator); dub.generateProject(generator, gensettings); if( build_type == "ddox" ) dub.runDdox(); break; case "describe": - if (!loadCwdPackage()) return 1; + if (!loadCwdPackage(null)) return 1; dub.describeProject(build_platform, build_config); break; } @@ -321,8 +342,9 @@ Available commands: help Prints this help screen init [] Initializes an empty project in the specified directory - run Compiles and runs the application (default command) - build Just compiles the application in the project directory + run [] Builds and runs a package (default command) + build [] Builds a package (uses the main package in the current + working directory by default) upgrade Forces an upgrade of all dependencies install Manually installs a package. See 'dub help install'. uninstall Uninstalls a package. See 'dub help uninstall'. @@ -332,7 +354,8 @@ add-path Adds a default package search path remove-path Removes a package search path list-installed Prints a list of all installed packages - generate Generates project files using the specified generator: + generate [] + Generates project files using the specified generator: visuald, visuald-combined, mono-d, build, rdmd describe Prints a JSON description of the project and its dependencies diff --git a/source/dub/dub.d b/source/dub/dub.d index 1428905..9e923b2 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -50,7 +50,7 @@ private { PackageManager m_packageManager; PackageSupplier[] m_packageSuppliers; - Path m_cwd, m_tempPath; + Path m_rootPath, m_tempPath; Path m_userDubPath, m_systemDubPath; Json m_systemConfig, m_userConfig; Path m_projectPath; @@ -61,8 +61,8 @@ /// under root. this(PackageSupplier[] additional_package_suppliers = null, string root_path = ".") { - m_cwd = Path(root_path); - if (!m_cwd.absolute) m_cwd = Path(getcwd()) ~ m_cwd; + m_rootPath = Path(root_path); + if (!m_rootPath.absolute) m_rootPath = Path(getcwd()) ~ m_rootPath; version(Windows){ m_systemDubPath = Path(environment.get("ProgramData")) ~ "dub/"; @@ -89,7 +89,7 @@ /** Returns the root path (usually the current working directory). */ - @property Path rootPath() const { return m_cwd; } + @property Path rootPath() const { return m_rootPath; } /// Returns the name listed in the package.json of the current /// application. @@ -105,7 +105,7 @@ /// project package. void loadPackageFromCwd() { - loadPackage(m_cwd); + loadPackage(m_rootPath); } /// Loads the package from the specified path as the main project package. @@ -116,6 +116,14 @@ 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) + { + m_projectPath = pack.path; + updatePackageSearchPath(); + m_project = new Project(m_packageManager, pack); + } + string getDefaultConfiguration(BuildPlatform platform) const { return m_project.getDefaultConfiguration(platform); } /// Performs installation and uninstallation as necessary for @@ -203,7 +211,7 @@ Path install_path; final switch (location) { - case InstallLocation.local: install_path = m_cwd; break; + case InstallLocation.local: install_path = m_rootPath; break; case InstallLocation.userWide: install_path = m_userDubPath ~ "packages/"; break; case InstallLocation.systemWide: install_path = m_systemDubPath ~ "packages/"; break; } @@ -325,7 +333,7 @@ void createEmptyPackage(Path path) { - if( !path.absolute() ) path = m_cwd ~ path; + if( !path.absolute() ) path = m_rootPath ~ path; path.normalize(); //Check to see if a target directory needs to be created @@ -432,6 +440,6 @@ m_packageManager.searchPath = paths; } - private Path makeAbsolute(Path p) const { return p.absolute ? p : m_cwd ~ p; } + private Path makeAbsolute(Path p) const { return p.absolute ? p : m_rootPath ~ p; } private Path makeAbsolute(string p) const { return makeAbsolute(Path(p)); } } diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d index de829b2..10f8e91 100644 --- a/source/dub/packagemanager.d +++ b/source/dub/packagemanager.d @@ -108,6 +108,13 @@ return null; } + Package getFirstPackage(string name) + { + foreach (ep; getPackageIterator(name)) + return ep; + return null; + } + Package getPackage(Path path) { foreach (p; getPackageIterator()) diff --git a/source/dub/project.d b/source/dub/project.d index 908c5c9..f3c39b1 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -36,6 +36,7 @@ /// Representing a full project, with a root Package and several dependencies. class Project { private { + bool m_fixedPackage; Path m_root; PackageManager m_packageManager; Json m_json; @@ -47,8 +48,19 @@ this(PackageManager package_manager, Path project_path) { - m_root = project_path; m_packageManager = package_manager; + m_root = project_path; + m_fixedPackage = false; + m_json = Json.EmptyObject; + reinit(); + } + + this(PackageManager package_manager, Package pack) + { + m_packageManager = package_manager; + m_root = pack.path; + m_main = pack; + m_fixedPackage = true; m_json = Json.EmptyObject; reinit(); } @@ -140,25 +152,29 @@ { scope(failure){ logDiagnostic("Failed to initialize project. Assuming defaults."); - m_main = new Package(serializeToJson(["name": "unknown"]), m_root); + if (!m_fixedPackage) m_main = new Package(serializeToJson(["name": "unknown"]), m_root); } m_dependencies = null; - m_main = null; m_packageManager.refresh(false); try m_json = jsonFromFile(m_root ~ ".dub/dub.json", true); catch(Exception t) logDiagnostic("Failed to read .dub/dub.json: %s", t.msg); - if( !existsFile(m_root~PackageJsonFilename) ){ - logWarn("There was no '"~PackageJsonFilename~"' found for the application in '%s'.", m_root.toNativeString()); - auto json = Json.EmptyObject; - json.name = "unknown"; - m_main = new Package(json, m_root); - return; + // load package description + if (!m_fixedPackage) { + if (!existsFile(m_root~PackageJsonFilename)) { + logWarn("There was no '"~PackageJsonFilename~"' found for the application in '%s'.", m_root.toNativeString()); + auto json = Json.EmptyObject; + json.name = "unknown"; + m_main = new Package(json, m_root); + return; + } + + m_main = m_packageManager.getPackage(m_root); } - m_main = m_packageManager.getPackage(m_root); + // some basic package lint m_main.warnOnSpecialCompilerFlags(); if (m_main.name != m_main.name.toLower()) { logWarn(`DUB package names should always be lower case, please change to {"name": "%s"}. You can use {"targetName": "%s"} to keep the current executable name.`,