Blame view

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