<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::{fs::File, io::Read, path::PathBuf};

use libmount;
use nix::mount::{umount2, MntFlags};

use devicemapper::{DevId, DmOptions};

use crate::engine::strat_engine::{
    cmd,
    dm::{get_dm, get_dm_init},
};

// For an explanation see:
// https://github.com/rust-lang-nursery/error-chain/issues/254.
// FIXME: Drop dependence on error-chain entirely.
#[allow(deprecated)]
mod cleanup_errors {
    use libmount;
    use nix;
    use std;

    error_chain! {
        foreign_links {
            Ioe(std::io::Error);
            Mnt(libmount::mountinfo::ParseError);
            Nix(nix::Error);
        }
    }
}

use self::cleanup_errors::{Error, Result};

/// Attempt to remove all device mapper devices which match the stratis naming convention.
/// FIXME: Current implementation complicated by https://bugzilla.redhat.com/show_bug.cgi?id=1506287
fn dm_stratis_devices_remove() -> Result<()> {
    /// One iteration of removing devicemapper devices
    fn one_iteration() -> Result<(bool, Vec<String>)> {
        let mut progress_made = false;
        let mut remain = Vec::new();

        for n in get_dm()
            .list_devices()
            .map_err(|e| {
                let err_msg = "failed while listing DM devices, giving up";
                Error::with_chain(e, err_msg)
            })?
            .iter()
            .map(|d| &d.0)
            .filter(|n| n.to_string().starts_with("stratis-1"))
        {
            match get_dm().device_remove(&DevId::Name(n), &DmOptions::new()) {
                Ok(_) => progress_made = true,
                Err(_) => remain.push(n.to_string()),
            }
        }
        Ok((progress_made, remain))
    }

    /// Do one iteration of removals until progress stops. Return remaining
    /// dm devices.
    fn do_while_progress() -> Result<Vec<String>> {
        let mut result = one_iteration()?;
        while result.0 {
            result = one_iteration()?;
        }
        Ok(result.1)
    }

    || -> Result<()> {
        cmd::udev_settle().unwrap();
        get_dm_init().map_err(|err| Error::with_chain(err, "Unable to initialize DM"))?;
        do_while_progress().and_then(|remain| {
            if !remain.is_empty() {
                Err(format!("Some Stratis DM devices remaining: {:?}", remain).into())
            } else {
                Ok(())
            }
        })
    }()
    .map_err(|e| e.chain_err(|| "Failed to ensure removal of all Stratis DM devices"))
}

/// Try and un-mount any filesystems that have the name stratis in the mount point, returning
/// immediately on the first one we are unable to unmount.
fn stratis_filesystems_unmount() -> Result<()> {
    || -> Result<()> {<commit_msg>Tidy up imports in tests submodule<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::{fs::File, io::Read, path::PathBuf};

use libmount;
use nix::mount::{umount2, MntFlags};

use devicemapper::{DevId, DmOptions};

use crate::engine::strat_engine::{
    cmd::udev_settle,
    dm::{get_dm, get_dm_init},
};

// For an explanation see:
// https://github.com/rust-lang-nursery/error-chain/issues/254.
// FIXME: Drop dependence on error-chain entirely.
#[allow(deprecated)]
mod cleanup_errors {
    use libmount;
    use nix;
    use std;

    error_chain! {
        foreign_links {
            Ioe(std::io::Error);
            Mnt(libmount::mountinfo::ParseError);
            Nix(nix::Error);
        }
    }
}

use self::cleanup_errors::{Error, Result};

/// Attempt to remove all device mapper devices which match the stratis naming convention.
/// FIXME: Current implementation complicated by https://bugzilla.redhat.com/show_bug.cgi?id=1506287
fn dm_stratis_devices_remove() -> Result<()> {
    /// One iteration of removing devicemapper devices
    fn one_iteration() -> Result<(bool, Vec<String>)> {
        let mut progress_made = false;
        let mut remain = Vec::new();

        for n in get_dm()
            .list_devices()
            .map_err(|e| {
                let err_msg = "failed while listing DM devices, giving up";
                Error::with_chain(e, err_msg)
            })?
            .iter()
            .map(|d| &d.0)
            .filter(|n| n.to_string().starts_with("stratis-1"))
        {
            match get_dm().device_remove(&DevId::Name(n), &DmOptions::new()) {
                Ok(_) => progress_made = true,
                Err(_) => remain.push(n.to_string()),
            }
        }
        Ok((progress_made, remain))
    }

    /// Do one iteration of removals until progress stops. Return remaining
    /// dm devices.
    fn do_while_progress() -> Result<Vec<String>> {
        let mut result = one_iteration()?;
        while result.0 {
            result = one_iteration()?;
        }
        Ok(result.1)
    }

    || -> Result<()> {
        udev_settle().unwrap();
        get_dm_init().map_err(|err| Error::with_chain(err, "Unable to initialize DM"))?;
        do_while_progress().and_then(|remain| {
            if !remain.is_empty() {
                Err(format!("Some Stratis DM devices remaining: {:?}", remain).into())
            } else {
                Ok(())
            }
        })
    }()
    .map_err(|e| e.chain_err(|| "Failed to ensure removal of all Stratis DM devices"))
}

/// Try and un-mount any filesystems that have the name stratis in the mount point, returning
/// immediately on the first one we are unable to unmount.
fn stratis_filesystems_unmount() -> Result<()> {
    || -> Result<()> {
{'fraction_non_alphanumeric': 0.1424910302409021, 'fraction_numerical': 0.006492397061336067, 'mean_word_length': 2.3261363636363637, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 35, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '806413', 'n_tokens_mistral': 1838, 'n_tokens_neox': 1801, 'n_words': 475}