Newer
Older
dub_jkp / source / app.d
@Sönke Ludwig Sönke Ludwig on 15 Sep 2013 13 KB Fix typo. See #122.
  1. /**
  2. The entry point to dub
  3.  
  4. Copyright: © 2012 Matthias Dondorff
  5. License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
  6. Authors: Matthias Dondorff, Sönke Ludwig
  7. */
  8. module app;
  9.  
  10. import dub.compilers.compiler;
  11. import dub.dependency;
  12. import dub.dub;
  13. import dub.generators.generator;
  14. import dub.internal.std.process;
  15. import dub.internal.vibecompat.core.file;
  16. import dub.internal.vibecompat.core.log;
  17. import dub.internal.vibecompat.inet.url;
  18. import dub.package_;
  19. import dub.packagesupplier;
  20. import dub.project;
  21. import dub.version_;
  22.  
  23. import std.algorithm;
  24. import std.array;
  25. import std.conv;
  26. import std.encoding;
  27. import std.exception;
  28. import std.file;
  29. import std.getopt;
  30.  
  31.  
  32. int main(string[] args)
  33. {
  34. string cmd;
  35.  
  36. version(Windows){
  37. // rdmd uses $TEMP to compute a temporary path. since cygwin substitutes backslashes
  38. // with slashes, this causes OPTLINK to fail (it thinks path segments are options)
  39. // we substitute the other way around here to fix this.
  40. environment["TEMP"] = environment["TEMP"].replace("/", "\\");
  41. }
  42.  
  43. try {
  44. // parse general options
  45. bool verbose, vverbose, quiet, vquiet;
  46. bool help, nodeps, annotate;
  47. LogLevel loglevel = LogLevel.info;
  48. string build_type, build_config;
  49. string compiler_name = "dmd";
  50. string arch;
  51. bool rdmd = false;
  52. bool print_platform, print_builds, print_configs;
  53. bool install_system = false, install_local = false;
  54. string install_version;
  55. string[] registry_urls;
  56. string[] debug_versions;
  57. getopt(args,
  58. "v|verbose", &verbose,
  59. "vverbose", &vverbose,
  60. "q|quiet", &quiet,
  61. "vquiet", &vquiet,
  62. "h|help", &help, // obsolete
  63. "nodeps", &nodeps,
  64. "annotate", &annotate,
  65. "build", &build_type,
  66. "compiler", &compiler_name,
  67. "arch", &arch,
  68. "rdmd", &rdmd,
  69. "config", &build_config,
  70. "debug", &debug_versions,
  71. "print-builds", &print_builds,
  72. "print-configs", &print_configs,
  73. "print-platform", &print_platform,
  74. "system", &install_system,
  75. "local", &install_local,
  76. "version", &install_version,
  77. "registry", &registry_urls
  78. );
  79.  
  80. if( vverbose ) loglevel = LogLevel.debug_;
  81. else if( verbose ) loglevel = LogLevel.diagnostic;
  82. else if( vquiet ) loglevel = LogLevel.none;
  83. else if( quiet ) loglevel = LogLevel.warn;
  84. setLogLevel(loglevel);
  85.  
  86. // extract the command
  87. if( args.length > 1 && !args[1].startsWith("-") ){
  88. cmd = args[1];
  89. args = args[0] ~ args[2 .. $];
  90. } else cmd = "run";
  91.  
  92. // contrary to the documentation, getopt does not remove --
  93. if( args.length >= 2 && args[1] == "--" ) args = args[0] ~ args[2 .. $];
  94.  
  95. // display help if requested (obsolete)
  96. if( help ){
  97. showHelp(cmd);
  98. return 0;
  99. }
  100.  
  101. BuildSettings build_settings;
  102. auto compiler = getCompiler(compiler_name);
  103. auto build_platform = compiler.determinePlatform(build_settings, compiler_name, arch);
  104. build_settings.addDebugVersions(debug_versions);
  105.  
  106. if( print_platform ){
  107. logInfo("Build platform:");
  108. logInfo(" Compiler: %s", build_platform.compiler);
  109. logInfo(" System: %s", build_platform.platform.join(" "));
  110. logInfo(" Architecture: %s", build_platform.architecture.join(" "));
  111. logInfo("");
  112. }
  113.  
  114. Dub dub = new Dub(registry_urls.map!(url => cast(PackageSupplier)new RegistryPackageSupplier(Url(url))).array);
  115. string def_config;
  116.  
  117. bool loadCwdPackage()
  118. {
  119. if( !existsFile("package.json") && !existsFile("source/app.d") ){
  120. logInfo("");
  121. logInfo("Neither package.json, nor source/app.d was found in the current directory.");
  122. logInfo("Please run dub from the root directory of an existing package, or create a new");
  123. logInfo("package using \"dub init <name>\".");
  124. logInfo("");
  125. showHelp(null);
  126. return false;
  127. }
  128.  
  129. dub.loadPackageFromCwd();
  130.  
  131. def_config = dub.getDefaultConfiguration(build_platform);
  132. if( !build_config.length ) build_config = def_config;
  133.  
  134. return true;
  135. }
  136.  
  137. // handle the command
  138. switch( cmd ){
  139. default:
  140. enforce(false, "Command is unknown: " ~ cmd);
  141. assert(false);
  142. case "help":
  143. if(args.length >= 2) cmd = args[1];
  144. showHelp(cmd);
  145. return 0;
  146. case "init":
  147. string dir;
  148. if( args.length >= 2 ) dir = args[1];
  149. dub.createEmptyPackage(Path(dir));
  150. return 0;
  151. case "upgrade":
  152. dub.loadPackageFromCwd();
  153. logInfo("Upgrading project in %s", dub.projectPath.toNativeString());
  154. dub.update(UpdateOptions.Upgrade | (annotate ? UpdateOptions.JustAnnotate : UpdateOptions.None));
  155. return 0;
  156. case "install":
  157. enforce(args.length >= 2, "Missing package name.");
  158. auto location = InstallLocation.userWide;
  159. auto name = args[1];
  160. enforce(!install_local || !install_system, "Cannot install locally and system wide at the same time.");
  161. if (install_local) location = InstallLocation.local;
  162. else if (install_system) location = InstallLocation.systemWide;
  163. if (install_version.length) dub.install(name, Dependency(install_version), location, true);
  164. else {
  165. try dub.install(name, Dependency(">=0.0.0"), location, true);
  166. catch(Exception e){
  167. logInfo("Installing a release version failed: %s", e.msg);
  168. logInfo("Retry with ~master...");
  169. dub.install(name, Dependency("~master"), location, true);
  170. }
  171. }
  172. break;
  173. case "uninstall":
  174. enforce(args.length >= 2, "Missing package name.");
  175. auto location = InstallLocation.userWide;
  176. auto package_id = args[1];
  177. enforce(!install_local || !install_system, "Cannot install locally and system wide at the same time.");
  178. if( install_local ) location = InstallLocation.local;
  179. else if( install_system ) location = InstallLocation.systemWide;
  180. try dub.uninstall(package_id, install_version, location);
  181. catch logError("Please specify a individual version or use the wildcard identifier '%s' (without quotes).", Dub.UninstallVersionWildcard);
  182. break;
  183. case "add-local":
  184. enforce(args.length >= 3, "Missing arguments.");
  185. dub.addLocalPackage(args[1], args[2], install_system);
  186. break;
  187. case "remove-local":
  188. enforce(args.length >= 2, "Missing path to package.");
  189. dub.removeLocalPackage(args[1], install_system);
  190. break;
  191. case "add-path":
  192. enforce(args.length >= 2, "Missing search path.");
  193. dub.addSearchPath(args[1], install_system);
  194. break;
  195. case "remove-path":
  196. enforce(args.length >= 2, "Missing search path.");
  197. dub.removeSearchPath(args[1], install_system);
  198. break;
  199. case "list-installed":
  200. logInfo("Installed packages:");
  201. foreach (p; dub.packageManager.getPackageIterator())
  202. logInfo(" %s %s: %s", p.name, p.ver, p.path.toNativeString());
  203. logInfo("");
  204. break;
  205. case "run":
  206. case "build":
  207. case "generate":
  208. if (!loadCwdPackage()) return 1;
  209.  
  210. string generator;
  211. if( cmd == "run" || cmd == "build" ) generator = rdmd ? "rdmd" : "build";
  212. else {
  213. if( args.length >= 2 ) generator = args[1];
  214. if(generator.empty) {
  215. logInfo("Usage: dub generate <generator_name>");
  216. return 1;
  217. }
  218. }
  219.  
  220. if( print_builds ){
  221. logInfo("Available build types:");
  222. foreach( tp; ["debug", "release", "unittest", "profile"] )
  223. logInfo(" %s", tp);
  224. logInfo("");
  225. }
  226.  
  227. if( print_configs ){
  228. logInfo("Available configurations:");
  229. foreach( tp; dub.configurations )
  230. logInfo(" %s%s", tp, tp == def_config ? " [default]" : null);
  231. logInfo("");
  232. }
  233.  
  234. if( !nodeps ){
  235. logInfo("Checking dependencies in '%s'", dub.projectPath.toNativeString());
  236. dub.update(annotate ? UpdateOptions.JustAnnotate : UpdateOptions.None);
  237. }
  238.  
  239. enforce(build_config.length == 0 || dub.configurations.canFind(build_config), "Unknown build configuration: "~build_config);
  240.  
  241. if (build_type.length == 0) {
  242. if (environment.get("DFLAGS")) build_type = "$DFLAGS";
  243. else build_type = "debug";
  244. }
  245.  
  246. GeneratorSettings gensettings;
  247. gensettings.platform = build_platform;
  248. gensettings.config = build_config;
  249. gensettings.buildType = build_type;
  250. gensettings.compiler = compiler;
  251. gensettings.compilerBinary = compiler_name;
  252. gensettings.buildSettings = build_settings;
  253. gensettings.run = cmd == "run";
  254. gensettings.runArgs = args[1 .. $];
  255.  
  256. logDiagnostic("Generating using %s", generator);
  257. dub.generateProject(generator, gensettings);
  258. if( build_type == "ddox" ) dub.runDdox();
  259. break;
  260. case "describe":
  261. if (!loadCwdPackage()) return 1;
  262. dub.describeProject(build_platform, build_config);
  263. break;
  264. }
  265.  
  266. return 0;
  267. }
  268. catch(Throwable e)
  269. {
  270. logError("Error: %s\n", e.msg);
  271. logDiagnostic("Full exception: %s", sanitize(e.toString()));
  272. logInfo("Run 'dub help' for usage information.");
  273. return 1;
  274. }
  275. }
  276.  
  277. private void showHelp(string command)
  278. {
  279. if(command == "uninstall" || command == "install") {
  280. logInfo(
  281. `Usage: dub <install|uninstall> <package> [<options>]
  282.  
  283. Note: use dependencies (package.json) if you want to add a dependency, you
  284. don't have to fiddle with installation stuff.
  285.  
  286. (Un)Installation of packages is only needed when you want to put packages to a
  287. place where several applications can share these. If you just have an
  288. dependency to a package, just add it to your package.json, dub will do the rest
  289. for you.
  290.  
  291. Without specified options, (un)installation will default to a user wide shared
  292. location.
  293.  
  294. Complete applications can be installed and run easily by e.g.
  295. dub install vibelog --local
  296. cd vibelog
  297. dub
  298. This will grab all needed dependencies and compile and run the application.
  299.  
  300. Install options:
  301. --version Use the specified version/branch instead of the latest
  302. For the uninstall command, this may be a wildcard
  303. string: "*", which will remove all packages from the
  304. specified location.
  305. --system Install system wide instead of user local
  306. --local Install as in a sub folder of the current directory
  307. Note that system and local cannot be mixed.
  308. `);
  309. return;
  310. }
  311.  
  312. // No specific help, show general help.
  313. logInfo(
  314. `Usage: dub [<command>] [<options...>] [-- <application arguments...>]
  315.  
  316. Manages the DUB project in the current directory. "--" can be used to separate
  317. DUB options from options passed to the application. If the command is omitted,
  318. dub will default to "run".
  319.  
  320. Available commands:
  321. help Prints this help screen
  322. init [<directory>] Initializes an empty project in the specified directory
  323. run Compiles and runs the application (default command)
  324. build Just compiles the application in the project directory
  325. upgrade Forces an upgrade of all dependencies
  326. install <name> Manually installs a package. See 'dub help install'.
  327. uninstall <name> Uninstalls a package. See 'dub help uninstall'.
  328. add-local <dir> <version>
  329. Adds a local package directory (e.g. a git repository)
  330. remove-local <dir> Removes a local package directory
  331. add-path <dir> Adds a default package search path
  332. remove-path <dir> Removes a package search path
  333. list-installed Prints a list of all installed packages
  334. generate <name> Generates project files using the specified generator:
  335. visuald, visuald-combined, mono-d, build, rdmd
  336. describe Prints a JSON description of the project and its
  337. dependencies
  338.  
  339. General options:
  340. --annotate Do not execute dependency installations, just print
  341. -v --verbose Also output debug messages
  342. --vverbose Also output trace messages (produces a lot of output)
  343. -q --quiet Only output warnings and errors
  344. --vquiet No output
  345. --registry=URL Search the given DUB registry URL first when resolving
  346. dependencies. Can be specified multiple times.
  347.  
  348. Build/run options:
  349. --build=NAME Specifies the type of build to perform. Note that
  350. setting the DFLAGS environment variable will override
  351. the build type with custom flags.
  352. Possible names:
  353. debug (default), plain, release, unittest, profile,
  354. docs, ddox, cov, unittest-cov and custom types
  355. --config=NAME Builds the specified configuration. Configurations can
  356. be defined in package.json
  357. --compiler=NAME Specifies the compiler binary to use. Arbitrary pre-
  358. and suffixes to the identifiers below are recognized
  359. (e.g. ldc2 or dmd-2.063) and matched to the proper
  360. compiler type:
  361. dmd (default), gdc, ldc, gdmd, ldmd
  362. --arch=NAME Force a different architecture (e.g. x86 or x86_64)
  363. --nodeps Do not check dependencies for 'run' or 'build'
  364. --print-builds Prints the list of available build types
  365. --print-configs Prints the list of available configurations
  366. --print-platform Prints the identifiers for the current build platform
  367. as used for the build fields in package.json
  368. --rdmd Use rdmd instead of directly invoking the compiler
  369. --debug=NAME Define the specified debug version identifier when
  370. building - can be used multiple times
  371.  
  372. Install options:
  373. --version Use the specified version/branch instead of the latest
  374. --system Install system wide instead of user local
  375. --local Install as in a sub folder of the current directory
  376.  
  377. `);
  378. logInfo("DUB version %s", dubVersion);
  379. }