jcs
/amend
/amendments
/31
Repo: Support file deletion, repo versioning and migration
I broke my own rule of always adding versions to things, so start
now and migrate all unversioned repos to version 2 which adds file
flags.
When a file is deleted, doing a diff of it will diff against a blank
file and then the file in the repo is marked as deleted. For now this
just draws the file with tildes in the file list, but a custom LDEF
will draw these as strucken through.
Also fix a few bugs along the way...
jcs made amendment 31 over 3 years ago
--- amend.π.r Thu Nov 11 11:18:12 2021
+++ amend.π.r Sun Nov 21 11:10:49 2021
@@ -21,11 +21,11 @@ data 'MENU' (130) {
data 'MENU' (131) {
$"0083 0000 0000 0000 0000 FFFF FFFF 0452" /* .É.............R */
- $"6570 6F0A 4164 6420 4669 6C65 2E2E 0000" /* epo.Add File.... */
- $"0000 1852 6576 6572 7420 5365 6C65 6374" /* ...Revert Select */
- $"6564 2046 696C 6573 2E2E 2E00 0000 000E" /* ed Files........ */
- $"4170 706C 7920 5061 7463 682E 2E2E 0000" /* Apply Patch..... */
- $"0000 00" /* ... */
+ $"6570 6F0B 4164 6420 4669 6C65 2E2E 2E00" /* epo.Add File.... */
+ $"0000 0018 5265 7665 7274 2053 656C 6563" /* ....Revert Selec */
+ $"7465 6420 4669 6C65 732E 2E2E 0000 0000" /* ted Files....... */
+ $"0E41 7070 6C79 2050 6174 6368 2E2E 2E00" /* .Apply Patch.... */
+ $"0000 0000" /* .... */
};
data 'MENU' (132) {
@@ -42,9 +42,12 @@ data 'ALRT' (129) {
$"0078 006C 00DA 0196 0081 5555 300A" /* .x.l...ñ.ÅUU0. */
};
+data 'ALRT' (130) {
+ $"0078 006C 00DA 0196 0082 5555 300A" /* .x.l...ñ.ÇUU0. */
+};
+
data 'DITL' (128) {
- $"0001 0000 0000 0046 012C 005A 0166 0402" /* .......F.,.Z.f.. */
- $"4F4B 0000 0000 0014 0023 004A 0143 0802" /* OK.......#.J.C.. */
+ $"0000 0000 0000 0014 001E 0032 013B 0802" /* ...........2.;.. */
$"5E30" /* ^0 */
};
@@ -54,6 +57,13 @@ data 'DITL' (129) {
$"5E30" /* ^0 */
};
+data 'DITL' (130) {
+ $"0002 0000 0000 0046 00E6 005A 0120 0403" /* .......F...Z. .. */
+ $"5965 7321 0000 0000 0046 00A0 005A 00DA" /* Yes!.....F.†.Z.. */
+ $"0402 4E6F 0000 0000 000A 003C 0040 011E" /* ..No.......<.@.. */
+ $"0802 5E30" /* ..^0 */
+};
+
data 'WIND' (128) {
$"002B 0060 012B 01A0 0003 0100 0000 0000" /* .+.`.+.†........ */
$"0000 0A41 626F 7574 2043 6172 6C56 280A" /* ...About CarlV(. */
@@ -103,11 +113,12 @@ data 'TMPL' (129, "AFIL") {
$"7065 544E 414D 0763 7265 6174 6F72 544E" /* peTNAM.creatorTN */
$"414D 0D63 7265 6174 696F 6E20 6461 7465" /* AM¬creation date */
$"444C 4E47 116D 6F64 6966 6963 6174 696F" /* DLNG.modificatio */
- $"6E20 6461 7465 444C 4E47" /* n dateDLNG */
+ $"6E20 6461 7465 444C 4E47 0566 6C61 6773" /* n dateDLNG.flags */
+ $"4842 5954" /* HBYT */
};
-data 'DLOG' (128) {
- $"0064 0083 00A0 017D 0001 0100 0100 0000" /* .d.É.†.}........ */
+data 'DLOG' (128, "WAIT_DLOG_ID") {
+ $"0066 0059 00A0 01A4 0001 0100 0100 0000" /* .f.Y.†.§........ */
$"0000 0080 001A 280A" /* ...Ä..(. */
};
--- amend.h Mon Oct 18 13:09:14 2021
+++ amend.h Wed Nov 17 17:43:23 2021
@@ -44,4 +44,13 @@
#define TABWIDTH_ID 130
+struct tmpl {
+ Handle h;
+ ResType type;
+ Str255 name;
+ short id;
+};
+extern struct tmpl tmpls[10];
+extern short ntmpls;
+
extern MenuHandle file_menu, edit_menu, repo_menu, commit_menu;
--- browser.c Mon Oct 18 13:09:06 2021
+++ browser.c Mon Nov 22 09:48:36 2021
@@ -126,6 +126,7 @@ browser_init(struct repo *repo)
browser->win, true, true, false, true);
if (!browser->file_list)
err(1, "Can't create file list");
+ LAddColumn(1, 0, browser->file_list);
(*(browser->file_list))->selFlags = lNoNilHilite;
/* diff button */
@@ -147,6 +148,7 @@ browser_init(struct repo *repo)
COMMIT_LDEF_ID, browser->win, true, true, false, true);
if (!browser->commit_list)
err(1, "Can't create commit list");
+ LAddColumn(1, 0, browser->commit_list);
(*(browser->commit_list))->selFlags = lOnlyOne;
/* diff text */
@@ -202,13 +204,13 @@ browser_close_committer(struct browser *browser)
committer_close(browser->committer);
browser->committer = NULL;
}
- browser->state = BROWSER_STATE_IDLE;
SetPort(browser->win);
}
void
browser_add_files(struct browser *browser)
{
+ char filename[256];
Cell cell = { 0, 0 };
short i;
@@ -226,9 +228,11 @@ browser_add_files(struct browser *browser)
/* fill in files */
for (i = 0; i < browser->repo->nfiles; i++) {
LAddRow(1, cell.v, browser->file_list);
- LSetCell(&browser->repo->files[i]->filename,
- strlen(browser->repo->files[i]->filename), cell,
- browser->file_list);
+ if (browser->repo->files[i]->flags & REPO_FILE_DELETED)
+ sprintf(filename, "~%s~", browser->repo->files[i]->filename);
+ else
+ strcpy(filename, browser->repo->files[i]->filename);
+ LSetCell(&filename, strlen(filename), cell, browser->file_list);
cell.v++;
}
@@ -285,7 +289,7 @@ browser_filter_commits(struct browser *browser)
LDoDraw(false, browser->commit_list);
LDelRow(0, 0, browser->commit_list);
browser_show_commit(browser, NULL);
-
+
/* fill in commits for selected files */
nselected_files = browser_selected_file_ids(browser, &selected_files);
cell.v = 0;
@@ -312,7 +316,7 @@ browser_filter_commits(struct browser *browser)
browser->commit_list);
cell.v++;
}
-
+
LDoDraw(true, browser->commit_list);
InvalRect(&(*(browser->commit_list))->rView);
--- browser.h Mon Oct 18 13:09:23 2021
+++ browser.h Wed Nov 17 15:46:59 2021
@@ -30,6 +30,7 @@ enum {
BROWSER_STATE_OPEN_COMMITTER,
BROWSER_STATE_COMMITTER_DO_DIFF,
BROWSER_STATE_WAITING_FOR_COMMITTER,
+ BROWSER_STATE_REMOVE_FILE,
BROWSER_STATE_REVERT_FILE,
BROWSER_STATE_EXPORT_PATCH,
BROWSER_STATE_APPLY_PATCH
--- committer.c Mon Oct 18 16:47:01 2021
+++ committer.c Fri Nov 19 16:56:03 2021
@@ -461,7 +461,7 @@ committer_status(char *format, ...)
if (committer_dialog == NULL)
committer_dialog = GetNewDialog(WAIT_DLOG_ID, NULL, (WindowPtr)-1);
- GetDItem(committer_dialog, 2, &ttype, &thandle, &trect);
+ GetDItem(committer_dialog, 1, &ttype, &thandle, &trect);
SetIText(thandle, status);
}
--- commit_list.c Mon Oct 18 13:13:50 2021
+++ commit_list.c Sun Nov 21 10:53:10 2021
@@ -72,18 +72,18 @@ commit_list_draw_cell(ListHandle theList, Cell theCell
textRect.bottom = cellRect->bottom + 1;
EraseRect(&textRect);
InsetRect(&textRect, 4, 4);
-
- HLock(commit->log);
- for (len = 1; len <= commit->log_len; len++) {
- if ((*(commit->log))[len - 1] == '\r')
- break;
- }
-
+
height = FontHeight(applFont, 9);
TextFace(bold);
TextFont(applFont);
TextSize(9);
MoveTo(textRect.left, textRect.top + 6);
+
+ HLock(commit->log);
+ for (len = 1; len <= commit->log_len; len++) {
+ if ((*(commit->log))[len - 1] == '\r')
+ break;
+ }
DrawText(*(commit->log), 0, len);
HUnlock(commit->log);
--- main.c Mon Oct 18 09:22:19 2021
+++ main.c Sun Nov 21 10:49:12 2021
@@ -28,6 +28,9 @@ Handle commit_list_ldef_h;
short quitting = 0;
struct browser *cur_browser = NULL;
+struct tmpl tmpls[10];
+short ntmpls;
+
void handle_menu(long menu_id);
void cur_browser_close(void);
void update_menu(void);
@@ -68,13 +71,26 @@ main(void)
update_menu();
DrawMenuBar();
+ /* load tmpls before we open a new resource file */
+ ntmpls = Count1Resources('TMPL');
+ if (ntmpls > nitems(tmpls))
+ err(1, "ntmpls %d > %d", ntmpls, nitems(tmpls));
+ for (i = 0; i < ntmpls; i++) {
+ tmpls[i].h = GetIndResource('TMPL', i + 1);
+ if (tmpls[i].h == NULL)
+ err(1, "Failed fetching TMPL %d", i + 1);
+ GetResInfo(tmpls[i].h, &tmpls[i].id, &tmpls[i].type,
+ &tmpls[i].name);
+ DetachResource(tmpls[i].h);
+ }
+
/* dynamically patch list LDEF to point to our *_list_ldef funcs */
commit_list_ldef_h = GetResource('LDEF', COMMIT_LDEF_ID);
if (!commit_list_ldef_h)
err(1, "Can't find commit list LDEF %d", COMMIT_LDEF_ID);
HLock(commit_list_ldef_h);
((tCodeStub *)*commit_list_ldef_h)->addr = &commit_list_ldef;
-
+
/* see if we were started by double-clicking a .repo file */
CountAppFiles(&finder_action, &finder_count);
--- repo.c Mon Oct 18 17:12:17 2021
+++ repo.c Sun Nov 21 16:49:03 2021
@@ -22,8 +22,8 @@
#include "diff.h"
#include "repo.h"
#include "util.h"
-
-struct repo *repo_init(SFReply reply);
+
+struct repo *repo_init(SFReply reply, short is_new);
void repo_sort_files(struct repo *repo);
void repo_sort_commits(struct repo *repo);
short repo_get_file_attrs(struct repo *repo, Str255 filename,
@@ -31,6 +31,7 @@ short repo_get_file_attrs(struct repo *repo, Str255 fi
short repo_file_update(struct repo *repo, struct repo_file *file);
unsigned short repo_diff_header(struct repo *repo,
struct repo_commit *commit, char **ret);
+short repo_migrate(struct repo *repo, short is_new);
struct repo *
repo_open(AppFile *file)
@@ -50,7 +51,7 @@ repo_open(AppFile *file)
return NULL;
}
- return repo_init(reply);
+ return repo_init(reply, 0);
}
struct repo *
@@ -58,14 +59,8 @@ repo_create(void)
{
Point pt = { 75, 100 };
SFReply reply;
- struct tmpl {
- Handle h;
- ResType type;
- Str255 name;
- short id;
- } tmpls[10] = { NULL };
char *newpath = NULL;
- short error, fh, i, ntmpls;
+ short error, fh, i;
SFPutFile(pt, "\pCreate new repository:", NULL, NULL, &reply);
if (!reply.good)
@@ -74,43 +69,21 @@ repo_create(void)
getpath(reply.vRefNum, reply.fName, &newpath, 1);
CtoPstr(newpath);
- /* copy TMPL from our own resource file */
- ntmpls = Count1Resources('TMPL');
- if (ntmpls > nitems(tmpls))
- err(1, "ntmpls %d > %d", ntmpls, nitems(tmpls));
- for (i = 0; i < ntmpls; i++) {
- tmpls[i].h = GetIndResource('TMPL', i + 1);
- if (tmpls[i].h == NULL)
- err(1, "Failed fetching TMPL %d", i + 1);
-
- GetResInfo(tmpls[i].h, &tmpls[i].id, &tmpls[i].type,
- &tmpls[i].name);
- DetachResource(tmpls[i].h);
- }
-
error = Create(reply.fName, reply.vRefNum, AMEND_CREATOR, REPO_TYPE);
- if (error != 0)
+ if (error != 0 && error != dupFNErr)
err(1, "Failed to create %s: %d", PtoCstr(reply.fName), error);
CreateResFile(newpath);
if (ResError() != 0)
- err(1, "Failed to open %s: %d", PtoCstr(reply.fName), ResError());
+ err(1, "Failed to create res file %s: %d", newpath, ResError());
- fh = OpenResFile(newpath);
- if (fh == -1)
- err(1, "Failed to open %s: %d", PtoCstr(reply.fName), ResError());
-
- for (i = 0; i < ntmpls; i++)
- AddResource(tmpls[i].h, tmpls[i].type, tmpls[i].id, tmpls[i].name);
-
- CloseResFile(fh);
free(newpath);
- return repo_init(reply);
+ return repo_init(reply, 1);
}
struct repo *
-repo_init(SFReply reply)
+repo_init(SFReply reply, short is_new)
{
Str255 buf;
struct repo *repo;
@@ -134,6 +107,11 @@ repo_init(SFReply reply)
memcpy(repo->filename, reply.fName, reply.fName[0] + 1);
PtoCstr(repo->filename);
+
+ if (repo_migrate(repo, is_new) != 0) {
+ free(repo);
+ return NULL;
+ }
/* fill in file info */
repo->nfiles = Count1Resources(REPO_FILE_RTYPE);
@@ -143,7 +121,6 @@ repo_init(SFReply reply)
resh = GetIndResource(REPO_FILE_RTYPE, i + 1);
if (resh == NULL)
err(1, "failed fetching file %d", i + 1);
- HLock(resh);
repo->files[i] = repo_parse_file(resh);
if (repo->files[i]->id >= repo->next_file_id)
repo->next_file_id = repo->files[i]->id + 1;
@@ -176,6 +153,7 @@ repo_close(struct repo *repo)
{
struct repo_file *file;
struct repo_commit *commit;
+ Handle h;
short i;
for (i = 0; i < repo->ncommits; i++) {
@@ -212,10 +190,13 @@ repo_parse_file(Handle hfile)
struct repo_file *file;
short len, i;
unsigned char *data;
+ short datapos, hlen;
Str255 buf;
HLock(hfile);
+ hlen = GetHandleSize(hfile);
data = (unsigned char *)(*hfile);
+ datapos = 0;
file = xmalloczero(sizeof(struct repo_file));
@@ -225,27 +206,35 @@ repo_parse_file(Handle hfile)
len = data[0];
memcpy(file->filename, data + 1, len);
file->filename[len] = '\0';
- data += (data[0] + 1);
+ datapos += (len + 1);
/* type fourcc, creator fourcc */
- memcpy(&file->type, data, 4);
- data += 4;
- memcpy(&file->creator, data, 4);
- data += 4;
+ memcpy(&file->type, data + datapos, 4);
+ datapos += 4;
+ memcpy(&file->creator, data + datapos, 4);
+ datapos += 4;
/* creation date, long */
- file->ctime = ((unsigned long)data[0] << 24) |
- ((unsigned long)data[1] << 16) |
- ((unsigned long)data[2] << 8) |
- ((unsigned long)data[3]);
- data += 4;
+ file->ctime = ((unsigned long)data[datapos] << 24) |
+ ((unsigned long)data[datapos + 1] << 16) |
+ ((unsigned long)data[datapos + 2] << 8) |
+ ((unsigned long)data[datapos + 3]);
+ datapos += 4;
/* modification date, long */
- file->mtime = ((unsigned long)data[0] << 24) |
- ((unsigned long)data[1] << 16) |
- ((unsigned long)data[2] << 8) |
- ((unsigned long)data[3]);
- data += 4;
+ file->mtime = ((unsigned long)data[datapos] << 24) |
+ ((unsigned long)data[datapos + 1] << 16) |
+ ((unsigned long)data[datapos + 2] << 8) |
+ ((unsigned long)data[datapos + 3]);
+ datapos += 4;
+
+ /* flags, char */
+ file->flags = (unsigned char)data[datapos];
+ datapos += 1;
+
+ if (datapos != hlen)
+ err(1, "repo_parse_file handle len %d, data position %d", hlen,
+ datapos);
HUnlock(hfile);
@@ -477,7 +466,7 @@ repo_add_file(struct repo *repo)
repo->nfiles++;
repo->files = xrealloc(repo->files, repo->nfiles * sizeof(Ptr));
file = repo->files[repo->nfiles - 1] =
- xmalloc(sizeof(struct repo_file));
+ xmalloczero(sizeof(struct repo_file));
file->id = repo->next_file_id;
repo->next_file_id++;
@@ -505,24 +494,33 @@ repo_file_update(struct repo *repo, struct repo_file *
CtoPstr(filename);
error = repo_get_file_attrs(repo, filename, &attrs);
- if (error) {
+ if (error && error != fnfErr) {
warn("Failed to get info for %s", file->filename);
return -1;
}
- memcpy(&file->type, &attrs.type, 4);
- memcpy(&file->creator, &attrs.creator, 4);
- memcpy(&file->ctime, &attrs.ctime, 4);
- memcpy(&file->mtime, &attrs.mtime, 4);
- /* filename len, filename, type, creator, ctime, mtime */
- len = 1 + filename[0] + 4 + 4 + 4 + 4;
+ if (error == fnfErr)
+ file->flags |= REPO_FILE_DELETED;
+ else {
+ file->flags &= ~REPO_FILE_DELETED;
+ memcpy(&file->type, &attrs.type, 4);
+ memcpy(&file->creator, &attrs.creator, 4);
+ memcpy(&file->ctime, &attrs.ctime, 4);
+ memcpy(&file->mtime, &attrs.mtime, 4);
+ }
+
+ /* filename len, filename, type, creator, ctime, mtime, flags */
+ len = 1 + filename[0] + 4 + 4 + 4 + 4 + 1;
+
fileh = Get1Resource(REPO_FILE_RTYPE, file->id);
if (fileh == NULL) {
/* build a new AFIL resource */
fileh = xNewHandle(len);
new = 1;
- }
+ } else if (len != GetHandleSize(fileh))
+ warn("repo_file_update len %d vs resource size %d", len,
+ GetHandleSize(fileh));
HLock(fileh);
@@ -534,17 +532,23 @@ repo_file_update(struct repo *repo, struct repo_file *
data += filename[0] + 1;
/* file type, creator, and dates */
- memcpy(data, &attrs.type, 4);
+ memcpy(data, &file->type, 4);
data += 4;
- memcpy(data, &attrs.creator, 4);
+ memcpy(data, &file->creator, 4);
data += 4;
- memcpy(data, &attrs.ctime, 4);
+ memcpy(data, &file->ctime, 4);
data += 4;
- memcpy(data, &attrs.mtime, 4);
+ memcpy(data, &file->mtime, 4);
data += 4;
+ memcpy(data, &file->flags, 1);
+ data += 1;
+ HUnlock(fileh);
+
if (new)
AddResource(fileh, REPO_FILE_RTYPE, file->id, filename);
+ else
+ ChangedResource(fileh);
WriteResource(fileh);
ReleaseResource(fileh);
@@ -560,10 +564,9 @@ repo_get_file_attrs(struct repo *repo, Str255 filename
char *filepath = NULL;
/* lookup file type and creator */
- if (GetFInfo(filename, repo->vrefnum, &fi) != 0) {
- warn("Failed to GetFInfo %s", PtoCstr(filename));
- return -1;
- }
+ error = GetFInfo(filename, repo->vrefnum, &fi);
+ if (error != 0)
+ return error;
memcpy(&attrs->type, &fi.fdType, 4);
memcpy(&attrs->creator, &fi.fdCreator, 4);
@@ -669,7 +672,7 @@ repo_diff_file(struct repo *repo, struct repo_file *fi
char *fromfilepath, *tofilepath;
char label0[255], label1[255];
long len;
- short error, ret, frefnum;
+ short error, ret, frefnum, tofile_empty = 0;
/* write out old file */
sprintf((char *)fromfilename, "%s (%s tmp)", file->filename,
@@ -692,8 +695,8 @@ repo_diff_file(struct repo *repo, struct repo_file *fi
getpath(repo->vrefnum, fromfilename, &fromfilepath, true);
- texth = Get1Resource(REPO_TEXT_RTYPE, file->id);
/* if there's no existing TEXT resource, it's a new file */
+ texth = Get1Resource(REPO_TEXT_RTYPE, file->id);
if (texth != NULL) {
len = GetHandleSize(texth);
HLock(texth);
@@ -711,9 +714,23 @@ repo_diff_file(struct repo *repo, struct repo_file *fi
getpath(repo->vrefnum, tofilename, &tofilepath, true);
error = repo_get_file_attrs(repo, tofilename, &attrs);
- if (error)
+ if (error == fnfErr) {
+ /* file no longer exists, create empty temp file */
+ sprintf((char *)tofilename, "%s (%s deleted)", file->filename,
+ PROGRAM_NAME);
+ CtoPstr(tofilename);
+
+ error = Create(tofilename, repo->vrefnum, file->creator,
+ file->type);
+ if (error && error != dupFNErr)
+ err(1, "Failed to create file %s: %d", PtoCstr(tofilename),
+ error);
+
+ getpath(repo->vrefnum, tofilename, &tofilepath, true);
+ tofile_empty = 1;
+ } else if (error)
err(1, "Failed to get info for %s", PtoCstr(tofilename));
-
+
/* specify diff header labels to avoid printing tmp filename */
/* (TODO: use paths relative to repo) */
label[0] = (char *)&label0;
@@ -734,9 +751,18 @@ repo_diff_file(struct repo *repo, struct repo_file *fi
err(1, "Failed to delete temp file %s: %d", PtoCstr(fromfilename),
error);
- free(fromfilepath);
- free(tofilepath);
+ if (tofile_empty) {
+ error = FSDelete(tofilename, repo->vrefnum);
+ if (error)
+ err(1, "Failed to delete temp file %s: %d",
+ PtoCstr(tofilename), error);
+ }
+ if (fromfilepath)
+ free(fromfilepath);
+ if (tofilepath)
+ free(tofilepath);
+
if (ret == D_SAME)
return 0;
@@ -800,14 +826,15 @@ repo_commit(struct repo *repo, short *files, short nfi
Str255 tfilename;
struct repo_file *file;
Handle commith, texth, fileh;
- short commit_len = 0, pos = 0, len;
+ FInfo finfo;
+ short commit_len, pos = 0, len;
time_t date;
char author[] = "jcs"; /* XXX */
long fsize;
short i, commit_id, id, error, frefnum;
/* date (long) */
- commit_len += sizeof(long);
+ commit_len = sizeof(long);
/* author (pstr) */
commit_len += 1 + strlen(author);
@@ -858,19 +885,20 @@ repo_commit(struct repo *repo, short *files, short nfi
HUnlock(log);
if (pos != commit_len)
- err(1, "Accumulated len %d != expected %d", pos, commit_len);
+ err(1, "repo_commit: accumulated len %d != expected %d", pos,
+ commit_len);
commit_id = repo->next_commit_id;
/* store diff */
- AddResource(diff, REPO_DIFF_RTYPE, commit_id, NULL);
+ AddResource(diff, REPO_DIFF_RTYPE, commit_id, "\p");
if (ResError())
err(1, "Failed storing diff in repo file (%d)", ResError());
WriteResource(diff);
ReleaseResource(diff);
/* store commit */
- AddResource(commith, REPO_COMMIT_RTYPE, commit_id, NULL);
+ AddResource(commith, REPO_COMMIT_RTYPE, commit_id, "\p");
if (ResError())
err(1, "Failed storing commit in repo file (%d)", ResError());
WriteResource(commith);
@@ -880,7 +908,17 @@ repo_commit(struct repo *repo, short *files, short nfi
file = repo_file_with_id(repo, files[i]);
if (file == NULL)
err(1, "Bogus file %d in commit", files[i]);
-
+
+ len = strlen(file->filename);
+ memcpy(tfilename, file->filename, len);
+ tfilename[len] = '\0';
+ CtoPstr(tfilename);
+
+ /* update file contents if file wasn't deleted */
+ error = GetFInfo(tfilename, repo->vrefnum, &finfo);
+ if (error && error != fnfErr)
+ err(1, "Error getting file info for %s", PtoCstr(tfilename));
+
SetResLoad(false);
texth = Get1Resource(REPO_TEXT_RTYPE, file->id);
if (texth != NULL) {
@@ -889,34 +927,31 @@ repo_commit(struct repo *repo, short *files, short nfi
}
SetResLoad(true);
- len = strlen(file->filename);
- memcpy(tfilename, file->filename, len);
- tfilename[len] = '\0';
- CtoPstr(tfilename);
+ if (error != fnfErr) {
+ error = FSOpen(tfilename, repo->vrefnum, &frefnum);
+ if (error)
+ err(1, "Failed to open file %s: %d", PtoCstr(tfilename),
+ error);
+
+ error = GetEOF(frefnum, &fsize);
+ if (error)
+ err(1, "Failed to get size of file %s: %d",
+ PtoCstr(tfilename), error);
+
+ texth = xNewHandle(fsize);
+ HLock(texth);
+ error = FSRead(frefnum, &fsize, *texth);
+ if (error)
+ err(1, "Failed to read %ul of file %s: %d", fsize,
+ PtoCstr(tfilename), error);
+
+ FSClose(frefnum);
+
+ AddResource(texth, REPO_TEXT_RTYPE, files[i], tfilename);
+ WriteResource(texth);
+ ReleaseResource(texth);
+ }
- error = FSOpen(tfilename, repo->vrefnum, &frefnum);
- if (error)
- err(1, "Failed to open file %s: %d", PtoCstr(tfilename),
- error);
-
- error = GetEOF(frefnum, &fsize);
- if (error)
- err(1, "Failed to get size of file %s: %d", PtoCstr(tfilename),
- error);
-
- texth = xNewHandle(fsize);
- HLock(texth);
- error = FSRead(frefnum, &fsize, *texth);
- if (error)
- err(1, "Failed to read %ul of file %s: %d", fsize,
- PtoCstr(tfilename), error);
-
- FSClose(frefnum);
-
- AddResource(texth, REPO_TEXT_RTYPE, files[i], tfilename);
- WriteResource(texth);
- ReleaseResource(texth);
-
repo_file_update(repo, file);
}
@@ -930,4 +965,81 @@ repo_commit(struct repo *repo, short *files, short nfi
ReleaseResource(commith);
repo_sort_commits(repo);
+
+ UpdateResFile(repo->fh);
+}
+
+short
+repo_migrate(struct repo *repo, short is_new)
+{
+ Handle verh, resh;
+ short ver, add = 0, i, nfiles, size;
+
+ if (is_new)
+ ver = REPO_CUR_VERS;
+ else {
+ verh = Get1Resource(REPO_VERS_RTYPE, 1);
+ if (verh == NULL)
+ ver = 1;
+ else {
+ ver = (unsigned char)((*verh)[0]);
+ ReleaseResource(verh);
+ }
+
+ if (ver == REPO_CUR_VERS)
+ return 0;
+
+ if (ask("Migrate this repo from version %d to %d to open it?",
+ ver, REPO_CUR_VERS) != ASK_YES)
+ return -1;
+ }
+
+ /* per-version migrations */
+ if (ver == 1) {
+ /* version 1 had no file flags */
+ nfiles = Count1Resources(REPO_FILE_RTYPE);
+ for (i = 1; i <= nfiles; i++) {
+ resh = GetIndResource(REPO_FILE_RTYPE, i);
+ if (resh == NULL)
+ err(1, "failed fetching file %d", i);
+ size = GetHandleSize(resh);
+ ReallocHandle(resh, size + 1);
+ if (MemError())
+ err(1, "Out of memory allocating new handle of size %ld",
+ size + 1);
+ HLock(resh);
+ (*resh)[size] = 0;
+ HUnlock(resh);
+ ChangedResource(resh);
+ WriteResource(resh);
+ ReleaseResource(resh);
+ }
+ ver = 2;
+ }
+
+ /* store new version */
+ verh = Get1Resource(REPO_VERS_RTYPE, 1);
+ if (verh == NULL) {
+ verh = NewHandle(1);
+ add = 1;
+ }
+ (*verh)[0] = ver;
+ if (add)
+ AddResource(verh, REPO_VERS_RTYPE, 1, "\p");
+ else
+ ChangedResource(verh);
+
+ /* update templates */
+ for (i = 0; i < ntmpls; i++) {
+ resh = Get1Resource(tmpls[i].type, tmpls[i].id);
+ if (resh)
+ RmveResource(resh);
+ AddResource(tmpls[i].h, tmpls[i].type, tmpls[i].id, tmpls[i].name);
+ WriteResource(tmpls[i].h);
+ DetachResource(tmpls[i].h);
+ }
+
+ UpdateResFile(repo->fh);
+
+ return 0;
}
--- repo.h Mon Oct 18 15:08:25 2021
+++ repo.h Thu Nov 18 11:01:03 2021
@@ -27,11 +27,14 @@
#define REPO_COMMIT_RTYPE 'CMMT'
#define REPO_DIFF_RTYPE 'DIFF'
#define REPO_TEXT_RTYPE 'TEXT'
+#define REPO_VERS_RTYPE 'RVER'
#define DIFF_FILE_TYPE 'TEXT'
#define REPO_DIFF_TOO_BIG "\r[ Diff too large to view, %lu bytes not shown ]"
+#define REPO_CUR_VERS 2
+
struct repo_file {
short id;
char filename[256];
@@ -39,6 +42,8 @@ struct repo_file {
OSType creator;
unsigned long ctime;
unsigned long mtime;
+ unsigned char flags;
+#define REPO_FILE_DELETED (1 << 0)
};
struct repo_file_attrs {
@@ -82,6 +87,7 @@ struct repo_file *repo_file_with_id(struct repo *repo,
void repo_show_diff_text(struct repo *repo, struct repo_commit *commit,
TEHandle te);
struct repo_file *repo_add_file(struct repo *repo);
+void repo_file_mark_for_deletion(struct repo *repo, struct repo_file *file);
short repo_diff_file(struct repo *repo, struct repo_file *file);
short repo_checkout_file(struct repo *repo, struct repo_file *file,
short vrefnum, Str255 filename);
--- util.c Mon Oct 18 13:14:58 2021
+++ util.c Mon Nov 22 09:48:09 2021
@@ -21,7 +21,10 @@
#include "util.h"
+/* ALRT resources */
#define ERROR_ALERT_ID 129
+#define ASK_ALERT_ID 130
+
#define ERROR_STRING_SIZE 1024
enum {
@@ -226,6 +229,32 @@ note(const char *format, ...)
va_end(ap);
}
+short
+ask(const char *format, ...)
+{
+ size_t len;
+ short ret;
+ WindowPtr win;
+ va_list ap;
+
+ GetPort(&win);
+
+ HLock(err_str);
+ va_start(ap, format);
+ len = vsprintf(*err_str, format, ap);
+ va_end(ap);
+ if (len >= ERROR_STRING_SIZE)
+ err(1, "ask string overflow!");
+
+ ParamText(CtoPstr(*err_str), "\p", "\p", "\p");
+ ret = StopAlert(ASK_ALERT_ID, nil);
+ HUnlock(err_str);
+
+ SetPort(win);
+ return ret;
+}
+
+
/*
* Error checking wrappers for Mac toolkit functions
*/
@@ -367,9 +396,9 @@ getpath(short vRefNum, Str255 fileName, char **ret, bo
warn("Unknown filesystem type 0x%x", wvol.ioVSigWord);
return 1;
}
-
- wcinfo.ioNamePtr = (StringPtr)&name;
+
wcinfo.ioVRefNum = vRefNum;
+ wcinfo.ioNamePtr = (StringPtr)&name;
wcinfo.ioFDirIndex = -1;
wcinfo.ioDrParID = wdir.ioWDDirID;
wcinfo.ioDrDirID = wdir.ioWDDirID;
--- util.h Mon Oct 18 13:09:59 2021
+++ util.h Fri Nov 19 13:34:19 2021
@@ -70,6 +70,9 @@ void warnx(const char *format, ...);
void warn(const char *format, ...);
void err(short retcode, const char *format, ...);
void note(const char *format, ...);
+short ask(const char *format, ...);
+#define ASK_YES 1
+#define ASK_NO 2
Handle xNewHandle(unsigned long size);
Handle xGetResource(ResType type, short id);
@@ -86,6 +89,8 @@ pascal Boolean open_dialog_filter(DialogPtr theDialog,
bool is_dir(char *path);
short stat(const char *path, struct stat *sb);
OSErr FSReadLine(short frefnum, char *buf, size_t buflen);
+
+Handle SetResSize(Handle res, size_t size);
short FontHeight(short font_id, short size);
void DrawGrowIconOnly(WindowPtr win);