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

fix: update windows for new changes #38

Merged
merged 6 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
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
1 change: 1 addition & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
- s390x-unknown-linux-gnu
- aarch64-apple-darwin
- x86_64-apple-darwin
- x86_64-pc-windows-gnu
runs-on: ${{ (matrix.target == 'aarch64-apple-darwin' || matrix.target == 'x86_64-apple-darwin') && 'macos-latest' || 'ubuntu-latest' }}
steps:
- name: Checkout repository
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
- s390x-unknown-linux-gnu
- aarch64-apple-darwin
- x86_64-apple-darwin
# - x86_64-pc-windows-gnu
- x86_64-pc-windows-gnu
runs-on: ${{ (matrix.target == 'aarch64-apple-darwin' || matrix.target == 'x86_64-apple-darwin') && 'macos-latest' || 'ubuntu-latest' }}
steps:
- name: Checkout repository
Expand Down
18 changes: 5 additions & 13 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use clap::{Parser, ValueEnum};
use clap_verbosity_flag::{Verbosity, WarnLevel};
use core::fmt;
use nix::sys::signal::Signal;
use std::str::FromStr;

use crate::signal::KillportSignal;

/// Modes of operation for killport.
#[derive(Debug, Clone, Copy, PartialEq, ValueEnum)]
Expand Down Expand Up @@ -67,7 +67,7 @@ pub struct KillPortArgs {
default_value = "sigkill",
value_parser = parse_signal
)]
pub signal: Signal,
pub signal: KillportSignal,

/// A verbosity flag to control the level of logging output.
#[command(flatten)]
Expand All @@ -81,14 +81,6 @@ pub struct KillPortArgs {
pub dry_run: bool,
}

fn parse_signal(arg: &str) -> Result<Signal, std::io::Error> {
let str_arg = arg.parse::<String>();
match str_arg {
Ok(str_arg) => {
let signal_str = str_arg.to_uppercase();
let signal = Signal::from_str(signal_str.as_str())?;
return Ok(signal);
}
Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e)),
}
fn parse_signal(arg: &str) -> Result<KillportSignal, std::io::Error> {
arg.to_uppercase().parse()
}
10 changes: 3 additions & 7 deletions src/docker.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::signal::KillportSignal;
use bollard::container::{KillContainerOptions, ListContainersOptions};
use bollard::Docker;
use log::debug;
use nix::sys::signal::Signal;
use std::collections::HashMap;
use std::io::Error;
use tokio::runtime::Runtime;
Expand All @@ -17,7 +17,7 @@ impl DockerContainer {
///
/// * `name` - A container name.
/// * `signal` - A enum value representing the signal type.
pub fn kill_container(name: &String, signal: Signal) -> Result<(), Error> {
pub fn kill_container(name: &str, signal: KillportSignal) -> Result<(), Error> {
let rt = Runtime::new()?;
rt.block_on(async {
let docker = Docker::connect_with_socket_defaults()
Expand Down Expand Up @@ -63,11 +63,7 @@ impl DockerContainer {
.as_ref()?
.first()
.map(|name| DockerContainer {
name: if name.starts_with('/') {
name[1..].to_string()
} else {
name.clone()
},
name: name.strip_prefix('/').unwrap_or(name).to_string(),
})
})
.collect())
Expand Down
93 changes: 31 additions & 62 deletions src/killport.rs
Original file line number Diff line number Diff line change
@@ -1,64 +1,34 @@
use crate::cli::Mode;
use crate::docker::DockerContainer;
#[cfg(target_os = "linux")]
use crate::linux::find_target_processes;
#[cfg(target_os = "macos")]
use crate::macos::find_target_processes;
use log::info;
use nix::sys::signal::{kill, Signal};
use nix::unistd::Pid;
use std::io::Error;

#[derive(Debug)]
pub struct NativeProcess {
/// System native process ID.
pub pid: Pid,
pub name: String,
}
#[cfg(target_os = "windows")]
use crate::windows::find_target_processes;
use crate::{cli::Mode, signal::KillportSignal};
use std::{fmt::Display, io::Error};

/// Interface for killable targets such as native process and docker container.
pub trait Killable {
fn kill(&self, signal: Signal) -> Result<bool, Error>;
fn get_type(&self) -> String;
fn kill(&self, signal: KillportSignal) -> Result<bool, Error>;

fn get_type(&self) -> KillableType;

fn get_name(&self) -> String;
}

impl Killable for NativeProcess {
/// Entry point to kill the linux native process.
///
/// # Arguments
///
/// * `signal` - A enum value representing the signal type.
fn kill(&self, signal: Signal) -> Result<bool, Error> {
info!("Killing process '{}' with PID {}", self.name, self.pid);

kill(self.pid, signal).map(|_| true).map_err(|e| {
Error::new(
std::io::ErrorKind::Other,
format!(
"Failed to kill process '{}' with PID {}: {}",
self.name, self.pid, e
),
)
})
}

/// Returns the type of the killable target.
///
/// This method is used to identify the type of the target (either a native process or a Docker container)
/// that is being handled. This information can be useful for logging, error handling, or other needs
/// where type of the target is relevant.
///
/// # Returns
///
/// * `String` - A string that describes the type of the killable target. For a `NativeProcess` it will return "process",
/// and for a `DockerContainer` it will return "container".
fn get_type(&self) -> String {
"process".to_string()
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum KillableType {
Process,
Container,
}

fn get_name(&self) -> String {
self.name.to_string()
impl Display for KillableType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
KillableType::Process => "process",
KillableType::Container => "container",
})
}
}

Expand All @@ -68,10 +38,8 @@ impl Killable for DockerContainer {
/// # Arguments
///
/// * `signal` - A enum value representing the signal type.
fn kill(&self, signal: Signal) -> Result<bool, Error> {
if let Err(err) = Self::kill_container(&self.name, signal) {
return Err(err);
}
fn kill(&self, signal: KillportSignal) -> Result<bool, Error> {
Self::kill_container(&self.name, signal)?;

Ok(true)
}
Expand All @@ -84,10 +52,10 @@ impl Killable for DockerContainer {
///
/// # Returns
///
/// * `String` - A string that describes the type of the killable target. For a `NativeProcess` it will return "process",
/// * `String` - A string that describes the type of the killable target. For a `UnixProcess` it will return "process",
/// and for a `DockerContainer` it will return "container".
fn get_type(&self) -> String {
"container".to_string()
fn get_type(&self) -> KillableType {
KillableType::Container
}

fn get_name(&self) -> String {
Expand All @@ -104,10 +72,10 @@ pub trait KillportOperations {
fn kill_service_by_port(
&self,
port: u16,
signal: Signal,
signal: KillportSignal,
mode: Mode,
dry_run: bool,
) -> Result<Vec<(String, String)>, Error>;
) -> Result<Vec<(KillableType, String)>, Error>;
}

pub struct Killport;
Expand All @@ -133,9 +101,10 @@ impl KillportOperations for Killport {

for process in target_processes {
// Check if the process name contains 'docker' and skip if in docker mode
if docker_present && process.name.to_lowercase().contains("docker") {
if docker_present && process.get_name().to_lowercase().contains("docker") {
continue;
jacobtread marked this conversation as resolved.
Show resolved Hide resolved
}

target_killables.push(Box::new(process));
}
}
Expand Down Expand Up @@ -166,10 +135,10 @@ impl KillportOperations for Killport {
fn kill_service_by_port(
&self,
port: u16,
signal: Signal,
signal: KillportSignal,
mode: Mode,
dry_run: bool,
) -> Result<Vec<(String, String)>, Error> {
) -> Result<Vec<(KillableType, String)>, Error> {
let mut results = Vec::new();
let target_killables = self.find_target_killables(port, mode)?; // Use the existing function to find targets

Expand All @@ -179,7 +148,7 @@ impl KillportOperations for Killport {
results.push((killable.get_type(), killable.get_name()));
} else {
// In actual mode, attempt to kill the entity and collect its information if successful
if killable.kill(signal)? {
if killable.kill(signal.clone())? {
results.push((killable.get_type(), killable.get_name()));
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
pub mod cli;
pub mod docker;
pub mod killport;
pub mod signal;

#[cfg(unix)]
pub mod unix;

#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "macos")]
Expand Down
11 changes: 4 additions & 7 deletions src/linux.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::killport::NativeProcess;
use crate::unix::UnixProcess;

use log::debug;
use nix::unistd::Pid;
Expand Down Expand Up @@ -75,8 +75,8 @@ fn find_target_inodes(port: u16) -> Vec<u64> {
/// # Arguments
///
/// * `inodes` - Target inodes
pub fn find_target_processes(port: u16) -> Result<Vec<NativeProcess>, Error> {
let mut target_pids: Vec<NativeProcess> = vec![];
pub fn find_target_processes(port: u16) -> Result<Vec<UnixProcess>, Error> {
let mut target_pids: Vec<UnixProcess> = vec![];
let inodes = find_target_inodes(port);

for inode in inodes {
Expand All @@ -96,10 +96,7 @@ pub fn find_target_processes(port: u16) -> Result<Vec<NativeProcess>, Error> {
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?
.join(" ");
debug!("Found process '{}' with PID {}", name, process.pid());
target_pids.push(NativeProcess {
pid: Pid::from_raw(process.pid),
name: name,
});
target_pids.push(UnixProcess::new(Pid::from_raw(process.pid), name));
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/macos.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::killport::NativeProcess;
use crate::unix::UnixProcess;

use libproc::libproc::file_info::pidfdinfo;
use libproc::libproc::file_info::{ListFDs, ProcFDType};
Expand All @@ -16,8 +16,8 @@ use std::io;
/// # Arguments
///
/// * `port` - Target port number
pub fn find_target_processes(port: u16) -> Result<Vec<NativeProcess>, io::Error> {
let mut target_pids: Vec<NativeProcess> = vec![];
pub fn find_target_processes(port: u16) -> Result<Vec<UnixProcess>, io::Error> {
let mut target_pids: Vec<UnixProcess> = vec![];

if let Ok(procs) = pids_by_type(ProcFilter::All) {
for p in procs {
Expand Down Expand Up @@ -56,10 +56,10 @@ pub fn find_target_processes(port: u16) -> Result<Vec<NativeProcess>, io::Error>
"Found process '{}' with PID {} listening on port {}",
process_name, pid, port
);
target_pids.push(NativeProcess {
pid: Pid::from_raw(pid),
name: process_name,
});
target_pids.push(UnixProcess::new(
Pid::from_raw(pid),
process_name,
));
}
}
_ => (),
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fn main() {

// Attempt to kill processes listening on specified ports
for port in args.ports {
match killport.kill_service_by_port(port, args.signal, args.mode, args.dry_run) {
match killport.kill_service_by_port(port, args.signal.clone(), args.mode, args.dry_run) {
Ok(killed_services) => {
if killed_services.is_empty() {
println!("No {} found using port {}", service_type_singular, port);
Expand Down
35 changes: 35 additions & 0 deletions src/signal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//! Wrapper around signals for platforms that they are not supported on

use std::{fmt::Display, str::FromStr};

#[cfg(unix)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KillportSignal(pub nix::sys::signal::Signal);

/// On a platform where we don't have the proper signals enum
#[cfg(not(unix))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KillportSignal(pub String);

impl Display for KillportSignal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)
}
}

impl FromStr for KillportSignal {
type Err = std::io::Error;

fn from_str(value: &str) -> Result<Self, Self::Err> {
#[cfg(unix)]
{
let signal = nix::sys::signal::Signal::from_str(value)?;
Ok(KillportSignal(signal))
}

#[cfg(not(unix))]
{
Ok(KillportSignal(value.to_string()))
}
}
}
Loading
Loading