зеркало из https://github.com/microsoft/git.git
Merge branch 'mt/parallel-checkout-part-1'
Preparatory API changes for parallel checkout. * mt/parallel-checkout-part-1: entry: add checkout_entry_ca() taking preloaded conv_attrs entry: move conv_attrs lookup up to checkout_entry() entry: extract update_ce_after_write() from write_entry() entry: make fstat_output() and read_blob_entry() public entry: extract a header file for entry.c functions convert: add classification for conv_attrs struct convert: add get_stream_filter_ca() variant convert: add [async_]convert_to_working_tree_ca() variants convert: make convert_attrs() and convert structs public
This commit is contained in:
Коммит
c47679d040
1
apply.c
1
apply.c
|
@ -21,6 +21,7 @@
|
|||
#include "quote.h"
|
||||
#include "rerere.h"
|
||||
#include "apply.h"
|
||||
#include "entry.h"
|
||||
|
||||
struct gitdiff_data {
|
||||
struct strbuf *root;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "quote.h"
|
||||
#include "cache-tree.h"
|
||||
#include "parse-options.h"
|
||||
#include "entry.h"
|
||||
|
||||
#define CHECKOUT_ALL 4
|
||||
static int nul_term_line;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "unpack-trees.h"
|
||||
#include "wt-status.h"
|
||||
#include "xdiff-interface.h"
|
||||
#include "entry.h"
|
||||
|
||||
static const char * const checkout_usage[] = {
|
||||
N_("git checkout [<options>] <branch>"),
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "lockfile.h"
|
||||
#include "object-store.h"
|
||||
#include "dir.h"
|
||||
#include "entry.h"
|
||||
|
||||
static int trust_exit_code;
|
||||
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
#include "strvec.h"
|
||||
#include "run-command.h"
|
||||
#include "dir.h"
|
||||
#include "entry.h"
|
||||
#include "rerere.h"
|
||||
#include "revision.h"
|
||||
#include "log-tree.h"
|
||||
#include "diffcore.h"
|
||||
#include "exec-cmd.h"
|
||||
#include "entry.h"
|
||||
|
||||
#define INCLUDE_ALL_FILES 2
|
||||
|
||||
|
|
24
cache.h
24
cache.h
|
@ -1621,30 +1621,6 @@ const char *show_ident_date(const struct ident_split *id,
|
|||
*/
|
||||
int ident_cmp(const struct ident_split *, const struct ident_split *);
|
||||
|
||||
struct checkout {
|
||||
struct index_state *istate;
|
||||
const char *base_dir;
|
||||
int base_dir_len;
|
||||
struct delayed_checkout *delayed_checkout;
|
||||
struct checkout_metadata meta;
|
||||
unsigned force:1,
|
||||
quiet:1,
|
||||
not_new:1,
|
||||
clone:1,
|
||||
refresh_cache:1;
|
||||
};
|
||||
#define CHECKOUT_INIT { NULL, "" }
|
||||
|
||||
#define TEMPORARY_FILENAME_LENGTH 25
|
||||
int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath, int *nr_checkouts);
|
||||
void enable_delayed_checkout(struct checkout *state);
|
||||
int finish_delayed_checkout(struct checkout *state, int *nr_checkouts);
|
||||
/*
|
||||
* Unlink the last component and schedule the leading directories for
|
||||
* removal, such that empty directories get removed.
|
||||
*/
|
||||
void unlink_entry(const struct cache_entry *ce);
|
||||
|
||||
struct cache_def {
|
||||
struct strbuf path;
|
||||
int flags;
|
||||
|
|
143
convert.c
143
convert.c
|
@ -24,17 +24,6 @@
|
|||
#define CONVERT_STAT_BITS_TXT_CRLF 0x2
|
||||
#define CONVERT_STAT_BITS_BIN 0x4
|
||||
|
||||
enum crlf_action {
|
||||
CRLF_UNDEFINED,
|
||||
CRLF_BINARY,
|
||||
CRLF_TEXT,
|
||||
CRLF_TEXT_INPUT,
|
||||
CRLF_TEXT_CRLF,
|
||||
CRLF_AUTO,
|
||||
CRLF_AUTO_INPUT,
|
||||
CRLF_AUTO_CRLF
|
||||
};
|
||||
|
||||
struct text_stat {
|
||||
/* NUL, CR, LF and CRLF counts */
|
||||
unsigned nul, lonecr, lonelf, crlf;
|
||||
|
@ -172,7 +161,7 @@ static int text_eol_is_crlf(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static enum eol output_eol(enum crlf_action crlf_action)
|
||||
static enum eol output_eol(enum convert_crlf_action crlf_action)
|
||||
{
|
||||
switch (crlf_action) {
|
||||
case CRLF_BINARY:
|
||||
|
@ -246,7 +235,7 @@ static int has_crlf_in_index(const struct index_state *istate, const char *path)
|
|||
}
|
||||
|
||||
static int will_convert_lf_to_crlf(struct text_stat *stats,
|
||||
enum crlf_action crlf_action)
|
||||
enum convert_crlf_action crlf_action)
|
||||
{
|
||||
if (output_eol(crlf_action) != EOL_CRLF)
|
||||
return 0;
|
||||
|
@ -499,7 +488,7 @@ static int encode_to_worktree(const char *path, const char *src, size_t src_len,
|
|||
static int crlf_to_git(const struct index_state *istate,
|
||||
const char *path, const char *src, size_t len,
|
||||
struct strbuf *buf,
|
||||
enum crlf_action crlf_action, int conv_flags)
|
||||
enum convert_crlf_action crlf_action, int conv_flags)
|
||||
{
|
||||
struct text_stat stats;
|
||||
char *dst;
|
||||
|
@ -585,8 +574,8 @@ static int crlf_to_git(const struct index_state *istate,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int crlf_to_worktree(const char *src, size_t len,
|
||||
struct strbuf *buf, enum crlf_action crlf_action)
|
||||
static int crlf_to_worktree(const char *src, size_t len, struct strbuf *buf,
|
||||
enum convert_crlf_action crlf_action)
|
||||
{
|
||||
char *to_free = NULL;
|
||||
struct text_stat stats;
|
||||
|
@ -1247,7 +1236,7 @@ static const char *git_path_check_encoding(struct attr_check_item *check)
|
|||
return value;
|
||||
}
|
||||
|
||||
static enum crlf_action git_path_check_crlf(struct attr_check_item *check)
|
||||
static enum convert_crlf_action git_path_check_crlf(struct attr_check_item *check)
|
||||
{
|
||||
const char *value = check->value;
|
||||
|
||||
|
@ -1297,18 +1286,10 @@ static int git_path_check_ident(struct attr_check_item *check)
|
|||
return !!ATTR_TRUE(value);
|
||||
}
|
||||
|
||||
struct conv_attrs {
|
||||
struct convert_driver *drv;
|
||||
enum crlf_action attr_action; /* What attr says */
|
||||
enum crlf_action crlf_action; /* When no attr is set, use core.autocrlf */
|
||||
int ident;
|
||||
const char *working_tree_encoding; /* Supported encoding or default encoding if NULL */
|
||||
};
|
||||
|
||||
static struct attr_check *check;
|
||||
|
||||
static void convert_attrs(const struct index_state *istate,
|
||||
struct conv_attrs *ca, const char *path)
|
||||
void convert_attrs(const struct index_state *istate,
|
||||
struct conv_attrs *ca, const char *path)
|
||||
{
|
||||
struct attr_check_item *ccheck = NULL;
|
||||
|
||||
|
@ -1465,19 +1446,16 @@ void convert_to_git_filter_fd(const struct index_state *istate,
|
|||
ident_to_git(dst->buf, dst->len, dst, ca.ident);
|
||||
}
|
||||
|
||||
static int convert_to_working_tree_internal(const struct index_state *istate,
|
||||
const char *path, const char *src,
|
||||
size_t len, struct strbuf *dst,
|
||||
int normalizing,
|
||||
const struct checkout_metadata *meta,
|
||||
struct delayed_checkout *dco)
|
||||
static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca,
|
||||
const char *path, const char *src,
|
||||
size_t len, struct strbuf *dst,
|
||||
int normalizing,
|
||||
const struct checkout_metadata *meta,
|
||||
struct delayed_checkout *dco)
|
||||
{
|
||||
int ret = 0, ret_filter = 0;
|
||||
struct conv_attrs ca;
|
||||
|
||||
convert_attrs(istate, &ca, path);
|
||||
|
||||
ret |= ident_to_worktree(src, len, dst, ca.ident);
|
||||
ret |= ident_to_worktree(src, len, dst, ca->ident);
|
||||
if (ret) {
|
||||
src = dst->buf;
|
||||
len = dst->len;
|
||||
|
@ -1487,49 +1465,56 @@ static int convert_to_working_tree_internal(const struct index_state *istate,
|
|||
* is a smudge or process filter (even if the process filter doesn't
|
||||
* support smudge). The filters might expect CRLFs.
|
||||
*/
|
||||
if ((ca.drv && (ca.drv->smudge || ca.drv->process)) || !normalizing) {
|
||||
ret |= crlf_to_worktree(src, len, dst, ca.crlf_action);
|
||||
if ((ca->drv && (ca->drv->smudge || ca->drv->process)) || !normalizing) {
|
||||
ret |= crlf_to_worktree(src, len, dst, ca->crlf_action);
|
||||
if (ret) {
|
||||
src = dst->buf;
|
||||
len = dst->len;
|
||||
}
|
||||
}
|
||||
|
||||
ret |= encode_to_worktree(path, src, len, dst, ca.working_tree_encoding);
|
||||
ret |= encode_to_worktree(path, src, len, dst, ca->working_tree_encoding);
|
||||
if (ret) {
|
||||
src = dst->buf;
|
||||
len = dst->len;
|
||||
}
|
||||
|
||||
ret_filter = apply_filter(
|
||||
path, src, len, -1, dst, ca.drv, CAP_SMUDGE, meta, dco);
|
||||
if (!ret_filter && ca.drv && ca.drv->required)
|
||||
die(_("%s: smudge filter %s failed"), path, ca.drv->name);
|
||||
path, src, len, -1, dst, ca->drv, CAP_SMUDGE, meta, dco);
|
||||
if (!ret_filter && ca->drv && ca->drv->required)
|
||||
die(_("%s: smudge filter %s failed"), path, ca->drv->name);
|
||||
|
||||
return ret | ret_filter;
|
||||
}
|
||||
|
||||
int async_convert_to_working_tree(const struct index_state *istate,
|
||||
const char *path, const char *src,
|
||||
size_t len, struct strbuf *dst,
|
||||
const struct checkout_metadata *meta,
|
||||
void *dco)
|
||||
int async_convert_to_working_tree_ca(const struct conv_attrs *ca,
|
||||
const char *path, const char *src,
|
||||
size_t len, struct strbuf *dst,
|
||||
const struct checkout_metadata *meta,
|
||||
void *dco)
|
||||
{
|
||||
return convert_to_working_tree_internal(istate, path, src, len, dst, 0, meta, dco);
|
||||
return convert_to_working_tree_ca_internal(ca, path, src, len, dst, 0,
|
||||
meta, dco);
|
||||
}
|
||||
|
||||
int convert_to_working_tree(const struct index_state *istate,
|
||||
const char *path, const char *src,
|
||||
size_t len, struct strbuf *dst,
|
||||
const struct checkout_metadata *meta)
|
||||
int convert_to_working_tree_ca(const struct conv_attrs *ca,
|
||||
const char *path, const char *src,
|
||||
size_t len, struct strbuf *dst,
|
||||
const struct checkout_metadata *meta)
|
||||
{
|
||||
return convert_to_working_tree_internal(istate, path, src, len, dst, 0, meta, NULL);
|
||||
return convert_to_working_tree_ca_internal(ca, path, src, len, dst, 0,
|
||||
meta, NULL);
|
||||
}
|
||||
|
||||
int renormalize_buffer(const struct index_state *istate, const char *path,
|
||||
const char *src, size_t len, struct strbuf *dst)
|
||||
{
|
||||
int ret = convert_to_working_tree_internal(istate, path, src, len, dst, 1, NULL, NULL);
|
||||
struct conv_attrs ca;
|
||||
int ret;
|
||||
|
||||
convert_attrs(istate, &ca, path);
|
||||
ret = convert_to_working_tree_ca_internal(&ca, path, src, len, dst, 1,
|
||||
NULL, NULL);
|
||||
if (ret) {
|
||||
src = dst->buf;
|
||||
len = dst->len;
|
||||
|
@ -1956,34 +1941,25 @@ static struct stream_filter *ident_filter(const struct object_id *oid)
|
|||
}
|
||||
|
||||
/*
|
||||
* Return an appropriately constructed filter for the path, or NULL if
|
||||
* Return an appropriately constructed filter for the given ca, or NULL if
|
||||
* the contents cannot be filtered without reading the whole thing
|
||||
* in-core.
|
||||
*
|
||||
* Note that you would be crazy to set CRLF, smudge/clean or ident to a
|
||||
* large binary blob you would want us not to slurp into the memory!
|
||||
*/
|
||||
struct stream_filter *get_stream_filter(const struct index_state *istate,
|
||||
const char *path,
|
||||
const struct object_id *oid)
|
||||
struct stream_filter *get_stream_filter_ca(const struct conv_attrs *ca,
|
||||
const struct object_id *oid)
|
||||
{
|
||||
struct conv_attrs ca;
|
||||
struct stream_filter *filter = NULL;
|
||||
|
||||
convert_attrs(istate, &ca, path);
|
||||
if (ca.drv && (ca.drv->process || ca.drv->smudge || ca.drv->clean))
|
||||
if (classify_conv_attrs(ca) != CA_CLASS_STREAMABLE)
|
||||
return NULL;
|
||||
|
||||
if (ca.working_tree_encoding)
|
||||
return NULL;
|
||||
|
||||
if (ca.crlf_action == CRLF_AUTO || ca.crlf_action == CRLF_AUTO_CRLF)
|
||||
return NULL;
|
||||
|
||||
if (ca.ident)
|
||||
if (ca->ident)
|
||||
filter = ident_filter(oid);
|
||||
|
||||
if (output_eol(ca.crlf_action) == EOL_CRLF)
|
||||
if (output_eol(ca->crlf_action) == EOL_CRLF)
|
||||
filter = cascade_filter(filter, lf_to_crlf_filter());
|
||||
else
|
||||
filter = cascade_filter(filter, &null_filter_singleton);
|
||||
|
@ -1991,6 +1967,15 @@ struct stream_filter *get_stream_filter(const struct index_state *istate,
|
|||
return filter;
|
||||
}
|
||||
|
||||
struct stream_filter *get_stream_filter(const struct index_state *istate,
|
||||
const char *path,
|
||||
const struct object_id *oid)
|
||||
{
|
||||
struct conv_attrs ca;
|
||||
convert_attrs(istate, &ca, path);
|
||||
return get_stream_filter_ca(&ca, oid);
|
||||
}
|
||||
|
||||
void free_stream_filter(struct stream_filter *filter)
|
||||
{
|
||||
filter->vtbl->free(filter);
|
||||
|
@ -2024,3 +2009,21 @@ void clone_checkout_metadata(struct checkout_metadata *dst,
|
|||
if (blob)
|
||||
oidcpy(&dst->blob, blob);
|
||||
}
|
||||
|
||||
enum conv_attrs_classification classify_conv_attrs(const struct conv_attrs *ca)
|
||||
{
|
||||
if (ca->drv) {
|
||||
if (ca->drv->process)
|
||||
return CA_CLASS_INCORE_PROCESS;
|
||||
if (ca->drv->smudge || ca->drv->clean)
|
||||
return CA_CLASS_INCORE_FILTER;
|
||||
}
|
||||
|
||||
if (ca->working_tree_encoding)
|
||||
return CA_CLASS_INCORE;
|
||||
|
||||
if (ca->crlf_action == CRLF_AUTO || ca->crlf_action == CRLF_AUTO_CRLF)
|
||||
return CA_CLASS_INCORE;
|
||||
|
||||
return CA_CLASS_STREAMABLE;
|
||||
}
|
||||
|
|
96
convert.h
96
convert.h
|
@ -63,6 +63,30 @@ struct checkout_metadata {
|
|||
struct object_id blob;
|
||||
};
|
||||
|
||||
enum convert_crlf_action {
|
||||
CRLF_UNDEFINED,
|
||||
CRLF_BINARY,
|
||||
CRLF_TEXT,
|
||||
CRLF_TEXT_INPUT,
|
||||
CRLF_TEXT_CRLF,
|
||||
CRLF_AUTO,
|
||||
CRLF_AUTO_INPUT,
|
||||
CRLF_AUTO_CRLF
|
||||
};
|
||||
|
||||
struct convert_driver;
|
||||
|
||||
struct conv_attrs {
|
||||
struct convert_driver *drv;
|
||||
enum convert_crlf_action attr_action; /* What attr says */
|
||||
enum convert_crlf_action crlf_action; /* When no attr is set, use core.autocrlf */
|
||||
int ident;
|
||||
const char *working_tree_encoding; /* Supported encoding or default encoding if NULL */
|
||||
};
|
||||
|
||||
void convert_attrs(const struct index_state *istate,
|
||||
struct conv_attrs *ca, const char *path);
|
||||
|
||||
extern enum eol core_eol;
|
||||
extern char *check_roundtrip_encoding;
|
||||
const char *get_cached_convert_stats_ascii(const struct index_state *istate,
|
||||
|
@ -75,15 +99,34 @@ const char *get_convert_attr_ascii(const struct index_state *istate,
|
|||
int convert_to_git(const struct index_state *istate,
|
||||
const char *path, const char *src, size_t len,
|
||||
struct strbuf *dst, int conv_flags);
|
||||
int convert_to_working_tree(const struct index_state *istate,
|
||||
const char *path, const char *src,
|
||||
size_t len, struct strbuf *dst,
|
||||
const struct checkout_metadata *meta);
|
||||
int async_convert_to_working_tree(const struct index_state *istate,
|
||||
const char *path, const char *src,
|
||||
size_t len, struct strbuf *dst,
|
||||
const struct checkout_metadata *meta,
|
||||
void *dco);
|
||||
int convert_to_working_tree_ca(const struct conv_attrs *ca,
|
||||
const char *path, const char *src,
|
||||
size_t len, struct strbuf *dst,
|
||||
const struct checkout_metadata *meta);
|
||||
int async_convert_to_working_tree_ca(const struct conv_attrs *ca,
|
||||
const char *path, const char *src,
|
||||
size_t len, struct strbuf *dst,
|
||||
const struct checkout_metadata *meta,
|
||||
void *dco);
|
||||
static inline int convert_to_working_tree(const struct index_state *istate,
|
||||
const char *path, const char *src,
|
||||
size_t len, struct strbuf *dst,
|
||||
const struct checkout_metadata *meta)
|
||||
{
|
||||
struct conv_attrs ca;
|
||||
convert_attrs(istate, &ca, path);
|
||||
return convert_to_working_tree_ca(&ca, path, src, len, dst, meta);
|
||||
}
|
||||
static inline int async_convert_to_working_tree(const struct index_state *istate,
|
||||
const char *path, const char *src,
|
||||
size_t len, struct strbuf *dst,
|
||||
const struct checkout_metadata *meta,
|
||||
void *dco)
|
||||
{
|
||||
struct conv_attrs ca;
|
||||
convert_attrs(istate, &ca, path);
|
||||
return async_convert_to_working_tree_ca(&ca, path, src, len, dst, meta, dco);
|
||||
}
|
||||
int async_query_available_blobs(const char *cmd,
|
||||
struct string_list *available_paths);
|
||||
int renormalize_buffer(const struct index_state *istate,
|
||||
|
@ -136,6 +179,8 @@ struct stream_filter; /* opaque */
|
|||
struct stream_filter *get_stream_filter(const struct index_state *istate,
|
||||
const char *path,
|
||||
const struct object_id *);
|
||||
struct stream_filter *get_stream_filter_ca(const struct conv_attrs *ca,
|
||||
const struct object_id *oid);
|
||||
void free_stream_filter(struct stream_filter *);
|
||||
int is_null_stream_filter(struct stream_filter *);
|
||||
|
||||
|
@ -155,4 +200,37 @@ int stream_filter(struct stream_filter *,
|
|||
const char *input, size_t *isize_p,
|
||||
char *output, size_t *osize_p);
|
||||
|
||||
enum conv_attrs_classification {
|
||||
/*
|
||||
* The blob must be loaded into a buffer before it can be
|
||||
* smudged. All smudging is done in-proc.
|
||||
*/
|
||||
CA_CLASS_INCORE,
|
||||
|
||||
/*
|
||||
* The blob must be loaded into a buffer, but uses a
|
||||
* single-file driver filter, such as rot13.
|
||||
*/
|
||||
CA_CLASS_INCORE_FILTER,
|
||||
|
||||
/*
|
||||
* The blob must be loaded into a buffer, but uses a
|
||||
* long-running driver process, such as LFS. This might or
|
||||
* might not use delayed operations. (The important thing is
|
||||
* that there is a single subordinate long-running process
|
||||
* handling all associated blobs and in case of delayed
|
||||
* operations, may hold per-blob state.)
|
||||
*/
|
||||
CA_CLASS_INCORE_PROCESS,
|
||||
|
||||
/*
|
||||
* The blob can be streamed and smudged without needing to
|
||||
* completely read it into a buffer.
|
||||
*/
|
||||
CA_CLASS_STREAMABLE,
|
||||
};
|
||||
|
||||
enum conv_attrs_classification classify_conv_attrs(
|
||||
const struct conv_attrs *ca);
|
||||
|
||||
#endif /* CONVERT_H */
|
||||
|
|
85
entry.c
85
entry.c
|
@ -6,6 +6,7 @@
|
|||
#include "submodule.h"
|
||||
#include "progress.h"
|
||||
#include "fsmonitor.h"
|
||||
#include "entry.h"
|
||||
|
||||
static void create_directories(const char *path, int path_len,
|
||||
const struct checkout *state)
|
||||
|
@ -83,7 +84,7 @@ static int create_file(const char *path, unsigned int mode)
|
|||
return open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
|
||||
}
|
||||
|
||||
static void *read_blob_entry(const struct cache_entry *ce, unsigned long *size)
|
||||
void *read_blob_entry(const struct cache_entry *ce, unsigned long *size)
|
||||
{
|
||||
enum object_type type;
|
||||
void *blob_data = read_object_file(&ce->oid, &type, size);
|
||||
|
@ -108,7 +109,7 @@ static int open_output_fd(char *path, const struct cache_entry *ce, int to_tempf
|
|||
}
|
||||
}
|
||||
|
||||
static int fstat_output(int fd, const struct checkout *state, struct stat *st)
|
||||
int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st)
|
||||
{
|
||||
/* use fstat() only when path == ce->name */
|
||||
if (fstat_is_reliable() &&
|
||||
|
@ -131,7 +132,7 @@ static int streaming_write_entry(const struct cache_entry *ce, char *path,
|
|||
return -1;
|
||||
|
||||
result |= stream_blob_to_fd(fd, &ce->oid, filter, 1);
|
||||
*fstat_done = fstat_output(fd, state, statbuf);
|
||||
*fstat_done = fstat_checkout_output(fd, state, statbuf);
|
||||
result |= close(fd);
|
||||
|
||||
if (result)
|
||||
|
@ -250,8 +251,21 @@ int finish_delayed_checkout(struct checkout *state, int *nr_checkouts)
|
|||
return errs;
|
||||
}
|
||||
|
||||
static int write_entry(struct cache_entry *ce,
|
||||
char *path, const struct checkout *state, int to_tempfile)
|
||||
void update_ce_after_write(const struct checkout *state, struct cache_entry *ce,
|
||||
struct stat *st)
|
||||
{
|
||||
if (state->refresh_cache) {
|
||||
assert(state->istate);
|
||||
fill_stat_cache_info(state->istate, ce, st);
|
||||
ce->ce_flags |= CE_UPDATE_IN_BASE;
|
||||
mark_fsmonitor_invalid(state->istate, ce);
|
||||
state->istate->cache_changed |= CE_ENTRY_CHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: ca is used (and required) iff the entry refers to a regular file. */
|
||||
static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca,
|
||||
const struct checkout *state, int to_tempfile)
|
||||
{
|
||||
unsigned int ce_mode_s_ifmt = ce->ce_mode & S_IFMT;
|
||||
struct delayed_checkout *dco = state->delayed_checkout;
|
||||
|
@ -268,8 +282,7 @@ static int write_entry(struct cache_entry *ce,
|
|||
clone_checkout_metadata(&meta, &state->meta, &ce->oid);
|
||||
|
||||
if (ce_mode_s_ifmt == S_IFREG) {
|
||||
struct stream_filter *filter = get_stream_filter(state->istate, ce->name,
|
||||
&ce->oid);
|
||||
struct stream_filter *filter = get_stream_filter_ca(ca, &ce->oid);
|
||||
if (filter &&
|
||||
!streaming_write_entry(ce, path, filter,
|
||||
state, to_tempfile,
|
||||
|
@ -316,14 +329,17 @@ static int write_entry(struct cache_entry *ce,
|
|||
* Convert from git internal format to working tree format
|
||||
*/
|
||||
if (dco && dco->state != CE_NO_DELAY) {
|
||||
ret = async_convert_to_working_tree(state->istate, ce->name, new_blob,
|
||||
size, &buf, &meta, dco);
|
||||
ret = async_convert_to_working_tree_ca(ca, ce->name,
|
||||
new_blob, size,
|
||||
&buf, &meta, dco);
|
||||
if (ret && string_list_has_string(&dco->paths, ce->name)) {
|
||||
free(new_blob);
|
||||
goto delayed;
|
||||
}
|
||||
} else
|
||||
ret = convert_to_working_tree(state->istate, ce->name, new_blob, size, &buf, &meta);
|
||||
} else {
|
||||
ret = convert_to_working_tree_ca(ca, ce->name, new_blob,
|
||||
size, &buf, &meta);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
free(new_blob);
|
||||
|
@ -345,7 +361,7 @@ static int write_entry(struct cache_entry *ce,
|
|||
|
||||
wrote = write_in_full(fd, new_blob, size);
|
||||
if (!to_tempfile)
|
||||
fstat_done = fstat_output(fd, state, &st);
|
||||
fstat_done = fstat_checkout_output(fd, state, &st);
|
||||
close(fd);
|
||||
free(new_blob);
|
||||
if (wrote < 0)
|
||||
|
@ -370,15 +386,10 @@ static int write_entry(struct cache_entry *ce,
|
|||
|
||||
finish:
|
||||
if (state->refresh_cache) {
|
||||
assert(state->istate);
|
||||
if (!fstat_done)
|
||||
if (lstat(ce->name, &st) < 0)
|
||||
return error_errno("unable to stat just-written file %s",
|
||||
ce->name);
|
||||
fill_stat_cache_info(state->istate, ce, &st);
|
||||
ce->ce_flags |= CE_UPDATE_IN_BASE;
|
||||
mark_fsmonitor_invalid(state->istate, ce);
|
||||
state->istate->cache_changed |= CE_ENTRY_CHANGED;
|
||||
if (!fstat_done && lstat(ce->name, &st) < 0)
|
||||
return error_errno("unable to stat just-written file %s",
|
||||
ce->name);
|
||||
update_ce_after_write(state, ce , &st);
|
||||
}
|
||||
delayed:
|
||||
return 0;
|
||||
|
@ -429,19 +440,13 @@ static void mark_colliding_entries(const struct checkout *state,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the contents from ce out to the working tree.
|
||||
*
|
||||
* When topath[] is not NULL, instead of writing to the working tree
|
||||
* file named by ce, a temporary file is created by this function and
|
||||
* its name is returned in topath[], which must be able to hold at
|
||||
* least TEMPORARY_FILENAME_LENGTH bytes long.
|
||||
*/
|
||||
int checkout_entry(struct cache_entry *ce, const struct checkout *state,
|
||||
char *topath, int *nr_checkouts)
|
||||
int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
|
||||
const struct checkout *state, char *topath,
|
||||
int *nr_checkouts)
|
||||
{
|
||||
static struct strbuf path = STRBUF_INIT;
|
||||
struct stat st;
|
||||
struct conv_attrs ca_buf;
|
||||
|
||||
if (ce->ce_flags & CE_WT_REMOVE) {
|
||||
if (topath)
|
||||
|
@ -454,8 +459,13 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (topath)
|
||||
return write_entry(ce, topath, state, 1);
|
||||
if (topath) {
|
||||
if (S_ISREG(ce->ce_mode) && !ca) {
|
||||
convert_attrs(state->istate, &ca_buf, ce->name);
|
||||
ca = &ca_buf;
|
||||
}
|
||||
return write_entry(ce, topath, ca, state, 1);
|
||||
}
|
||||
|
||||
strbuf_reset(&path);
|
||||
strbuf_add(&path, state->base_dir, state->base_dir_len);
|
||||
|
@ -517,9 +527,16 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state,
|
|||
return 0;
|
||||
|
||||
create_directories(path.buf, path.len, state);
|
||||
|
||||
if (nr_checkouts)
|
||||
(*nr_checkouts)++;
|
||||
return write_entry(ce, path.buf, state, 0);
|
||||
|
||||
if (S_ISREG(ce->ce_mode) && !ca) {
|
||||
convert_attrs(state->istate, &ca_buf, ce->name);
|
||||
ca = &ca_buf;
|
||||
}
|
||||
|
||||
return write_entry(ce, path.buf, ca, state, 0);
|
||||
}
|
||||
|
||||
void unlink_entry(const struct cache_entry *ce)
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef ENTRY_H
|
||||
#define ENTRY_H
|
||||
|
||||
#include "cache.h"
|
||||
#include "convert.h"
|
||||
|
||||
struct checkout {
|
||||
struct index_state *istate;
|
||||
const char *base_dir;
|
||||
int base_dir_len;
|
||||
struct delayed_checkout *delayed_checkout;
|
||||
struct checkout_metadata meta;
|
||||
unsigned force:1,
|
||||
quiet:1,
|
||||
not_new:1,
|
||||
clone:1,
|
||||
refresh_cache:1;
|
||||
};
|
||||
#define CHECKOUT_INIT { NULL, "" }
|
||||
|
||||
#define TEMPORARY_FILENAME_LENGTH 25
|
||||
/*
|
||||
* Write the contents from ce out to the working tree.
|
||||
*
|
||||
* When topath[] is not NULL, instead of writing to the working tree
|
||||
* file named by ce, a temporary file is created by this function and
|
||||
* its name is returned in topath[], which must be able to hold at
|
||||
* least TEMPORARY_FILENAME_LENGTH bytes long.
|
||||
*
|
||||
* With checkout_entry_ca(), callers can optionally pass a preloaded
|
||||
* conv_attrs struct (to avoid reloading it), when ce refers to a
|
||||
* regular file. If ca is NULL, the attributes will be loaded
|
||||
* internally when (and if) needed.
|
||||
*/
|
||||
int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
|
||||
const struct checkout *state, char *topath,
|
||||
int *nr_checkouts);
|
||||
static inline int checkout_entry(struct cache_entry *ce,
|
||||
const struct checkout *state, char *topath,
|
||||
int *nr_checkouts)
|
||||
{
|
||||
return checkout_entry_ca(ce, NULL, state, topath, nr_checkouts);
|
||||
}
|
||||
|
||||
void enable_delayed_checkout(struct checkout *state);
|
||||
int finish_delayed_checkout(struct checkout *state, int *nr_checkouts);
|
||||
|
||||
/*
|
||||
* Unlink the last component and schedule the leading directories for
|
||||
* removal, such that empty directories get removed.
|
||||
*/
|
||||
void unlink_entry(const struct cache_entry *ce);
|
||||
|
||||
void *read_blob_entry(const struct cache_entry *ce, unsigned long *size);
|
||||
int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);
|
||||
void update_ce_after_write(const struct checkout *state, struct cache_entry *ce,
|
||||
struct stat *st);
|
||||
|
||||
#endif /* ENTRY_H */
|
|
@ -16,6 +16,7 @@
|
|||
#include "fsmonitor.h"
|
||||
#include "object-store.h"
|
||||
#include "promisor-remote.h"
|
||||
#include "entry.h"
|
||||
|
||||
/*
|
||||
* Error messages expected by scripts out of plumbing commands such as
|
||||
|
|
Загрузка…
Ссылка в новой задаче