Merge branch 'subtree'
[nikiroo-utils.git] / src / be / nikiroo / utils / VersionCheck.java
1 package be.nikiroo.utils;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.InputStreamReader;
7 import java.net.URL;
8 import java.util.ArrayList;
9 import java.util.HashMap;
10 import java.util.List;
11 import java.util.Locale;
12 import java.util.Map;
13
14 /**
15 * Version checker: can check the current version of the program against a
16 * remote changelog, and list the missed updates and their description.
17 *
18 * @author niki
19 */
20 public class VersionCheck {
21 private static final String base = "https://github.com/${PROJECT}/raw/master/changelog${LANG}.md";
22 private static Downloader downloader = new Downloader(null);
23
24 private Version current;
25 private List<Version> newer;
26 private Map<Version, List<String>> changes;
27
28 /**
29 * Create a new {@link VersionCheck}.
30 *
31 * @param current
32 * the current version of the program
33 * @param newer
34 * the list of available {@link Version}s newer the current one
35 * @param changes
36 * the list of changes
37 */
38 private VersionCheck(Version current, List<Version> newer,
39 Map<Version, List<String>> changes) {
40 this.current = current;
41 this.newer = newer;
42 this.changes = changes;
43 }
44
45 /**
46 * Check if there are more recent {@link Version}s of this program
47 * available.
48 *
49 * @return TRUE if there is at least one
50 */
51 public boolean isNewVersionAvailable() {
52 return !newer.isEmpty();
53 }
54
55 /**
56 * The current {@link Version} of the program.
57 *
58 * @return the current {@link Version}
59 */
60 public Version getCurrentVersion() {
61 return current;
62 }
63
64 /**
65 * The list of available {@link Version}s newer than the current one.
66 *
67 * @return the newer {@link Version}s
68 */
69 public List<Version> getNewer() {
70 return newer;
71 }
72
73 /**
74 * The list of changes for each available {@link Version} newer than the
75 * current one.
76 *
77 * @return the list of changes
78 */
79 public Map<Version, List<String>> getChanges() {
80 return changes;
81 }
82
83 /**
84 * Check if there are available {@link Version}s of this program more recent
85 * than the current one.
86 *
87 * @param githubProject
88 * the GitHub project to check on, for instance "nikiroo/fanfix"
89 * @param lang
90 * the current locale, so we can try to get the changelog in the
91 * correct language (can be NULL, will fetch the default
92 * changelog)
93 *
94 * @return a {@link VersionCheck}
95 *
96 * @throws IOException
97 * in case of I/O error
98 */
99 public static VersionCheck check(String githubProject, Locale lang)
100 throws IOException {
101 Version current = Version.getCurrentVersion();
102 List<Version> newer = new ArrayList<Version>();
103 Map<Version, List<String>> changes = new HashMap<Version, List<String>>();
104
105 // Use the right project:
106 String base = VersionCheck.base.replace("${PROJECT}", githubProject);
107
108 // Prepare the URLs according to the user's language (we take here
109 // "-fr_BE" as an example):
110 String fr = lang == null ? "" : "-" + lang.getLanguage();
111 String BE = lang == null ? ""
112 : "_" + lang.getCountry().replace(".UTF8", "");
113 String urlFrBE = base.replace("${LANG}", fr + BE);
114 String urlFr = base.replace("${LANG}", "-" + fr);
115 String urlDefault = base.replace("${LANG}", "");
116
117 InputStream in = null;
118 for (String url : new String[] { urlFrBE, urlFr, urlDefault }) {
119 try {
120 in = downloader.open(new URL(url), false);
121 break;
122 } catch (IOException e) {
123 }
124 }
125
126 if (in == null) {
127 throw new IOException("No changelog found");
128 }
129
130 BufferedReader reader = new BufferedReader(
131 new InputStreamReader(in, "UTF-8"));
132 try {
133 Version version = new Version();
134 for (String line = reader.readLine(); line != null; line = reader
135 .readLine()) {
136 if (line.startsWith("## Version ")) {
137 version = new Version(
138 line.substring("## Version ".length()));
139 if (version.isNewerThan(current)) {
140 newer.add(version);
141 changes.put(version, new ArrayList<String>());
142 } else {
143 version = new Version();
144 }
145 } else if (!version.isEmpty() && !newer.isEmpty()
146 && !line.isEmpty()) {
147 List<String> ch = changes.get(newer.get(newer.size() - 1));
148 if (!ch.isEmpty() && !line.startsWith("- ")) {
149 int i = ch.size() - 1;
150 ch.set(i, ch.get(i) + " " + line.trim());
151 } else {
152 ch.add(line.substring("- ".length()).trim());
153 }
154 }
155 }
156 } finally {
157 reader.close();
158 }
159
160 return new VersionCheck(current, newer, changes);
161 }
162
163 @Override
164 public String toString() {
165 return String.format(
166 "Version checker: version [%s], %d releases behind latest version [%s]", //
167 current, //
168 newer.size(), //
169 newer.isEmpty() ? current : newer.get(newer.size() - 1)//
170 );
171 }
172 }