1 module glued.application.scanlisteners.bundles;
2 
3 import std.algorithm;
4 import std.path;
5 import std.array;
6 
7 import glued.logging;
8 
9 //todo listener should public import scannable
10 import glued.codescan.scannable;
11 import glued.codescan.listener;
12 
13 import glued.adhesives.bundles;
14 import glued.adhesives.config;
15 
16 import dejector;
17 
18 ///from top-level paths towards lower-level ones; if depth is the same, alphabetical order
19 auto assetComparator(Asset a, Asset b){
20     auto aDepth = a.path.depth;
21     auto bDepth = b.path.depth;
22     if (aDepth == bDepth)
23     {
24         auto aName = a.path.baseName;
25         auto bName = b.path.baseName;
26         return cmp(aName, bName) < 0;
27     }
28     else
29     {
30         return aDepth < bDepth;
31     }
32 }
33 
34 class BundlesListener: ScanListener!Dejector 
35 {
36     mixin CreateLogger;
37     private Logger log;
38     private Dejector injector;
39     private BundleRegistrar registrar;
40     private Config config;
41 
42     void init(Dejector injector)
43     {
44         this.injector = injector;
45         log = Logger(injector.get!LogSink);
46         registrar = new BundleRegistrar;
47         config = new Config(injector.get!LogSink);
48         injector.bind!(BundleRegistrar)(new InstanceProvider(registrar));
49         injector.bind!(Config)(new InstanceProvider(config));
50         registrar.register(new BuildTimeBundle);
51     }
52 
53     void onScannable(alias scannable)() if (isScannable!scannable)
54     {
55         //todo track what scannable does asset come from
56     }
57     
58     void onType(T)()
59     {
60     }
61     
62     void onBundleModule(string modName)()
63     {
64         log.info.emit("Tracking glue-d bundle for module "~modName);
65         registrar.register!(modName)();
66     }
67     
68     void onScannerFreeze()
69     {
70         auto configAssets = registrar
71             .ls()
72             .filter!(a => 
73                 a.path.baseName == "logging.conf" ||
74                 a.path.baseName == "application.conf"
75             );
76         
77         //1. scheme=glued
78         //sort from top-level packages towards lower ones
79         auto gluedAssets = configAssets
80             .filter!(a => a.scheme == "glued")
81             .array //required so that result of prev step is random access range
82             .sort!(assetComparator);
83         foreach (a; gluedAssets)
84             config.feed(a);
85         
86         //2. scheme=build
87         //order defined in bundles adhesive
88         foreach(n; buildTimeAssetNames)
89         {
90             auto a = registrar.find("build", n);
91             if (!a.empty)
92             {
93                 config.feed(a.front());
94             }
95         }
96 
97         //3. others
98         //ditto when it comes to sorting
99         auto otherAssets = configAssets
100             .filter!(a => a.scheme != "glued" && a.scheme != "build")
101             .array //required so that result of prev step is random access range
102             .sort!(assetComparator);
103         foreach (a; otherAssets)
104             config.feed(a);
105         
106         //TODO 4. files specified with CLI, in the order of specifying
107     }
108 }