class Autoproj::CLI::Locate

Deal with locating a package source or build directory in an existing workspace

It is based on a installation manifest file, a YAML file generated to list that information and thus avoid loading the Autoproj configuration (which takes fairly long).

Constants

RESOLUTION_MODES

Attributes

package_sets[R]
packages[R]

Public Class Methods

new(ws = Workspace.default, installation_manifest: try_loading_installation_manifest(ws)) click to toggle source

Create the locate CLI interface

@param [Workspace] ws the workspace we’re working on @param [InstallationManifest,nil] installation_manifest the

manifest. If nil, loads the whole autoproj configuration and
rebuilds the manifest
Calls superclass method Autoproj::CLI::Base::new
# File lib/autoproj/cli/locate.rb, line 25
def initialize(ws = Workspace.default, installation_manifest: try_loading_installation_manifest(ws))
    super(ws)
    ws.load_config

    if installation_manifest
        update_from_installation_manifest(installation_manifest)
    end
end

Public Instance Methods

build_dir_of(selection) click to toggle source

Returns the build directory for a given selection

@raise [NoSuchDir] if the selection points to a package set,

or to a package that has no build directory
# File lib/autoproj/cli/locate.rb, line 219
def build_dir_of(selection)
    if workspace_dir?(selection)
        raise NoSuchDir, "#{selection} points to the workspace itself, which has no build dir"
    elsif find_package_set(selection)
        raise NoSuchDir, "#{selection} is a package set, and package sets do not have build directories"
    else
        pkg = resolve_package(selection)
        if pkg.respond_to?(:builddir) && pkg.builddir
            pkg.builddir
        else
            raise NoSuchDir, "#{selection} resolves to the package #{pkg.name}, which does not have a build directory"
        end
    end
end
find_package_set(selection) click to toggle source

Find a package set that matches a given selection

@param [String] selection a string that is matched against the

package set name and its various directories. Directories are
matched against the full path and must end with /

@return [PackageSet,nil]

# File lib/autoproj/cli/locate.rb, line 51
def find_package_set(selection)
    package_sets.find do |pkg_set|
        name = pkg_set.name
        name == selection ||
            selection.start_with?("#{pkg_set.raw_local_dir}/") ||
            selection.start_with?("#{pkg_set.user_local_dir}/")
    end
end
find_packages(selection) click to toggle source
# File lib/autoproj/cli/locate.rb, line 60
def find_packages(selection)
    selection_rx = Regexp.new(Regexp.quote(selection))
    candidates = []
    packages.each do |pkg|
        name = pkg.name
        if name == selection || selection.start_with?("#{pkg.srcdir}/")
            return [pkg]
        elsif pkg.respond_to?(:builddir) && pkg.builddir && selection.start_with?("#{pkg.builddir}/")
            return [pkg]
        elsif name =~ selection_rx
            candidates << pkg
        end
    end
    candidates
end
find_packages_with_directory_shortnames(selection) click to toggle source
# File lib/autoproj/cli/locate.rb, line 76
def find_packages_with_directory_shortnames(selection)
    *directories, basename = *selection.split("/")
    dirname_rx = directories
                 .map { |d| "#{Regexp.quote(d)}\\w*" }
                 .join("/")

    rx        = Regexp.new("#{dirname_rx}/#{Regexp.quote(basename)}")
    rx_strict = Regexp.new("#{dirname_rx}/#{Regexp.quote(basename)}$")

    candidates = []
    candidates_strict = []
    packages.each do |pkg|
        name = pkg.name
        candidates << pkg if name =~ rx
        candidates_strict << pkg if name =~ rx_strict
    end

    if candidates.size > 1 && candidates_strict.size == 1
        candidates_strict
    else
        candidates
    end
end
initialize_from_workspace() click to toggle source
# File lib/autoproj/cli/locate.rb, line 100
def initialize_from_workspace
    initialize_and_load
    finalize_setup # this exports the manifest

    @packages = ws.manifest.each_autobuild_package.to_a
    @package_sets = ws.manifest.each_package_set.to_a
end
logs_of(selection, log: nil) click to toggle source

Resolve logs available for what points to the given selection

The workspace is resolved as the main configuration

If ‘log’ is nil and multiple logs are available,

# File lib/autoproj/cli/locate.rb, line 239
def logs_of(selection, log: nil)
    if workspace_dir?(selection) || (pkg_set = find_package_set(selection))
        return [] if log && log != "import"

        name = if pkg_set then pkg_set.name
               else
                   "autoproj main configuration"
               end

        import_log = File.join(ws.log_dir, "#{name}-import.log")
        if File.file?(import_log)
            [import_log]
        else
            []
        end
    else
        pkg = resolve_package(selection)
        Dir.enum_for(:glob, File.join(pkg.logdir, "#{pkg.name}-#{log || '*'}.log")).to_a
    end
end
prefix_dir_of(selection) click to toggle source

Returns the prefix directory for a given selection

@raise [NoSuchDir] if the selection points to a package set

# File lib/autoproj/cli/locate.rb, line 205
def prefix_dir_of(selection)
    if workspace_dir?(selection)
        ws.prefix_dir
    elsif find_package_set(selection)
        raise NoSuchDir, "#{selection} is a package set, and package sets do not have prefixes"
    else
        resolve_package(selection).prefix
    end
end
resolve_package(selection) click to toggle source

Resolve the package that matches a given selection

@return [PackageDefinition] @raise [CLIInvalidArguments] if nothing matches @raise [AmbiguousSelection] if the selection is ambiguous

# File lib/autoproj/cli/locate.rb, line 163
def resolve_package(selection)
    matching_packages = find_packages(selection)
    if matching_packages.empty?
        matching_packages = find_packages_with_directory_shortnames(selection)
    end

    if matching_packages.size > 1
        # If there is more than one candidate, check if there are some that are not
        # present on disk
        present = matching_packages.find_all { |pkg| File.directory?(pkg.srcdir) }
        matching_packages = present if present.size == 1
    end

    if matching_packages.empty?
        raise CLIInvalidArguments, "cannot find '#{selection}' in the current autoproj installation"
    elsif matching_packages.size > 1
        raise CLIAmbiguousArguments, "multiple packages match '#{selection}' in the current autoproj installation: #{matching_packages.map(&:name).sort.join(', ')}"
    else
        matching_packages.first
    end
end
run(selections, cache: !!packages, mode: :source_dir, log: nil) click to toggle source
# File lib/autoproj/cli/locate.rb, line 127
def run(selections, cache: !!packages, mode: :source_dir, log: nil)
    if !RESOLUTION_MODES.include?(mode)
        raise ArgumentError, "'#{mode}' was expected to be one of #{RESOLUTION_MODES}"
    elsif !cache
        initialize_from_workspace
    end

    selections.each do |string|
        string = "#{File.expand_path(string)}/" if File.directory?(string)
        if mode == :source_dir
            puts source_dir_of(string)
        elsif mode == :build_dir
            puts build_dir_of(string)
        elsif mode == :prefix_dir
            puts prefix_dir_of(string)
        elsif mode == :log
            if (all_logs = (log == "all"))
                log = nil
            end
            result = logs_of(string, log: log)
            if (result.size == 1) || all_logs
                result.each { |p| puts p }
            elsif result.size > 1
                puts select_log_file(result)
            elsif result.empty?
                raise NotFound, "no logs found for #{string}"
            end
        end
    end
end
select_log_file(log_files) click to toggle source

Interactively select a log file among a list

# File lib/autoproj/cli/locate.rb, line 261
def select_log_file(log_files)
    require "tty/prompt"

    log_files = log_files.map do |path|
        [path, File.stat(path).mtime]
    end.sort_by(&:last).reverse

    choices = Hash.new
    log_files.each do |path, mtime|
        if path =~ /-(\w+)\.log/
            choices["(#{mtime}) #{$1}"] = path
        else
            choices["(#{mtime}) #{path}"] = path
        end
    end

    prompt = TTY::Prompt.new
    begin
        prompt.select("Select the log file", choices)
    rescue TTY::Reader::InputInterrupt
        raise Interrupt
    end
end
source_dir_of(selection) click to toggle source

Returns the source directory for a given selection

# File lib/autoproj/cli/locate.rb, line 192
def source_dir_of(selection)
    if workspace_dir?(selection)
        ws.root_dir
    elsif (pkg_set = find_package_set(selection))
        pkg_set.user_local_dir
    else
        resolve_package(selection).srcdir
    end
end
try_loading_installation_manifest(ws = self.ws) click to toggle source

Load the installation manifest

# File lib/autoproj/cli/locate.rb, line 40
def try_loading_installation_manifest(ws = self.ws)
    Autoproj::InstallationManifest.from_workspace_root(ws.root_dir)
rescue ConfigError
end
update_from_installation_manifest(installation_manifest) click to toggle source
# File lib/autoproj/cli/locate.rb, line 34
def update_from_installation_manifest(installation_manifest)
    @packages = installation_manifest.each_package.to_a
    @package_sets = installation_manifest.each_package_set.to_a
end
validate_options(selections, options = Hash.new) click to toggle source
Calls superclass method Autoproj::CLI::Base#validate_options
# File lib/autoproj/cli/locate.rb, line 108
def validate_options(selections, options = Hash.new)
    selections, options = super
    mode = if options.delete(:build)
               :build_dir
           elsif options.delete(:prefix)
               :prefix_dir
           elsif (log_type = options[:log])
               options.delete(:log) if log_type == "log"
               :log
           else
               :source_dir
           end
    options[:mode] ||= mode
    selections << ws.root_dir if selections.empty?
    [selections, options]
end
workspace_dir?(selection) click to toggle source

Tests whether ‘selection’ points to one of the workspace’s root directories

# File lib/autoproj/cli/locate.rb, line 187
def workspace_dir?(selection)
    selection == "#{ws.root_dir}/" || selection == "#{ws.prefix_dir}/"
end