Skip to content

Commit deb6073

Browse files
committed
Assure basic 'organize' operation is working as expected
1 parent 800a2f4 commit deb6073

File tree

7 files changed

+82
-17
lines changed

7 files changed

+82
-17
lines changed

git-features/src/fs.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
///
1111
pub mod walkdir {
1212
pub use jwalk::{DirEntry as DirEntryGeneric, Error, WalkDir};
13-
use std::path::PathBuf;
13+
use std::path::{Path, PathBuf};
1414

1515
/// An alias for an uncustomized directory entry to match the one of the non-parallel version offered by `walkdir`.
1616
pub type DirEntry = DirEntryGeneric<((), ())>;
@@ -24,12 +24,17 @@ pub mod walkdir {
2424
pub fn direntry_path(entry: &DirEntry) -> PathBuf {
2525
entry.path()
2626
}
27+
28+
/// Instantiate a new directory iterator which will not skip hidden files.
29+
pub fn walkdir_new(root: impl AsRef<Path>) -> WalkDir {
30+
WalkDir::new(root).skip_hidden(false)
31+
}
2732
}
2833

2934
#[cfg(not(feature = "parallel"))]
3035
///
3136
pub mod walkdir {
32-
use std::path::PathBuf;
37+
use std::path::{Path, PathBuf};
3338
pub use walkdir::{DirEntry, Error, WalkDir};
3439

3540
/// Enable sorting by filename
@@ -41,6 +46,11 @@ pub mod walkdir {
4146
pub fn direntry_path(entry: &DirEntry) -> PathBuf {
4247
entry.path().to_owned()
4348
}
49+
50+
/// Instantiate a new directory iterator which will not skip hidden files.
51+
pub fn walkdir_new(root: impl AsRef<Path>) -> WalkDir {
52+
WalkDir::new(root)
53+
}
4454
}
4555

46-
pub use self::walkdir::{direntry_path, sorted, DirEntry, WalkDir};
56+
pub use self::walkdir::{direntry_path, sorted, walkdir_new, DirEntry, WalkDir};

gitoxide-core/src/organize.rs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,15 @@ fn find_git_repository_workdirs(root: impl AsRef<Path>, mut progress: impl Progr
3434
}
3535
}
3636

37-
let walk = fs::sorted(fs::WalkDir::new(root).follow_links(false));
37+
let walk = fs::sorted(fs::walkdir_new(root).follow_links(false));
3838
walk.into_iter()
3939
.filter_map(move |entry| {
4040
progress.step();
4141
match entry {
4242
Ok(entry) => Some(entry),
43-
Err(err) => {
44-
progress.fail(format!("Ignored: {}", err.to_string()));
43+
Err(_err) => {
44+
// TODO: remove this line once we properly ignore git repository - they get moved
45+
// progress.fail(format!("Ignored: {}", _err.to_string()));
4546
None
4647
}
4748
}
@@ -69,10 +70,15 @@ fn find_origin_remote(repo: &Path) -> anyhow::Result<Option<git_url::Url>> {
6970
}
7071
}
7172

72-
fn handle(mode: Mode, git_workdir: &Path, destination: &Path, progress: &mut impl Progress) -> anyhow::Result<()> {
73+
fn handle(
74+
mode: Mode,
75+
git_workdir: &Path,
76+
canonicalized_destination: &Path,
77+
progress: &mut impl Progress,
78+
) -> anyhow::Result<()> {
7379
fn to_relative(path: PathBuf) -> PathBuf {
74-
std::iter::once(std::path::Component::CurDir)
75-
.chain(path.components())
80+
path.components()
81+
.skip_while(|c| c == &std::path::Component::RootDir)
7682
.collect()
7783
}
7884

@@ -95,16 +101,30 @@ fn handle(mode: Mode, git_workdir: &Path, destination: &Path, progress: &mut imp
95101
return Ok(());
96102
}
97103

98-
let destination = destination.join(to_relative(git_url::expand_path(None, url.path.as_bstr())?));
104+
let destination = canonicalized_destination
105+
.join(
106+
url.host
107+
.as_ref()
108+
.ok_or_else(|| anyhow::Error::msg(format!("Remote URLs must have host names: {}", url)))?,
109+
)
110+
.join(to_relative(git_url::expand_path(None, url.path.as_bstr())?));
99111
match mode {
100112
Mode::Simulate => progress.info(format!(
101113
"WOULD move {} to {}",
102114
git_workdir.display(),
103115
destination.display()
104116
)),
105117
Mode::Execute => {
106-
std::fs::rename(git_workdir, &destination)?;
107-
progress.info(format!("Moved {} to {}", git_workdir.display(), destination.display()))
118+
if git_workdir.canonicalize()? == destination {
119+
progress.info(format!(
120+
"Skipping {:?} as it is in the correct spot",
121+
git_workdir.display()
122+
));
123+
} else {
124+
std::fs::create_dir_all(destination.parent().expect("repo destination is not the root"))?;
125+
progress.info(format!("Moving {} to {}", git_workdir.display(), destination.display()));
126+
std::fs::rename(git_workdir, &destination)?;
127+
}
108128
}
109129
}
110130
Ok(())
@@ -114,6 +134,7 @@ pub fn run(mode: Mode, source_dir: PathBuf, destination: PathBuf, mut progress:
114134
let search_progress = progress.add_child("Searching repositories");
115135

116136
let mut num_errors = 0usize;
137+
let destination = destination.canonicalize()?;
117138
for path_to_move in find_git_repository_workdirs(source_dir, search_progress) {
118139
if let Err(err) = handle(mode, &path_to_move, &destination, &mut progress) {
119140
progress.fail(format!(

src/porcelain/lean.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ pub fn main() -> Result<()> {
7373
} else {
7474
organize::Mode::Simulate
7575
},
76-
repository_source.unwrap_or_else(|| std::env::current_dir().expect("CWD as default source")),
77-
destination_directory.unwrap_or_else(|| std::env::current_dir().expect("CWD as default destination")),
76+
repository_source.unwrap_or_else(|| [std::path::Component::CurDir].iter().collect()),
77+
destination_directory.unwrap_or_else(|| [std::path::Component::CurDir].iter().collect()),
7878
DoOrDiscard::from(progress),
7979
)
8080
}

src/porcelain/pretty.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,8 @@ pub fn main() -> Result<()> {
7878
} else {
7979
organize::Mode::Simulate
8080
},
81-
repository_source.unwrap_or_else(|| std::env::current_dir().expect("CWD as default source")),
82-
destination_directory
83-
.unwrap_or_else(|| std::env::current_dir().expect("CWD as default destination")),
81+
repository_source.unwrap_or_else(|| [std::path::Component::CurDir].iter().collect()),
82+
destination_directory.unwrap_or_else(|| [std::path::Component::CurDir].iter().collect()),
8483
DoOrDiscard::from(progress),
8584
)
8685
},
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.
2+
├── dir
3+
│   └── one-origin
4+
├── example.com
5+
│   ├── one-origin
6+
│   └── origin-and-fork
7+
├── no-origin
8+
├── origin-and-fork
9+
└── special-origin
10+
11+
8 directories, 0 files

tests/snapshots/organize/execute-success

Whitespace-only changes.

tests/stateless-journey.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,30 @@ title "Porcelain ${kind}"
6262
expect_run $SUCCESSFULLY tree -L 2
6363
}
6464
)
65+
66+
(when "running with --execute"
67+
it "succeeds" && {
68+
WITH_SNAPSHOT="$snapshot/execute-success" \
69+
expect_run_sh $SUCCESSFULLY "$exe organize --execute 2>/dev/null"
70+
}
71+
72+
it "changes the directory structure" && {
73+
WITH_SNAPSHOT="$snapshot/directory-structure-after-organize" \
74+
expect_run $SUCCESSFULLY tree -L 2
75+
}
76+
)
77+
78+
(when "running with --execute again"
79+
it "succeeds" && {
80+
WITH_SNAPSHOT="$snapshot/execute-success" \
81+
expect_run_sh $SUCCESSFULLY "$exe organize --execute 2>/dev/null"
82+
}
83+
84+
it "does not alter the directory structure as these are already in place" && {
85+
WITH_SNAPSHOT="$snapshot/directory-structure-after-organize" \
86+
expect_run $SUCCESSFULLY tree -L 2
87+
}
88+
)
6589
)
6690
)
6791
)

0 commit comments

Comments
 (0)