1 /++
2  + License: MIT
3  + Copyright: Copyright (c) 2018, Christian Koestlin
4  + Authors: Christian Koestlin
5  +/
6 
7 module ponies.dlang.dub.registry;
8 
9 import asdf;
10 import ponies.dlang.dub;
11 import ponies.shields;
12 import requests;
13 import std.experimental.logger;
14 import std;
15 import std.datetime.stopwatch;
16 
17 struct Package {
18     string name;
19 }
20 class DubRegistryCache
21 {
22     private static bool packagesRead;
23 
24     private static Package[] packages;
25 
26     bool includes(string name)
27     {
28         if (!packagesRead)
29         {
30             packages = getPackages();
31             packagesRead = true;
32         }
33         return packages.any!(v => v.name == name);
34     }
35 
36 
37     private auto getPackages()
38     {
39         const path = "%s/.ponies".format(environment.get("HOME"));
40         const cachePath = "%s/dub-registry.cache".format(path);
41         if (!cachePath.exists)
42         {
43             "Populating cache %s".format(cachePath).info;
44             const url = "https://code.dlang.org/api/packages/dump";
45             auto sw = std.datetime.stopwatch.StopWatch(AutoStart.yes);
46             auto content = url.getContent;
47             "Downloading took %s".format(sw.peek).info;
48             sw.reset;
49             auto packages = content.to!string.deserialize!(Package[]);
50             "Parsing took %s".format(sw.peek).info;
51             if (!path.exists)
52             {
53                 path.mkdir;
54             }
55             std.file.write(cachePath, packages.map!(v => v.name).join("\n"));
56             return packages;
57         }
58         auto sw = std.datetime.stopwatch.StopWatch(AutoStart.yes);
59         auto result = cachePath.readText.splitter("\n").map!(v => Package(v)).array;
60         "Loading cache took %s".format(sw.peek).info;
61         return result;
62     }
63 }
64 
65 class DubRegistryShieldPony : ShieldPony
66 {
67     DubRegistryCache cache;
68     string dubPackageName;
69     string what;
70 
71     this(DubRegistryCache cache, string what)
72     {
73         this.cache = cache;
74         this.dubPackageName = getFromDubSdl("name");
75         this.what = what;
76     }
77 
78     override bool applicable()
79     {
80         if (dubPackageName == null)
81         {
82             return false;
83         }
84         return dubSdlAvailable && cache.includes(dubPackageName) && super.applicable;
85     }
86 
87     override string[] doctor()
88     {
89         string[] hints;
90         if (!exists("readme.org"))
91         {
92             hints ~= "Please add readme.org";
93         }
94         if (!dubSdlAvailable)
95         {
96             hints ~= "Please add dub.sdl";
97         }
98         if (!cache.includes(dubPackageName)) {
99             hints ~= "Please upload you package to the https://code.dlang.org";
100         }
101         return hints;
102     }
103 
104     override string shield()
105     {
106         return "[[http://code.dlang.org/packages/%1$s][https://img.shields.io/dub/%2$s/%1$s.svg?style=flat-square]]"
107             .format(dubPackageName, what);
108     }
109 
110 }
111 
112 class DubLicenseShieldPony : DubRegistryShieldPony
113 {
114     this(DubRegistryCache cache)
115     {
116         super(cache, "l");
117     }
118 
119     override string name()
120     {
121         return "Setup dub registry license shield in readme.org";
122     }
123 }
124 
125 class DubVersionShieldPony : DubRegistryShieldPony
126 {
127     this(DubRegistryCache cache)
128     {
129         super(cache, "v");
130     }
131 
132     override string name()
133     {
134         return "Setup dub registry version shield in readme.org";
135     }
136 }
137 
138 class DubWeeklyDownloadsShieldPony : DubRegistryShieldPony
139 {
140     this(DubRegistryCache cache)
141     {
142         super(cache, "dw");
143     }
144 
145     override string name()
146     {
147         return "Setup dub registry weekly downloads shield in readme.org";
148     }
149 }