Commonize into PathUtils; On Linux/BSD try to use xdg-open/x-www-browser if Java...
[SquirrelJME.git] / buildSrc / src / main / java / cc / squirreljme / plugin / general / DeveloperNoteTask.java
blob6bf3fe1cf6f83de2c02d9631974d28e7b8e3a2a3
1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the GNU General Public License v3+, or later.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package cc.squirreljme.plugin.general;
12 import cc.squirreljme.plugin.multivm.AlwaysFalse;
13 import cc.squirreljme.plugin.util.FossilExe;
14 import cc.squirreljme.plugin.util.PathUtils;
15 import cc.squirreljme.plugin.util.SimpleHTTPRequest;
16 import cc.squirreljme.plugin.util.SimpleHTTPResponse;
17 import cc.squirreljme.plugin.util.SimpleHTTPResponseBuilder;
18 import cc.squirreljme.plugin.util.SimpleHTTPStatus;
19 import java.awt.Desktop;
20 import java.awt.HeadlessException;
21 import java.io.ByteArrayOutputStream;
22 import java.io.IOException;
23 import java.io.PrintStream;
24 import java.io.UnsupportedEncodingException;
25 import java.net.URI;
26 import java.net.URLDecoder;
27 import java.nio.charset.StandardCharsets;
28 import java.nio.file.Path;
29 import java.time.LocalDate;
30 import java.time.LocalDateTime;
31 import java.util.Arrays;
32 import java.util.Objects;
33 import javax.inject.Inject;
34 import org.gradle.api.DefaultTask;
35 import org.gradle.api.Task;
36 import org.gradle.internal.os.OperatingSystem;
38 /**
39 * Edits the current day in developer notes.
41 * @since 2020/06/26
43 public class DeveloperNoteTask
44 extends DefaultTask
46 /** The server only handles this single path. */
47 private static final String _THE_ONLY_PATH =
48 "/";
50 /**
51 * Initializes the task.
53 * @param __exeTask The executable task.
54 * @since 2020/06/26
56 @Inject
57 public DeveloperNoteTask(FossilExeTask __exeTask)
59 // Set details of this task
60 this.setGroup("squirreljmeGeneral");
61 this.setDescription("Edits the developer note for the current day.");
63 // The executable task must run first
64 this.dependsOn(__exeTask);
66 // Fossil must exist
67 this.onlyIf(__task -> FossilExe.isAvailable(true));
68 this.getOutputs().upToDateWhen(new AlwaysFalse());
70 // Action to perform
71 this.doLast(new DeveloperNoteTaskAction());
74 /**
75 * Returns the blog file path.
77 * @param __date The date to get.
78 * @return The path to the blog file.
79 * @throws NullPointerException On null arguments.
80 * @since 2020/06/27
82 static String __blogFilePath(LocalDate __date)
83 throws NullPointerException
85 return DeveloperNoteTask.__blogFilePath(__date,
86 FossilExe.instance().currentUser());
89 /**
90 * Returns the blog file path.
92 * @param __date The date to get.
93 * @param __user The user to lookup.
94 * @return The path to the blog file.
95 * @throws NullPointerException On null arguments.
96 * @since 2020/06/27
98 private static String __blogFilePath(LocalDate __date, String __user)
99 throws NullPointerException
101 if (__date == null || __user == null)
102 throw new NullPointerException("NARG");
104 // Determine where this is
105 return String.format("developer-notes/%s/%tY/%tm/%td.mkd",
106 __user.replace('.', '-'), __date, __date, __date);
110 * Handles the HTTP request.
112 * @param __session The session being used.
113 * @param __request The request.
114 * @return The response, may be {@code null}.
115 * @throws NullPointerException On null arguments.
116 * @since 2020/06/26
118 @SuppressWarnings("FeatureEnvy")
119 static SimpleHTTPResponse __httpHandler(__DeveloperNoteSession__ __session,
120 SimpleHTTPRequest __request)
121 throws NullPointerException
123 if (__session == null || __request == null)
124 throw new NullPointerException("NARG");
126 // Setup base response, always returning the same path
127 SimpleHTTPResponseBuilder response = new SimpleHTTPResponseBuilder();
129 // If we got a request that is not from the root, it is somewhere else
130 if (!DeveloperNoteTask._THE_ONLY_PATH.equals(
131 __request.path.getPath()))
132 return response.status(SimpleHTTPStatus.NOT_FOUND).build();
134 // Submission of the form? Load in that data
135 String query;
138 query = URLDecoder.decode(Objects.toString(
139 __request.path.getRawQuery(), ""), "utf-8");
141 catch (UnsupportedEncodingException e)
143 throw new RuntimeException("Could not decode query", e);
146 // Form content?
147 if (query != null && query.startsWith("content="))
149 // Split off the data
150 String data = query.substring("content=".length())
151 .replace("\r\n", "\n");
153 // Store into the session bytes
154 __session._content = data.getBytes(StandardCharsets.UTF_8);
155 __session._saveCount++;
157 // Note it down
158 System.out.println("Notes saved!");
161 // All done?
162 else if (query != null && query.startsWith("finish="))
163 return null;
165 // Everything is okay
166 response.status(SimpleHTTPStatus.OK);
168 // Setup some headers
169 response.addHeader("Content-Type",
170 "text/html; charset=UTF-8");
171 response.addHeader("Server",
172 "SquirrelJME-Build/0.3.0");
173 response.addHeader("Connection",
174 "close");
176 // Splice in resources
177 response.spliceResources(DeveloperNoteTask.class,
178 "form-header.html", "form-footer.html",
179 __session._content);
181 // Build final response
182 return response.build();
186 * Attempts to launch a browser.
188 * @param __task The task used.
189 * @param __url The URL to launch.
190 * @throws NullPointerException On null arguments.
191 * @since 2020/06/27
193 static void __launchBrowser(Task __task, String __url)
194 throws NullPointerException
196 if (__url == null)
197 throw new NullPointerException("NARG");
199 // Inform on the terminal what the URL is for the server
200 __task.getLogger().lifecycle(String.format(
201 "Notes URL is at %s !", __url));
203 // Try to use normal AWT stuff?
206 // Not a supported desktop?
207 if (!Desktop.isDesktopSupported())
208 throw new HeadlessException();
210 // Open browser, or try to anyway
211 Desktop desktop = Desktop.getDesktop();
212 desktop.browse(URI.create(__url));
214 // It worked, so stop
215 return;
218 // Do not fail on this, just try more
219 catch (Throwable ignored)
221 ignored.printStackTrace();
224 // If we are on Linux, try to launch browser
225 if (OperatingSystem.current() == OperatingSystem.LINUX ||
226 OperatingSystem.current() == OperatingSystem.FREE_BSD)
228 // Try different potential browsers
229 for (String attempt : Arrays.asList(
230 "xdg-open", // Standard XDG Open
231 "x-www-browser" // On Debian
234 // Find executable
235 Path path = PathUtils.findPathExecutable(attempt);
236 if (path != null)
239 ProcessBuilder builder = new ProcessBuilder(
240 path.toAbsolutePath().toString(), __url);
242 builder.start();
243 return;
245 catch (IOException ignored)
251 // Open the browser using another means
252 System.err.printf("TODO -- Open browser?%n");
256 * Returns template for blank notes.
258 * @param __at The date.
259 * @return The note template.
260 * @throws NullPointerException On null arguments.
261 * @since 2020/06/27
263 @SuppressWarnings("resource")
264 static byte[] __template(LocalDateTime __at)
265 throws NullPointerException
267 if (__at == null)
268 throw new NullPointerException("NARG");
270 // Write the template
271 try (ByteArrayOutputStream out = new ByteArrayOutputStream();
272 PrintStream ps = new PrintStream(
273 out, true, "utf-8"))
275 // Header
276 ps.printf("# %tY/%tm/%td\n", __at, __at, __at);
277 ps.print("\n");
279 // Current time
280 ps.printf("## %tH:%tM", __at, __at);
281 ps.print("\n");
283 // Ending space line for content
284 ps.print("\n");
286 // Clear out and use this template
287 ps.flush();
288 return out.toByteArray();
291 // Failed to write
292 catch (IOException e)
294 throw new RuntimeException("Could not create template", e);