Blame view

blimp.nim 5.15 KB
db95b901   Göran Krampe   Various fixes, mo...
1
  import md5, os, osproc, parseopt2, strutils, parsecfg, streams, lapp
74272cdb   Göran Krampe   First commit
2
  
5fc367ad   Göran Krampe   Renamed to blimp,...
3
  # blimp is a little utility program for handling large files
74272cdb   Göran Krampe   First commit
4
  # in git repositories. Its inspired by git-fat and s3annex
5fc367ad   Göran Krampe   Renamed to blimp,...
5
6
  # but doesn't rely on S3 for storage, is a single binary without
  # need for Python, and has less features than git-fat. So far.
74272cdb   Göran Krampe   First commit
7
  #
5fc367ad   Göran Krampe   Renamed to blimp,...
8
9
10
11
  # Manual use:
  #
  # Use "blimp d mybigfile" to deflate it before commit.
  # Use "blimp i mybigfile" to inflate it back to original size.
74272cdb   Göran Krampe   First commit
12
13
14
15
  #
  # When deflated the file only has an md5sum string inside it.
  #
  # The file is copied over into:
5fc367ad   Göran Krampe   Renamed to blimp,...
16
17
18
19
20
  #  <homedir>/blimpStore/<originalfilename>-<md5sum>
  #
  # Configuration is in:
  #   <gitroot>/.blimp.conf
  #   ~/blimpstore/.blimp.conf
74272cdb   Göran Krampe   First commit
21
  
db95b901   Göran Krampe   Various fixes, mo...
22
23
  var blimpStore, remoteBlimpStore: string = nil
  var verbose: bool
74272cdb   Göran Krampe   First commit
24
25
  
  
5fc367ad   Göran Krampe   Renamed to blimp,...
26
  # Load blimp.conf file, overkill for now but...
74272cdb   Göran Krampe   First commit
27
  proc parseConfFile(filename: string) =
74272cdb   Göran Krampe   First commit
28
29
30
31
32
33
34
35
36
37
38
39
40
    var f = newFileStream(filename, fmRead)
    if f != nil:
      var p: CfgParser
      open(p, f, filename)
      while true:
        var e = next(p)
        case e.kind
        of cfgEof: 
          break
        of cfgSectionStart:
          continue # Ignore
        of cfgKeyValuePair:
          if e.key == "remote":
5fc367ad   Göran Krampe   Renamed to blimp,...
41
            remoteBlimpStore = e.value
74272cdb   Göran Krampe   First commit
42
43
44
45
46
47
48
49
          else:
            quit("Unknown configuration: " & e.key)
        of cfgOption:
          quit("Unknown configuration: " & e.key)
        of cfgError:
          quit("Parsing " & filename & ": " & e.msg)
      close(p)
  
db95b901   Göran Krampe   Various fixes, mo...
50
51
52
53
  # Trivial helper to enable verbose
  proc run(cmd: string): auto =
    if verbose: echo(cmd)
    execCmd(cmd)
74272cdb   Göran Krampe   First commit
54
  
5fc367ad   Göran Krampe   Renamed to blimp,...
55
56
57
58
  # Upload a file to the remote master blimpStore
  proc uploadFile(blimpFilename: string) =
    if remoteBlimpStore.isNil:
      echo("Remote blimpstore not set in configuration file, not uploading content:\n\t" & blimpFilename)
74272cdb   Göran Krampe   First commit
59
      return
db95b901   Göran Krampe   Various fixes, mo...
60
    let errorCode = run("rsync -a " & blimpStore / blimpFilename & " " & remoteBlimpStore)
5fc367ad   Göran Krampe   Renamed to blimp,...
61
    if errorCode != 0: quit("Something went wrong uploading content to " & remoteBlimpStore, 2)
74272cdb   Göran Krampe   First commit
62
    
5fc367ad   Göran Krampe   Renamed to blimp,...
63
64
65
66
  # Download a file to the remote master blimpStore
  proc downloadFile(blimpFilename: string) =
    if remoteBlimpStore.isNil:
      quit("Remote blimpstore not set in configuration file, can not download content:\n\t" & blimpFilename)
db95b901   Göran Krampe   Various fixes, mo...
67
    let errorCode = run("rsync -a " & remoteBlimpStore / blimpFilename & " " & blimpStore / "")
5fc367ad   Göran Krampe   Renamed to blimp,...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
    if errorCode != 0: quit("Something went wrong downloading " & blimpFilename & " from " & remoteBlimpStore, 3)
  
  
  # Copy content to blimpStore, no upload yet.
  proc copyToBlimpStore(filename, blimpFilename: string) =
    if not existsFile(blimpStore / blimpFilename):
      copyFile(filename, blimpStore / blimpFilename)
      uploadFile(blimpFilename)
  
  # Copy content from blimpStore, and downloading first if needed
  proc copyFromblimpStore(blimpFilename, filename: string) =
    if not existsFile(blimpStore / blimpFilename):
      downloadFile(blimpFilename)
    copyFile(blimpStore / blimpFilename, filename)
74272cdb   Göran Krampe   First commit
82
83
  
      
5fc367ad   Göran Krampe   Renamed to blimp,...
84
  # Copy original file to blimpStore and replace with hash stub in git.
74272cdb   Göran Krampe   First commit
85
  proc deflate(filename: string) =
db95b901   Göran Krampe   Various fixes, mo...
86
87
88
89
90
    var content: string
    try:
      content = readFile(filename)
    except:
      quit("Failed opening file: " & filename, 1)
74272cdb   Göran Krampe   First commit
91
92
93
    if content[0..4] == "hash:":
      quit("File is already deflated, ignored.", 5)
    let hash = getMD5(content)
5fc367ad   Göran Krampe   Renamed to blimp,...
94
95
96
    let blimpFilename = filename & "-" & hash
    copyToBlimpStore(filename, blimpFilename)
    writeFile(filename, "hash:" & blimpFilename)
db95b901   Göran Krampe   Various fixes, mo...
97
98
    echo("\t" & filename & " deflated.")
    
5fc367ad   Göran Krampe   Renamed to blimp,...
99
  # Parse out hash from hash stub and copy back original content from blimpStore.
74272cdb   Göran Krampe   First commit
100
101
102
  proc inflate(filename: string) =
    var hashfile: File
    if not open(hashfile, filename):
db95b901   Göran Krampe   Various fixes, mo...
103
      quit("Failed opening file: " & filename, 4)
74272cdb   Göran Krampe   First commit
104
105
    let hashline = split(string(readLine(hashfile)), {':'})
    if hashline[0] == "hash":
5fc367ad   Göran Krampe   Renamed to blimp,...
106
      let blimpfilename = hashline[1]
74272cdb   Göran Krampe   First commit
107
      #removeFile(filename)
5fc367ad   Göran Krampe   Renamed to blimp,...
108
      copyFromblimpStore(blimpfilename, filename)
74272cdb   Göran Krampe   First commit
109
    else:
db95b901   Göran Krampe   Various fixes, mo...
110
111
      quit("\t" & filename & " is not deflated.", 5)
    echo("\t" & filename & " inflated.")
5fc367ad   Göran Krampe   Renamed to blimp,...
112
113
114
115
116
117
118
119
120
121
122
  
  # Find git root dir or fall back on current dir
  proc gitRoot(): string =
    try:
      let tup = execCmdEx("git rev-parse --show-toplevel")
      if tup[1] == 0:
        result = tup[0]
      else:
        result = getCurrentDir()
    except:
      result = getCurrentDir()
74272cdb   Göran Krampe   First commit
123
  
db95b901   Göran Krampe   Various fixes, mo...
124
125
126
127
128
129
130
  let help = """
    blimp [options] <command> <filenames...>
      -v,--verbose             Verbosity
      <command>   (string)     (i)nflate or (d)eflate
      <filenames> (string...)  One or more filepaths to inflate/deflate
    """
  
74272cdb   Göran Krampe   First commit
131
132
  ################################ main #####################################
  
5fc367ad   Göran Krampe   Renamed to blimp,...
133
134
  # Hardwired to "blimpstore" directory in home dir.
  blimpStore = getHomeDir() / "blimpstore"
74272cdb   Göran Krampe   First commit
135
136
137
  
  # Make sure we have the dir, or create it.
  try:
5fc367ad   Göran Krampe   Renamed to blimp,...
138
    if not existsDir(blimpStore): createDir(blimpStore)
74272cdb   Göran Krampe   First commit
139
  except:
5fc367ad   Göran Krampe   Renamed to blimp,...
140
    quit("Could not create " & blimpStore & " directory.", 1)
74272cdb   Göran Krampe   First commit
141
142
  
  
5fc367ad   Göran Krampe   Renamed to blimp,...
143
144
145
  # Parse configuration files if they exist
  parseConfFile(gitRoot() / ".blimp.conf")
  parseConfFile(blimpStore / ".blimp.conf")
74272cdb   Göran Krampe   First commit
146
  
db95b901   Göran Krampe   Various fixes, mo...
147
148
149
150
151
  # Using lapp to get args
  let args = parse(help)
  let command = args["command"].asString
  let filenames = args["filenames"].asSeq
  verbose = args["verbose"].asBool
74272cdb   Göran Krampe   First commit
152
153
154
  
  # Do the deed
  if command == "d" or command == "deflate":
db95b901   Göran Krampe   Various fixes, mo...
155
156
    for fn in filenames:
      deflate(fn.asString)
74272cdb   Göran Krampe   First commit
157
  elif command == "i" or command == "inflate":
db95b901   Göran Krampe   Various fixes, mo...
158
159
    for fn in filenames:
      inflate(fn.asString)
74272cdb   Göran Krampe   First commit
160
161
162
163
164
  else:
    quit("Unknown command, only (d)eflate or (i)inflate are valid.", 6)
  
  # All good
  quit(0)