1. Wang Dingwei
  2. hgsync


hgsync / HgMon.py

#!/usr/bin/env python

"""HgMon.py -- Monitoring directory change and sync project directories upon

If a file named 'SYNC!' is in the project directory, the script will try to
read into the file, parse out user name and commit message, then commit the
project, then sync (hg push) to other directories of the same project. If any
conflict is found, it will create a branch named by 'date-time-conflictdir',
record the conflicts to the branch, then branch to default and update the
previous pushed content.

If a file named 'LOCKED!' is in the project directory, the script will ignore
the directory, no change will be pushed or synchronized to the project.

Content format of 'SYNC!' is 'User Message String', e.g.,
    Joel Fixed a bug.

The first word in the message is treated as user name, other strings are treated
as commit messages.


import os, re, shutil, filecmp, yaml
import logging, logging.config
from time import sleep
from datetime import datetime
from hgcmd import init, commit, autosync

def make_project_dir(project_dir):
    "Make sure project directory actually exists and create one if it doesn't."
    if os.path.exists(project_dir):
        if not os.path.isdir(project_dir): 
            try: shutil.rmtree(project_dir)
                print "Unable to remove non-project directory %s" % project_dir
                print "Unable to create project directory %s" % project_dir
    else:   # path not exist
        try: os.makedirs(project_dir)
            print "Unable to create project directory %s" % project_dir

def parse_flag(chflag):
    "change flag file -> user, comment"
    with open(chflag, 'r') as fh:
        user, comment = tuple(
            fh.readline().strip().split(' ', 1))
    return user, comment
def hg_modify_config(project_dir):
    "Writes config to do auto update after hg push."
    hgrc_src = 'hgrc.template'
    hgtags_src = 'hgtags.template'
    hgignore_src = 'hgignore.template'
    hgrc_dst = os.path.join(project_dir, '.hg', 'hgrc')
    hgtags_dst = os.path.join(project_dir, '.hg', '.hgtags')
    hgignore_dst = os.path.join(project_dir, '.hgignore')
    configpairs = [(hgrc_src, hgrc_dst),
                   (hgignore_src, hgignore_dst),
                   (hgtags_src, hgtags_dst)]
    for src, dst in configpairs:
        if os.path.exists(src) and not os.path.exists(dst):
            shutil.copy(src, dst)
        elif os.path.exists(src) and os.path.exists(dst):
            if not filecmp.cmp(src, dst):
                shutil.copy(src, dst)
        else: pass

def load_project_config(configfile):
    "config_file -> dir group list"
    with open(configfile) as f:
        y = yaml.load(f)
    grouplist = []
    for entry in y:
        for group in entry.itervalues():
            for k, v in group.iteritems():
                grouplist.append(set(map(lambda x: os.path.join(x, k),
    return grouplist

def main():
    log = logging.getLogger('SyncLog')
    configfile = 'config.yaml'
    fn_syncflag = 'SYNC!'       # Command sync
    fn_lockflag = 'LOCKED!'     # Status locked
    fn_statflag = 'DOING'       # Status synchronizing

    while True:
        grouplist = load_project_config(configfile)
        for group in grouplist:
            for project_dir in group:
                fd_syncflag = os.path.join(project_dir, fn_syncflag)
                fd_hgflag = os.path.join(project_dir, '.hg')
                fd_lockflag = os.path.join(project_dir, fn_lockflag)
                if os.path.exists(fd_lockflag): continue
                if not os.path.exists(fd_hgflag):
                    os.environ['HGUSER'] = 'root'
                    commit(project_dir, "First Commit")
                if os.path.exists(fd_syncflag):
                    user, comment = parse_flag(fd_syncflag)
                    fd_statflag = os.path.join(project_dir, fn_statflag)
                    sf = open(fd_statflag, 'w')
                    log.info("%s changed %s" % (user, project_dir))
                    log.info("Message: '%s'" % comment)
                    os.environ['HGUSER'] = user
                    log.info("Commiting changes for %s" % project_dir)
                    commit(project_dir, comment)
                    syncgroup = group.copy()
                    autosync(project_dir, syncgroup)
                    log.info("Sync completed!")

if __name__ == '__main__':