Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
8a757ae2
Commit
8a757ae2
authored
Apr 04, 2020
by
Edward Thomson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cli: introduce a clone command
parent
7babe76f
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
201 additions
and
23 deletions
+201
-23
src/cli/cmd.h
+1
-0
src/cli/cmd_clone.c
+176
-0
src/cli/main.c
+1
-0
src/cli/progress.c
+19
-19
src/cli/progress.h
+4
-4
No files found.
src/cli/cmd.h
View file @
8a757ae2
...
@@ -26,6 +26,7 @@ extern const cli_cmd_spec *cli_cmd_spec_byname(const char *name);
...
@@ -26,6 +26,7 @@ extern const cli_cmd_spec *cli_cmd_spec_byname(const char *name);
/* Commands */
/* Commands */
extern
int
cmd_cat_file
(
int
argc
,
char
**
argv
);
extern
int
cmd_cat_file
(
int
argc
,
char
**
argv
);
extern
int
cmd_clone
(
int
argc
,
char
**
argv
);
extern
int
cmd_hash_object
(
int
argc
,
char
**
argv
);
extern
int
cmd_hash_object
(
int
argc
,
char
**
argv
);
extern
int
cmd_help
(
int
argc
,
char
**
argv
);
extern
int
cmd_help
(
int
argc
,
char
**
argv
);
...
...
src/cli/cmd_clone.c
0 → 100644
View file @
8a757ae2
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include <stdio.h>
#include <git2.h>
#include "cli.h"
#include "cmd.h"
#include "error.h"
#include "sighandler.h"
#include "progress.h"
#include "fs_path.h"
#include "futils.h"
#define COMMAND_NAME "clone"
static
char
*
branch
,
*
remote_path
,
*
local_path
;
static
int
show_help
,
quiet
,
checkout
=
1
,
bare
;
static
bool
local_path_exists
;
static
cli_progress
progress
=
CLI_PROGRESS_INIT
;
static
const
cli_opt_spec
opts
[]
=
{
{
CLI_OPT_TYPE_SWITCH
,
"help"
,
0
,
&
show_help
,
1
,
CLI_OPT_USAGE_HIDDEN
|
CLI_OPT_USAGE_STOP_PARSING
,
NULL
,
"display help about the "
COMMAND_NAME
" command"
},
{
CLI_OPT_TYPE_SWITCH
,
"quiet"
,
'q'
,
&
quiet
,
1
,
CLI_OPT_USAGE_DEFAULT
,
NULL
,
"display the type of the object"
},
{
CLI_OPT_TYPE_SWITCH
,
"no-checkout"
,
'n'
,
&
checkout
,
0
,
CLI_OPT_USAGE_DEFAULT
,
NULL
,
"don't checkout HEAD"
},
{
CLI_OPT_TYPE_SWITCH
,
"bare"
,
0
,
&
bare
,
1
,
CLI_OPT_USAGE_DEFAULT
,
NULL
,
"don't create a working directory"
},
{
CLI_OPT_TYPE_VALUE
,
"branch"
,
'b'
,
&
branch
,
0
,
CLI_OPT_USAGE_DEFAULT
,
"name"
,
"branch to check out"
},
{
CLI_OPT_TYPE_LITERAL
},
{
CLI_OPT_TYPE_ARG
,
"repository"
,
0
,
&
remote_path
,
0
,
CLI_OPT_USAGE_REQUIRED
,
"repository"
,
"repository path"
},
{
CLI_OPT_TYPE_ARG
,
"directory"
,
0
,
&
local_path
,
0
,
CLI_OPT_USAGE_DEFAULT
,
"directory"
,
"directory to clone into"
},
{
0
}
};
static
void
print_help
(
void
)
{
cli_opt_usage_fprint
(
stdout
,
PROGRAM_NAME
,
COMMAND_NAME
,
opts
);
printf
(
"
\n
"
);
printf
(
"Clone a repository into a new directory.
\n
"
);
printf
(
"
\n
"
);
printf
(
"Options:
\n
"
);
cli_opt_help_fprint
(
stdout
,
opts
);
}
static
char
*
compute_local_path
(
const
char
*
orig_path
)
{
const
char
*
slash
;
char
*
local_path
;
if
((
slash
=
strrchr
(
orig_path
,
'/'
))
==
NULL
&&
(
slash
=
strrchr
(
orig_path
,
'\\'
))
==
NULL
)
local_path
=
git__strdup
(
orig_path
);
else
local_path
=
git__strdup
(
slash
+
1
);
return
local_path
;
}
static
bool
validate_local_path
(
const
char
*
path
)
{
if
(
!
git_fs_path_exists
(
path
))
return
false
;
if
(
!
git_fs_path_isdir
(
path
)
||
!
git_fs_path_is_empty_dir
(
path
))
{
fprintf
(
stderr
,
"fatal: destination path '%s' already exists and is not an empty directory.
\n
"
,
path
);
exit
(
128
);
}
return
true
;
}
static
void
cleanup
(
void
)
{
int
rmdir_flags
=
GIT_RMDIR_REMOVE_FILES
;
cli_progress_abort
(
&
progress
);
if
(
local_path_exists
)
rmdir_flags
|=
GIT_RMDIR_SKIP_ROOT
;
if
(
!
git_fs_path_isdir
(
local_path
))
return
;
git_futils_rmdir_r
(
local_path
,
NULL
,
rmdir_flags
);
}
static
void
interrupt_cleanup
(
void
)
{
cleanup
();
exit
(
130
);
}
int
cmd_clone
(
int
argc
,
char
**
argv
)
{
git_clone_options
clone_opts
=
GIT_CLONE_OPTIONS_INIT
;
git_repository
*
repo
=
NULL
;
cli_opt
invalid_opt
;
char
*
computed_path
=
NULL
;
int
ret
=
0
;
if
(
cli_opt_parse
(
&
invalid_opt
,
opts
,
argv
+
1
,
argc
-
1
,
CLI_OPT_PARSE_GNU
))
return
cli_opt_usage_error
(
COMMAND_NAME
,
opts
,
&
invalid_opt
);
if
(
show_help
)
{
print_help
();
return
0
;
}
if
(
!
remote_path
)
{
ret
=
cli_error_usage
(
"you must specify a repository to clone"
);
goto
done
;
}
if
(
bare
)
clone_opts
.
bare
=
1
;
if
(
branch
)
clone_opts
.
checkout_branch
=
branch
;
if
(
!
checkout
)
clone_opts
.
checkout_opts
.
checkout_strategy
=
GIT_CHECKOUT_NONE
;
if
(
!
local_path
)
local_path
=
computed_path
=
compute_local_path
(
remote_path
);
local_path_exists
=
validate_local_path
(
local_path
);
cli_sighandler_set_interrupt
(
interrupt_cleanup
);
if
(
!
local_path_exists
&&
git_futils_mkdir
(
local_path
,
0777
,
0
)
<
0
)
{
ret
=
cli_error_git
();
goto
done
;
}
if
(
!
quiet
)
{
clone_opts
.
fetch_opts
.
callbacks
.
sideband_progress
=
cli_progress_fetch_sideband
;
clone_opts
.
fetch_opts
.
callbacks
.
transfer_progress
=
cli_progress_fetch_transfer
;
clone_opts
.
fetch_opts
.
callbacks
.
payload
=
&
progress
;
clone_opts
.
checkout_opts
.
progress_cb
=
cli_progress_checkout
;
clone_opts
.
checkout_opts
.
progress_payload
=
&
progress
;
printf
(
"Cloning into '%s'...
\n
"
,
local_path
);
}
if
(
git_clone
(
&
repo
,
remote_path
,
local_path
,
&
clone_opts
)
<
0
)
{
cleanup
();
ret
=
cli_error_git
();
goto
done
;
}
cli_progress_finish
(
&
progress
);
done:
cli_progress_dispose
(
&
progress
);
git__free
(
computed_path
);
git_repository_free
(
repo
);
return
ret
;
}
src/cli/main.c
View file @
8a757ae2
...
@@ -29,6 +29,7 @@ const cli_opt_spec cli_common_opts[] = {
...
@@ -29,6 +29,7 @@ const cli_opt_spec cli_common_opts[] = {
const
cli_cmd_spec
cli_cmds
[]
=
{
const
cli_cmd_spec
cli_cmds
[]
=
{
{
"cat-file"
,
cmd_cat_file
,
"Display an object in the repository"
},
{
"cat-file"
,
cmd_cat_file
,
"Display an object in the repository"
},
{
"clone"
,
cmd_clone
,
"Clone a repository into a new directory"
},
{
"hash-object"
,
cmd_hash_object
,
"Hash a raw object and product its object ID"
},
{
"hash-object"
,
cmd_hash_object
,
"Hash a raw object and product its object ID"
},
{
"help"
,
cmd_help
,
"Display help information"
},
{
"help"
,
cmd_help
,
"Display help information"
},
{
NULL
}
{
NULL
}
...
...
src/cli/progress.c
View file @
8a757ae2
...
@@ -43,7 +43,7 @@ GIT_INLINE(size_t) nl_len(bool *has_nl, const char *str, size_t len)
...
@@ -43,7 +43,7 @@ GIT_INLINE(size_t) nl_len(bool *has_nl, const char *str, size_t len)
return
i
;
return
i
;
}
}
static
int
progress_write
(
cli_progress
*
progress
,
bool
force
,
git_
buf
*
line
)
static
int
progress_write
(
cli_progress
*
progress
,
bool
force
,
git_
str
*
line
)
{
{
bool
has_nl
;
bool
has_nl
;
size_t
no_nl
=
no_nl_len
(
line
->
ptr
,
line
->
size
);
size_t
no_nl
=
no_nl_len
(
line
->
ptr
,
line
->
size
);
...
@@ -54,9 +54,9 @@ static int progress_write(cli_progress *progress, bool force, git_buf *line)
...
@@ -54,9 +54,9 @@ static int progress_write(cli_progress *progress, bool force, git_buf *line)
/* Avoid spamming the console with progress updates */
/* Avoid spamming the console with progress updates */
if
(
!
force
&&
line
->
ptr
[
line
->
size
-
1
]
!=
'\n'
&&
progress
->
last_update
)
{
if
(
!
force
&&
line
->
ptr
[
line
->
size
-
1
]
!=
'\n'
&&
progress
->
last_update
)
{
if
(
now
-
progress
->
last_update
<
PROGRESS_UPDATE_TIME
)
{
if
(
now
-
progress
->
last_update
<
PROGRESS_UPDATE_TIME
)
{
git_
buf
_clear
(
&
progress
->
deferred
);
git_
str
_clear
(
&
progress
->
deferred
);
git_
buf
_put
(
&
progress
->
deferred
,
line
->
ptr
,
line
->
size
);
git_
str
_put
(
&
progress
->
deferred
,
line
->
ptr
,
line
->
size
);
return
git_
buf
_oom
(
&
progress
->
deferred
)
?
-
1
:
0
;
return
git_
str
_oom
(
&
progress
->
deferred
)
?
-
1
:
0
;
}
}
}
}
...
@@ -79,17 +79,17 @@ static int progress_write(cli_progress *progress, bool force, git_buf *line)
...
@@ -79,17 +79,17 @@ static int progress_write(cli_progress *progress, bool force, git_buf *line)
fflush
(
stdout
)
!=
0
)
fflush
(
stdout
)
!=
0
)
return_os_error
(
"could not print status"
);
return_os_error
(
"could not print status"
);
git_
buf
_clear
(
&
progress
->
onscreen
);
git_
str
_clear
(
&
progress
->
onscreen
);
if
(
line
->
ptr
[
line
->
size
-
1
]
==
'\n'
)
{
if
(
line
->
ptr
[
line
->
size
-
1
]
==
'\n'
)
{
progress
->
last_update
=
0
;
progress
->
last_update
=
0
;
}
else
{
}
else
{
git_
buf
_put
(
&
progress
->
onscreen
,
line
->
ptr
,
line
->
size
);
git_
str
_put
(
&
progress
->
onscreen
,
line
->
ptr
,
line
->
size
);
progress
->
last_update
=
now
;
progress
->
last_update
=
now
;
}
}
git_
buf
_clear
(
&
progress
->
deferred
);
git_
str
_clear
(
&
progress
->
deferred
);
return
git_
buf
_oom
(
&
progress
->
onscreen
)
?
-
1
:
0
;
return
git_
str
_oom
(
&
progress
->
onscreen
)
?
-
1
:
0
;
}
}
static
int
progress_printf
(
cli_progress
*
progress
,
bool
force
,
const
char
*
fmt
,
...)
static
int
progress_printf
(
cli_progress
*
progress
,
bool
force
,
const
char
*
fmt
,
...)
...
@@ -97,12 +97,12 @@ static int progress_printf(cli_progress *progress, bool force, const char *fmt,
...
@@ -97,12 +97,12 @@ static int progress_printf(cli_progress *progress, bool force, const char *fmt,
int
progress_printf
(
cli_progress
*
progress
,
bool
force
,
const
char
*
fmt
,
...)
int
progress_printf
(
cli_progress
*
progress
,
bool
force
,
const
char
*
fmt
,
...)
{
{
git_
buf
buf
=
GIT_BUF_INIT
;
git_
str
buf
=
GIT_BUF_INIT
;
va_list
ap
;
va_list
ap
;
int
error
;
int
error
;
va_start
(
ap
,
fmt
);
va_start
(
ap
,
fmt
);
error
=
git_
buf
_vprintf
(
&
buf
,
fmt
,
ap
);
error
=
git_
str
_vprintf
(
&
buf
,
fmt
,
ap
);
va_end
(
ap
);
va_end
(
ap
);
if
(
error
<
0
)
if
(
error
<
0
)
...
@@ -110,7 +110,7 @@ int progress_printf(cli_progress *progress, bool force, const char *fmt, ...)
...
@@ -110,7 +110,7 @@ int progress_printf(cli_progress *progress, bool force, const char *fmt, ...)
error
=
progress_write
(
progress
,
force
,
&
buf
);
error
=
progress_write
(
progress
,
force
,
&
buf
);
git_
buf
_dispose
(
&
buf
);
git_
str
_dispose
(
&
buf
);
return
error
;
return
error
;
}
}
...
@@ -123,8 +123,8 @@ static int progress_complete(cli_progress *progress)
...
@@ -123,8 +123,8 @@ static int progress_complete(cli_progress *progress)
if
(
printf
(
"
\n
"
)
<
0
)
if
(
printf
(
"
\n
"
)
<
0
)
return_os_error
(
"could not print status"
);
return_os_error
(
"could not print status"
);
git_
buf
_clear
(
&
progress
->
deferred
);
git_
str
_clear
(
&
progress
->
deferred
);
git_
buf
_clear
(
&
progress
->
onscreen
);
git_
str
_clear
(
&
progress
->
onscreen
);
progress
->
last_update
=
0
;
progress
->
last_update
=
0
;
progress
->
action_start
=
0
;
progress
->
action_start
=
0
;
progress
->
action_finish
=
0
;
progress
->
action_finish
=
0
;
...
@@ -149,7 +149,7 @@ int cli_progress_fetch_sideband(const char *str, int len, void *payload)
...
@@ -149,7 +149,7 @@ int cli_progress_fetch_sideband(const char *str, int len, void *payload)
return
0
;
return
0
;
/* Accumulate the sideband data, then print it line-at-a-time. */
/* Accumulate the sideband data, then print it line-at-a-time. */
if
(
git_
buf
_put
(
&
progress
->
sideband
,
str
,
len
)
<
0
)
if
(
git_
str
_put
(
&
progress
->
sideband
,
str
,
len
)
<
0
)
return
-
1
;
return
-
1
;
str
=
progress
->
sideband
.
ptr
;
str
=
progress
->
sideband
.
ptr
;
...
@@ -174,7 +174,7 @@ int cli_progress_fetch_sideband(const char *str, int len, void *payload)
...
@@ -174,7 +174,7 @@ int cli_progress_fetch_sideband(const char *str, int len, void *payload)
remain
-=
line_len
;
remain
-=
line_len
;
}
}
git_
buf
_consume_bytes
(
&
progress
->
sideband
,
(
progress
->
sideband
.
size
-
remain
));
git_
str
_consume_bytes
(
&
progress
->
sideband
,
(
progress
->
sideband
.
size
-
remain
));
return
0
;
return
0
;
}
}
...
@@ -272,7 +272,7 @@ int cli_progress_fetch_transfer(const git_indexer_progress *stats, void *payload
...
@@ -272,7 +272,7 @@ int cli_progress_fetch_transfer(const git_indexer_progress *stats, void *payload
default
:
default
:
/* should not be reached */
/* should not be reached */
cli_die
(
"unexpected progress state"
);
GIT_ASSERT
(
!
"unexpected progress state"
);
}
}
return
error
;
return
error
;
...
@@ -322,9 +322,9 @@ void cli_progress_dispose(cli_progress *progress)
...
@@ -322,9 +322,9 @@ void cli_progress_dispose(cli_progress *progress)
if
(
progress
==
NULL
)
if
(
progress
==
NULL
)
return
;
return
;
git_
buf
_dispose
(
&
progress
->
sideband
);
git_
str
_dispose
(
&
progress
->
sideband
);
git_
buf
_dispose
(
&
progress
->
onscreen
);
git_
str
_dispose
(
&
progress
->
onscreen
);
git_
buf
_dispose
(
&
progress
->
deferred
);
git_
str
_dispose
(
&
progress
->
deferred
);
memset
(
progress
,
0
,
sizeof
(
cli_progress
));
memset
(
progress
,
0
,
sizeof
(
cli_progress
));
}
}
src/cli/progress.h
View file @
8a757ae2
...
@@ -9,7 +9,7 @@
...
@@ -9,7 +9,7 @@
#define CLI_progress_h__
#define CLI_progress_h__
#include <git2.h>
#include <git2.h>
#include "
buffe
r.h"
#include "
st
r.h"
/*
/*
* A general purpose set of progress printing functions. An individual
* A general purpose set of progress printing functions. An individual
...
@@ -37,9 +37,9 @@ typedef struct {
...
@@ -37,9 +37,9 @@ typedef struct {
double
last_update
;
double
last_update
;
/* Accumulators for partial output and deferred updates. */
/* Accumulators for partial output and deferred updates. */
git_
buf
sideband
;
git_
str
sideband
;
git_
buf
onscreen
;
git_
str
onscreen
;
git_
buf
deferred
;
git_
str
deferred
;
}
cli_progress
;
}
cli_progress
;
#define CLI_PROGRESS_INIT { 0 }
#define CLI_PROGRESS_INIT { 0 }
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment