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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).