Add support for a 'put_raw_obj' capability/instruction to send new
objects to an external odb. Objects will be sent as they are (in
their 'raw' format). They will not be converted to Git objects.

For now any new Git object (blob, tree, commit, ...) would be sent
if 'put_raw_obj' is supported by an odb helper. This is not a great
default, but let's leave it to following commits to tweak that.

Signed-off-by: Christian Couder <chrisc...@tuxfamily.org>
---
 external-odb.c | 15 +++++++++++++++
 external-odb.h |  2 ++
 odb-helper.c   | 43 ++++++++++++++++++++++++++++++++++++++-----
 odb-helper.h   |  3 +++
 sha1_file.c    |  2 ++
 5 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/external-odb.c b/external-odb.c
index 2622c12853..337bdd2540 100644
--- a/external-odb.c
+++ b/external-odb.c
@@ -151,3 +151,18 @@ int external_odb_get_direct(const unsigned char *sha1)
 
        return -1;
 }
+
+int external_odb_put_object(const void *buf, size_t len,
+                           const char *type, unsigned char *sha1)
+{
+       struct odb_helper *o;
+
+       external_odb_init();
+
+       for (o = helpers; o; o = o->next) {
+               int r = odb_helper_put_object(o, buf, len, type, sha1);
+               if (r <= 0)
+                       return r;
+       }
+       return 1;
+}
diff --git a/external-odb.h b/external-odb.h
index fb8b94972f..26bb931685 100644
--- a/external-odb.h
+++ b/external-odb.h
@@ -6,5 +6,7 @@ extern const char *external_odb_root(void);
 extern int external_odb_has_object(const unsigned char *sha1);
 extern int external_odb_get_object(const unsigned char *sha1);
 extern int external_odb_get_direct(const unsigned char *sha1);
+extern int external_odb_put_object(const void *buf, size_t len,
+                                  const char *type, unsigned char *sha1);
 
 #endif /* EXTERNAL_ODB_H */
diff --git a/odb-helper.c b/odb-helper.c
index ea642fd438..6f56f07b38 100644
--- a/odb-helper.c
+++ b/odb-helper.c
@@ -72,9 +72,10 @@ static void prepare_helper_command(struct argv_array *argv, 
const char *cmd,
        strbuf_release(&buf);
 }
 
-__attribute__((format (printf,3,4)))
+__attribute__((format (printf,4,5)))
 static int odb_helper_start(struct odb_helper *o,
                            struct odb_helper_cmd *cmd,
+                           int use_stdin,
                            const char *fmt, ...)
 {
        va_list ap;
@@ -91,7 +92,10 @@ static int odb_helper_start(struct odb_helper *o,
 
        cmd->child.argv = cmd->argv.argv;
        cmd->child.use_shell = 1;
-       cmd->child.no_stdin = 1;
+       if (use_stdin)
+               cmd->child.in = -1;
+       else
+               cmd->child.no_stdin = 1;
        cmd->child.out = -1;
 
        if (start_command(&cmd->child) < 0) {
@@ -120,7 +124,7 @@ int odb_helper_init(struct odb_helper *o)
        FILE *fh;
        struct strbuf line = STRBUF_INIT;
 
-       if (odb_helper_start(o, &cmd, "init") < 0)
+       if (odb_helper_start(o, &cmd, 0, "init") < 0)
                return -1;
 
        fh = xfdopen(cmd.child.out, "r");
@@ -180,7 +184,7 @@ static void odb_helper_load_have(struct odb_helper *o)
                return;
        o->have_valid = 1;
 
-       if (odb_helper_start(o, &cmd, "have") < 0)
+       if (odb_helper_start(o, &cmd, 0, "have") < 0)
                return;
 
        fh = xfdopen(cmd.child.out, "r");
@@ -235,7 +239,7 @@ int odb_helper_get_object(struct odb_helper *o, const 
unsigned char *sha1,
        if (!obj)
                return -1;
 
-       if (odb_helper_start(o, &cmd, "get_git_obj %s", sha1_to_hex(sha1)) < 0)
+       if (odb_helper_start(o, &cmd, 0, "get_git_obj %s", sha1_to_hex(sha1)) < 
0)
                return -1;
 
        memset(&stream, 0, sizeof(stream));
@@ -335,3 +339,32 @@ int odb_helper_get_direct(struct odb_helper *o,
 
        return res;
 }
+
+int odb_helper_put_object(struct odb_helper *o,
+                         const void *buf, size_t len,
+                         const char *type, unsigned char *sha1)
+{
+       struct odb_helper_cmd cmd;
+
+       if (odb_helper_start(o, &cmd, 1, "put_raw_obj %s %"PRIuMAX" %s",
+                            sha1_to_hex(sha1), (uintmax_t)len, type) < 0)
+               return -1;
+
+       do {
+               int w = xwrite(cmd.child.in, buf, len);
+               if (w < 0) {
+                       error("unable to write to odb helper '%s': %s",
+                             o->name, strerror(errno));
+                       close(cmd.child.in);
+                       close(cmd.child.out);
+                       odb_helper_finish(o, &cmd);
+                       return -1;
+               }
+               len -= w;
+       } while (len > 0);
+
+       close(cmd.child.in);
+       close(cmd.child.out);
+       odb_helper_finish(o, &cmd);
+       return 0;
+}
diff --git a/odb-helper.h b/odb-helper.h
index f8eac7f44c..4a9cc7f07b 100644
--- a/odb-helper.h
+++ b/odb-helper.h
@@ -46,5 +46,8 @@ extern int odb_helper_get_object(struct odb_helper *o,
                                 int fd);
 extern int odb_helper_get_direct(struct odb_helper *o,
                                 const unsigned char *sha1);
+extern int odb_helper_put_object(struct odb_helper *o,
+                                const void *buf, size_t len,
+                                const char *type, unsigned char *sha1);
 
 #endif /* ODB_HELPER_H */
diff --git a/sha1_file.c b/sha1_file.c
index f1d688c10a..8c873554b2 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1695,6 +1695,8 @@ int write_sha1_file(const void *buf, unsigned long len, 
const char *type, unsign
         * it out into .git/objects/??/?{38} file.
         */
        write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
+       if (!external_odb_put_object(buf, len, type, sha1))
+               return 0;
        if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
                return 0;
        return write_loose_object(sha1, hdr, hdrlen, buf, len, 0);
-- 
2.16.0.rc0.16.g82191dbc6c.dirty

Reply via email to