Commit e914743a56027342c159eb2158cbd593e2542f5e
1 parent
19f977a4
Added remove command that unblimps a file.
Showing
2 changed files
with
95 additions
and
27 deletions
blimp.nim
@@ -20,17 +20,22 @@ import md5, os, osproc, parseopt2, strutils, parsecfg, streams, lapp, subexes | @@ -20,17 +20,22 @@ import md5, os, osproc, parseopt2, strutils, parsecfg, streams, lapp, subexes | ||
20 | # ~/blimpstore/.blimp.conf | 20 | # ~/blimpstore/.blimp.conf |
21 | 21 | ||
22 | var | 22 | var |
23 | - blimpStore, uploadCommandFormat, downloadCommandFormat: string | 23 | + blimpStore, uploadCommandFormat, downloadCommandFormat, deleteCommandFormat: string |
24 | remoteBlimpStore: string = nil | 24 | remoteBlimpStore: string = nil |
25 | verbose: bool | 25 | verbose: bool |
26 | 26 | ||
27 | let | 27 | let |
28 | defaultConfig = """ | 28 | defaultConfig = """ |
29 | [rsync] | 29 | [rsync] |
30 | +# Set this to your remote rsync daemon area | ||
30 | remote = "blimp@some-rsync-server.com::blimpstore" | 31 | remote = "blimp@some-rsync-server.com::blimpstore" |
32 | + | ||
33 | +# The following three formats should not need editing | ||
31 | # $1 is filename, $2 is remote and $3 is the local blimpstore | 34 | # $1 is filename, $2 is remote and $3 is the local blimpstore |
32 | upload = "rsync --password-file ~/blimp.pass -avzP $3/$1 $2/" | 35 | upload = "rsync --password-file ~/blimp.pass -avzP $3/$1 $2/" |
33 | -download = "rsync -avzP $2/$1 $3/" | 36 | +download = "rsync --password-file ~/blimp.pass -avzP $2/$1 $3/" |
37 | +# This deletes a single file from destination, that is already deleted in source | ||
38 | +delete = "rsync --password-file ~/blimp.pass -dv --delete --existing --ignore-existing --include '$1' --exclude '*' $3/ $2" | ||
34 | """ | 39 | """ |
35 | 40 | ||
36 | # Load blimp.conf file, overkill for now but... | 41 | # Load blimp.conf file, overkill for now but... |
@@ -54,6 +59,8 @@ proc parseConfFile(filename: string) = | @@ -54,6 +59,8 @@ proc parseConfFile(filename: string) = | ||
54 | uploadCommandFormat = e.value | 59 | uploadCommandFormat = e.value |
55 | of "download": | 60 | of "download": |
56 | downloadCommandFormat = e.value | 61 | downloadCommandFormat = e.value |
62 | + of "delete": | ||
63 | + deleteCommandFormat = e.value | ||
57 | else: | 64 | else: |
58 | quit("Unknown configuration: " & e.key) | 65 | quit("Unknown configuration: " & e.key) |
59 | of cfgOption: | 66 | of cfgOption: |
@@ -70,7 +77,7 @@ proc run(cmd: string): auto = | @@ -70,7 +77,7 @@ proc run(cmd: string): auto = | ||
70 | # Upload a file to the remote master blimpStore | 77 | # Upload a file to the remote master blimpStore |
71 | proc uploadFile(blimpFilename: string) = | 78 | proc uploadFile(blimpFilename: string) = |
72 | if remoteBlimpStore.isNil: | 79 | if remoteBlimpStore.isNil: |
73 | - echo("Remote blimpstore not set in configuration file, not uploading content:\n\t" & blimpFilename) | 80 | + echo("Remote blimpstore not set in configuration file, skipping uploading content:\n\t" & blimpFilename) |
74 | return | 81 | return |
75 | let errorCode = run(format(uploadCommandFormat, blimpFilename, remoteBlimpStore, blimpStore)) | 82 | let errorCode = run(format(uploadCommandFormat, blimpFilename, remoteBlimpStore, blimpStore)) |
76 | if errorCode != 0: | 83 | if errorCode != 0: |
@@ -84,6 +91,13 @@ proc downloadFile(blimpFilename: string) = | @@ -84,6 +91,13 @@ proc downloadFile(blimpFilename: string) = | ||
84 | if errorCode != 0: | 91 | if errorCode != 0: |
85 | quit("Something went wrong downloading " & blimpFilename & " from " & remoteBlimpStore, 3) | 92 | quit("Something went wrong downloading " & blimpFilename & " from " & remoteBlimpStore, 3) |
86 | 93 | ||
94 | +# Delete a file from the remote master blimpStore | ||
95 | +proc remoteDeleteFile(blimpFilename: string) = | ||
96 | + if remoteBlimpStore.isNil: | ||
97 | + return | ||
98 | + let errorCode = run(format(deleteCommandFormat, blimpFilename, remoteBlimpStore, blimpStore)) | ||
99 | + if errorCode != 0: | ||
100 | + quit("Something went wrong deleting " & blimpFilename & " from " & remoteBlimpStore, 3) | ||
87 | 101 | ||
88 | # Copy content to blimpStore, no upload yet. | 102 | # Copy content to blimpStore, no upload yet. |
89 | proc copyToBlimpStore(filename, blimpFilename: string) = | 103 | proc copyToBlimpStore(filename, blimpFilename: string) = |
@@ -92,40 +106,71 @@ proc copyToBlimpStore(filename, blimpFilename: string) = | @@ -92,40 +106,71 @@ proc copyToBlimpStore(filename, blimpFilename: string) = | ||
92 | uploadFile(blimpFilename) | 106 | uploadFile(blimpFilename) |
93 | 107 | ||
94 | # Copy content from blimpStore, and downloading first if needed | 108 | # Copy content from blimpStore, and downloading first if needed |
95 | -proc copyFromblimpStore(blimpFilename, filename: string) = | 109 | +proc copyFromBlimpStore(blimpFilename, filename: string) = |
96 | if not existsFile(blimpStore / blimpFilename): | 110 | if not existsFile(blimpStore / blimpFilename): |
97 | downloadFile(blimpFilename) | 111 | downloadFile(blimpFilename) |
98 | copyFile(blimpStore / blimpFilename, filename) | 112 | copyFile(blimpStore / blimpFilename, filename) |
99 | 113 | ||
100 | - | 114 | +# Delete from blimpStore and remote. |
115 | +proc deleteFromBlimpStore(blimpFilename, filename: string) = | ||
116 | + if existsFile(blimpStore / blimpFilename): | ||
117 | + removeFile(blimpStore / blimpFilename) | ||
118 | + remoteDeleteFile(blimpFilename) | ||
119 | + | ||
120 | +# Pick out blimpFilename (filename & "-" & hash) | ||
121 | +proc blimpFileName(filename: string): string= | ||
122 | + var hashfile: File | ||
123 | + if not open(hashfile, filename): | ||
124 | + quit("Failed opening file: " & filename, 4) | ||
125 | + let hashline = split(string(readLine(hashfile)), {':'}) | ||
126 | + if hashline[0] == "hash": | ||
127 | + result = hashline[1] | ||
128 | + else: | ||
129 | + result = nil | ||
130 | + | ||
131 | +# Get hash and compute blimpFilename | ||
132 | +proc computeBlimpFilename(filename: string): string = | ||
133 | + result = blimpFilename(filename) | ||
134 | + if result.isNil: | ||
135 | + var content: string | ||
136 | + try: | ||
137 | + content = readFile(filename) | ||
138 | + except: | ||
139 | + quit("Failed opening file: " & filename, 1) | ||
140 | + let hash = getMD5(content) | ||
141 | + result = filename & "-" & hash | ||
142 | + | ||
101 | # Copy original file to blimpStore and replace with hash stub in git. | 143 | # Copy original file to blimpStore and replace with hash stub in git. |
102 | proc deflate(filename: string) = | 144 | proc deflate(filename: string) = |
103 | - var content: string | ||
104 | - try: | ||
105 | - content = readFile(filename) | ||
106 | - except: | ||
107 | - quit("Failed opening file: " & filename, 1) | ||
108 | - if content[0..4] == "hash:": | ||
109 | - quit("File is already deflated, ignored.", 5) | ||
110 | - let hash = getMD5(content) | ||
111 | - let blimpFilename = filename & "-" & hash | 145 | + let blimpFilename = computeBlimpFilename(filename) |
112 | copyToBlimpStore(filename, blimpFilename) | 146 | copyToBlimpStore(filename, blimpFilename) |
113 | writeFile(filename, "hash:" & blimpFilename) | 147 | writeFile(filename, "hash:" & blimpFilename) |
114 | echo("\t" & filename & " deflated.") | 148 | echo("\t" & filename & " deflated.") |
149 | + | ||
150 | +proc isInBlimpStore(filename: string): bool = | ||
151 | + let blimpFilename = blimpFilename(filename) | ||
152 | + if not blimpFilename.isNil: | ||
153 | + return true | ||
115 | 154 | ||
116 | # Parse out hash from hash stub and copy back original content from blimpStore. | 155 | # Parse out hash from hash stub and copy back original content from blimpStore. |
117 | proc inflate(filename: string) = | 156 | proc inflate(filename: string) = |
118 | - var hashfile: File | ||
119 | - if not open(hashfile, filename): | ||
120 | - quit("Failed opening file: " & filename, 4) | ||
121 | - let hashline = split(string(readLine(hashfile)), {':'}) | ||
122 | - if hashline[0] == "hash": | ||
123 | - let blimpfilename = hashline[1] | ||
124 | - #removeFile(filename) | ||
125 | - copyFromblimpStore(blimpfilename, filename) | 157 | + let blimpFilename = blimpFilename(filename) |
158 | + if blimpFilename.isNil: | ||
159 | + echo("\t" & filename & " is not deflated, skipping.", 5) | ||
160 | + else: | ||
161 | + copyFromBlimpStore(blimpfilename, filename) | ||
162 | + echo("\t" & filename & " inflated.") | ||
163 | + | ||
164 | +# Inflates file first (if deflated) and then removes current content for it, | ||
165 | +# both locally and in remote. | ||
166 | +proc remove(filename: string) = | ||
167 | + var blimpFilename = blimpFilename(filename) | ||
168 | + if not blimpFilename.isNil: | ||
169 | + copyFromBlimpStore(blimpfilename, filename) | ||
126 | else: | 170 | else: |
127 | - quit("\t" & filename & " is not deflated.", 5) | ||
128 | - echo("\t" & filename & " inflated.") | 171 | + blimpFilename = computeBlimpFilename(filename) |
172 | + deleteFromBlimpStore(blimpfilename, filename) | ||
173 | + echo("\t" & filename & " content removed from blimpstore locally and remotely.") | ||
129 | 174 | ||
130 | # Find git root dir or fall back on current dir | 175 | # Find git root dir or fall back on current dir |
131 | proc gitRoot(): string = | 176 | proc gitRoot(): string = |
@@ -141,8 +186,26 @@ proc gitRoot(): string = | @@ -141,8 +186,26 @@ proc gitRoot(): string = | ||
141 | let help = """ | 186 | let help = """ |
142 | blimp [options] <command> <filenames...> | 187 | blimp [options] <command> <filenames...> |
143 | -v,--verbose Verbosity | 188 | -v,--verbose Verbosity |
144 | - <command> (string) (i)nflate or (d)eflate | 189 | + <command> (string) (d)eflate, (i)nflate, delete, (c)heck, (r)ecover |
145 | <filenames> (string...) One or more filepaths to inflate/deflate | 190 | <filenames> (string...) One or more filepaths to inflate/deflate |
191 | + | ||
192 | + Edit ~/blimpstore/.blimp.conf or <gitroot>/.blimp.conf and set a proper | ||
193 | + remote and also create ~/blimp.pass with the proper rsync password to use. | ||
194 | + | ||
195 | + Deflate is run before you add the big file to the index for committing. | ||
196 | + Deflate will replace the file contents with a hash, and copy the | ||
197 | + real content to ~/blimpstore, and if configured also upload it to | ||
198 | + remote, using rsync. | ||
199 | + | ||
200 | + Inflate will bring back the original content by copying from | ||
201 | + ~/blimpstore, and if its not there, first downloading from the remote. | ||
202 | + Use this whenever you need to work/edit the big file - in order to get | ||
203 | + its real content. | ||
204 | + | ||
205 | + Remove (no single character shortcut) will remove the file(s) content | ||
206 | + both from the local ~/blimpstore and from the remote. This only removes | ||
207 | + the current content version, not older versions. The file itself is first | ||
208 | + inflated, if needed, and not deleted. This only "unblimps" the file. | ||
146 | """ | 209 | """ |
147 | 210 | ||
148 | ################################ main ##################################### | 211 | ################################ main ##################################### |
@@ -161,8 +224,10 @@ except: | @@ -161,8 +224,10 @@ except: | ||
161 | 224 | ||
162 | 225 | ||
163 | # Parse configuration files if they exist | 226 | # Parse configuration files if they exist |
164 | -parseConfFile(gitRoot() / ".blimp.conf") | 227 | +# The one in gitroot overrides settings from the store. |
165 | parseConfFile(blimpStore / ".blimp.conf") | 228 | parseConfFile(blimpStore / ".blimp.conf") |
229 | +parseConfFile(gitRoot() / ".blimp.conf") | ||
230 | + | ||
166 | 231 | ||
167 | # Using lapp to get args | 232 | # Using lapp to get args |
168 | let args = parse(help) | 233 | let args = parse(help) |
@@ -177,6 +242,9 @@ if command == "d" or command == "deflate": | @@ -177,6 +242,9 @@ if command == "d" or command == "deflate": | ||
177 | elif command == "i" or command == "inflate": | 242 | elif command == "i" or command == "inflate": |
178 | for fn in filenames: | 243 | for fn in filenames: |
179 | inflate(fn.asString) | 244 | inflate(fn.asString) |
245 | +elif command == "remove": | ||
246 | + for fn in filenames: | ||
247 | + remove(fn.asString) | ||
180 | else: | 248 | else: |
181 | quit("Unknown command, only (d)eflate or (i)inflate are valid.", 6) | 249 | quit("Unknown command, only (d)eflate or (i)inflate are valid.", 6) |
182 | 250 |
blimp.nimble
1 | [Package] | 1 | [Package] |
2 | name = "blimp" | 2 | name = "blimp" |
3 | -version = "0.1" | 3 | +version = "0.2" |
4 | author = "Göran Krampe" | 4 | author = "Göran Krampe" |
5 | description = "Utility that helps with big files in git, very similar to git-fat, s3annnex etc." | 5 | description = "Utility that helps with big files in git, very similar to git-fat, s3annnex etc." |
6 | license = "MIT" | 6 | license = "MIT" |