Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed-os
neo.py@5:37ac884d9477, 2016-03-29 (annotated)
- Committer:
- Christopher Haster
- Date:
- Tue Mar 29 23:03:50 2016 -0500
- Revision:
- 5:37ac884d9477
- Parent:
- 4:6e987db7a950
- Child:
- 6:622a477ef55c
Added deploy command
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
screamer | 4:6e987db7a950 | 1 | #!/usr/bin/env python |
screamer | 4:6e987db7a950 | 2 | |
screamer | 4:6e987db7a950 | 3 | import argparse |
screamer | 4:6e987db7a950 | 4 | import sys |
screamer | 4:6e987db7a950 | 5 | import re |
screamer | 4:6e987db7a950 | 6 | import subprocess |
screamer | 4:6e987db7a950 | 7 | import os |
screamer | 4:6e987db7a950 | 8 | import contextlib |
screamer | 4:6e987db7a950 | 9 | import collections |
screamer | 4:6e987db7a950 | 10 | |
screamer | 4:6e987db7a950 | 11 | # Subparser handling |
screamer | 4:6e987db7a950 | 12 | parser = argparse.ArgumentParser() |
screamer | 4:6e987db7a950 | 13 | subparsers = parser.add_subparsers() |
screamer | 4:6e987db7a950 | 14 | |
screamer | 4:6e987db7a950 | 15 | def subcommand(name, *args, **kwargs): |
screamer | 4:6e987db7a950 | 16 | def subcommand(command): |
screamer | 4:6e987db7a950 | 17 | subparser = subparsers.add_parser(name, **kwargs) |
screamer | 4:6e987db7a950 | 18 | |
screamer | 4:6e987db7a950 | 19 | for arg in args: |
screamer | 4:6e987db7a950 | 20 | subparser.add_argument(arg) |
screamer | 4:6e987db7a950 | 21 | |
screamer | 4:6e987db7a950 | 22 | def thunk(parsed_args): |
screamer | 4:6e987db7a950 | 23 | ordered_args = [vars(parsed_args)[arg] for arg in args] |
screamer | 4:6e987db7a950 | 24 | return command(*ordered_args) |
screamer | 4:6e987db7a950 | 25 | |
screamer | 4:6e987db7a950 | 26 | subparser.set_defaults(command=thunk) |
screamer | 4:6e987db7a950 | 27 | return command |
screamer | 4:6e987db7a950 | 28 | return subcommand |
screamer | 4:6e987db7a950 | 29 | |
screamer | 4:6e987db7a950 | 30 | # Process execution |
screamer | 4:6e987db7a950 | 31 | class ProcessException(Exception): |
screamer | 4:6e987db7a950 | 32 | pass |
screamer | 4:6e987db7a950 | 33 | |
screamer | 4:6e987db7a950 | 34 | def popen(command, stdin=None): |
screamer | 4:6e987db7a950 | 35 | # print for debugging |
screamer | 4:6e987db7a950 | 36 | print ' '.join(command) |
screamer | 4:6e987db7a950 | 37 | proc = subprocess.Popen(command) |
screamer | 4:6e987db7a950 | 38 | |
screamer | 4:6e987db7a950 | 39 | if proc.wait() != 0: |
screamer | 4:6e987db7a950 | 40 | raise ProcessException(proc.returncode) |
screamer | 4:6e987db7a950 | 41 | |
screamer | 4:6e987db7a950 | 42 | def pquery(command, stdin=None): |
screamer | 4:6e987db7a950 | 43 | proc = subprocess.Popen(command, stdout=subprocess.PIPE) |
screamer | 4:6e987db7a950 | 44 | stdout, _ = proc.communicate(stdin) |
screamer | 4:6e987db7a950 | 45 | |
screamer | 4:6e987db7a950 | 46 | if proc.returncode != 0: |
screamer | 4:6e987db7a950 | 47 | raise ProcessException(proc.returncode) |
screamer | 4:6e987db7a950 | 48 | |
screamer | 4:6e987db7a950 | 49 | return stdout |
screamer | 4:6e987db7a950 | 50 | |
screamer | 4:6e987db7a950 | 51 | # Directory navigation |
screamer | 4:6e987db7a950 | 52 | @contextlib.contextmanager |
screamer | 4:6e987db7a950 | 53 | def cd(newdir): |
screamer | 4:6e987db7a950 | 54 | prevdir = os.getcwd() |
screamer | 4:6e987db7a950 | 55 | os.chdir(newdir) |
screamer | 4:6e987db7a950 | 56 | try: |
screamer | 4:6e987db7a950 | 57 | yield |
screamer | 4:6e987db7a950 | 58 | finally: |
screamer | 4:6e987db7a950 | 59 | os.chdir(prevdir) |
screamer | 4:6e987db7a950 | 60 | |
screamer | 4:6e987db7a950 | 61 | def iterlibs(dir=None): |
screamer | 4:6e987db7a950 | 62 | for file in os.listdir(dir or os.getcwd()): |
screamer | 4:6e987db7a950 | 63 | if file.startswith('.'): |
screamer | 4:6e987db7a950 | 64 | continue |
screamer | 4:6e987db7a950 | 65 | elif os.path.isfile(file) and file.endswith('.lib'): |
screamer | 4:6e987db7a950 | 66 | with open(file) as f: |
screamer | 4:6e987db7a950 | 67 | yield f.read().strip() |
screamer | 4:6e987db7a950 | 68 | |
screamer | 4:6e987db7a950 | 69 | def savelib(repo): |
screamer | 4:6e987db7a950 | 70 | print repo.name, '->', repo.url |
screamer | 4:6e987db7a950 | 71 | |
screamer | 4:6e987db7a950 | 72 | with open(repo.lib, 'w') as f: |
screamer | 4:6e987db7a950 | 73 | f.write(repo.url + '\n') |
screamer | 4:6e987db7a950 | 74 | |
screamer | 4:6e987db7a950 | 75 | |
screamer | 4:6e987db7a950 | 76 | # Handling for multiple version controls |
screamer | 4:6e987db7a950 | 77 | class Repo(object): |
screamer | 4:6e987db7a950 | 78 | def __init__(self, path=None): |
screamer | 4:6e987db7a950 | 79 | self.path = path or os.getcwd() |
screamer | 4:6e987db7a950 | 80 | self.name = os.path.basename(self.path) |
screamer | 4:6e987db7a950 | 81 | self.update() |
screamer | 4:6e987db7a950 | 82 | |
screamer | 4:6e987db7a950 | 83 | @classmethod |
screamer | 4:6e987db7a950 | 84 | def fromurl(cls, url): |
screamer | 4:6e987db7a950 | 85 | repo = cls.__new__(cls) |
screamer | 4:6e987db7a950 | 86 | |
screamer | 4:6e987db7a950 | 87 | m = re.match('^(.*/([+a-zA-Z0-9_-]+)/?)(?:#(.*))?$', url) |
screamer | 4:6e987db7a950 | 88 | repo.repo = m.group(1) |
screamer | 4:6e987db7a950 | 89 | repo.name = m.group(2) |
screamer | 4:6e987db7a950 | 90 | repo.hash = m.group(3) |
screamer | 4:6e987db7a950 | 91 | |
screamer | 4:6e987db7a950 | 92 | repo.path = os.path.join(os.getcwd(), repo.name) |
screamer | 4:6e987db7a950 | 93 | return repo |
screamer | 4:6e987db7a950 | 94 | |
screamer | 4:6e987db7a950 | 95 | @property |
screamer | 4:6e987db7a950 | 96 | def lib(self): |
screamer | 4:6e987db7a950 | 97 | return self.path + '.lib' |
screamer | 3:47aa05d37724 | 98 | |
screamer | 4:6e987db7a950 | 99 | @property |
screamer | 4:6e987db7a950 | 100 | def url(self): |
screamer | 4:6e987db7a950 | 101 | if self.repo: |
screamer | 4:6e987db7a950 | 102 | if self.hash: |
screamer | 4:6e987db7a950 | 103 | return self.repo + '#' + self.hash |
screamer | 4:6e987db7a950 | 104 | else: |
screamer | 4:6e987db7a950 | 105 | return self.repo |
screamer | 4:6e987db7a950 | 106 | |
screamer | 4:6e987db7a950 | 107 | def update(self): |
screamer | 4:6e987db7a950 | 108 | if os.path.isdir(self.path): |
screamer | 4:6e987db7a950 | 109 | self.type = self.gettype() |
screamer | 4:6e987db7a950 | 110 | self.hash = self.gethash() |
screamer | 4:6e987db7a950 | 111 | |
screamer | 4:6e987db7a950 | 112 | if os.path.isfile(self.lib): |
screamer | 4:6e987db7a950 | 113 | with open(self.lib) as f: |
screamer | 4:6e987db7a950 | 114 | temp = Repo.fromurl(f.read()) |
screamer | 4:6e987db7a950 | 115 | self.repo = temp.repo |
screamer | 4:6e987db7a950 | 116 | |
screamer | 4:6e987db7a950 | 117 | def gettype(self): |
screamer | 4:6e987db7a950 | 118 | for type, dir in [('git', '.git'), ('hg', '.hg')]: |
screamer | 4:6e987db7a950 | 119 | if os.path.isdir(os.path.join(self.path, dir)): |
screamer | 4:6e987db7a950 | 120 | return type |
screamer | 4:6e987db7a950 | 121 | |
screamer | 4:6e987db7a950 | 122 | def gethash(self): |
screamer | 4:6e987db7a950 | 123 | with cd(self.path): |
screamer | 4:6e987db7a950 | 124 | if self.type == 'git': |
screamer | 4:6e987db7a950 | 125 | return pquery(['git', 'rev-parse', '--short', 'HEAD']).strip() |
screamer | 4:6e987db7a950 | 126 | elif self.type == 'hg': |
screamer | 4:6e987db7a950 | 127 | return pquery(['hg', 'id', '-i']).strip() |
screamer | 4:6e987db7a950 | 128 | |
screamer | 4:6e987db7a950 | 129 | # Clone command |
screamer | 4:6e987db7a950 | 130 | @subcommand('import', 'url', |
screamer | 4:6e987db7a950 | 131 | help='recursively import a repository') |
screamer | 4:6e987db7a950 | 132 | def import_(url): |
screamer | 4:6e987db7a950 | 133 | repo = Repo.fromurl(url) |
screamer | 4:6e987db7a950 | 134 | |
screamer | 4:6e987db7a950 | 135 | for type in ['git', 'hg']: |
screamer | 4:6e987db7a950 | 136 | try: |
screamer | 4:6e987db7a950 | 137 | popen([type, 'clone', repo.repo]) |
screamer | 4:6e987db7a950 | 138 | break |
screamer | 4:6e987db7a950 | 139 | except: |
screamer | 4:6e987db7a950 | 140 | pass |
screamer | 4:6e987db7a950 | 141 | |
screamer | 4:6e987db7a950 | 142 | repo.type = repo.gettype() |
screamer | 4:6e987db7a950 | 143 | |
screamer | 4:6e987db7a950 | 144 | if repo.hash: |
screamer | 4:6e987db7a950 | 145 | with cd(repo.path): |
screamer | 4:6e987db7a950 | 146 | popen([repo.type, 'checkout', repo.hash]) |
screamer | 4:6e987db7a950 | 147 | |
screamer | 4:6e987db7a950 | 148 | repo.update() |
screamer | 4:6e987db7a950 | 149 | |
screamer | 4:6e987db7a950 | 150 | with cd(repo.path): |
screamer | 4:6e987db7a950 | 151 | for lib in iterlibs(): |
screamer | 4:6e987db7a950 | 152 | import_(lib) |
screamer | 4:6e987db7a950 | 153 | |
Christopher Haster |
5:37ac884d9477 | 154 | # Deploy command |
Christopher Haster |
5:37ac884d9477 | 155 | @subcommand('deploy', |
Christopher Haster |
5:37ac884d9477 | 156 | help='recursively import libraries in current directory') |
Christopher Haster |
5:37ac884d9477 | 157 | def deploy(): |
Christopher Haster |
5:37ac884d9477 | 158 | for lib in iterlibs(): |
Christopher Haster |
5:37ac884d9477 | 159 | import_(lib) |
Christopher Haster |
5:37ac884d9477 | 160 | |
screamer | 4:6e987db7a950 | 161 | # Install/uninstall command |
screamer | 4:6e987db7a950 | 162 | @subcommand('add', 'url', |
screamer | 4:6e987db7a950 | 163 | help='add a library to the current repository') |
screamer | 4:6e987db7a950 | 164 | def add(url): |
screamer | 4:6e987db7a950 | 165 | cwd = Repo() |
screamer | 4:6e987db7a950 | 166 | repo = Repo.fromurl(url) |
screamer | 4:6e987db7a950 | 167 | |
screamer | 4:6e987db7a950 | 168 | import_(url) |
screamer | 4:6e987db7a950 | 169 | |
screamer | 4:6e987db7a950 | 170 | repo.update() |
screamer | 4:6e987db7a950 | 171 | savelib(repo) |
screamer | 4:6e987db7a950 | 172 | |
screamer | 4:6e987db7a950 | 173 | popen([cwd.type, 'add', repo.lib]) |
screamer | 4:6e987db7a950 | 174 | |
screamer | 4:6e987db7a950 | 175 | @subcommand('remove', 'library', |
screamer | 4:6e987db7a950 | 176 | help='remove a library from the current repository folder') |
screamer | 4:6e987db7a950 | 177 | def remove(library): |
screamer | 4:6e987db7a950 | 178 | cwd = Repo() |
screamer | 4:6e987db7a950 | 179 | repo = Repo(library) |
screamer | 4:6e987db7a950 | 180 | |
screamer | 4:6e987db7a950 | 181 | popen([cwd.type, 'rm', '-f', repo.lib]) |
screamer | 4:6e987db7a950 | 182 | if cwd.type == 'hg': |
screamer | 4:6e987db7a950 | 183 | popen(['rm', '-f', repo.lib]) |
screamer | 4:6e987db7a950 | 184 | |
screamer | 4:6e987db7a950 | 185 | popen(['rm', '-rf', repo.path]) |
screamer | 4:6e987db7a950 | 186 | |
screamer | 4:6e987db7a950 | 187 | # Synch command |
screamer | 4:6e987db7a950 | 188 | @subcommand('synch', |
screamer | 4:6e987db7a950 | 189 | help='synchronize lib files') |
screamer | 4:6e987db7a950 | 190 | def synch(): |
screamer | 4:6e987db7a950 | 191 | cwd = Repo() |
screamer | 4:6e987db7a950 | 192 | |
screamer | 4:6e987db7a950 | 193 | for lib in iterlibs(): |
screamer | 4:6e987db7a950 | 194 | repo = Repo.fromurl(lib) |
screamer | 4:6e987db7a950 | 195 | repo.update() |
screamer | 4:6e987db7a950 | 196 | if lib == repo.url: |
screamer | 4:6e987db7a950 | 197 | continue |
screamer | 4:6e987db7a950 | 198 | |
screamer | 4:6e987db7a950 | 199 | savelib(repo) |
screamer | 4:6e987db7a950 | 200 | |
screamer | 4:6e987db7a950 | 201 | if cwd.type == 'git': |
screamer | 4:6e987db7a950 | 202 | popen([cwd.type, 'add', repo.lib]) |
screamer | 4:6e987db7a950 | 203 | |
screamer | 4:6e987db7a950 | 204 | # Parse/run command |
screamer | 4:6e987db7a950 | 205 | args = parser.parse_args() |
screamer | 4:6e987db7a950 | 206 | status = args.command(args) |
screamer | 4:6e987db7a950 | 207 | sys.exit(status or 0) |
screamer | 4:6e987db7a950 | 208 |