1 module wand; 2 3 import mage; 4 import std.conv : to; 5 import std.uni : isWhite; 6 import std.algorithm : strip; 7 8 debug = ShuffleTargets; 9 debug = LogResolveDeps; 10 11 struct MageConfig 12 { 13 Path sourceRootPath; 14 GeneratorConfig[] genConfigs; 15 } 16 17 struct GeneratorConfig 18 { 19 string name; 20 } 21 22 auto readMageConfig(in Path p) { 23 MageConfig cfg; 24 auto lines = p.open().byLine; 25 cfg.sourceRootPath = Path(cast(string)lines.front); 26 lines.popFront(); 27 foreach(line; lines) { 28 GeneratorConfig gen; 29 gen.name = cast(string)line.strip!(a => a.isWhite); 30 cfg.genConfigs ~= gen; 31 } 32 return cfg; 33 } 34 35 const(TypeInfo)[] targetOrder(ITargetWrapper[] targets) 36 { 37 debug(ShuffleTargets) 38 { 39 import std.random; 40 randomShuffle(targets); 41 } 42 debug(LogResolveDeps) log.info("Original Target Order: %-(\n %s%)", targets.map!(a => a.wrappedTypeInfo)); 43 44 const(TypeInfo)[] queue; 45 void helper(ref const(TypeInfo)[] queue, const(ITargetWrapper) wrapper) 46 { 47 auto _begin = log.Block("%s", wrapper.targetName); 48 debug(LogResolveDeps) log.info("Deps: %s", wrapper.dependencies); 49 foreach(dep; wrapper.dependencies) 50 { 51 helper(queue, targets.find!(a => a.wrappedTypeInfo == dep)[0]); 52 } 53 if(!queue.canFind!(a => a == wrapper.wrappedTypeInfo)) { 54 queue ~= wrapper.wrappedTypeInfo; 55 debug(LogResolveDeps) log.info("[add]"); 56 } 57 else 58 { 59 debug(LogResolveDeps) log.info("[skip]"); 60 } 61 } 62 foreach(wrapper; targets) 63 { 64 helper(queue, wrapper); 65 } 66 67 debug(LogResolveDeps) log.info("Sorted Target Type Infos (Queue):%-(\n %s%)", queue); 68 69 return queue; 70 } 71 72 // Is expected to be run in the `temp` dir that `mage` created. 73 int main(string[] args) 74 { 75 log.info("Running wand."); 76 Target[] targets; 77 78 auto order = targetOrder(wrappedTargets); 79 80 auto context = new MagicContext(); 81 foreach(ti; order) { 82 auto wrapper = wrappedTargets.find!(a => a.wrappedTypeInfo == ti)[0]; 83 auto _chdir = ScopedChdir(wrapper.filePath.parent); 84 auto _block = log.Block(`Creating target %s`, wrapper.targetName); 85 86 auto target = wrapper.create(); 87 target.properties["name"] = wrapper.targetName; 88 target.properties["mageFilePath"] = wrapper.filePath; 89 target.properties["dependencies"] = wrapper.dependencies.map!(a => targets.find!(t => a == typeid(t))[0]).array; 90 log.info("Target deps: %s", wrapper.dependencies); 91 target.context = context; 92 targets ~= target; 93 } 94 95 with(log.forcedBlock("Set Dependency instances")) 96 { 97 foreach(wrapper; wrappedTargets) { 98 auto target = targets.find!(a => typeid(a) == wrapper.wrappedTypeInfo)[0]; 99 foreach(dep; wrapper.dependencies) { 100 auto dependentTarget = targets.find!(a => typeid(a) == dep)[0]; 101 wrapper.setDependencyInstance(target, dependentTarget); 102 } 103 } 104 } 105 106 with(log.forcedBlock("Configure Targets")) 107 { 108 foreach(target; targets) 109 { 110 auto _chdir = ScopedChdir(target.properties["mageFilePath"].get!Path.parent); 111 target.configure(); 112 } 113 } 114 115 // Iterate all configured generators and pass all targets.` 116 auto mageCfg = readMageConfig(cwd() ~ "mage.cfg"); 117 G["sourceRootPath"] = mageCfg.sourceRootPath; 118 foreach(cfg; mageCfg.genConfigs) { 119 log.info(`Generator "%s"`, cfg.name); 120 121 auto path = Path(cfg.name); 122 if(!path.exists) { 123 path.mkdir(true); 124 } 125 with(ScopedChdir(path)) { 126 G["genRootPath"] = cwd(); 127 generatorRegistry[cfg.name].generate(context, targets); 128 } 129 } 130 131 return 0; 132 }