Loading .gitignore 0 → 100644 +1 −0 Original line number Diff line number Diff line *.exe Breakfile.py 0 → 100644 +12 −0 Original line number Diff line number Diff line from breakable import * class BreakTasks(object): CC = which("c++") @provides("hello_world.exe") def build_hello_world(self): needs("main.cpp") self.CC("main.cpp -o hello_world.exe") def clean(self): rm("*.exe") breakable.py 0 → 100755 +227 −0 Original line number Diff line number Diff line #!/usr/bin/env python """ Break: For when you're frustrated with Make. Inspired by the elegant process invocation and management features of Spack (https://github.com/LLNL/spack). """ from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals import subprocess import shlex import os import argparse import sys import re import urllib class log(object): red = '1;31' blue = '1;34' yellow = '1;33' gray = '1;30' @classmethod def _print(cls, msg, prefix=None, color=None): if color: msg = "\033[{0}m{1}\033[0m".format(color, msg) if prefix: msg = prefix + msg print(msg) @classmethod def info(cls, msg): cls._print(msg, '# ', cls.yellow) @classmethod def prompt(cls, msg): cls._print(msg, '==> ', cls.blue) class Executable(object): def __init__(self, path, defaults=[]): self.path = path self.defaults = defaults def _generate_command(self, *args): return ' '.join([self.path] + self.defaults + list(args)) def __call__(self, argstring=""): command = self._generate_command(argstring) log.prompt(command) real_command = shlex.split("bash -c \"%s\"" % command) rc = subprocess.call(real_command) if rc != 0: # pragma: no cover sys.exit(rc) def collect(self, argstring): command = self._generate_command(argstring) log.prompt(command) real_command = shlex.split("bash -c \"%s\"" % command) proc = subprocess.Popen( real_command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True, bufsize=1) for line in proc.stdout: yield line rc = proc.wait() if rc != 0: # pragma: no cover sys.exit(rc) def grab(self, argstring): return ''.join(self.collect(argstring)) def which(tool, defaults=[]): paths = ["."] + os.environ['PATH'].split(':') for path in paths: tool_path = os.path.join(path, tool) if os.path.exists(tool_path): return Executable(tool_path, defaults=defaults) rm = which("rm", defaults=["-f"]) touch = which("touch") def find_files(pattern, directory="."): for root, dirs, files in os.walk(directory): for f in files: path = os.path.join(root, f) if re.match(pattern, path): yield path def _get_args(argv): parser = argparse.ArgumentParser() parser.add_argument( "-l", "--list-tasks", help="display available tasks", action="store_true") parser.add_argument( "-c", "--clean", help="Clean up breakstamps", action="store_true") parser.add_argument( "-u", "--update", help="Update breakable.py", action="store_true") parser.add_argument( "-f", "--breakfile", help="path to Breakfile.py", default="Breakfile.py") parser.add_argument( "-t", "--task", help="Entrypoint in Breakfile.py", default=None) return parser.parse_args(argv) def needs(*filenames): for f in filenames: if not os.path.exists(f): raise Exception("%s is needed but not found" % f) def only_if_modified(*filenames): needs(*(filenames + (__file__,))) def wrapper(func): def wrapped(self=None): timestamp_file = path(".breakstamp.%s" % func.__name__) dirty = False for f in filenames: if timestamp_file.dirtier_than(f): dirty = True break if dirty: of_the_jedi = func(self) touch(timestamp_file) return of_the_jedi wrapped.__doc__ = func.__doc__ return wrapped return wrapper def provides(filename): def wrapper(func): def wrapped(self=None): if not path(filename).exists: return func(self) wrapped.__doc__ = func.__doc__ return wrapped return wrapper class BreakPath(str): def newer_than(self, other): if not os.path.exists(self): msg = "Cannot compare %s with %s." % (self, other) msg += " %s does not exist." % (self) raise Exception(msg) if not os.path.exists(other): msg = "Cannot compare %s with %s." % (self, other) msg += " %s does not exist." % (other) raise Exception(msg) return os.path.getmtime(self) > os.path.getmtime(other) def dirtier_than(self, dependency): if not os.path.exists(dependency): msg = "Cannot compare %s with %s." % (self, dependency) msg += " %s does not exist." % (dependency) raise Exception(msg) if not os.path.exists(self): return True return path(dependency).newer_than(self) @property def exists(self): return os.path.exists(self) def path(*filename_parts): return BreakPath(os.path.join(*filename_parts)) def belhorn_property(function): '''Pirated implementation of @mpbelhorn's cached property decorator''' @property def _belhorn_wrapper(self): cached_name = "_cached_%s" % function.__name__ if not hasattr(self, cached_name): setattr(self, cached_name, function(self)) return getattr(self, cached_name) return _belhorn_wrapper _url_for_latest_breakable = \ 'http://raw.githubusercontent.com/robertdfrench/break/master/breakable.py' __all__ = [ 'which', 'Executable', 'rm', 'needs', 'find_files', 'path', 'touch', 'only_if_modified', 'provides', 'log', 'belhorn_property'] if __name__ == "__main__": # pragma: no cover args = _get_args(sys.argv[1:]) if args.clean: for f in find_files(r".*breakstamp.*", "."): rm(f) log.info("Removing timestamps; All targets should rebuild now") sys.exit(0) if args.update: new_breakable = urllib.urlopen(_url_for_latest_breakable) with open(__file__, "w") as old_breakable: old_breakable.write(new_breakable.read()) log.info("Overwriting your old-ass breakable.py with the latest copy") log.info("Be sure to include these changes in your next commit!") sys.exit(0) from Breakfile import BreakTasks tasklist = BreakTasks() if args.list_tasks: for attr in dir(tasklist): if not attr.startswith('_'): typename = type(getattr(tasklist, attr)).__name__ docs = getattr(tasklist, attr).__doc__ if typename == 'instancemethod': print("%s: %s" % (attr, docs)) else: if args.task: getattr(tasklist, args.task)() else: print("You should probably specify a task") main.cpp 0 → 100644 +5 −0 Original line number Diff line number Diff line #include <iostream> int main(int argc, char** argv) { std::cout << "Hello, World!\n"; } Loading
Breakfile.py 0 → 100644 +12 −0 Original line number Diff line number Diff line from breakable import * class BreakTasks(object): CC = which("c++") @provides("hello_world.exe") def build_hello_world(self): needs("main.cpp") self.CC("main.cpp -o hello_world.exe") def clean(self): rm("*.exe")
breakable.py 0 → 100755 +227 −0 Original line number Diff line number Diff line #!/usr/bin/env python """ Break: For when you're frustrated with Make. Inspired by the elegant process invocation and management features of Spack (https://github.com/LLNL/spack). """ from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals import subprocess import shlex import os import argparse import sys import re import urllib class log(object): red = '1;31' blue = '1;34' yellow = '1;33' gray = '1;30' @classmethod def _print(cls, msg, prefix=None, color=None): if color: msg = "\033[{0}m{1}\033[0m".format(color, msg) if prefix: msg = prefix + msg print(msg) @classmethod def info(cls, msg): cls._print(msg, '# ', cls.yellow) @classmethod def prompt(cls, msg): cls._print(msg, '==> ', cls.blue) class Executable(object): def __init__(self, path, defaults=[]): self.path = path self.defaults = defaults def _generate_command(self, *args): return ' '.join([self.path] + self.defaults + list(args)) def __call__(self, argstring=""): command = self._generate_command(argstring) log.prompt(command) real_command = shlex.split("bash -c \"%s\"" % command) rc = subprocess.call(real_command) if rc != 0: # pragma: no cover sys.exit(rc) def collect(self, argstring): command = self._generate_command(argstring) log.prompt(command) real_command = shlex.split("bash -c \"%s\"" % command) proc = subprocess.Popen( real_command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True, bufsize=1) for line in proc.stdout: yield line rc = proc.wait() if rc != 0: # pragma: no cover sys.exit(rc) def grab(self, argstring): return ''.join(self.collect(argstring)) def which(tool, defaults=[]): paths = ["."] + os.environ['PATH'].split(':') for path in paths: tool_path = os.path.join(path, tool) if os.path.exists(tool_path): return Executable(tool_path, defaults=defaults) rm = which("rm", defaults=["-f"]) touch = which("touch") def find_files(pattern, directory="."): for root, dirs, files in os.walk(directory): for f in files: path = os.path.join(root, f) if re.match(pattern, path): yield path def _get_args(argv): parser = argparse.ArgumentParser() parser.add_argument( "-l", "--list-tasks", help="display available tasks", action="store_true") parser.add_argument( "-c", "--clean", help="Clean up breakstamps", action="store_true") parser.add_argument( "-u", "--update", help="Update breakable.py", action="store_true") parser.add_argument( "-f", "--breakfile", help="path to Breakfile.py", default="Breakfile.py") parser.add_argument( "-t", "--task", help="Entrypoint in Breakfile.py", default=None) return parser.parse_args(argv) def needs(*filenames): for f in filenames: if not os.path.exists(f): raise Exception("%s is needed but not found" % f) def only_if_modified(*filenames): needs(*(filenames + (__file__,))) def wrapper(func): def wrapped(self=None): timestamp_file = path(".breakstamp.%s" % func.__name__) dirty = False for f in filenames: if timestamp_file.dirtier_than(f): dirty = True break if dirty: of_the_jedi = func(self) touch(timestamp_file) return of_the_jedi wrapped.__doc__ = func.__doc__ return wrapped return wrapper def provides(filename): def wrapper(func): def wrapped(self=None): if not path(filename).exists: return func(self) wrapped.__doc__ = func.__doc__ return wrapped return wrapper class BreakPath(str): def newer_than(self, other): if not os.path.exists(self): msg = "Cannot compare %s with %s." % (self, other) msg += " %s does not exist." % (self) raise Exception(msg) if not os.path.exists(other): msg = "Cannot compare %s with %s." % (self, other) msg += " %s does not exist." % (other) raise Exception(msg) return os.path.getmtime(self) > os.path.getmtime(other) def dirtier_than(self, dependency): if not os.path.exists(dependency): msg = "Cannot compare %s with %s." % (self, dependency) msg += " %s does not exist." % (dependency) raise Exception(msg) if not os.path.exists(self): return True return path(dependency).newer_than(self) @property def exists(self): return os.path.exists(self) def path(*filename_parts): return BreakPath(os.path.join(*filename_parts)) def belhorn_property(function): '''Pirated implementation of @mpbelhorn's cached property decorator''' @property def _belhorn_wrapper(self): cached_name = "_cached_%s" % function.__name__ if not hasattr(self, cached_name): setattr(self, cached_name, function(self)) return getattr(self, cached_name) return _belhorn_wrapper _url_for_latest_breakable = \ 'http://raw.githubusercontent.com/robertdfrench/break/master/breakable.py' __all__ = [ 'which', 'Executable', 'rm', 'needs', 'find_files', 'path', 'touch', 'only_if_modified', 'provides', 'log', 'belhorn_property'] if __name__ == "__main__": # pragma: no cover args = _get_args(sys.argv[1:]) if args.clean: for f in find_files(r".*breakstamp.*", "."): rm(f) log.info("Removing timestamps; All targets should rebuild now") sys.exit(0) if args.update: new_breakable = urllib.urlopen(_url_for_latest_breakable) with open(__file__, "w") as old_breakable: old_breakable.write(new_breakable.read()) log.info("Overwriting your old-ass breakable.py with the latest copy") log.info("Be sure to include these changes in your next commit!") sys.exit(0) from Breakfile import BreakTasks tasklist = BreakTasks() if args.list_tasks: for attr in dir(tasklist): if not attr.startswith('_'): typename = type(getattr(tasklist, attr)).__name__ docs = getattr(tasklist, attr).__doc__ if typename == 'instancemethod': print("%s: %s" % (attr, docs)) else: if args.task: getattr(tasklist, args.task)() else: print("You should probably specify a task")
main.cpp 0 → 100644 +5 −0 Original line number Diff line number Diff line #include <iostream> int main(int argc, char** argv) { std::cout << "Hello, World!\n"; }