• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Aucun tag

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

CLI interface to medialist (fossil mirror)


Commit MetaInfo

Révision1e158176c27abba819f2a3ccc384f80f526079d4 (tree)
l'heure2022-01-10 15:09:22
Auteurmio <stigma@disr...>
Commitermio

Message de Log

add an implementation for the MLCommand.delete_ command. This also changes the MediaList structure to use public members instead of package.

FossilOrigin-Name: 873d7974aad4307a8b86764ff3ae7b5e6439173eca595b54838a9c8a6b0c79c5

Change Summary

Modification

--- a/medialist.d
+++ b/medialist.d
@@ -18,25 +18,37 @@
1818 */
1919 module medialist;
2020
21+import std.algorithm.sorting;
22+import std.conv;
2123 import std.datetime.date;
2224 import std.datetime.systime;
2325 import std.file;
26+import std.path;
2427 import std.stdio;
2528 import std.string;
2629
2730 struct MediaList
2831 {
29-package:
30- string filePath;
32+ immutable string filePath;
33+ immutable string listName;
3134 bool isOpen = false;
3235 }
3336
3437 enum MLCommand
3538 {
3639 /**
37- * Args: ["Item Name", "(Optional) Progress", "(Optional) Status".
40+ * Add a new item to a list.
41+ *
42+ * Args: ["Item Name", "(Optional) Progress", "(Optional) Status"]
3843 */
3944 add,
45+ /**
46+ * Delete items from a list.
47+ *
48+ * If no "Item ID"s are provided, this will delete the entire list.
49+ *
50+ * Args: ["(Optional) Item ID", ...(repeat for the amount of ids needed)]
51+ */
4052 delete_,
4153 update,
4254 }
@@ -51,7 +63,8 @@ enum MLError
5163
5264 MediaList* ml_open_list(string filePath)
5365 {
54- MediaList* ml = new MediaList(filePath);
66+ string listName = stripExtension(baseName(filePath));
67+ MediaList* ml = new MediaList(filePath, listName);
5568
5669 if (false == exists(filePath)) {
5770 File f = File(filePath, "w+");
@@ -96,6 +109,7 @@ MLError ml_send_command(MediaList* list, MLCommand command, string[] args)
96109 res = _ml_add(list, args);
97110 break;
98111 case MLCommand.delete_:
112+ res = _ml_delete(list, args);
99113 break;
100114 case MLCommand.update:
101115 break;
@@ -167,6 +181,105 @@ private MLError _ml_add(MediaList* list, string[] args)
167181 return MLError.success;
168182 }
169183
184+/**
185+ * Convert and sort an array of strings to "size_t".
186+ *
187+ * This assumes all elements in the array can be converted. If any fail,
188+ * then "null" is returned from the function.
189+ */
190+private size_t[] _ml_conv_sort_num_list(const string[] args)
191+{
192+ size_t[] ids = new size_t[args.length];
193+
194+ foreach(size_t idx, const ref string arg; args) {
195+ try {
196+ ids[idx] = to!size_t(arg);
197+ } catch (Exception e) {
198+ return null;
199+ }
200+ }
201+
202+ sort(ids);
203+
204+ return ids;
205+}
206+
207+private MLError _ml_delete(MediaList* list, string[] args)
208+{
209+ if (true == list.isOpen)
210+ return MLError.fileAlreadyOpen;
211+
212+ if (0 == args.length) {
213+ remove(list.filePath);
214+ return MLError.success;
215+ }
216+
217+ size_t[] ids = _ml_conv_sort_num_list(args);
218+
219+ if (null is ids)
220+ return MLError.invalidArgs;
221+
222+ File listFile = File(list.filePath);
223+ list.isOpen = true;
224+
225+ /*
226+ * To avoid storing all lines in memory, we create a temporary file with
227+ * which we write all lines that we are keeping. Once we're done writing,
228+ * we then overwrite the actual list file with the contents of the temporary
229+ * file.
230+ *
231+ * If someone knows of a better way to go about this, I wouldn't mind
232+ * knowing.
233+ */
234+ string tempFilePath = buildPath(tempDir(),
235+ "temp" ~ baseName(list.filePath));
236+ File tempFile = File(tempFilePath, "w+");
237+
238+ size_t currentID = 1;
239+ size_t idsIndex = 0;
240+ string line;
241+ bool pastHeader = false;
242+
243+ while ((line = listFile.readln()) !is null) {
244+ if (line[0] == '#') {
245+ tempFile.write(line);
246+ continue;
247+ }
248+
249+ if (false == pastHeader) {
250+ tempFile.write(line);
251+ pastHeader = true;
252+ continue;
253+ }
254+
255+ if (ids[idsIndex] != currentID)
256+ tempFile.write(line);
257+ else
258+ idsIndex += 1;
259+
260+ currentID += 1;
261+ }
262+
263+ listFile.close();
264+ tempFile.close();
265+
266+ listFile = File(list.filePath, "w+");
267+ tempFile = File(tempFilePath);
268+
269+ while ((line = tempFile.readln) !is null) {
270+ listFile.write(line);
271+ }
272+
273+ listFile.close();
274+ tempFile.close();
275+
276+ remove(tempFilePath);
277+
278+ list.isOpen = false;
279+
280+ return MLError.success;
281+}
282+
170283 private enum MLHeaders
171284 {
172285 title = 0,
@@ -294,7 +407,6 @@ void main()
294407 @("Create a new list")
295408 unittest
296409 {
297- import std.conv : to;
298410 import std.path : buildPath;
299411
300412 const listPath = buildPath(tempDir(), "unittest1.tsv");