ae/bin/ae

269 lines
8.3 KiB
Python
Executable File

#!/usr/bin/env python
import abc
import os
import os.path
import re
import sys
import yaml
CACHE_DIR = os.path.join(os.path.abspath(os.path.curdir), '.ae')
ROOT_DIR = os.path.join(CACHE_DIR, 'root')
# We'll need these everywhere basically
os.putenv('SCHEMATIC_INSTALL_PREFIX', ROOT_DIR)
os.putenv('SCHEMATIC_PARALLELISM', '1')
# Put our own ROOT_DIR bits in the path first to make sure `ae run` can execute
# schematic installed binaries
os.environ['PATH'] = os.pathsep.join([os.path.join(ROOT_DIR, 'bin'), os.environ['PATH']])
def read_pipe(name, pipe):
while True:
line = pipe.readline()
if not line:
break
sys.stdout.write("[%s] %s" % (name, line))
sys.stdout.flush()
class SchematicHandler(object):
def __init__(self, schematic):
self.schematic = schematic
self.name = schematic['name']
def bootstrap(self):
if not os.path.isdir(CACHE_DIR):
os.mkdir(CACHE_DIR)
return self
def prepare(self):
print '>> prepare'
steps = self.schematic['prepare'] or []
self.__run_steps__(steps)
return self
def build(self):
print '>> build'
steps = self.schematic['build'] or []
self.__run_steps__(steps)
return self
def install(self):
print '>> install'
steps = self.schematic['install'] or []
self.__run_steps__(steps)
return self
def __run_steps__(self, steps):
for s in steps:
read_pipe(self.name,
os.popen("cd %s && %s" % (self.checkout_dir, s)))
class GitSchematicHandler(SchematicHandler):
def checkout(self):
print '>> checkout'
url = self.schematic['source']['url']
branch = self.schematic['source']['ref'] or 'master'
repos_dir = os.path.join(CACHE_DIR, 'repos')
self.checkout_dir = os.path.join(repos_dir, self.name)
if not os.path.isdir(repos_dir):
os.mkdir(repos_dir)
if not os.path.isdir(self.checkout_dir):
command = "git clone --depth 1 %s %s" % (url, self.checkout_dir)
else:
command = "cd %s && git fetch" % (self.checkout_dir)
read_pipe(self.name, os.popen(command))
read_pipe(self.name, os.popen("cd %s && git checkout origin/%s" % (self.checkout_dir, branch)))
return self
class FileSchematicHandler(SchematicHandler):
def checkout(self):
print '>> checkout'
url = self.schematic['source']['url']
repos_dir = os.path.join(CACHE_DIR, 'repos')
self.checkout_dir = os.path.join(repos_dir, self.name)
versions = self.schematic['source']['versions']
filename = versions[0]['filename']
url = versions[0]['url']
if not os.path.isdir(repos_dir):
os.mkdir(repos_dir)
if not os.path.isdir(self.checkout_dir):
if not os.path.isfile(os.path.join(repos_dir, filename)):
read_pipe(self.name, os.popen('cd %s && curl -s %s > %s' % (repos_dir, url, filename)))
command = 'cd %s && mkdir %s && tar -C %s --strip-components 1 -zxvf %s' % (repos_dir, self.name, self.name, filename)
read_pipe(self.name, os.popen(command))
return self
def traverse_schematic_graph(graph, key=None):
if not key:
install = []
for key in graph.iterkeys():
result = traverse_schematic_graph(graph, key)
if result:
install.append(result)
install.append(key)
return install
if not graph.has_key(key):
return key
for key in graph[key]:
return traverse_schematic_graph(graph, key)
class Catalog(object):
def __init__(self, uri):
self.uri = uri
self.schematics = {}
def has_schematic(self, schematic):
if self.schematics.has_key(schematic):
return self.schematics[schematic]
return None
class FileCatalog(Catalog):
def load(self):
path = re.split('file:\/\/', self.uri)[1]
catalog_dir = os.path.join(path, 'catalog')
if not os.path.isdir(catalog_dir):
return
for root, dirs, files in os.walk(catalog_dir):
for f in files:
if not f.endswith('.yaml'):
continue
publisher = os.path.basename(root)
name = re.sub('\.yaml', '', f)
qualified_name = '/'.join([publisher, name])
self.schematics[qualified_name] = yaml.load(file(os.path.join(root, f)))
def __str__(self):
return "FileCatalog(%s)" % self.uri
class GitCatalog(FileCatalog):
def load(self):
repo_dir = os.path.join(CACHE_DIR, 'repos')
repo = re.match('git:\/\/(.*)\/(.*)\.git', self.uri).group(2)
full_path = os.path.join(repo_dir, repo)
if os.path.isdir(full_path):
read_pipe('git', os.popen('cd %s && git pull --rebase' % full_path))
else:
read_pipe('git',
os.popen('cd %s && git clone --depth 1 %s' % (repo_dir, self.uri)))
self.uri = ''.join(['file://', full_path])
return super(GitCatalog, self).load()
def install():
if not os.path.isfile('schematics.yaml'):
return 1
schematics = yaml.load(file('schematics.yaml'))
catalogs = []
for catalog in schematics['catalogs']:
c = None
if re.match('file:\/\/', catalog):
c = FileCatalog(catalog)
elif re.match('git:\/\/', catalog):
c = GitCatalog(catalog)
c.load()
catalogs.append(c)
graph = {}
todo = {}
dependencies = []
for schematic in schematics['schematics']:
components = schematic.split('@')
version = None
schematic = components[0]
if len(components) == 2:
version = components[1]
for catalog in catalogs:
graph[schematic] = []
s = catalog.has_schematic(schematic)
if not s:
print "!!! Could not find schematic for %s !!!" % schematic
return 1
todo[schematic] = None
if s['source']['scm'] == 'git':
todo[schematic] = GitSchematicHandler(s)
elif s['source']['scm'] == 'file':
todo[schematic] = FileSchematicHandler(s)
depends = s['schematics'] or []
graph[schematic].extend(depends)
dependencies.extend(depends)
for schematic in dependencies:
for catalog in catalogs:
s = catalog.has_schematic(schematic)
if not s:
print "!!! Could not find schematic for %s !!!" % schematic
return 1
todo[schematic] = None
if s['source']['scm'] == 'git':
todo[schematic] = GitSchematicHandler(s)
elif s['source']['scm'] == 'file':
todo[schematic] = FileSchematicHandler(s)
depends = s['schematics'] or []
for d in depends:
if not graph.has_key(d):
graph[d] = []
graph[d].append(schematic)
for schematic in traverse_schematic_graph(graph):
print "Installing schematic %s" % schematic
todo[schematic].bootstrap().checkout().prepare().build().install()
return 0
def run():
if len(sys.argv) < 3:
print "Must specify a command to run"
return -1
env = {}
for e in os.environ:
env[e] = os.environ[e]
project_path = os.path.join(ROOT_DIR, 'lib', 'gnat')
key = 'ADA_PROJECT_PATH'
if os.environ.has_key(key):
env[key] = ':'.join([project_path, os.environ[key]])
else:
env[key] = project_path
key = 'GPR_PROJECT_PATH'
if os.environ.has_key(key):
env[key] = ':'.join([project_path, os.environ[key]])
else:
env[key] = project_path
key = 'ADA_INCLUDE_PATH'
include_path = os.path.join(ROOT_DIR, 'include')
if os.environ.has_key(key):
env[key] = ':'.join([include_path, os.environ[key]])
else:
env[key] = include_path
return os.execvpe(sys.argv[2], sys.argv[2:], env)
def main():
if len(sys.argv) > 1:
if sys.argv[1] == 'install':
sys.exit(install())
if sys.argv[1] == 'run':
sys.exit(run())
else:
print "Welcome to the Analytical Engine"
if __name__ == '__main__':
main()