Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ addons:

# Perform the manual steps on osx to install python3 and activate venv
before_install:
# Follow documentation process from from https://github.com/kmcallister/travis-doc-upload
- openssl aes-256-cbc -K $encrypted_2722dee00096_key -iv $encrypted_2722dee00096_iv
-in .ci/id_rsa.enc -out ~/.ssh/id_rsa.github -d

- eval key=\$encrypted_${SSH_KEY_TRAVIS_ID}_key
- eval iv=\$encrypted_${SSH_KEY_TRAVIS_ID}_iv
- |
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew update
Expand Down
3 changes: 3 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ global-exclude *.so
# python modules
recursive-include src/faber *.py

# VERSION file
include src/faber/VERSION

# bjam sources
recursive-include src/bjam *

Expand Down
69 changes: 42 additions & 27 deletions scripts/faber
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@
# (Consult LICENSE or http://www.boost.org/LICENSE_1_0.txt)

import faber
from faber import scheduler
from faber import project
from faber import logging
import os.path
import argparse


try:
input = raw_input
except NameError:
pass


class PosArgsParser(argparse.Action):
def __init__(self, option_strings, dest, **kwds):
argparse.Action.__init__(self, option_strings, dest, **kwds)
Expand Down Expand Up @@ -81,6 +86,8 @@ def make_parser(prog='faber'):
help='print information about the build logic')
parser.add_argument('--shell', action='store_true',
help='run interactive shell')
parser.add_argument('-v', '--version', action='store_true',
help='report version and exit')
return parser


Expand All @@ -89,53 +96,61 @@ def main(argv):
parser = make_parser(argv[0])
try:
args, unknown = parser.parse_known_args(argv[1:])
if args.silent:
args.log = []
if args.version:
print('Faber version {}'.format(faber.version))
return True

def with_gen(w):
k, v = w.split('=', 1) if '=' in w else (w, None)
yield k[7:]
yield k[2:]
yield v
with_ = dict(map(with_gen, [w for w in unknown if w.startswith('--with-')]))
without = [w[10:] for w in unknown if w.startswith('--without-')]
args.options = dict(with_=with_, without=without)
args.options = dict(map(with_gen, [w for w in unknown
if w.startswith('--with-')]))
args.options.update(dict.fromkeys([w[2:] for w in unknown
if w.startswith('--without-')], None))

unknown = [a for a in unknown
if not a.startswith('--with-') and not a.startswith('--without-')]
# Parse the remainder, as there may be more positional arguments.
# (See https://bugs.python.org/issue14191 for context)
args = parser.parse_args(unknown, args)

logging.setup(args.log, args.loglevel,
args.debug, args.silent, args.profile)
logging.setup(args.log, args.loglevel, args.debug, args.profile)
if args.debug:
faber.debug = True
scheduler.init(args.parameters, args.builddir, readonly=args.info=='tools',
log=args.log and 'process' in args.log,
jobs=args.parallel,
force=args.force,
intermediates=args.intermediates,
timeout=args.timeout,
noexec=args.noexec)
if args.rc:
project.config(os.path.expanduser(args.rc))
elif os.path.exists(os.path.expanduser('~/.faber')):
project.config(os.path.expanduser('~/.faber'))

if args.srcdir and os.path.exists(os.path.join(args.srcdir, '.faber')):
project.config(os.path.join(args.srcdir, '.faber'))

if args.srcdir and os.path.exists(os.path.join(args.srcdir, '.faberrc')):
project.config(os.path.join(args.srcdir, '.faberrc'))
info = project.buildinfo(args.builddir, args.srcdir)
if args.parameters and info.parameters and \
args.parameters != info.parameters and \
input('override existing parameters ? [y/N]:') != 'y':
return False
if args.options and info.options and \
args.options != info.options and \
input('override existing options ? [y/N]:') != 'y':
return False
info.parameters = args.parameters
info.options = args.options
proj = project.project(info,
parallel=args.parallel, force=args.force,
intermediates=args.intermediates,
timeout=args.timeout,
noexec=args.noexec)
if args.info:
result = project.info(args.info,
args.goals, args.options, args.parameters,
args.srcdir, args.builddir)
result = proj.info(args.info, args.goals)
elif args.shell:
result = project.shell(args.goals, args.options, args.parameters,
args.srcdir, args.builddir)
result = proj.shell()
elif args.clean:
result = project.clean(args.clean, args.options, args.parameters,
args.srcdir, args.builddir)
result = proj.clean(args.clean)
else:
result = project.build(args.goals, args.options, args.parameters,
args.srcdir, args.builddir)
scheduler.finish()
result = proj.build(args.goals)
return result
except KeyboardInterrupt:
pass
Expand Down
44 changes: 32 additions & 12 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,12 @@
# (Consult LICENSE or http://www.boost.org/LICENSE_1_0.txt)

from distutils.core import setup, Extension
from distutils.command import build, install_scripts
from distutils.command import build, install_scripts, install_data, sdist
import sys, os, os.path, glob, shutil
import subprocess
import re

try:
out = subprocess.check_output('git describe --tags --match release/*'.split(),
stderr=subprocess.STDOUT).decode().strip()
version=re.match('release/(.+)', out).group(1)
except Exception as e:
version='snapshot'
# allow the in-place import of the version
sys.path.insert(0, 'src')
from faber import version

def prefix(pref, list): return [pref + x for x in list]

Expand Down Expand Up @@ -71,6 +66,29 @@ def run(self):
'--srcdir={}'.format('doc'),
'--builddir={}'.format('doc')])


class finstall_data(install_data.install_data):
"""Install VERSION file."""

def finalize_options(self):
self.set_undefined_options('install', ('install_lib', 'install_dir'),)
install_data.install_data.finalize_options(self)

def run(self):
install_data.install_data.run(self)
vf = os.path.join(self.install_dir, 'faber', 'VERSION')
open(vf, 'w').write(version)
self.outfiles.append(vf)


class fsdist(sdist.sdist):

def make_release_tree(self, base_dir, files):
sdist.sdist.make_release_tree(self, base_dir, files)
print('base_dir=', base_dir)
open(os.path.join(base_dir, 'src', 'faber', 'VERSION'), 'w').write(version)


docs = []
if os.path.exists('doc/html'):
for root, dirs, files in os.walk('doc/html'):
Expand Down Expand Up @@ -108,7 +126,7 @@ def run(self):
with open(bat_file, 'wt') as fobj:
fobj.write(bat_contents)

class check(build.build):
class test(build.build):

description = "run tests"

Expand All @@ -126,7 +144,7 @@ def run(self):
maintainer='Stefan Seefeld',
maintainer_email='[email protected]',
description='Faber is a construction tool.',
url='http://github.com/stefanseefeld/faber',
url='https://stefanseefeld.github.io/faber',
download_url='https://github.com/stefanseefeld/faber/releases',
license='BSL',
classifiers = ['Environment :: Console',
Expand All @@ -138,8 +156,10 @@ def run(self):
'Programming Language :: Python',
'Programming Language :: C'],
cmdclass={'build_doc': build_doc,
'install_data': finstall_data,
'install_scripts': install_faber,
'check': check},
'test': test,
'sdist': fsdist},
package_dir={'':'src'},
packages=find_packages('src/faber', 'faber'),
ext_modules=[bjam],
Expand Down
4 changes: 2 additions & 2 deletions src/bjam/bjam.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ static LIST *list_from_sequence(PyObject *a)
for (; i < s; ++i)
{
PyObject *e = PySequence_GetItem(a, i);
char *s = PYSTRING_AS_STRING(e);
char *s = (char *)PYSTRING_AS_STRING(e);
if (!s)
{
PyErr_BadArgument();
Expand Down Expand Up @@ -209,7 +209,7 @@ static PyObject *bjam_define_action(PyObject *self, PyObject *args)
&PyList_Type, &bindlist_python))
return NULL;
if (PYSTRING_CHECK(body))
cmd = PYSTRING_AS_STRING(body);
cmd = (char *)PYSTRING_AS_STRING(body);
else if (!PyCallable_Check(body))
{
PyErr_SetString(PyExc_RuntimeError, "action is neither string nor callable");
Expand Down
1 change: 1 addition & 0 deletions src/bjam/function.c
Original file line number Diff line number Diff line change
Expand Up @@ -3783,6 +3783,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s )
instruction * code;
LIST * l;
LIST * result = L0;
void * saved_stack = s->data;

PROFILE_ENTER_LOCAL(function_run);

Expand Down
5 changes: 5 additions & 0 deletions src/faber/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@
# Boost Software License, Version 1.0.
# (Consult LICENSE or http://www.boost.org/LICENSE_1_0.txt)

from . import _version

debug = False

version = _version.get_version()
__version__ = version
39 changes: 39 additions & 0 deletions src/faber/_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#
# Copyright (c) 2018 Stefan Seefeld
# All rights reserved.
#
# This file is part of Faber. It is made available under the
# Boost Software License, Version 1.0.
# (Consult LICENSE or http://www.boost.org/LICENSE_1_0.txt)

from subprocess import check_output
import re
from os.path import join, dirname


def _get_version_from_git(path):
try:
out = check_output('git describe --tags --long --match release/*'.split(),
cwd=path).decode().strip()
match = re.match(r'release/'
r'(?P<version>[a-zA-Z0-9.]+)'
r'(?:-(?P<post>\d+)-g(?P<hash>[0-9a-f]{7,}))$',
out)
version, post, hash = match.groups()
return version if post == '0' else '{0}.post{1}+{2}'.format(version, post, hash)
except Exception:
return None


def _get_version_from_file(path):
try:
with open(join(path, 'VERSION'), 'r') as f:
return f.read().strip()
except Exception:
return None


def get_version():
here = dirname(__file__)
version = _get_version_from_file(here) or _get_version_from_git(here)
return version or 'unknown'
5 changes: 3 additions & 2 deletions src/faber/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

action_logger = logging.getLogger('actions')
command_logger = logging.getLogger('commands')
output_logger = logging.getLogger('output')


class CallError(Exception):
Expand Down Expand Up @@ -186,6 +187,6 @@ def __status__(self, targets, status, command, time, stdout, stderr):
action_logger.info(alog)
command_logger.info(command, extra={'time': time})
if stdout:
print(stdout)
output_logger.info(stdout)
if stderr:
print(stderr)
output_logger.info(stderr)
32 changes: 22 additions & 10 deletions src/faber/artefact.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from . import types
from .feature import set
from .delayed import delayed_property
from .utils import path_formatter
from .utils import path_formatter, add_metaclass
from . import logging
from os.path import normpath, join
from collections import defaultdict
Expand Down Expand Up @@ -135,6 +135,9 @@ def update(self):
from . import scheduler
return scheduler.update(self)

def reset(self):
self.status = None

def _register(self):
from . import scheduler
artefact._qnames[self.qname].append(self)
Expand All @@ -153,21 +156,24 @@ def __status__(self, status):
self.status = status


class source(artefact):
"""A source is a simple feature-less artefact representing an existing
file outside faber's control."""

_instances = {}

def __new__(cls, name, module=None):
class source_type(type):
def __call__(cls, name, *args, **kwds):
"""Make sure there is only one instance per source (file)."""
from .module import module as M
module = module or M.current
module = kwds.get('module') or M.current
qname = module.qname(name)
if qname not in cls._instances:
cls._instances[qname] = object.__new__(cls)
cls._instances[qname] = type.__call__(cls, name, *args, **kwds)
return cls._instances[qname]


@add_metaclass(source_type)
class source(artefact):
"""A source is a simple feature-less artefact representing an existing
file outside faber's control."""

_instances = {}

def _register(self):
# don't depend on anything
from . import scheduler
Expand Down Expand Up @@ -196,3 +202,9 @@ def __status__(self, status):
from . import scheduler
for d in self.dependent:
scheduler.add_dependency(d, self.a)


def init():
"""reset globals"""

source._instances.clear()
Loading