Commit 74272cdbacfafba0ff73372af3eb1568da46571e
0 parents
First commit
Showing
2 changed files
with
127 additions
and
0 deletions
README.md
0 → 100644
1 | +++ a/README.md | ... | ... |
fat.nim
0 → 100644
1 | +++ a/fat.nim | |
1 | +import md5, os, osproc, parseopt2, strutils, parsecfg, streams | |
2 | + | |
3 | +# This is a little utility program for handling large files | |
4 | +# in git repositories. Its inspired by git-fat and s3annex | |
5 | +# but doesn't rely on S3 for storage. | |
6 | +# | |
7 | +# Use "fat d mybigfile" to deflate it before commit. | |
8 | +# Use "fat i mybigfile" to inflate it back to original size. | |
9 | +# | |
10 | +# When deflated the file only has an md5sum string inside it. | |
11 | +# | |
12 | +# The file is copied over into: | |
13 | +# <homedir>/fatstore/<originalfilename>-<md5sum> | |
14 | + | |
15 | +var fatstore, remoteFatstore: string | |
16 | + | |
17 | + | |
18 | +# Load fatstore.conf file, overkill for now but... | |
19 | +proc parseConfFile(filename: string) = | |
20 | + echo filename | |
21 | + var f = newFileStream(filename, fmRead) | |
22 | + if f != nil: | |
23 | + var p: CfgParser | |
24 | + open(p, f, filename) | |
25 | + while true: | |
26 | + var e = next(p) | |
27 | + case e.kind | |
28 | + of cfgEof: | |
29 | + break | |
30 | + of cfgSectionStart: | |
31 | + continue # Ignore | |
32 | + of cfgKeyValuePair: | |
33 | + if e.key == "remote": | |
34 | + remoteFatstore = e.value | |
35 | + else: | |
36 | + quit("Unknown configuration: " & e.key) | |
37 | + of cfgOption: | |
38 | + quit("Unknown configuration: " & e.key) | |
39 | + of cfgError: | |
40 | + quit("Parsing " & filename & ": " & e.msg) | |
41 | + close(p) | |
42 | + | |
43 | + | |
44 | +# Upload a file to the remote master fatstore | |
45 | +proc uploadFile(fatfilename: string) = | |
46 | + if remoteFatstore.isNil: | |
47 | + echo("Remote fatstore not set in configuration file, not uploading content:\n\t" & fatfilename) | |
48 | + return | |
49 | + let errorCode = execCmd("rsync -a " & fatstore / fatfilename & " " & remoteFatstore) | |
50 | + if errorCode != 0: quit("Something went wrong uploading content to " & remoteFatstore, 2) | |
51 | + | |
52 | +# Download a file to the remote master fatstore | |
53 | +proc downloadFile(fatfilename: string) = | |
54 | + if remoteFatstore.isNil: | |
55 | + quit("Remote fatstore not set in configuration file, can not download content:\n\t" & fatfilename) | |
56 | + let errorCode = execCmd("rsync -a " & remoteFatstore / fatfilename & " " & fatstore / "") | |
57 | + if errorCode != 0: quit("Something went wrong downloading " & fatfilename & " from " & remoteFatstore, 3) | |
58 | + | |
59 | + | |
60 | +# Copy content to fatstore, no upload yet. | |
61 | +proc copyToFatstore(filename, fatfilename: string) = | |
62 | + if not existsFile(fatstore / fatfilename): | |
63 | + copyFile(filename, fatstore / fatfilename) | |
64 | + uploadFile(fatfilename) | |
65 | + | |
66 | +# Copy content from fatstore, and downloading first if needed | |
67 | +proc copyFromFatstore(fatfilename, filename: string) = | |
68 | + if not existsFile(fatstore / fatfilename): | |
69 | + downloadFile(fatfilename) | |
70 | + copyFile(fatstore / fatfilename, filename) | |
71 | + | |
72 | + | |
73 | +# Copy original file to fatstore and replace with hash stub in git. | |
74 | +proc deflate(filename: string) = | |
75 | + let content = readFile(filename) | |
76 | + if content[0..4] == "hash:": | |
77 | + quit("File is already deflated, ignored.", 5) | |
78 | + let hash = getMD5(content) | |
79 | + let fatfilename = filename & "-" & hash | |
80 | + copyToFatstore(filename, fatfilename) | |
81 | + writeFile(filename, "hash:" & fatfilename) | |
82 | + | |
83 | +# Parse out hash from hash stub and copy back original content from fatstore. | |
84 | +proc inflate(filename: string) = | |
85 | + var hashfile: File | |
86 | + if not open(hashfile, filename): | |
87 | + quit("Could not open file: " & filename, 4) | |
88 | + let hashline = split(string(readLine(hashfile)), {':'}) | |
89 | + if hashline[0] == "hash": | |
90 | + let fatfilename = hashline[1] | |
91 | + #removeFile(filename) | |
92 | + copyFromFatstore(fatfilename, filename) | |
93 | + else: | |
94 | + quit("File is not a fat file.", 5) | |
95 | + | |
96 | + | |
97 | +################################ main ##################################### | |
98 | + | |
99 | +# Hardwired to "fatstore" directory in home dir. | |
100 | +fatstore = getHomeDir() / "fatstore" | |
101 | + | |
102 | +# Make sure we have the dir, or create it. | |
103 | +try: | |
104 | + if not existsDir(fatstore): createDir(fatstore) | |
105 | +except: | |
106 | + quit("Could not create " & fatstore & " directory.", 1) | |
107 | + | |
108 | + | |
109 | +# Parse configuration if it exists | |
110 | +parseConfFile(fatstore / "fatstore.conf") | |
111 | + | |
112 | +# Only a command and a path as argument | |
113 | +let argv = commandLineParams() | |
114 | +let command = argv[0] | |
115 | +let filename = argv[1] | |
116 | + | |
117 | + | |
118 | +# Do the deed | |
119 | +if command == "d" or command == "deflate": | |
120 | + deflate(filename) | |
121 | +elif command == "i" or command == "inflate": | |
122 | + inflate(filename) | |
123 | +else: | |
124 | + quit("Unknown command, only (d)eflate or (i)inflate are valid.", 6) | |
125 | + | |
126 | +# All good | |
127 | +quit(0) | ... | ... |