1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
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
;
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
;
39 * Edits the current day in developer notes.
43 public class DeveloperNoteTask
46 /** The server only handles this single path. */
47 private static final String _THE_ONLY_PATH
=
51 * Initializes the task.
53 * @param __exeTask The executable task.
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
);
67 this.onlyIf(__task
-> FossilExe
.isAvailable(true));
68 this.getOutputs().upToDateWhen(new AlwaysFalse());
71 this.doLast(new DeveloperNoteTaskAction());
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.
82 static String
__blogFilePath(LocalDate __date
)
83 throws NullPointerException
85 return DeveloperNoteTask
.__blogFilePath(__date
,
86 FossilExe
.instance().currentUser());
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.
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.
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
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
);
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
++;
158 System
.out
.println("Notes saved!");
162 else if (query
!= null && query
.startsWith("finish="))
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",
176 // Splice in resources
177 response
.spliceResources(DeveloperNoteTask
.class,
178 "form-header.html", "form-footer.html",
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.
193 static void __launchBrowser(Task __task
, String __url
)
194 throws NullPointerException
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
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
235 Path path
= PathUtils
.findPathExecutable(attempt
);
239 ProcessBuilder builder
= new ProcessBuilder(
240 path
.toAbsolutePath().toString(), __url
);
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.
263 @SuppressWarnings("resource")
264 static byte[] __template(LocalDateTime __at
)
265 throws NullPointerException
268 throw new NullPointerException("NARG");
270 // Write the template
271 try (ByteArrayOutputStream out
= new ByteArrayOutputStream();
272 PrintStream ps
= new PrintStream(
276 ps
.printf("# %tY/%tm/%td\n", __at
, __at
, __at
);
280 ps
.printf("## %tH:%tM", __at
, __at
);
283 // Ending space line for content
286 // Clear out and use this template
288 return out
.toByteArray();
292 catch (IOException e
)
294 throw new RuntimeException("Could not create template", e
);