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

[PR196 3/3] Adding support for partial workspace cleaning #293

Merged
merged 43 commits into from
Apr 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
396ab3b
color: Adding color env variable, fixing catkin build 'skipped' align…
jbohren Feb 9, 2016
5608ea8
clean: Adding support for partial workspace cleaning based on #196
jbohren Feb 12, 2016
12872fd
list: Clarifying depends and depends-on behavior, adding recursive fu…
jbohren Feb 13, 2016
b6c186d
build: Not forcing CMake when cmake args aren't given
jbohren Feb 13, 2016
5073cec
tests: adding linked devel test and fixing pep8 stuff
jbohren Feb 13, 2016
007b3d4
color: Adding color env variable, fixing catkin build 'skipped' align…
jbohren Feb 9, 2016
a149648
clean: Adding support for partial workspace cleaning based on #196
jbohren Feb 12, 2016
0e4619f
list: Clarifying depends and depends-on behavior, adding recursive fu…
jbohren Feb 13, 2016
74bce75
build: Not forcing CMake when cmake args aren't given
jbohren Feb 13, 2016
d29c21b
tests: adding linked devel test and fixing pep8 stuff
jbohren Feb 13, 2016
0d523ab
Merge branch 'pre-0.4.0-clean-pkgs' of github.com:catkin/catkin_tools…
jbohren Feb 24, 2016
2689f63
clean: Making linked devel cleanup more robust to missing files
jbohren Feb 24, 2016
73457aa
common: improving workspace root detection
jbohren Mar 22, 2016
251967d
context: Adding new log space for log files
jbohren Mar 22, 2016
f0c44f4
utils: adding copy files function stage functor
jbohren Mar 22, 2016
4240eca
metadata: restructuring metadata layout
jbohren Mar 22, 2016
3ae0326
clean: Numerous improvments and fixes
jbohren Mar 22, 2016
d67d169
tests: updating tests for new log space, clean cli
jbohren Mar 22, 2016
d14cf9f
locate: adding quiet option for use in shell completion
jbohren Mar 22, 2016
09e2b12
list: adding --this option
jbohren Mar 22, 2016
32b2925
testing: temporarily switching back to osrf_pycommon 0.1.0
jbohren Mar 22, 2016
ffe83e0
testing: trying experimental osrf_pycommon branch
jbohren Mar 28, 2016
10687cd
testing
wjwwood Mar 28, 2016
104a272
ensure trollius is imported before osrf_pycommon.process_utils
wjwwood Mar 28, 2016
82fce23
Revert "ensure trollius is imported before osrf_pycommon.process_utils"
wjwwood Mar 29, 2016
98b5450
use released version of osrf_pycommon
wjwwood Mar 29, 2016
7e77d04
Merge remote-tracking branch 'osrf/testing_process_utils' into pre-0.…
jbohren Mar 30, 2016
0d2cdaf
testing: returning osrf_pycommon branch to master
jbohren Mar 30, 2016
72a29d7
Merge branch 'pre-0.4.0-clean-pkgs' of https://github.com/catkin/catk…
jbohren Mar 30, 2016
841c4c0
clean: Numerous imrovements/bugfixes
jbohren Apr 1, 2016
7d07b05
metadata: Adding 0.3.1 -> 0.4.0 metadata migration
jbohren Apr 3, 2016
ac23683
config: Changing default to use linked develspace
jbohren Apr 4, 2016
9ae02df
clean: cleaning now respects destdir, destdir now works with linked d…
jbohren Apr 4, 2016
187a004
remove unused imports
wjwwood Apr 11, 2016
6ce2f83
typo
wjwwood Apr 11, 2016
bf89dd0
add missing import
wjwwood Apr 11, 2016
912821a
clean: add an additional check before removing directories outside of…
jbohren Apr 12, 2016
b9ccbac
clean: switching to use log function instead of print function
jbohren Apr 12, 2016
043a692
clean, build: Cleaning up unused variables
jbohren Apr 12, 2016
bec0447
Merge branch 'pre-0.4.0-clean-pkgs' of https://github.com/catkin/catk…
jbohren Apr 12, 2016
4be1c69
clean: pep8 cleanup
jbohren Apr 12, 2016
f7cf89c
tests: updating for new clean cli args
jbohren Apr 12, 2016
13aa6e5
clean: Making cli more consistent
jbohren Apr 12, 2016
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
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ matrix:
before_install:
# Install catkin_tools dependencies
- source .travis.before_install.bash
- pip install setuptools argparse catkin-pkg distribute PyYAML psutil trollius
- pip install git+https://github.com/osrf/osrf_pycommon.git
- pip install setuptools argparse catkin-pkg distribute PyYAML psutil trollius osrf_pycommon
install:
# Install catkin_tools
- python setup.py develop
Expand Down
2 changes: 1 addition & 1 deletion catkin_tools/commands/catkin.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def catkin_main(sysargs):

# Get colors config
no_color = False
force_color = False
force_color = os.environ.get('CATKIN_TOOLS_FORCE_COLOR', False)
for arg in sysargs:
if arg == '--no-color':
no_color = True
Expand Down
56 changes: 46 additions & 10 deletions catkin_tools/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,35 @@ def get_recursive_build_dependants_in_workspace(package_name, ordered_packages):
return recursive_dependants


def get_recursive_run_dependants_in_workspace(package_name, ordered_packages):
"""Calculates the recursive run dependants of a package which are also in
the ordered_packages

:param package: package for which the recursive depends should be calculated
:type package: :py:class:`catkin_pkg.package.Package`
:param ordered_packages: packages in the workspace, ordered topologically
:type ordered_packages: list(tuple(package path,
:py:class:`catkin_pkg.package.Package`))
:returns: list of package path, package object tuples which are the
recursive run depends for the given package
:rtype: list(tuple(package path, :py:class:`catkin_pkg.package.Package`))
"""
recursive_dependants = list()

for pth, pkg in reversed(ordered_packages):
# Break if this is one to check
if pkg.name == package_name:
break

# Check if this package depends on the target package
deps = get_recursive_run_depends_in_workspace([pkg], ordered_packages)
deps_names = [p.name for _, p in deps]
if package_name in deps_names:
recursive_dependants.insert(0, (pth, pkg))

return recursive_dependants


def is_tty(stream):
"""Returns True if the given stream is a tty, else False"""
return hasattr(stream, 'isatty') and stream.isatty()
Expand Down Expand Up @@ -555,22 +584,29 @@ def get_build_type(package):


def find_enclosing_package(search_start_path=None, ws_path=None, warnings=None, symlinks=True):
"""Get the package containing the current directory."""
"""Get the package containing a specific directory.

search_start_path = search_start_path or getcwd(symlinks=symlinks)
child_path = ''
:param search_start_path: The path to crawl upward to find a package, CWD if None
:param ws_path: The path at which the search should stop
"""

search_path = search_start_path or getcwd(symlinks=symlinks)
stop_path = ws_path or '/'
child_path = '.'

while True:
pkgs = find_packages(search_start_path, warnings=warnings)
while search_path != stop_path:
# Find packages under the search path
try:
pkgs = find_packages(search_path, warnings=warnings)
except:
return None

# Check if the previous directory is a catkin package
# Check if the directory is a catkin package
if child_path in pkgs:
return pkgs[child_path].name

# Update search path or end
(search_start_path, child_path) = os.path.split(search_start_path)
if len(child_path) == 0 or search_start_path == ws_path:
break
# Update search path
(search_path, child_path) = os.path.split(search_path)

return None

Expand Down
72 changes: 57 additions & 15 deletions catkin_tools/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Context(object):
This context can be locked, so that changing the members is prevented.
"""

DEFAULT_LOG_SPACE = 'logs'
DEFAULT_SOURCE_SPACE = 'src'
DEFAULT_BUILD_SPACE = 'build'
DEFAULT_DEVEL_SPACE = 'devel'
Expand All @@ -57,6 +58,7 @@ class Context(object):
STORED_KEYS = [
'extend_path',
'source_space',
'log_space',
'build_space',
'devel_space',
'install_space',
Expand Down Expand Up @@ -193,6 +195,7 @@ def __init__(
profile=None,
extend_path=None,
source_space=None,
log_space=None,
build_space=None,
devel_space=None,
install_space=None,
Expand Down Expand Up @@ -220,6 +223,8 @@ def __init__(
:type extend_path: str
:param source_space: relative location of source space, defaults to '<workspace>/src'
:type source_space: str
:param log_space: relative location of log space, defaults to '<workspace>/logs'
:type log_space: str
:param build_space: relativetarget location of build space, defaults to '<workspace>/build'
:type build_space: str
:param devel_space: relative target location of devel space, defaults to '<workspace>/devel'
Expand Down Expand Up @@ -268,6 +273,7 @@ def __init__(
self.profile = profile

self.source_space = Context.DEFAULT_SOURCE_SPACE if source_space is None else source_space
self.log_space = Context.DEFAULT_LOG_SPACE + ss if ss or log_space is None else log_space
self.build_space = Context.DEFAULT_BUILD_SPACE + ss if ss or build_space is None else build_space
self.devel_space = Context.DEFAULT_DEVEL_SPACE + ss if ss or devel_space is None else devel_space
self.install_space = Context.DEFAULT_INSTALL_SPACE + ss if ss or install_space is None else install_space
Expand All @@ -278,7 +284,7 @@ def __init__(
self.blacklist = blacklist or []

# Handle build options
self.devel_layout = devel_layout if devel_layout else 'merged'
self.devel_layout = devel_layout if devel_layout else 'linked'
self.install = install
self.isolate_install = isolate_install

Expand Down Expand Up @@ -401,16 +407,18 @@ def summary(self, notes=[]):
clr("@{cf}Profile:@| @{yf}{profile}@|"),
clr("@{cf}Extending:@| {extend_mode} @{yf}{extend}@|"),
clr("@{cf}Workspace:@| @{yf}{_Context__workspace}@|"),
],
[
clr("@{cf}Source Space:@| {source_missing} @{yf}{_Context__source_space_abs}@|"),
clr("@{cf}Log Space:@| {log_missing} @{yf}{_Context__log_space_abs}@|"),
clr("@{cf}Build Space:@| {build_missing} @{yf}{_Context__build_space_abs}@|"),
clr("@{cf}Devel Space:@| {devel_missing} @{yf}{_Context__devel_space_abs}@|"),
clr("@{cf}Install Space:@| {install_missing} @{yf}{_Context__install_space_abs}@|"),
clr("@{cf}DESTDIR:@| @{yf}{_Context__destdir}@|"),
clr("@{cf}DESTDIR:@| {destdir_missing} @{yf}{_Context__destdir}@|")
],
[
clr("@{cf}Devel Space Layout:@| @{yf}{_Context__devel_layout}@|"),
clr("@{cf}Install Packages:@| @{yf}{_Context__install}@|"),
clr("@{cf}Isolate Installs:@| @{yf}{_Context__isolate_install}@|"),
clr("@{cf}Install Space Layout:@| @{yf}{install_layout}@|"),
],
[
clr("@{cf}Additional CMake Args:@| @{yf}{cmake_args}@|"),
Expand Down Expand Up @@ -441,21 +449,31 @@ def summary(self, notes=[]):
extend_value = 'None'
extend_mode = clr(' ')

def existence_str(path):
return clr(' @{gf}[exists]@|' if os.path.exists(path) else '@{rf}[missing]@|')
def existence_str(path, used=True):
if used:
return clr(' @{gf}[exists]@|' if os.path.exists(path) else '@{rf}[missing]@|')
else:
return clr(' @{bf}[unused]@|')

install_layout = 'None'
if self.__install:
install_layout = 'merged' if not self.__isolate_install else 'isolated'

subs = {
'profile': self.profile,
'extend_mode': extend_mode,
'extend': extend_value,
'install_layout': install_layout,
'cmake_prefix_path': (self.cmake_prefix_path or ['Empty']),
'cmake_args': ' '.join(self.__cmake_args or ['None']),
'make_args': ' '.join(self.__make_args + self.__jobs_args or ['None']),
'catkin_make_args': ', '.join(self.__catkin_make_args or ['None']),
'source_missing': existence_str(self.source_space_abs),
'log_missing': existence_str(self.log_space_abs),
'build_missing': existence_str(self.build_space_abs),
'devel_missing': existence_str(self.devel_space_abs),
'install_missing': existence_str(self.install_space_abs),
'install_missing': existence_str(self.install_space_abs, used=self.__install),
'destdir_missing': existence_str(self.destdir, used=self.destdir),
'whitelisted_packages': ' '.join(self.__whitelist or ['None']),
'blacklisted_packages': ' '.join(self.__blacklist or ['None']),
}
Expand Down Expand Up @@ -539,6 +557,21 @@ def initialized(self):
"""Check if this context is initialized."""
return self.workspace == find_enclosing_workspace(self.workspace)

@property
def log_space_abs(self):
return self.__log_space_abs

@property
def log_space(self):
return self.__log_space

@log_space.setter
def log_space(self, value):
if self.__locked:
raise RuntimeError("Setting of context members is not allowed while locked.")
self.__log_space = value
self.__log_space_abs = os.path.join(self.__workspace, value)

@property
def build_space_abs(self):
return self.__build_space_abs
Expand All @@ -551,7 +584,6 @@ def build_space(self):
def build_space(self, value):
if self.__locked:
raise RuntimeError("Setting of context members is not allowed while locked.")
# TODO: check that build space was not run with a different context before
self.__build_space = value
self.__build_space_abs = os.path.join(self.__workspace, value)

Expand All @@ -567,7 +599,6 @@ def devel_space(self):
def devel_space(self, value):
if self.__locked:
raise RuntimeError("Setting of context members is not allowed while locked.")
# TODO: check that devel space was not run with a different context before
self.__devel_space = value
self.__devel_space_abs = os.path.join(self.__workspace, value)

Expand All @@ -583,7 +614,6 @@ def install_space(self):
def install_space(self, value):
if self.__locked:
raise RuntimeError("Setting of context members is not allowed while locked.")
# TODO: check that install space was not run with a different context before
self.__install_space = value
self.__install_space_abs = os.path.join(self.__workspace, value)

Expand Down Expand Up @@ -730,14 +760,14 @@ def blacklist(self, value):
self.__blacklist = value

@property
def linked_devel_path(self):
def private_devel_path(self):
"""The path to the hidden directory in the develspace that
contains the symbollically-linked isolated develspaces."""
return os.path.join(self.devel_space_abs, '.catkin_tools')
return os.path.join(self.devel_space_abs, '.private')

def package_linked_devel_path(self, package):
def package_private_devel_path(self, package):
"""The path to the linked devel space for a given package."""
return os.path.join(self.linked_devel_path, package.name)
return os.path.join(self.private_devel_path, package.name)

def package_build_space(self, package):
"""Get the build directory for a specific package."""
Expand All @@ -752,7 +782,7 @@ def package_devel_space(self, package):
elif self.isolate_devel:
return os.path.join(self.devel_space_abs, package.name)
elif self.link_devel:
return os.path.join(self.linked_devel_path, package.name)
return os.path.join(self.private_devel_path, package.name)
else:
raise ValueError('Unkown devel space layout: {}'.format(self.devel_layout))

Expand Down Expand Up @@ -788,3 +818,15 @@ def package_final_path(self, package):
return self.devel_space_abs
else:
return self.package_devel_space(package)

def metadata_path(self):
"""Get the path to the metadata directory for this profile."""
profile_path, _ = metadata.get_paths(self.workspace, self.profile)
return profile_path

def package_metadata_path(self, package=None):
"""Get the workspace and profile-specific metadata path for a package"""
profile_path, _ = metadata.get_paths(self.workspace, self.profile)
if package is None:
return os.path.join(profile_path, 'packages')
return os.path.join(profile_path, 'packages', package.name)
3 changes: 0 additions & 3 deletions catkin_tools/execution/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,13 @@
from Queue import Empty

import math
import os
import operator
import sys
import threading
import time

from catkin_tools.common import disable_wide_log
from catkin_tools.common import format_time_delta
from catkin_tools.common import format_time_delta_short
from catkin_tools.common import log
from catkin_tools.common import remove_ansi_escape
from catkin_tools.common import terminal_width
from catkin_tools.common import wide_log
Expand Down
11 changes: 9 additions & 2 deletions catkin_tools/execution/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
from __future__ import print_function

import os
import time
import threading
import traceback

from itertools import tee
Expand Down Expand Up @@ -147,6 +145,11 @@ def async_job(verb, job, threadpool, locks, event_queue, log_path):
logger,
event_queue))
except:
logger.err('Stage `{}` failed with arguments:'.format(stage.label))
for arg_val in stage.args:
logger.err(' {}'.format(arg_val))
for arg_name, arg_val in stage.kwargs.items():
logger.err(' {}: {}'.format(arg_name, arg_val))
logger.err(str(traceback.format_exc()))
retcode = 3
else:
Expand Down Expand Up @@ -215,6 +218,10 @@ def execute_jobs(
# List of jobs whose deps failed
abandoned_jobs = []

# Make sure job server has been initialized
if not job_server.initialized():
raise RuntimeError('JobServer has not been initialized.')

# Create a thread pool executor for blocking python stages in the asynchronous jobs
threadpool = ThreadPoolExecutor(max_workers=job_server.max_jobs())

Expand Down
5 changes: 5 additions & 0 deletions catkin_tools/execution/job_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ def _running_jobs(cls):
return cls._max_jobs


def initialized():
"""Return True if the job server has been initialized."""
return JobServer._initialized


def initialize(max_jobs=None, max_load=None, max_mem=None, gnu_make_enabled=False):
"""
Initialize the global GNU Make jobserver.
Expand Down
4 changes: 3 additions & 1 deletion catkin_tools/execution/stages.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
# limitations under the License.

import os
import sys

from catkin_tools.common import string_type

Expand Down Expand Up @@ -166,6 +165,9 @@ def __init__(
raise ValueError('Function stage must be callable.')
super(FunctionStage, self).__init__(label, logger_factory, occupy_job, locked_resource)

self.args = args
self.kwargs = kwargs

def function_proxy(logger, event_queue):
return function(logger, event_queue, *args, **kwargs)
self.function = function_proxy
Loading