From: "René Scharfe" <rene.scharfe@lsrfire.ath.cx>
To: "Shawn O. Pearce" <spearce@spearce.org>
Cc: git@vger.kernel.org, Junio C Hamano <junkio@cox.net>,
Frank Lichtenheld <frank@lichtenheld.de>,
Johan Herland <johan@herland.net>,
Thomas Glanzmann <thomas@glanzmann.de>,
Michael Gernoth <simigern@cip.informatik.uni-erlangen.de>
Subject: Re: Commit ID in exported Tar Ball
Date: Wed, 23 May 2007 00:26:58 +0200 [thread overview]
Message-ID: <46536E32.6000202@lsrfire.ath.cx> (raw)
In-Reply-To: <4651F908.2000608@lsrfire.ath.cx>
[I'm quoting myself in full because I somehow sent my reply to everyone
but Shawn. A patch can be found at the end.]
René Scharfe schrieb:
> Shawn O. Pearce schrieb:
>> Ren?? Scharfe <rene.scharfe@lsrfire.ath.cx> wrote:
>>> Shawn O. Pearce schrieb:
>>>> git-describe is more human-friendly than a SHA-1...
>>> Yes, and the Makefile does even more than that: it adds a version
>>> file, a spec file and another version file for git-gui.
>>>
>>> The first two are probably useful for most projects that actually
>>> do versioned releases. We could have a simple parser that reads
>>> a template, replaces @@VERSION@@ with a git-describe output
>>> string and adds the result as a synthetic file to the archive.
>>> It's not exactly trivial -- e.g., how to specify git-describe
>>> options, template file and synthetic name, all in one command
>>> line parameter? -- but it's doable.
>> Maybe something just as simple as allowing the user to specify a
>> shell script in-tree that we unpack and run for them? That script
>> prints to stdout the content of the file to include.
>
> I doubt executing a shell script is simple. :-D You'd possibly get
> different results on different platforms (dare I mention Windows?).
>
> The template system I mentioned would be a kind of scripting language
> itself, but in this case we define its syntax and can guarantee
> consistency everywhere git runs. And since it would only have four
> types of tokens (@@VERSION@@, @@COMMITID@@, @@@@ and string literals)
> it could be fast and simple.
>
> We could implement it as a checkout converter, preferably one that is
> only applied by git-archive. Then we'd rename git.spec.in to
> git.spec, assign the "specfile" attribute to it and let git-archive
> replace the string @@VERSION@@ with git-describe's output.
> git-checkout would not expand the special strings, so you can simply
> edit and version the file as you can do with git.spec.in now.
> Michael would have a file containing only @@COMMITID@@ to solve his
> original problem. Make sense?
>
>> So now we're also really talking about, what should git-archive do
>> for a subproject? Sometimes you really do want to repackage and
>> redistribute the subproject as part of the superproject's tarball.
>> Sometimes you don't. I think in the case of git.git and
>> git-gui.git we want to include the subproject. ;-)
>
> Oh, yes, subprojects. git-archive currently exports them as empty
> directories. Using tar's append command you could simply build the
> project+subproject archive in the Makefile. That wouldn't work well
> with gitweb, though. Perhaps a --include-subproject=<path> option is
> needed?
OK, so here's a first shot at the mentioned parser. It only understands
@@COMMITID@@ and @@@@, but it's easily extendible. The internals of
git-describe would need to be converted to library functions, preferably
offering every piece of version info separately (see thread "[PATCH]
Make sure an autogenerated version has at least four parts" for why).
Before doing that, we should determine if this is the way to, though.
René
Documentation/gitattributes.txt | 19 ++++++-
archive-tar.c | 5 ++-
archive-zip.c | 5 ++-
cache.h | 1 +
convert.c | 112 +++++++++++++++++++++++++++++++++++++++
5 files changed, 139 insertions(+), 3 deletions(-)
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index d3ac9c7..84c414c 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -72,7 +72,7 @@ EFFECTS
-------
Certain operations by git can be influenced by assigning
-particular attributes to a path. Currently, three operations
+particular attributes to a path. Currently, four operations
are attributes-aware.
Checking-out and checking-in
@@ -374,6 +374,23 @@ frotz unspecified
----------------------------------------------------------------
+Creating an archive
+~~~~~~~~~~~~~~~~~~~
+
+
+`specfile`
+^^^^^^^^^^
+
+If the attribute `specfile` is set for a file then git will expand
+several placeholders when adding this file to an archive. The
+expansion depends on the availability of a commit ID, i.e. if
+`git-archive` has been given a tree instead of a commit or a tag
+then no replacement will be done.
+
+`@@COMMITID@@`:: is replaced by the commit hash.
+`@@@@`:: is replaced by `@@`.
+
+
GIT
---
Part of the gitlink:git[7] suite
diff --git a/archive-tar.c b/archive-tar.c
index 66fe3e3..eba24cb 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -17,6 +17,7 @@ static unsigned long offset;
static time_t archive_time;
static int tar_umask = 002;
static int verbose;
+static const unsigned char *commit_sha1;
/* writes out the whole block, but only if it is full */
static void write_if_needed(void)
@@ -285,7 +286,8 @@ static int write_tar_entry(const unsigned char *sha1,
buffer = NULL;
size = 0;
} else {
- buffer = convert_sha1_file(path.buf, sha1, mode, &type, &size);
+ buffer = sha1_file_to_archive(path.buf, sha1, mode, &type,
+ &size, commit_sha1);
if (!buffer)
die("cannot read %s", sha1_to_hex(sha1));
}
@@ -304,6 +306,7 @@ int write_tar_archive(struct archiver_args *args)
archive_time = args->time;
verbose = args->verbose;
+ commit_sha1 = args->commit_sha1;
if (args->commit_sha1)
write_global_extended_header(args->commit_sha1);
diff --git a/archive-zip.c b/archive-zip.c
index 444e162..93a5ab3 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -12,6 +12,7 @@
static int verbose;
static int zip_date;
static int zip_time;
+static const unsigned char *commit_sha1;
static unsigned char *zip_dir;
static unsigned int zip_dir_size;
@@ -195,7 +196,8 @@ static int write_zip_entry(const unsigned char *sha1,
if (S_ISREG(mode) && zlib_compression_level != 0)
method = 8;
result = 0;
- buffer = convert_sha1_file(path, sha1, mode, &type, &size);
+ buffer = sha1_file_to_archive(path, sha1, mode, &type, &size,
+ commit_sha1);
if (!buffer)
die("cannot read %s", sha1_to_hex(sha1));
crc = crc32(crc, buffer, size);
@@ -316,6 +318,7 @@ int write_zip_archive(struct archiver_args *args)
zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);
zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
verbose = args->verbose;
+ commit_sha1 = args->commit_sha1;
if (args->base && plen > 0 && args->base[plen - 1] == '/') {
char *base = xstrdup(args->base);
diff --git a/cache.h b/cache.h
index cd875bc..0484904 100644
--- a/cache.h
+++ b/cache.h
@@ -550,6 +550,7 @@ extern void trace_argv_printf(const char **argv, int count, const char *format,
extern char *convert_to_git(const char *path, const char *src, unsigned long *sizep);
extern char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep);
extern void *convert_sha1_file(const char *path, const unsigned char *sha1, unsigned int mode, enum object_type *type, unsigned long *size);
+extern void *sha1_file_to_archive(const char *path, const unsigned char *sha1, unsigned int mode, enum object_type *type, unsigned long *size, const unsigned char *commit_sha1);
/* match-trees.c */
void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, int);
diff --git a/convert.c b/convert.c
index 4b26b1a..1cdaec5 100644
--- a/convert.c
+++ b/convert.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "attr.h"
#include "run-command.h"
+#include "strbuf.h"
/*
* convert.c - convert a file when checking it out and checking it in.
@@ -667,3 +668,114 @@ void *convert_sha1_file(const char *path, const unsigned char *sha1,
}
return buffer;
}
+
+static void strbuf_append(struct strbuf *sb, const void *s, size_t len)
+{
+ if (sb->alloc < sb->len + len) {
+ sb->alloc = (sb->len + len) * 3 / 2 + 16;
+ sb->buf = xrealloc(sb->buf, sb->alloc);
+ }
+ memcpy(sb->buf + sb->len, s, len);
+ sb->len += len;
+}
+
+static unsigned int match_keyword(const char *data, unsigned int datalen,
+ const char *keyword)
+{
+ unsigned int keylen = strlen(keyword);
+ if (keylen > datalen)
+ return 0;
+ if (memcmp(data, keyword, keylen))
+ return 0;
+ return keylen;
+}
+
+static void *convert_to_archive(const char *path, const void *src,
+ unsigned long *sizep,
+ const unsigned char *commit_sha1)
+{
+ static struct git_attr *attr_specfile;
+ struct git_attr_check check[1];
+ const char *p = src;
+ unsigned long srcsize = *sizep;
+ int at_signs = 0;
+ struct strbuf dst;
+ unsigned int match;
+ int replaced_something = 0;
+
+ if (!commit_sha1)
+ return NULL;
+
+ if (!attr_specfile)
+ attr_specfile = git_attr("specfile", 8);
+
+ check[0].attr = attr_specfile;
+ if (git_checkattr(path, ARRAY_SIZE(check), check))
+ return NULL;
+ if (!ATTR_TRUE(check[0].value))
+ return NULL;
+
+ dst.alloc = srcsize + 128;
+ dst.buf = xmalloc(dst.alloc);
+ dst.len = dst.eof = 0;
+
+ while (srcsize > 0) {
+ if ((at_signs == 0 || at_signs == 1) && *p == '@') {
+ at_signs++;
+ p++;
+ srcsize--;
+ continue;
+ }
+ if (at_signs == 1) {
+ at_signs = 0;
+ strbuf_append(&dst, "@", 1);
+ }
+ if (at_signs == 0) {
+ strbuf_append(&dst, p, 1);
+ p++;
+ srcsize--;
+ continue;
+ }
+
+ if ((match = match_keyword(p, srcsize, "@@")))
+ strbuf_append(&dst, "@@", 2);
+ else if ((match = match_keyword(p, srcsize, "COMMITID@@")))
+ strbuf_append(&dst, sha1_to_hex(commit_sha1), 40);
+ else
+ strbuf_append(&dst, "@@", 2);
+ at_signs = 0;
+ p += match;
+ srcsize -= match;
+ replaced_something = 1;
+ }
+
+ if (!replaced_something) {
+ free(dst.buf);
+ return NULL;
+ }
+
+ *sizep = dst.len;
+ return dst.buf;
+}
+
+void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
+ unsigned int mode, enum object_type *type,
+ unsigned long *size,
+ const unsigned char *commit_sha1)
+{
+ void *buffer = read_sha1_file(sha1, type, size);
+ if (S_ISREG(mode) && buffer) {
+ void *converted = convert_to_working_tree(path, buffer, size);
+ if (converted) {
+ free(buffer);
+ buffer = converted;
+ }
+
+ converted = convert_to_archive(path, buffer, size, commit_sha1);
+ if (converted) {
+ free(buffer);
+ buffer = converted;
+ }
+ }
+ return buffer;
+}
next prev parent reply other threads:[~2007-05-22 22:27 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-05-17 16:38 Commit ID in exported Tar Ball Thomas Glanzmann
2007-05-17 16:57 ` Johan Herland
2007-05-17 17:11 ` Frank Lichtenheld
2007-05-17 17:14 ` Thomas Glanzmann
2007-05-17 17:28 ` Johan Herland
2007-05-18 22:09 ` [PATCH] git-archive: convert archive entries like checkouts do René Scharfe
2007-05-18 22:27 ` Daniel Barkalow
2007-05-18 22:58 ` René Scharfe
2007-05-19 20:22 ` Commit ID in exported Tar Ball René Scharfe
2007-05-19 21:00 ` Junio C Hamano
2007-05-19 21:39 ` A Large Angry SCM
2007-05-20 0:15 ` René Scharfe
2007-05-20 11:20 ` René Scharfe
2007-05-20 3:57 ` Shawn O. Pearce
2007-05-20 11:20 ` René Scharfe
2007-05-21 6:02 ` Shawn O. Pearce
2007-05-21 12:09 ` Petr Baudis
2007-05-21 19:54 ` René Scharfe
2007-05-22 22:26 ` René Scharfe [this message]
2007-05-22 22:54 ` Junio C Hamano
2007-05-22 23:44 ` René Scharfe
2007-05-23 5:22 ` Shawn O. Pearce
2007-05-20 11:20 ` René Scharfe
2007-05-20 16:10 ` Thomas Glanzmann
2007-05-20 16:28 ` Brian Gernhardt
2007-05-20 16:30 ` Thomas Glanzmann
2007-05-21 6:19 ` Peter Baumann
2007-05-21 6:24 ` Thomas Glanzmann
2007-05-21 6:29 ` Shawn O. Pearce
2007-05-21 6:37 ` Thomas Glanzmann
2007-05-21 6:53 ` Shawn O. Pearce
2007-05-21 7:00 ` Thomas Glanzmann
2007-05-21 6:56 ` Brian Gernhardt
2007-05-21 7:02 ` Thomas Glanzmann
2007-05-17 17:48 ` Frank Lichtenheld
2007-05-17 18:05 ` Johan Herland
2007-05-17 17:02 ` Kristian Høgsberg
2007-05-17 17:13 ` Thomas Glanzmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=46536E32.6000202@lsrfire.ath.cx \
--to=rene.scharfe@lsrfire.ath.cx \
--cc=frank@lichtenheld.de \
--cc=git@vger.kernel.org \
--cc=johan@herland.net \
--cc=junkio@cox.net \
--cc=simigern@cip.informatik.uni-erlangen.de \
--cc=spearce@spearce.org \
--cc=thomas@glanzmann.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.