Skip to content

Commit

Permalink
Fix windows path issue (#4)
Browse files Browse the repository at this point in the history
* fix path error on windows

* update docs

* bump version

* update pipeline to run in other OS

* run cargo fmt
  • Loading branch information
Pistonight authored Nov 27, 2023
1 parent a91cc02 commit d370a77
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 43 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ on:
jobs:
build:
name: Check, Build, Test
runs-on: ubuntu-latest
strategy: { matrix: { os: [ ubuntu-latest, macos-latest, windows-latest ] } }
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: arduino/setup-task@v1
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "magoo"
version = "0.1.0"
version = "0.1.1"
edition = "2021"
description = "A wrapper for git submodule that simplifies the workflows"
repository = "https://github.com/Pistonite/magoo"
Expand Down
66 changes: 45 additions & 21 deletions src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@ impl GitContext {
} else {
let path = pathdiff::diff_paths(top_level_dir, &cwd)
.unwrap_or(top_level_dir.to_path_buf());
let diff = path.display().to_string();
let diff = path.to_cmd_arg();
Some(quote_arg(&diff).to_string())
}
}
Err(_) => {
let top_level = top_level_dir.display().to_string();
let top_level = top_level_dir.to_cmd_arg();
Some(quote_arg(&top_level).to_string())
}
};
Expand Down Expand Up @@ -212,7 +212,7 @@ impl GitContext {

/// Run `git -C top_level ls-files ...`
pub fn ls_files(&self, extra_args: &[&str]) -> Result<Vec<String>, GitError> {
let top_level_dir = self.top_level_dir()?.display().to_string();
let top_level_dir = self.top_level_dir()?.to_cmd_arg();
let mut args = vec!["-C", &top_level_dir, "ls-files"];
args.extend_from_slice(extra_args);
self.run_git_command(&args, false)
Expand All @@ -238,7 +238,7 @@ impl GitContext {
where
S: AsRef<Path>,
{
let config_path = config_path.as_ref().display().to_string();
let config_path = config_path.to_cmd_arg();
let value = self
.run_git_command(&["config", "-f", &config_path, "--get", key], false)?
.into_iter()
Expand All @@ -257,7 +257,7 @@ impl GitContext {
where
S: AsRef<Path>,
{
let config_path = config_path.as_ref().display().to_string();
let config_path = config_path.to_cmd_arg();
let name_and_values = self.run_git_command(
&["config", "-f", &config_path, "--get-regexp", regexp],
false,
Expand Down Expand Up @@ -303,7 +303,7 @@ impl GitContext {
where
S: AsRef<Path>,
{
let config_path = config_path.as_ref().display().to_string();
let config_path = config_path.to_cmd_arg();
let mut args = vec!["config", "-f", &config_path];
match value {
Some(v) => {
Expand All @@ -326,7 +326,7 @@ impl GitContext {
where
S: AsRef<Path>,
{
let config_path = config_path.as_ref().display().to_string();
let config_path = config_path.to_cmd_arg();
self.run_git_command(
&["config", "-f", &config_path, "--remove-section", section],
false,
Expand All @@ -336,7 +336,7 @@ impl GitContext {

/// Remove an object from the index and stage the change. The path should be relative from repo top level
pub fn remove_from_index(&self, path: &str) -> Result<(), GitError> {
let top_level_dir = self.top_level_dir()?.display().to_string();
let top_level_dir = self.top_level_dir()?.to_cmd_arg();

// ignore the error because the file might not be in the index
let _ = self.run_git_command(&["-C", &top_level_dir, "rm", path], false);
Expand All @@ -347,15 +347,15 @@ impl GitContext {

/// Run `git add`
pub fn add(&self, path: &str) -> Result<(), GitError> {
let top_level_dir = self.top_level_dir()?.display().to_string();
let top_level_dir = self.top_level_dir()?.to_cmd_arg();

self.run_git_command(&["-C", &top_level_dir, "add", path], false)?;
Ok(())
}

/// Runs `git submodule deinit [-- <path>]`. Path should be from top level
pub fn submodule_deinit(&self, path: Option<&str>, force: bool) -> Result<(), GitError> {
let top_level_dir = self.top_level_dir()?.display().to_string();
let top_level_dir = self.top_level_dir()?.to_cmd_arg();
let mut args = vec!["-C", &top_level_dir, "submodule", "deinit"];

if force {
Expand All @@ -375,7 +375,7 @@ impl GitContext {

/// Runs `git submodule init [-- <path>]`. Path should be from top level
pub fn submodule_init(&self, path: Option<&str>) -> Result<(), GitError> {
let top_level_dir = self.top_level_dir()?.display().to_string();
let top_level_dir = self.top_level_dir()?.to_cmd_arg();
let mut args = vec!["-C", &top_level_dir, "submodule", "init"];

if let Some(path) = path {
Expand All @@ -389,7 +389,7 @@ impl GitContext {

/// Runs `git submodule sync [-- <path>]`. Path should be from top level
pub fn submodule_sync(&self, path: Option<&str>) -> Result<(), GitError> {
let top_level_dir = self.top_level_dir()?.display().to_string();
let top_level_dir = self.top_level_dir()?.to_cmd_arg();
let mut args = vec!["-C", &top_level_dir, "submodule", "sync"];

if let Some(path) = path {
Expand All @@ -403,7 +403,7 @@ impl GitContext {

/// Runs `git submodule set-branch`. Path should be from top level
pub fn submodule_set_branch(&self, path: &str, branch: Option<&str>) -> Result<(), GitError> {
let top_level_dir = self.top_level_dir()?.display().to_string();
let top_level_dir = self.top_level_dir()?.to_cmd_arg();
let mut args = vec!["-C", &top_level_dir, "submodule", "set-branch"];
match branch {
Some(branch) => {
Expand All @@ -422,7 +422,7 @@ impl GitContext {

/// Runs `git submodule set-url`. Path should be from top level
pub fn submodule_set_url(&self, path: &str, url: &str) -> Result<(), GitError> {
let top_level_dir = self.top_level_dir()?.display().to_string();
let top_level_dir = self.top_level_dir()?.to_cmd_arg();
self.run_git_command(
&[
"-C",
Expand All @@ -445,7 +445,7 @@ impl GitContext {
force: bool,
remote: bool,
) -> Result<(), GitError> {
let top_level_dir = self.top_level_dir()?.display().to_string();
let top_level_dir = self.top_level_dir()?.to_cmd_arg();
let mut args = vec!["-C", &top_level_dir, "submodule", "update"];

if force {
Expand Down Expand Up @@ -475,7 +475,7 @@ impl GitContext {
depth: Option<usize>,
force: bool,
) -> Result<(), GitError> {
let top_level_dir = self.top_level_dir()?.display().to_string();
let top_level_dir = self.top_level_dir()?.to_cmd_arg();
let mut args = vec!["-C", &top_level_dir, "submodule", "add"];
if force {
args.push("--force");
Expand Down Expand Up @@ -517,7 +517,7 @@ impl Guard {
{
let path = path.as_ref();
if path.exists() {
println_warn!("Waiting on file lock. If you are sure no other magoo processes are running, you can remove the lock file `{}`", path.display());
println_warn!("Waiting on file lock. If you are sure no other magoo processes are running, you can remove the lock file `{}`", path.to_cmd_arg());
}
while path.exists() {
println_verbose!("Waiting for lock file...");
Expand All @@ -528,17 +528,17 @@ impl Guard {
.write(true)
.create(true)
.open(path)
.map_err(|e| GitError::LockFailed(path.display().to_string(), e))?;
.map_err(|e| GitError::LockFailed(path.to_cmd_arg(), e))?;
file.lock_exclusive()
.map_err(|e| GitError::LockFailed(path.display().to_string(), e))?;
println_verbose!("Acquired lock file `{}`", path.display());
.map_err(|e| GitError::LockFailed(path.to_cmd_arg(), e))?;
println_verbose!("Acquired lock file `{}`", path.to_cmd_arg());
Ok(Self(file, path.to_path_buf()))
}
}

impl Drop for Guard {
fn drop(&mut self) {
let path = &self.1.display();
let path = &self.1.to_cmd_arg();
println_verbose!("Releasing lock file `{path}`");
if self.0.unlock().is_err() {
println_verbose!("Failed to unlock file `{path}`");
Expand Down Expand Up @@ -602,6 +602,30 @@ where
}
}

/// Helper trait to clean a path to be used as command line argument
pub trait GitCmdPath {
fn to_cmd_arg(&self) -> String;
}

impl<S> GitCmdPath for S
where
S: AsRef<Path>,
{
#[cfg(not(windows))]
fn to_cmd_arg(&self) -> String {
self.as_ref().display().to_string()
}

#[cfg(windows)]
fn to_cmd_arg(&self) -> String {
let s = self.as_ref().display().to_string();
match s.strip_prefix(r"\\?\") {
Some(x) => x.to_string(),
None => s,
}
}
}

/// Quote the argument for shell.
pub fn quote_arg(s: &str) -> Cow<'_, str> {
// note that this implementation doesn't work in a few edge cases
Expand Down
28 changes: 11 additions & 17 deletions src/status.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
//! Logic for getting the status of submodules
use std::collections::BTreeMap;
use std::path::Path;

use crate::git::{GitContext, GitError};
use crate::git::{GitCmdPath, GitContext, GitError};
use crate::print::println_verbose;
use crate::submodule::*;

/// Data returned from [`GitContext::submodule_status`]
/// Status of all submodules in a repository
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Status {
/// The submodule status map from name to [`Submodule`]
Expand Down Expand Up @@ -37,9 +39,6 @@ macro_rules! insert_with_name {

impl Status {
/// Return a flattened view of all the submodules
///
/// If the status was created with the `--all` flag, it will also include the nameless
/// submodules
pub fn flattened(&self) -> Vec<&Submodule> {
let mut modules = self.modules.values().collect::<Vec<_>>();
for index_obj in &self.nameless {
Expand All @@ -49,9 +48,6 @@ impl Status {
}

/// Return a flattened view of all the submodules
///
/// If the status was created with the `--all` flag, it will also include the nameless
/// submodules
pub fn flattened_mut(&mut self) -> Vec<&mut Submodule> {
let mut modules = self.modules.values_mut().collect::<Vec<_>>();
for index_obj in self.nameless.iter_mut() {
Expand All @@ -61,9 +57,6 @@ impl Status {
}

/// Flattens the submodules into a vector of [`Submodule`]
///
/// If the status was created with the `--all` flag, it will also include the nameless
/// submodules
pub fn into_flattened(self) -> Vec<Submodule> {
let mut modules = self.modules.into_values().collect::<Vec<_>>();
for index_obj in self.nameless {
Expand All @@ -80,6 +73,7 @@ impl Status {
.collect()
}

/// Check if all submodules are healthy
pub fn is_healthy(&self, context: &GitContext) -> Result<bool, GitError> {
for submodule in self.flattened() {
if !submodule.is_healthy(context)? {
Expand All @@ -89,7 +83,7 @@ impl Status {
Ok(true)
}

/// Get the submodule status in the repository.
/// Factory function. Get the submodule status in the repository.
pub fn read_from(context: &GitContext) -> Result<Self, GitError> {
let mut status = Self::default();
status.read_dot_gitmodules(context)?;
Expand All @@ -107,7 +101,7 @@ impl Status {
let dot_gitmodules_path = top_level_dir.join(".gitmodules");

let config_entries =
Self::read_submodule_from_config(context, &dot_gitmodules_path.display().to_string())?;
Self::read_submodule_from_config(context, &dot_gitmodules_path.to_cmd_arg())?;

for (key, value) in config_entries {
let name = if let Some(name) = key.strip_suffix(".path") {
Expand Down Expand Up @@ -135,7 +129,7 @@ impl Status {

let config_entries = match Self::read_submodule_from_config(
context,
&dot_git_config_path.display().to_string(),
&dot_git_config_path.to_cmd_arg(),
) {
Ok(entries) => entries,
Err(e) => {
Expand Down Expand Up @@ -208,7 +202,7 @@ impl Status {
name: Option<&str>,
dir_path: &Path,
) {
println_verbose!("Scanning for git modules in `{}`", dir_path.display());
println_verbose!("Scanning for git modules in `{}`", dir_path.to_cmd_arg());
let config_path = dir_path.join("config");
if config_path.is_file() {
if let Some(name) = name {
Expand Down Expand Up @@ -239,7 +233,7 @@ impl Status {
// dir_path is not a module, recurse
let dir = match dir_path.read_dir() {
Err(e) => {
println_verbose!("Failed to read directory `{}`: {e}", dir_path.display());
println_verbose!("Failed to read directory `{}`: {e}", dir_path.to_cmd_arg());
return;
}
Ok(dir) => dir,
Expand All @@ -249,7 +243,7 @@ impl Status {
Err(e) => {
println_verbose!(
"Failed to read directory entry in `{}`: {e}",
dir_path.display()
dir_path.to_cmd_arg()
);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions src/submodule.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Submodule data and operations
use std::path::{Path, PathBuf};

use crate::git::{quote_arg, GitCanonicalize, GitContext, GitError};
use crate::git::{quote_arg, GitCanonicalize, GitCmdPath, GitContext, GitError};
use crate::print::{
print_info, print_warn, println_error, println_hint, println_info, println_verbose,
println_warn,
Expand Down Expand Up @@ -488,7 +490,7 @@ impl Submodule {
if worktree_path.exists() {
println_info!(
"Deleting the worktree of submodule `{name}` at `{}`",
worktree_path.display().to_string()
worktree_path.to_cmd_arg()
);
let _ = std::fs::remove_dir_all(worktree_path);
}
Expand Down

0 comments on commit d370a77

Please sign in to comment.