1 /**
2 	Copyright: © 2013 rejectedsoftware e.K.
3 	License: Subject to the terms of the GNU GPLv3 license, as written in the included LICENSE.txt file.
4 	Authors: Sönke Ludwig
5 */
6 module dubregistry.viewutils;
7 
8 import std.datetime;
9 import std.string;
10 import vibe.data.json;
11 
12 string formatDate(Json date)
13 {
14 	return formatDate(date.opt!string);
15 }
16 
17 string formatDate(string iso_ext_date)
18 {
19 	if (iso_ext_date.length == 0) return "---";
20 	return formatDate(SysTime.fromISOExtString(iso_ext_date));
21 }
22 
23 string formatDate(SysTime st)
24 {
25 	return (cast(Date)st).toSimpleString();
26 }
27 
28 string formatDateTime(Json dateTime)
29 {
30 	return formatDateTime(dateTime.opt!string);
31 }
32 
33 string formatDateTime(string iso_ext_date)
34 {
35 	if (iso_ext_date.length == 0) return "---";
36 	return formatDateTime(SysTime.fromISOExtString(iso_ext_date));
37 }
38 
39 string formatDateTime(SysTime st)
40 {
41 	return st.toSimpleString();
42 }
43 
44 string formatFuzzyDate(Json dateTime)
45 {
46 	return formatFuzzyDate(dateTime.opt!string);
47 }
48 
49 string formatFuzzyDate(string iso_ext_date)
50 {
51 	if (iso_ext_date.length == 0) return "---";
52 	return formatFuzzyDate(SysTime.fromISOExtString(iso_ext_date));
53 }
54 
55 string formatFuzzyDate(SysTime st)
56 {
57 	auto now = Clock.currTime(UTC());
58 
59 	// TODO: proper singular forms etc. (probably done together with l8n)
60 	auto tm = now - st;
61 	if (tm < dur!"seconds"(0)) return "still going to happen";
62 	else if (tm < dur!"seconds"(1)) return "just now";
63 	else if (tm < dur!"minutes"(1)) return "less than a minute ago";
64 	else if (tm < dur!"minutes"(2)) return "a minute ago";
65 	else if (tm < dur!"hours"(1)) return format("%s minutes ago", tm.total!"minutes"());
66 	else if (tm < dur!"hours"(2)) return "an hour ago";
67 	else if (tm < dur!"days"(1)) return format("%s hours ago", tm.total!"hours"());
68 	else if (tm < dur!"days"(2)) return "a day ago";
69 	else if (tm < dur!"weeks"(5)) return format("%s days ago", tm.total!"days"());
70 	else if (tm < dur!"weeks"(52)) {
71 		auto m1 = st.month;
72 		auto m2 = now.month;
73 		auto months = (now.year - st.year) * 12 + m2 - m1;
74 		if (months == 1) return "a month ago";
75 		else return format("%s months ago", months);
76 	} else if (now.year - st.year <= 1) return "a year ago";
77 	else return format("%s years ago", now.year - st.year);
78 }
79 
80 /** Takes an input range of version strings and returns the index of the "best"
81 	version.
82 
83 	"Best" version in this case means the highest released version. Numbered
84 	versions will be preferred over branch names.
85 
86 */
87 size_t getBestVersionIndex(R)(R versions)
88 {
89 	import dub.semver;
90 
91 	size_t ret = size_t.max;
92 	string retv;
93 	size_t i = 0;
94 	foreach (vstr; versions) {
95 		if (ret == size_t.max) {
96 			ret = i;
97 			retv = vstr;
98 		} else {
99 			if (retv.startsWith("~")) {
100 				if (vstr == "~master" || !vstr.startsWith("~")) {
101 					ret = i;
102 					retv = vstr;
103 				}
104 			} else if (!vstr.startsWith("~") && compareVersions(vstr, retv) > 0) {
105 				ret = i;
106 				retv = vstr;
107 			}
108 		}
109 		i++;
110 	}
111 	return ret;
112 }
113 
114 unittest {
115 	assert(getBestVersionIndex(["~master", "0.0.1", "1.0.0"]) == 2);
116 	assert(getBestVersionIndex(["~master", "0.0.1-alpha"]) == 1);
117 	assert(getBestVersionIndex(["~somebranch", "~master"]) == 1);
118 	assert(getBestVersionIndex(["~master", "~somebranch"]) == 0);
119 	assert(getBestVersionIndex(["1.0.0", "1.0.1-alpha"]) == 1);
120 }