mirror of
https://github.com/git/git
synced 2024-08-25 02:35:46 +00:00
![Jeff King](/assets/img/avatar_default.png)
The process for guessing an archive output format based on the filename is something like this: a. parse --output in cmd_archive; check the filename against a static set of mapping heuristics (right now it just matches ".zip" for zip files). b. if found, stick a fake "--format=zip" at the beginning of the arguments list (if the user did specify a --format manually, the later option will override our fake one) c. if it's a remote call, ship the arguments to the remote (including the fake), which will call write_archive on their end d. if it's local, ship the arguments to write_archive locally There are two problems: 1. The set of mappings is static and at too high a level. The write_archive level is going to check config for user-defined formats, some of which will specify extensions. We need to delay lookup until those are parsed, so we can match against them. 2. For a remote archive call, our set of mappings (or formats) may not match the remote side's. This is OK in practice right now, because all versions of git understand "zip" and "tar". But as new formats are added, there is going to be a mismatch between what the client can do and what the remote server can do. To fix (1), this patch refactors the location guessing to happen at the write_archive level, instead of the cmd_archive level. So instead of sticking a fake --format field in the argv list, we actually pass a "name hint" down the callchain; this hint is used at the appropriate time to guess the format (if one hasn't been given already). This patch leaves (2) unfixed. The name_hint is converted to a "--format" option as before, and passed to the remote. This means the local side's idea of how extensions map to formats will take precedence. Another option would be to pass the name hint to the remote side and let the remote choose. This isn't a good idea for two reasons: 1. There's no room in the protocol for passing that information. We can pass a new argument, but older versions of git on the server will choke on it. 2. Letting the remote side decide creates a silent inconsistency in user experience. Consider the case that the locally installed git knows about the "tar.gz" format, but a remote server doesn't. Running "git archive -o foo.tar.gz" will use the tar.gz format. If we use --remote, and the local side chooses the format, then we send "--format=tar.gz" to the remote, which will complain about the unknown format. But if we let the remote side choose the format, then it will realize that it doesn't know about "tar.gz" and output uncompressed tar without even issuing a warning. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
37 lines
1.1 KiB
C
37 lines
1.1 KiB
C
#ifndef ARCHIVE_H
|
|
#define ARCHIVE_H
|
|
|
|
struct archiver_args {
|
|
const char *base;
|
|
size_t baselen;
|
|
struct tree *tree;
|
|
const unsigned char *commit_sha1;
|
|
const struct commit *commit;
|
|
time_t time;
|
|
const char **pathspec;
|
|
unsigned int verbose : 1;
|
|
unsigned int worktree_attributes : 1;
|
|
int compression_level;
|
|
};
|
|
|
|
#define ARCHIVER_WANT_COMPRESSION_LEVELS 1
|
|
struct archiver {
|
|
const char *name;
|
|
int (*write_archive)(const struct archiver *, struct archiver_args *);
|
|
unsigned flags;
|
|
void *data;
|
|
};
|
|
extern void register_archiver(struct archiver *);
|
|
|
|
extern void init_tar_archiver(void);
|
|
extern void init_zip_archiver(void);
|
|
|
|
typedef int (*write_archive_entry_fn_t)(struct archiver_args *args, const unsigned char *sha1, const char *path, size_t pathlen, unsigned int mode, void *buffer, unsigned long size);
|
|
|
|
extern int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
|
|
extern int write_archive(int argc, const char **argv, const char *prefix, int setup_prefix, const char *name_hint);
|
|
|
|
const char *archive_format_from_filename(const char *filename);
|
|
|
|
#endif /* ARCHIVE_H */
|