defmodule Mix.Tasks.CopyMibs do @shortdoc "Copies MIB files from source directory to app MIB directory" @moduledoc """ Copies MIB files from a source directory to the application's MIB directory. ## Usage # Copy all MIB files mix copy_mibs --source-path ~/mibs # Copy specific vendor MIB directories mix copy_mibs --source-path ~/mibs --vendors mikrotik,cisco,ubiquiti """ use Mix.Task require Logger def run(args) do {opts, _} = OptionParser.parse!(args, strict: [ source_path: :string, vendors: :string, target_dir: :string ] ) source_path = opts[:source_path] || raise "Missing --source-path argument" target_dir = opts[:target_dir] || get_default_target_dir() vendors = parse_vendors(opts[:vendors]) source_mibs = source_path if !File.exists?(source_mibs) do raise "LibreNMS MIB directory not found: #{source_mibs}" end # Ensure target directory exists File.mkdir_p!(target_dir) case vendors do :all -> copy_all_mibs(source_mibs, target_dir) vendor_list -> copy_vendor_mibs(source_mibs, target_dir, vendor_list) end end defp get_default_target_dir do # In development, use priv/mibs; in production use /app/mibs if Application.get_env(:towerops, :env) == :dev do Path.join([File.cwd!(), "priv", "mibs"]) else Application.get_env(:towerops, :mib_dir, "/app/mibs") end end defp parse_vendors(nil), do: :all defp parse_vendors(""), do: :all defp parse_vendors(vendors_string) do vendors_string |> String.split(",") |> Enum.map(&String.trim/1) |> Enum.reject(&(&1 == "")) end defp copy_all_mibs(source_dir, target_dir) do Logger.info("Copying all MIB files from #{source_dir} to #{target_dir}...") # Use rsync for efficient copying case System.cmd("rsync", ["-av", "--exclude=.git", "#{source_dir}/", target_dir]) do {output, 0} -> Logger.info("Successfully copied MIB files") Logger.debug(output) :ok {error, exit_code} -> Logger.error("Failed to copy MIB files (exit code #{exit_code}): #{error}") {:error, :copy_failed} end rescue _e in ErlangError -> # rsync not found, fall back to File.cp_r Logger.warning("rsync not found, using File.cp_r (slower)") copy_mibs_recursive(source_dir, target_dir) end defp copy_vendor_mibs(source_dir, target_dir, vendors) do Logger.info("Copying MIB files for vendors: #{Enum.join(vendors, ", ")}") results = Enum.map(vendors, fn vendor -> source_path = Path.join(source_dir, vendor) target_path = Path.join(target_dir, vendor) if File.exists?(source_path) do Logger.info("Copying #{vendor} MIBs...") File.mkdir_p!(target_path) _ = File.cp_r!(source_path, target_path) {:ok, vendor} else Logger.warning("Vendor MIB directory not found: #{vendor}") {:error, vendor} end end) successes = Enum.count(results, &match?({:ok, _}, &1)) failures = Enum.count(results, &match?({:error, _}, &1)) Logger.info("Copied #{successes} vendor MIB directories (#{failures} not found)") end defp copy_mibs_recursive(source_dir, target_dir) do case File.cp_r(source_dir, target_dir) do {:ok, _files} -> Logger.info("Successfully copied MIB files") :ok {:error, reason, file} -> Logger.error("Failed to copy #{file}: #{inspect(reason)}") {:error, :copy_failed} end end end