Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
D
DMP
Manage
Activity
Members
Labels
Plan
Issues
0
Issue boards
Milestones
Wiki
Code
Merge requests
2
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Equipe info plateforme CBI
DMP
Merge requests
!20
Draft: Rclone support
Code
Review changes
Check out branch
Download
Patches
Plain diff
Open
Draft: Rclone support
rclone
into
main
Overview
0
Commits
3
Pipelines
3
Changes
2
Open
Sasha
requested to merge
rclone
into
main
1 year ago
Overview
0
Commits
3
Pipelines
3
Changes
2
Expand
0
0
Merge request reports
Compare
main
version 2
13c55a04
1 year ago
version 1
12a99718
1 year ago
main (HEAD)
and
latest version
latest version
a28240b2
3 commits,
1 year ago
version 2
13c55a04
2 commits,
1 year ago
version 1
12a99718
1 commit,
1 year ago
2 files
+
102
−
1
Expand all files
Preferences
File browser
List view
Tree view
Compare changes
Inline
Side-by-side
Show whitespace changes
Show one file at a time
Search (e.g. *.vue) (Ctrl+P)
packages/backend/src/middleware/filesystem/rclone.rs
0 → 100644
+
101
−
0
Options
use
crate
::
result
::
Error
;
use
regex
::
Regex
;
use
std
::
io
::
BufRead
;
use
std
::
process
::{
Command
,
Stdio
};
use
which
::
which
;
/// Returns whether rclone is installed on the system or not
#[allow(dead_code)]
fn
is_rclone_installed
()
->
bool
{
match
which
(
"rclone"
)
{
Ok
(
_pathbuff
)
=>
true
,
Err
(
_error
)
=>
false
,
}
}
/// Uses rclone to copy files from a source to a destination path. Returns -1 if rclone is not installed and the usual rclone status code otherwise.
///
/// # Arguments
///
/// *`source` - The path of the folder we want to copy
///
/// *`destination` - The path of the destination folder
///
/// *`handle_function` - A function that receives the current progress percentage of the copy.
///
#[allow(dead_code)]
fn
rclone_with_progress
(
source
:
&
str
,
destination
:
&
str
,
handle_function
:
fn
(
usize
),
)
->
Result
<
i32
,
Error
>
{
if
!
is_rclone_installed
()
{
return
Err
(
Error
::
PackageNotInstalled
(
String
::
from
(
"rclone"
)));
}
//rclone copy -P -l --create-empty-src-dirs --transfers=12 --check-first <source> <destination>
let
mut
progress
=
Command
::
new
(
"rclone"
)
.args
([
"-lP"
,
"--create-empty-src-dirs"
,
"--transfers=12"
,
"--check-first"
,
"--stats-one-line"
,
source
,
destination
,
])
.stdout
(
Stdio
::
piped
())
.spawn
()
.unwrap
();
if
let
Some
(
progress
)
=
progress
.stdout
.take
()
{
let
reader
=
std
::
io
::
BufReader
::
new
(
progress
);
let
progress_percentage_regex
=
Regex
::
new
(
r"(\d+)%"
)
.unwrap
();
for
line
in
reader
.lines
()
.flatten
()
{
if
let
Some
(
progress_percentage
)
=
progress_percentage_regex
.find
(
&
line
)
{
let
mut
progress
=
progress_percentage
.as_str
()
.to_string
();
// Remove trailing %;
progress
.pop
();
handle_function
(
progress
.parse
::
<
usize
>
()
.unwrap
());
}
}
}
Ok
(
progress
.wait
()
.unwrap
()
.code
()
.unwrap
())
}
#[cfg(test)]
mod
tests
{
use
std
::
fs
;
use
std
::
fs
::
File
;
use
std
::
io
::
prelude
::
*
;
use
tempfile
::
tempdir
;
use
super
::
rclone_with_progress
;
#[test]
fn
test_rclone_with_progress
()
{
let
temp_source_dir
=
tempdir
()
.unwrap
();
let
temp_destination_dir
=
tempdir
()
.unwrap
();
for
i
in
1
..
1000
{
let
temp_file
=
temp_source_dir
.path
()
.join
(
format!
(
"{}"
,
i
));
let
mut
file
=
File
::
create
(
temp_file
)
.unwrap
();
file
.write_all
(
format!
(
"{}"
,
i
)
.as_bytes
())
.unwrap
();
}
let
handle_function
=
|
percentage
:
usize
|
println!
(
"{percentage}"
);
let
result
=
rclone_with_progress
(
temp_source_dir
.path
()
.to_str
()
.unwrap
(),
temp_destination_dir
.path
()
.to_str
()
.unwrap
(),
handle_function
,
);
assert_eq!
(
result
.unwrap
(),
0
);
let
destination_directory
=
temp_destination_dir
.path
()
.join
(
temp_source_dir
.path
());
for
i
in
1
..
1000
{
let
destination_file
=
destination_directory
.join
(
format!
(
"{}"
,
i
));
let
file_content
=
fs
::
read_to_string
(
destination_file
)
.unwrap
();
assert_eq!
(
file_content
,
format!
(
"{}"
,
i
));
}
drop
(
temp_source_dir
);
drop
(
temp_destination_dir
);
}
}