• 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évision7645bcaf4f5391ffb2694b8e15240ae12dff85fc (tree)
l'heure2021-11-21 19:09:36
Auteurmio <stigma@disr...>
Commitermio

Message de Log

Share the code for adding missing headers between add.d and update.d (now located in util.d). These are the only places where the code should be required.

FossilOrigin-Name: 46ca890bccd96877f1e48144414e435bf8ea446de1e032f133b38df6312fb958

Change Summary

Modification

--- a/add.d
+++ b/add.d
@@ -59,16 +59,16 @@ import util;
5959 _log("list '" ~ listName ~ "' doesn't exist.", true);
6060 return false;
6161 }
62-
62+
6363 // no status or progress.
6464 if (args.length < 3)
6565 {
6666 return addItem(listFilePath, title);
6767 }
68-
68+
6969 string status = "UNKNOWN";
7070 string progress = "??/??";
71-
71+
7272 getopt(args,
7373 "status|s", "Set the initial status for the new item", &status,
7474 "progress|p", "Set the initial progress for the new item", &progress);
@@ -78,7 +78,7 @@ import util;
7878 writefln("Added %s to %s (status: %s, progress: %s)", title, listName, status, progress);
7979 return true;
8080 }
81-
81+
8282 return false;
8383 }
8484
@@ -86,115 +86,14 @@ private bool addItem(string listFilePath, string itemName,
8686 string status = "UNKNOWN", string progress = "??/??")
8787 {
8888 File listFile = File(listFilePath, "a+");
89-
90- string[] headers = retrieveListHeaders(&listFile);
91- if (headers is null)
92- {
93- return false;
94- }
95- addMissingHeaders(headers, &listFile);
96- auto headersAndPositions = parseMLHeader(headers);
97- writeNewItem(&listFile, headersAndPositions, itemName, status, progress);
98-
99- return true;
100-}
101-
102-private string[] retrieveListHeaders(File* listFile)
103-{
104- string line;
105-
106- while ((line = listFile.readln()) !is null)
107- {
108- if ('#' != line[0])
109- {
110- return line.strip().split('\t');
111- }
112- }
113-
114- return null;
115-}
116-
117-private void addMissingHeaders(ref string[] fileHeaders, File* listFile)
118-{
119- import std.algorithm.searching : canFind;
120-
121- if (false == canFind(fileHeaders, "start_date"))
122- {
123- addHeader(listFile, "start_date");
124- fileHeaders ~= "start_date";
125- }
126-
127- if (false == canFind(fileHeaders, "end_date"))
128- {
129- addHeader(listFile, "end_date");
130- fileHeaders ~= "end_date";
131- }
132-
133- if (false == canFind(fileHeaders, "last_updated"))
134- {
135- addHeader(listFile, "last_updated");
136- fileHeaders ~= "last_updated";
137- }
138-}
139-
140-private
141-void addHeader(File* f, string newHeader) @trusted
142-in
143-{
144- assert(f.isOpen == true);
145- assert(newHeader !is null);
146-}
147-out
148-{
149- assert(f.isOpen == true);
150-}
151-do
152-{
153- import std.file : rename, remove, tempDir;
154- import std.path : buildPath, baseName;
155-
156- immutable origPath = f.name;
157- immutable tempPath = buildPath(tempDir(), baseName(origPath));
158-
159- File tempFile = File(tempPath, "w+");
160-
161- string line = "";
162- bool pastHeader = false;
163-
164- f.rewind();
165-
166- while ((line = f.readln()) !is null)
167- {
168- if (false == pastHeader && '#' != line[0])
169- {
170- pastHeader = true;
171- tempFile.writefln("%s\t%s", line.strip, newHeader);
172- }
173- else
174- {
175- /* line may not have a newline character */
176- tempFile.writeln(line.strip);
177- }
178- }
179-
180- f.close();
181-
182- remove(origPath);
18389
184- /* some operating systems don't like to copy from the tempdir? */
185- f.open(origPath, "a+");
186- tempFile.rewind();
90+ string[] headers = retrieveListHeaders (&listFile);
91+ addMissingHeaders (headers, &listFile);
18792
188- while ((line = tempFile.readln()) !is null)
189- {
190- f.write(line);
191- }
192-
193- /* rewind because we need to re-read the headers */
194- f.rewind();
93+ auto headersAndPositions = parseMLHeader(headers);
94+ writeNewItem(&listFile, headersAndPositions, itemName, status, progress);
19595
196- tempFile.close();
197- remove(tempPath);
96+ return true;
19897 }
19998
20099 private void writeNewItem(File* listFile, HeaderPairType[NUMBER_OF_ML_HEADERS] headersAndPositions,
@@ -203,9 +102,9 @@ private void writeNewItem(File* listFile, HeaderPairType[NUMBER_OF_ML_HEADERS] h
203102 import std.datetime.date : Date;
204103 import std.datetime.systime : Clock;
205104 import std.string : toLower;
206-
105+
207106 size_t previousIndent = 0;
208-
107+
209108 immutable currentDT = Clock.currTime();
210109 immutable currentDateString = Date(currentDT.year, currentDT.month,
211110 currentDT.day).toISOExtString();
@@ -215,7 +114,7 @@ private void writeNewItem(File* listFile, HeaderPairType[NUMBER_OF_ML_HEADERS] h
215114 /* unset header -- no more headers possible */
216115 if (headerPair[0] == 0 && headerPair[1] is null)
217116 break;
218-
117+
219118 listFile.replicateIndent(headerPair, &previousIndent);
220119
221120 switch (headerPair[1])
@@ -262,7 +161,7 @@ private void replicateIndent(File* listFile, HeaderPairType headerPair, size_t*
262161 import core.stdc.stdio : fprintf;
263162 import core.stdc.stdio : cstderr = stderr;
264163 import core.stdc.stdlib : malloc, free;
265-
164+
266165 // Can't add NULL byte to D string, so allocate a temp string and free it.
267166 char* progname = cast(char*)malloc(char.sizeof * programName.length);
268167 scope(exit) free(progname);
@@ -279,3 +178,29 @@ options:
279178 -p, --progress the initial progress of the new item (default: ??/??)
280179 -s, --status the initial status of the new item (default: UNKNOWN)\n", progname);
281180 }
181+
182+
183+/* Testing pre-0.2 files with the addHeaders */
184+unittest
185+{
186+ import std.file : remove;
187+ import std.stdio : File;
188+
189+ enum listName = "unittest-add-pre-0.2";
190+ string line;
191+
192+ auto listFile = File (listName ~ ".tsv", "w+");
193+ scope (exit) remove(listName ~ ".tsv");
194+
195+ listFile.writeln("TITLE\tPROGRESS\tSTATUS");
196+ listFile.close();
197+
198+ /* Shouldn't crash */
199+ handle_add (listName, [listName, "Item 1", "-p", "??/??", "-s", "PLAN-TO-READ"], ".");
200+
201+ listFile.open(listName ~ ".tsv", "r");
202+ listFile.rewind();
203+ line = listFile.readln();
204+ assert ("TITLE\tPROGRESS\tSTATUS\tstart_date\tend_date\tlast_updated\n" == line, "'" ~ line ~ "'");
205+}
206+
--- a/update.d
+++ b/update.d
@@ -110,6 +110,13 @@ handle_update(string program_name, string[] args, string data_dir)
110110 bool read_header = false;
111111 Tuple!(size_t, string)[NUMBER_OF_ML_HEADERS] headers;
112112
113+ /* Add missing headers */
114+ {
115+ File listFile = File(filename, "a+");
116+ string[] headers_ = retrieveListHeaders(&listFile);
117+ addMissingHeaders(headers_, &listFile);
118+ }
119+
113120 /*
114121 * line_number represents the line number in file.
115122 * index initially represents a matching ID number
--- a/util.d
+++ b/util.d
@@ -18,6 +18,7 @@
1818 */
1919 module util;
2020
21+import std.stdio : File;
2122 import std.typecons : Tuple, tuple;
2223
2324 alias HeaderPairType = Tuple!(size_t, string);
@@ -183,3 +184,118 @@ parseMLHeader(string[] headerSections)
183184
184185 return sections;
185186 }
187+
188+public string[]
189+retrieveListHeaders (File* listFile)
190+{
191+ import std.string : strip, split;
192+
193+ string line = null;
194+ string[] fileHeaders;
195+
196+ listFile.rewind ();
197+
198+ while ((line = listFile.readln()) !is null)
199+ {
200+ if ('#' != line[0])
201+ {
202+ fileHeaders = line.strip().split('\t');
203+ break;
204+ }
205+ }
206+
207+ return fileHeaders;
208+}
209+
210+public void
211+addMissingHeaders(ref string[] fileHeaders, File* listFile)
212+{
213+ import core.stdc.stdio : SEEK_END;
214+ import std.algorithm.searching : canFind;
215+
216+ /* Version 0.2 */
217+ if (false == canFind(fileHeaders, "start_date"))
218+ {
219+ addHeader(listFile, "start_date");
220+ fileHeaders ~= "start_date";
221+ }
222+
223+ if (false == canFind(fileHeaders, "end_date"))
224+ {
225+ addHeader(listFile, "end_date");
226+ fileHeaders ~= "end_date";
227+ }
228+
229+ if (false == canFind(fileHeaders, "last_updated"))
230+ {
231+ addHeader(listFile, "last_updated");
232+ fileHeaders ~= "last_updated";
233+ }
234+
235+ listFile.seek(0, SEEK_END);
236+}
237+
238+@trusted private void
239+addHeader(File* f, string newHeader)
240+in
241+{
242+ assert (f.isOpen == true, "f.isOpen == true (in)");
243+ assert (newHeader !is null, "newHeader !is null");
244+}
245+out
246+{
247+ assert (f.isOpen == true, "f.isOpen == true (out)");
248+}
249+do
250+{
251+ import std.file : remove, tempDir;
252+ import std.path : buildPath, baseName;
253+ import std.string : strip;
254+
255+ immutable originalPath = f.name;
256+ immutable tempPath = buildPath(tempDir, baseName(originalPath));
257+
258+ File tempFile = File(tempPath, "w+");
259+
260+ string line = "";
261+ bool pastHeader = false;
262+
263+ /* Make sure we're at the start of the file. */
264+ f.rewind ();
265+
266+ while ((line = f.readln()) !is null)
267+ {
268+ if (false == pastHeader && '#' != line[0])
269+ {
270+ pastHeader = true;
271+ tempFile.writefln ("%s\t%s", strip (line), newHeader);
272+ }
273+ else
274+ {
275+ /* strip + writeln since the previous one may not have had the newline */
276+ tempFile.writeln (strip (line));
277+ }
278+ }
279+
280+ f.close ();
281+
282+ /*
283+ * Since the temporary directory *could* be mounted differently (e.g. remotely)
284+ * some systems don't like to copy from the temporary directory.
285+ */
286+ remove (originalPath);
287+
288+ f.open (originalPath, "w+");
289+ tempFile.rewind ();
290+
291+ while ((line = tempFile.readln()) !is null)
292+ {
293+ f.write (line);
294+ }
295+
296+ /* Rewind since we need to re-parse the headers */
297+ f.rewind ();
298+
299+ tempFile.close();
300+ remove (tempPath);
301+}