Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new initial command stage to mutex all reads of the installspace. #391

Merged
merged 4 commits into from
Jan 28, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 1 addition & 4 deletions catkin_tools/execution/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,6 @@ def async_job(verb, job, threadpool, locks, event_queue, log_path):
# Jobs start occuping a jobserver job
occupying_job = True

# Load environment for this job
job_env = job.getenv(os.environ)

# Execute each stage of this job
for stage in job.stages:
# Logger reference in this scope for error reporting
Expand Down Expand Up @@ -102,7 +99,7 @@ def async_job(verb, job, threadpool, locks, event_queue, log_path):
while True:
try:
# Update the environment for this stage (respects overrides)
stage.update_env(job_env)
stage.update_env(job.env)

# Get the logger
protocol_type = stage.logger_factory(verb, job.jid, stage.label, event_queue, log_path)
Expand Down
7 changes: 2 additions & 5 deletions catkin_tools/execution/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Job(object):

"""A Job is a series of operations, each of which is considered a "stage" of the job."""

def __init__(self, jid, deps, env_loader, stages, continue_on_failure=True):
def __init__(self, jid, deps, env, stages, continue_on_failure=True):
"""
jid: Unique job identifier
deps: Dependencies (in terms of other jid's)
Expand All @@ -33,7 +33,7 @@ def __init__(self, jid, deps, env_loader, stages, continue_on_failure=True):
"""
self.jid = jid
self.deps = deps
self.env_loader = env_loader
self.env = env
self.stages = stages
self.continue_on_failure = continue_on_failure

Expand All @@ -48,6 +48,3 @@ def all_deps_succeeded(self, completed_jobs):
def any_deps_failed(self, completed_jobs):
"""Return True if any dependencies which have been completed have failed."""
return any([not completed_jobs.get(dep_id, True) for dep_id in self.deps])

def getenv(self, env):
return self.env_loader(env)
37 changes: 32 additions & 5 deletions catkin_tools/jobs/catkin.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from .commands.make import MAKE_EXEC

from .utils import copyfiles
from .utils import get_env_loader
from .utils import load_env
from .utils import makedirs
from .utils import rmfiles

Expand Down Expand Up @@ -350,10 +350,23 @@ def create_catkin_build_job(context, package, package_path, dependencies, force_
install_space = context.package_install_space(package)
# Package metadata path
metadata_path = context.package_metadata_path(package)
# Environment dictionary for the job, which will be built
# up by the executions in the getenv stage.
job_env = dict(os.environ)

# Create job stages
stages = []

# Get environment for job.
stages.append(FunctionStage(
'getenv',
load_env,
locked_resource='installspace',
job_env=job_env,
package=package,
context=context
))

# Create package build space
stages.append(FunctionStage(
'mkdir',
Expand Down Expand Up @@ -478,7 +491,7 @@ def create_catkin_build_job(context, package, package_path, dependencies, force_
return Job(
jid=package.name,
deps=dependencies,
env_loader=get_env_loader(package, context),
env=job_env,
stages=stages)


Expand All @@ -493,12 +506,26 @@ def create_catkin_clean_job(
clean_install):
"""Generate a Job that cleans a catkin package"""

stages = []

# Package build space path
build_space = context.package_build_space(package)
# Package metadata path
metadata_path = context.package_metadata_path(package)
# Environment dictionary for the job, which will be built
# up by the executions in the getenv stage.
job_env = dict(os.environ)

# Create job stages
stages = []

# Get environment for job.
stages.append(FunctionStage(
'getenv',
load_env,
locked_resource='installspace',
job_env=job_env,
package=package,
context=context
))

# Remove installed files
if clean_install:
Expand Down Expand Up @@ -566,7 +593,7 @@ def create_catkin_clean_job(
return Job(
jid=package.name,
deps=dependencies,
env_loader=get_env_loader(package, context),
env=job_env,
stages=stages)


Expand Down
34 changes: 31 additions & 3 deletions catkin_tools/jobs/cmake.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from .commands.make import MAKE_EXEC

from .utils import copyfiles
from .utils import get_env_loader
from .utils import load_env
from .utils import makedirs
from .utils import rmfiles

Expand Down Expand Up @@ -217,6 +217,9 @@ def create_cmake_build_job(context, package, package_path, dependencies, force_c
build_space = context.package_build_space(package)
# Package metadata path
metadata_path = context.package_metadata_path(package)
# Environment dictionary for the job, which will be built
# up by the executions in the getenv stage.
job_env = dict(os.environ)

# Get actual staging path
dest_path = context.package_dest_path(package)
Expand All @@ -225,6 +228,16 @@ def create_cmake_build_job(context, package, package_path, dependencies, force_c
# Create job stages
stages = []

# Get environment for job.
stages.append(FunctionStage(
'getenv',
load_env,
locked_resource='installspace',
job_env=job_env,
package=package,
context=context
))

# Create package build space
stages.append(FunctionStage(
'mkdir',
Expand Down Expand Up @@ -321,7 +334,7 @@ def create_cmake_build_job(context, package, package_path, dependencies, force_c
return Job(
jid=package.name,
deps=dependencies,
env_loader=get_env_loader(package, context),
env=job_env,
stages=stages)


Expand All @@ -340,9 +353,24 @@ def create_cmake_clean_job(
build_space = context.package_build_space(package)
# Package metadata path
metadata_path = context.package_metadata_path(package)
# Environment dictionary for the job, which will be built
# up by the executions in the getenv stage.
job_env = dict(os.environ)

# Create job stages
stages = []

# Get environment for job.
stages.append(FunctionStage(
'getenv',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could call this loadenv or something instead; I'm not attached one way or another.

load_env,
locked_resource='installspace',
job_env=job_env,
package=package,
context=context
))

# Remove installed files
if clean_install and context.install:
installed_files = get_installed_files(context.package_metadata_path(package))
stages.append(FunctionStage(
Expand Down Expand Up @@ -381,7 +409,7 @@ def create_cmake_clean_job(
return Job(
jid=package.name,
deps=dependencies,
env_loader=get_env_loader(package, context),
env=job_env,
stages=stages)


Expand Down
45 changes: 19 additions & 26 deletions catkin_tools/jobs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,32 +50,25 @@ def get_env_loaders(package, context):
return sources


def get_env_loader(package, context):
"""This function returns a function object which extends a base environment
based on a set of environments to load."""

def load_env(base_env):
# Copy the base environment to extend
job_env = dict(base_env)
# Get the paths to the env loaders
env_loader_paths = get_env_loaders(package, context)
# If DESTDIR is set, set _CATKIN_SETUP_DIR as well
if context.destdir is not None:
job_env['_CATKIN_SETUP_DIR'] = context.package_dest_path(package)

for env_loader_path in env_loader_paths:
# print(' - Loading resultspace env from: {}'.format(env_loader_path))
resultspace_env = get_resultspace_environment(
os.path.split(env_loader_path)[0],
base_env=job_env,
quiet=True,
cached=context.use_env_cache,
strict=False)
job_env.update(resultspace_env)

return job_env

return load_env
def load_env(logger, event_queue, job_env, package, context):
# Get the paths to the env loaders
env_loader_paths = get_env_loaders(package, context)
# If DESTDIR is set, set _CATKIN_SETUP_DIR as well
if context.destdir is not None:
job_env['_CATKIN_SETUP_DIR'] = context.package_dest_path(package)

for env_loader_path in env_loader_paths:
if logger:
logger.out('Loading environment from: {}'.format(env_loader_path))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logger.out could just be dropped if we don't like it; the conditional is because of the print_build_env invocation, which doesn't have a logger to pass it.

resultspace_env = get_resultspace_environment(
os.path.split(env_loader_path)[0],
base_env=job_env,
quiet=True,
cached=context.use_env_cache,
strict=False)
job_env.update(resultspace_env)

return 0
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've simplified this to no longer return a closure, since the arguments can all be captured in the FunctionStage which invokes it.



def makedirs(logger, event_queue, path):
Expand Down
5 changes: 3 additions & 2 deletions catkin_tools/verbs/catkin_build/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

import catkin_tools.execution.job_server as job_server

from catkin_tools.jobs.utils import get_env_loader
from catkin_tools.jobs.utils import load_env

from catkin_tools.metadata import find_enclosing_workspace
from catkin_tools.metadata import get_metadata
Expand Down Expand Up @@ -228,7 +228,8 @@ def print_build_env(context, package_name):
# Load the environment used by this package for building
for pth, pkg in workspace_packages.items():
if pkg.name == package_name:
environ = get_env_loader(pkg, context)(os.environ)
environ = dict(os.environ)
load_env(None, None, environ, pkg, context)
print(format_env_dict(environ))
return 0
print('[build] Error: Package `{}` not in workspace.'.format(package_name),
Expand Down