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 | 20 | # ~/blimpstore/.blimp.conf |
21 | 21 | |
22 | 22 | var |
23 | - blimpStore, uploadCommandFormat, downloadCommandFormat: string | |
23 | + blimpStore, uploadCommandFormat, downloadCommandFormat, deleteCommandFormat: string | |
24 | 24 | remoteBlimpStore: string = nil |
25 | 25 | verbose: bool |
26 | 26 | |
27 | 27 | let |
28 | 28 | defaultConfig = """ |
29 | 29 | [rsync] |
30 | +# Set this to your remote rsync daemon area | |
30 | 31 | remote = "blimp@some-rsync-server.com::blimpstore" |
32 | + | |
33 | +# The following three formats should not need editing | |
31 | 34 | # $1 is filename, $2 is remote and $3 is the local blimpstore |
32 | 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 | 41 | # Load blimp.conf file, overkill for now but... |
... | ... | @@ -54,6 +59,8 @@ proc parseConfFile(filename: string) = |
54 | 59 | uploadCommandFormat = e.value |
55 | 60 | of "download": |
56 | 61 | downloadCommandFormat = e.value |
62 | + of "delete": | |
63 | + deleteCommandFormat = e.value | |
57 | 64 | else: |
58 | 65 | quit("Unknown configuration: " & e.key) |
59 | 66 | of cfgOption: |
... | ... | @@ -70,7 +77,7 @@ proc run(cmd: string): auto = |
70 | 77 | # Upload a file to the remote master blimpStore |
71 | 78 | proc uploadFile(blimpFilename: string) = |
72 | 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 | 81 | return |
75 | 82 | let errorCode = run(format(uploadCommandFormat, blimpFilename, remoteBlimpStore, blimpStore)) |
76 | 83 | if errorCode != 0: |
... | ... | @@ -84,6 +91,13 @@ proc downloadFile(blimpFilename: string) = |
84 | 91 | if errorCode != 0: |
85 | 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 | 102 | # Copy content to blimpStore, no upload yet. |
89 | 103 | proc copyToBlimpStore(filename, blimpFilename: string) = |
... | ... | @@ -92,40 +106,71 @@ proc copyToBlimpStore(filename, blimpFilename: string) = |
92 | 106 | uploadFile(blimpFilename) |
93 | 107 | |
94 | 108 | # Copy content from blimpStore, and downloading first if needed |
95 | -proc copyFromblimpStore(blimpFilename, filename: string) = | |
109 | +proc copyFromBlimpStore(blimpFilename, filename: string) = | |
96 | 110 | if not existsFile(blimpStore / blimpFilename): |
97 | 111 | downloadFile(blimpFilename) |
98 | 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 | 143 | # Copy original file to blimpStore and replace with hash stub in git. |
102 | 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 | 146 | copyToBlimpStore(filename, blimpFilename) |
113 | 147 | writeFile(filename, "hash:" & blimpFilename) |
114 | 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 | 155 | # Parse out hash from hash stub and copy back original content from blimpStore. |
117 | 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 | 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 | 175 | # Find git root dir or fall back on current dir |
131 | 176 | proc gitRoot(): string = |
... | ... | @@ -141,8 +186,26 @@ proc gitRoot(): string = |
141 | 186 | let help = """ |
142 | 187 | blimp [options] <command> <filenames...> |
143 | 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 | 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 | 211 | ################################ main ##################################### |
... | ... | @@ -161,8 +224,10 @@ except: |
161 | 224 | |
162 | 225 | |
163 | 226 | # Parse configuration files if they exist |
164 | -parseConfFile(gitRoot() / ".blimp.conf") | |
227 | +# The one in gitroot overrides settings from the store. | |
165 | 228 | parseConfFile(blimpStore / ".blimp.conf") |
229 | +parseConfFile(gitRoot() / ".blimp.conf") | |
230 | + | |
166 | 231 | |
167 | 232 | # Using lapp to get args |
168 | 233 | let args = parse(help) |
... | ... | @@ -177,6 +242,9 @@ if command == "d" or command == "deflate": |
177 | 242 | elif command == "i" or command == "inflate": |
178 | 243 | for fn in filenames: |
179 | 244 | inflate(fn.asString) |
245 | +elif command == "remove": | |
246 | + for fn in filenames: | |
247 | + remove(fn.asString) | |
180 | 248 | else: |
181 | 249 | quit("Unknown command, only (d)eflate or (i)inflate are valid.", 6) |
182 | 250 | ... | ... |