/** Package skeleton initialization code. Copyright: © 2013-2016 rejectedsoftware e.K. License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. Authors: Sönke Ludwig */ module dub.init; import dub.internal.vibecompat.core.file; import dub.internal.vibecompat.core.log; import dub.package_ : PackageFormat, packageInfoFiles, defaultPackageFilename; import dub.recipe.packagerecipe; import dub.dependency; import std.datetime; import std.exception; import std.file; import std.format; import std.process; import std.string; /** Intializes a new package in the given directory. The given `root_path` will be checked for any of the files that will be created by this function. If any exist, an exception will be thrown before altering the directory. Params: root_path = Directory in which to create the new package. If the directory doesn't exist, a new one will be created. deps = A set of extra dependencies to add to the package recipe. The associative array is expected to map from package name to package version. type = The type of package skeleton to create. Can currently be "minimal", "vibe.d" or "deimos" recipe_callback = Optional callback that can be used to customize the package recipe and the file format used to store it prior to writing it to disk. */ void initPackage(Path root_path, string[string] deps, string type, PackageFormat format, scope RecipeCallback recipe_callback = null) { import std.conv : to; import dub.recipe.io : writePackageRecipe; void enforceDoesNotExist(string filename) { enforce(!existsFile(root_path ~ filename), "The target directory already contains a '"~filename~"' file. Aborting."); } string username = getUserName(); PackageRecipe p; p.name = root_path.head.toString().toLower(); p.authors ~= username; p.license = "proprietary"; p.copyright = .format("Copyright © %s, %s", Clock.currTime().year, username); foreach (pack, v; deps) { import std.ascii : isDigit; p.buildSettings.dependencies[pack] = Dependency(v); } //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); void processRecipe() { if (recipe_callback) recipe_callback(p, format); } switch (type) { default: throw new Exception("Unknown package init type: "~type); case "minimal": initMinimalPackage(root_path, p, &processRecipe); break; case "vibe.d": initVibeDPackage(root_path, p, &processRecipe); break; case "deimos": initDeimosPackage(root_path, p, &processRecipe); break; } writePackageRecipe(root_path ~ ("dub."~format.to!string), p); writeGitignore(root_path); } alias RecipeCallback = void delegate(ref PackageRecipe, ref PackageFormat); private void initMinimalPackage(Path root_path, ref PackageRecipe p, scope void delegate() pre_write_callback) { p.description = "A minimal D application."; pre_write_callback(); 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."); } }); } private void initVibeDPackage(Path root_path, ref PackageRecipe p, scope void delegate() pre_write_callback) { if ("vibe-d" !in p.buildSettings.dependencies) p.buildSettings.dependencies["vibe-d"] = Dependency("~>0.7.30"); p.description = "A simple vibe.d server application."; pre_write_callback(); createDirectory(root_path ~ "source"); createDirectory(root_path ~ "views"); createDirectory(root_path ~ "public"); write((root_path ~ "source/app.d").toNativeString(), q{import vibe.vibe; void main() { 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."); runApplication(); } void hello(HTTPServerRequest req, HTTPServerResponse res) { res.writeBody("Hello, World!"); } }); } private void initDeimosPackage(Path root_path, ref PackageRecipe p, scope void delegate() pre_write_callback) { import dub.compilers.buildsettings : TargetType; auto name = root_path.head.toString().toLower(); p.description = format("Deimos Bindings for "~p.name~"."); p.buildSettings.importPaths[""] ~= "."; p.buildSettings.targetType = TargetType.sourceLibrary; pre_write_callback(); createDirectory(root_path ~ "C"); createDirectory(root_path ~ "deimos"); } private void writeGitignore(Path root_path) { write((root_path ~ ".gitignore").toNativeString(), ".dub\ndocs.json\n__dummy.html\n*.o\n*.obj\n__test__*__\n"); } private string getUserName() { version (Windows) return environment.get("USERNAME", "Peter Parker"); else version (Posix) { import core.sys.posix.pwd, core.sys.posix.unistd, core.stdc.string : strlen; import std.algorithm : splitter; if (auto pw = getpwuid(getuid)) { auto uinfo = pw.pw_gecos[0 .. strlen(pw.pw_gecos)].splitter(','); if (!uinfo.empty && uinfo.front.length) return uinfo.front.idup; } return environment.get("USER", "Peter Parker"); } else static assert(0); }