#!/usr/bin/env ruby # This test checks whether the packages create a dependency cycle. require 'find' require_relative '../lib/const' require_relative '../lib/color' require_relative '../lib/package' # Add >LOCAL< lib to LOAD_PATH so that packages can be loaded $LOAD_PATH.unshift File.join(CREW_LIB_PATH, 'lib') @all_pkgs = {} puts "Running dependency cycle tests...\n".yellow # Loads all packages Dir['../packages/*.rb'].each do |filename| name = File.basename(filename, '.rb') pkg = Package.load_package(filename) @all_pkgs[name] = pkg end # Looking for cycles. @path will keep the current dependency path. # @state will store :on_path for vertices on the current dependency path # and :visited for vertices that have already been checked not to lead to # cycles. @failed = 0 @state = {} @path = [] @uniq_path = [] def dfs(pkg) @path.push(pkg.name) case @state[pkg] when :on_path @path.shift while @path.first != @path.last if (!@uniq_path.include? @path.to_s) && @path.to_s.include?(',') @uniq_path.push(@path.to_s) @failed += 1 end when nil @state[pkg] = :on_path pkg.dependencies&.each_key do |name| dfs(@all_pkgs[name]) if name != pkg.name end @state[pkg] = :visited end @path.pop end # Calls dfs for every path @all_pkgs.each_value do |pkg| dfs(pkg) end # Display dependency cycles @uniq_path.sort.each do |path| puts path.lightred end @cycles = 'cycles' @cycles = 'cycle' if @failed == 1 if @failed.positive? abort "\n#{@failed} dependency #{@cycles} found.".lightred else puts "\nNo dependency cycles found.".lightgreen end