Skip to content

Instantly share code, notes, and snippets.

@prologic
Last active August 29, 2015 14:21
Show Gist options
  • Save prologic/aa6e46a096e8a0c835d5 to your computer and use it in GitHub Desktop.
Save prologic/aa6e46a096e8a0c835d5 to your computer and use it in GitHub Desktop.
A very simple naive VCS in ~130 lines of Python
#!/usr/bin/env python
"""Simple VCS"""
from hashlib import sha256
from json import dumps, loads
from argparse import ArgumentParser
def sha256sum(filename, bufsize=(1024 * 1024)):
checksum = sha256()
with open(filename, "r") as f:
checksum.update(f.read(bufsize))
return checksum.hexdigest()
class DB(object):
def __init__(self):
try:
self.data = loads(open(".db", "r").read())
except IOError:
self.data = {}
def __contains__(self, filename):
return filename in self.data
def add(self, filename):
self.data[filename] = [sha256sum(filename)]
def remove(self, filename):
del self.data[filename]
def update(self, filename):
self.data[filename].append(sha256sum(filename))
def status(self):
for filename, hashes in self.data.iteritems():
if sha256sum(filename) != hashes[-1]:
yield "M", filename
def commit(self):
for status, filename in self.status():
self.update(filename)
def save(self):
with open(".db", "w") as f:
f.write(dumps(self.data))
def add(db, args):
if args.file in db:
print("File {} already added!".format(args.file))
return -1
db.add(args.file)
def status(db, args):
for status, filename in db.status():
print("{0:<4} {1:s}".format(status, filename))
return 0
def commit(db, args):
db.commit()
return 0
def parse_args():
parser = ArgumentParser(description=__doc__)
parser.add_argument(
"-q", "--quiet", dest="quiet",
action="store_true", default=False,
help="Enable quiet mode",
)
subparsers = parser.add_subparsers(
title="Commands",
description="Available Commands",
help="Description"
)
# add
add_parser = subparsers.add_parser(
"add",
help="Add a file"
)
add_parser.set_defaults(func=add)
add_parser.add_argument(
"file", metavar="FILE", type=str,
help="File to add"
)
# status
status_parser = subparsers.add_parser(
"status",
help="Display status"
)
status_parser.set_defaults(func=status)
# commit
commit_parser = subparsers.add_parser(
"commit",
help="Commit changes"
)
commit_parser.set_defaults(func=commit)
return parser.parse_args()
def main():
args = parse_args()
db = DB()
try:
raise SystemExit(args.func(db, args))
finally:
db.save()
if __name__ == "__main__":
main()
@prologic
Copy link
Author

Demo:

$ ./simplevcs.py status
$ echo "foo" > foo.txt
$ ./simplevcs.py add foo.txt
$ ./simplevcs.py status
$ echo "bar" >> foo.txt
$ ./simplevcs.py status
M    foo.txt
$ ./simplevcs.py commit
$ ./simplevcs.py status

cat .db:

{"foo.txt": ["b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c", "d78931fcf2660108eec0d6674ecb4e02401b5256a6b5ee82527766ef6d198c67"]}

@prologic
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment