Morpheus / Mbed OS mbed-Client-Morpheus-hg

Dependencies:   mbed-os

Revision:
36:5f4546dde73b
Parent:
35:ffcfa5ace437
Child:
37:bf73ffd98cca
--- a/neo.py	Wed Mar 30 10:51:38 2016 -0500
+++ b/neo.py	Wed Mar 30 12:58:34 2016 -0500
@@ -67,28 +67,6 @@
     finally:
         os.chdir(prevdir)
 
-def iterlibs(dir=None):
-    for root, dirs, files in os.walk(dir or os.getcwd()):
-        if os.path.basename(root).startswith('.'):
-            del dirs[:]
-            continue
-
-        for file in files:
-            if file.startswith('.'):
-                continue
-            elif file.endswith('.lib'):
-                with open(os.path.join(root, file)) as f:
-                    yield f.read().strip(), os.path.join(root, file[:-4])
-                if file[:-4] in dirs:
-                    dirs.remove(file[:-4])
-
-def savelib(repo):
-    print repo.name, '->', repo.url
-
-    with open(repo.lib, 'w') as f:
-        f.write(repo.url + '\n')
-
-
 # Handling for multiple version controls
 scms = OrderedDict()
 def scm(name):
@@ -99,7 +77,7 @@
 
 def staticclass(cls):
     for k, v in cls.__dict__.items():
-        if not k.startswith('__'):
+        if hasattr(v, '__call__') and not k.startswith('__'):
             setattr(cls, k, staticmethod(v))
 
     return cls
@@ -125,7 +103,7 @@
         popen(['hg', 'update'] + (['-r', hash] if hash else []))
 
     def hash(): return pquery(['hg', 'id', '-i']).strip().strip('+')
-    def modified(): return pquery(['hg', 'status', '-q'])
+    def dirty(): return pquery(['hg', 'status', '-q'])
 
 @scm('git')
 @staticclass
@@ -140,27 +118,37 @@
     def commit(): popen(['git', 'commit', '-a'])
 
     def hash(): return pquery(['git', 'rev-parse', '--short', 'HEAD']).strip()
-    def modified(): return pquery(['git', 'diff', '--name-only', 'HEAD'])
+    def dirty(): return pquery(['git', 'diff', '--name-only', 'HEAD'])
     
 
 # Repository object
 class Repo(object):
-    def __init__(self, path=None):
-        self.path = path or os.getcwd()
-        self.name = os.path.basename(self.path)
-        self.update()
+    @classmethod
+    def fromurl(cls, url, path=None):
+        repo = cls()
+
+        m = re.match('^(.*/([+a-zA-Z0-9_-]+)/?)(?:#(.*))?$', url.strip())
+        repo.name = os.path.basename(path or m.group(2))
+        repo.path = os.path.abspath(
+            path or os.path.join(os.getcwd(), repo.name))
+
+        repo.repo = m.group(1)
+        repo.hash = m.group(3)
+        return repo
 
     @classmethod
-    def fromurl(cls, url, name=None):
-        repo = cls.__new__(cls)
-        url = url.strip()
+    def fromlib(cls, lib=None):
+        assert lib.endswith('.lib')
+        with open(lib) as f:
+            return cls.fromurl(f.read(), lib[:-4])
 
-        m = re.match('^(.*/([+a-zA-Z0-9_-]+)/?)(?:#(.*))?$', url)
-        repo.repo = m.group(1)
-        repo.name = name or m.group(2)
-        repo.hash = m.group(3)
+    @classmethod
+    def fromrepo(cls, path=None):
+        repo = cls()
+        repo.path = os.path.abspath(path or os.getcwd())
+        repo.name = os.path.basename(repo.path)
 
-        repo.path = os.path.join(os.getcwd(), repo.name)
+        repo.synch()
         return repo
 
     @property
@@ -170,39 +158,47 @@
     @property
     def url(self):
         if self.repo:
-            if self.hash:
-                return self.repo + '#' + self.hash
-            else:
-                return self.repo
+            return self.repo + ('#'+self.hash if self.hash else '')
 
-    def update(self):
+    def synch(self):
         if os.path.isdir(self.path):
-            self.type = self.gettype()
             self.scm  = self.getscm()
             self.hash = self.gethash()
-
-        if os.path.isfile(self.lib):
-            with open(self.lib) as f:
-                temp = Repo.fromurl(f.read())
-                self.repo = temp.repo
-
-    def gettype(self):
-        for type, dir in [('hg', '.hg'), ('git', '.git')]:
-            if os.path.isdir(os.path.join(self.path, dir)):
-                return type
+            self.libs = list(self.getlibs())
 
     def getscm(self):
-        return scms[self.type]
+        for name, scm in scms.items():
+            if os.path.isdir(os.path.join(self.path, '.'+name)):
+                return scm
 
     def gethash(self):
         with cd(self.path):
             return self.scm.hash()
 
+    def getlibs(self):
+        for root, dirs, files in os.walk(self.path):
+            dirs[:]  = [d for d in dirs  if not d.startswith('.')]
+            files[:] = [f for f in files if not f.startswith('.')]
+
+            for file in files:
+                if file.endswith('.lib'):
+                    yield Repo.fromlib(os.path.join(root, file))
+
+    def write(self):
+        print repo.name, '->', repo.url
+
+        with open(repo.lib) as f:
+            if f.read().strip() == repo.url.strip():
+                return
+
+        with open(repo.lib, 'w') as f:
+            f.write(repo.url + '\n')
+
 # Clone command
 @subcommand('import', 'url', 'name?',
     help='recursively import a repository')
-def import_(url, name=None):
-    repo = Repo.fromurl(url, name)
+def import_(url, path=None):
+    repo = Repo.fromurl(url, path)
 
     for scm in scms.values():
         try:
@@ -211,11 +207,11 @@
         except ProcessException:
             pass
 
-    repo.update()
+    repo.synch()
 
     with cd(repo.path):
-        for url, lib in iterlibs():
-            import_(url, lib)
+        for lib in repo.libs:
+            import_(lib.url, lib.path)
 
         if (not os.path.isfile('mbed_settings.py') and 
             os.path.isfile('mbed-os/tools/settings.py')):
@@ -225,56 +221,52 @@
 @subcommand('deploy',
     help='recursively import libraries in current directory')
 def deploy():
-    for url, lib in iterlibs():
-        import_(url, lib)
+    repo = Repo.fromrepo()
+    for lib in repo.libs:
+        import_(lib.url, lib.path)
 
 # Install/uninstall command
 @subcommand('add', 'url', 'name?',
     help='add a library to the current repository')
-def add(url, name):
-    cwd = Repo()
-    repo = Repo.fromurl(url, name)
+def add(url, path=None):
+    repo = Repo.fromrepo()
 
-    import_(url)
-
-    repo.update()
-    savelib(repo)
+    lib = Repo.fromurl(url, path)
+    import_(lib.url, lib.path)
+    lib.synch()
 
-    repo.scm.add(repo.lib)
+    lib.write()
+    repo.scm.add(lib.lib)
 
-@subcommand('remove', 'library',
+@subcommand('remove', 'path',
     help='remove a library from the current repository folder')
-def remove(library):
-    cwd = Repo()
-    repo = Repo(library)
+def remove(path):
+    repo = Repo.fromrepo()
+    lib = Repo.fromrepo(path)
 
-    cwd.scm.remove(repo.lib)
-    shutil.rmtree(repo.path)
+    repo.scm.remove(lib.lib)
+    shutil.rmtree(lib.path)
 
 # Publish command
 @subcommand('publish',
     help='recursively publish changes to remote repositories')
 def publish(always=True):
-    cwd = Repo()
+    repo = Repo.fromrepo()
+    for lib in repo.libs:
+        with cd(lib.path):
+            publish(False)
+    synch()
 
-    for url, lib in iterlibs():
-        if os.path.isdir(lib):
-            with cd(lib):
-                publish(False)
-
-    synch()
-    modified = cwd.scm.modified()
+    dirty = repo.scm.dirty()
 
-    if modified:
-        print cwd.path
-        print 'Uncommitted changes in %s' % cwd.name
+    if dirty:
+        print 'Uncommitted changes in %s (%s)' % (repo.name, repo.path)
         raw_input('Press enter to commit and push ')
+        repo.scm.commit()
 
-        cwd.scm.commit()
-
-    if modified or always:
+    if dirty or always:
         try:
-            cwd.scm.push()
+            repo.scm.push()
         except ProcessException as e:
             sys.exit(e[0])
 
@@ -282,36 +274,42 @@
 @subcommand('update', 'ref?',
     help='recursively updates libraries and current repository')
 def update(ref=None):
-    cwd = Repo()
-    cwd.scm.pull(ref)
+    repo = Repo.fromrepo()
+    repo.scm.pull(ref)
+
+    for lib in repo.libs:
+        if not os.path.isfile(lib.lib):
+            with cd(lib.path):
+                if lib.cwd.dirty():
+                    sys.stderr.write('Uncommitted changes in %s (%s)'
+                        % (lib.name, lib.path))
+                    sys.exit(1)
 
-    for url, lib in iterlibs():
-        repo = Repo.fromurl(url, lib)
-        if os.path.isdir(lib):
-            with cd(repo.path):
-                update(repo.hash)
+            shutil.rmtree(lib.path)
+
+    repo.synch()
+
+    for lib in repo.libs:
+        if os.path.isdir(lib.path):
+            with cd(lib.path):
+                update(lib.hash)
         else:
-            import_(url, lib)
+            import_(lib.url, lib.path)
 
 # Synch command
 @subcommand('synch',
     help='synchronize lib files')
 def synch():
-    cwd = Repo()
-
-    for url, lib in iterlibs():
-        repo = Repo.fromurl(url, lib)
-        repo.update()
-        if url == repo.url:
-            continue
-
-        savelib(repo)
+    repo = Repo.fromrepo()
+    for lib in repo.libs:
+        lib.synch()
+        lib.save()
 
 # Compile command
 @subcommand('compile', 'args*',
     help='compile project using workspace_tools')
 def compile(args):
-    cwd = Repo()
+    repo = Repo.fromrepo()
 
     if not os.path.isdir('mbed-os'):
         sys.stderr.write('Warning! mbed-os not found?')
@@ -326,8 +324,8 @@
     env['PYTHONPATH'] = '.'
     popen(['python', 'mbed-os/tools/make.py']
         + list(chain.from_iterable(izip(repeat('-D'), macros)))
-        + ['--source=%s' % cwd.path,
-           '--build=%s' % os.path.join(cwd.path, '.build')]
+        + ['--source=%s' % repo.path,
+           '--build=%s' % os.path.join(repo.path, '.build')]
         + args,
         env=env)
 
@@ -335,7 +333,7 @@
 @subcommand('export', 'args*',
     help='generate project files')
 def export(args):
-    cwd = Repo()
+    repo = Repo.fromrepo()
 
     if not os.path.isdir('mbed-os'):
         sys.stderr.write('Warning! mbed-os not found?')
@@ -344,7 +342,7 @@
     env = os.environ.copy()
     env['PYTHONPATH'] = '.'
     popen(['python', 'mbed-os/tools/project.py',
-           '--source=%s' % cwd.path]
+           '--source=%s' % repo.path]
         + args,
         env=env)