XMLTO_EXTRA =
INSTALL?=install
RM ?= rm -f
-DOC_REF = origin/man
-HTML_REF = origin/html
+MAN_REPO = ../../git-manpages
+HTML_REPO = ../../git-htmldocs
infodir?=$(prefix)/share/info
MAKEINFO=makeinfo
install-webdoc : html
'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
+# You must have a clone of git-htmldocs and git-manpages repositories
+# next to the git repository itself for the following to work.
+
quick-install: quick-install-man
-quick-install-man:
- '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir)
+require-manrepo::
+ @if test ! -d $(MAN_REPO); \
+ then echo "git-manpages repository must exist at $(MAN_REPO)"; exit 1; fi
+
+quick-install-man: require-manrepo
+ '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(MAN_REPO) $(DESTDIR)$(mandir)
+
+require-htmlrepo::
+ @if test ! -d $(HTML_REPO); \
+ then echo "git-htmldocs repository must exist at $(HTML_REPO)"; exit 1; fi
-quick-install-html:
- '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
+quick-install-html: require-htmlrepo
+ '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REPO) $(DESTDIR)$(htmldir)
.PHONY: FORCE
--- /dev/null
+Git v1.7.7.2 Release Notes
+==========================
+
+Fixes since v1.7.7.1
+--------------------
+
+ * We used to drop error messages from libcurl on certain kinds of
+ errors.
+
+ * Error report from smart HTTP transport, when the connection was
+ broken in the middle of a transfer, showed a useless message on
+ a corrupt packet.
+
+ * "git fetch --prune" was unsafe when used with refspecs from the
+ command line.
+
+ * The attribute mechanism did not use case insensitive match when
+ core.ignorecase was set.
+
+ * "git bisect" did not notice when it failed to update the working tree
+ to the next commit to be tested.
+
+ * "git config --bool --get-regexp" failed to separate the variable name
+ and its value "true" when the variable is defined without "= true".
+
+ * "git remote rename $a $b" were not careful to match the remote name
+ against $a (i.e. source side of the remote nickname).
+
+ * "git mergetool" did not use its arguments as pathspec, but as a path to
+ the file that may not even have any conflict.
+
+ * "git diff --[num]stat" used to use the number of lines of context
+ different from the default, potentially giving different results from
+ "git diff | diffstat" and confusing the users.
+
+ * "git pull" and "git rebase" did not work well even when GIT_WORK_TREE is
+ set correctly with GIT_DIR if the current directory is outside the working
+ tree.
+
+ * "git send-email" did not honor the configured hostname when restarting
+ the HELO/EHLO exchange after switching TLS on.
+
+ * "gitweb" used to produce a non-working link while showing the contents
+ of a blob, when JavaScript actions are enabled.
--- /dev/null
+Git v1.7.7.3 Release Notes
+==========================
+
+Fixes since v1.7.7.2
+--------------------
+
+ * Adjust the "quick-install-doc" procedures as preformatted
+ html/manpage are no longer in the source repository.
+
+ * The logic to optimize the locality of the data in a pack introduced in
+ 1.7.7 was grossly inefficient.
+
+ * The logic to filter out forked projects in the project list in
+ "gitweb" was broken for some time.
+
+ * "git branch -m/-M" advertised to update RENAME_REF ref in the
+ commit log message that introduced the feature but not anywhere in
+ the documentation, and never did update such a ref anyway. This
+ undocumented misfeature that did not exist has been excised.
* "git ls-remote" learned to respond to "-h"(elp) requests.
+ * "mediawiki" remote helper can interact with (surprise!) MediaWiki
+ with "git fetch" & "git push".
+
* "git merge" learned the "--edit" option to allow users to edit the
merge commit log message.
* "git stash" learned "--include-untracked" option to stash away
untracked/ignored cruft from the working tree.
+ * "git submodule clone" does not leak an error message to the UI
+ level unnecessarily anymore.
+
* "git submodule update" learned to honor "none" as the value for
submodule.<name>.update to specify that the named submodule should
not be checked out by default.
between commits in the superproject that has and does not have the
submodule in the tree without re-cloning.
- * "mediawiki" remote helper can interact with (surprise!) MediaWiki
- with "git fetch" & "git push".
+ * "git upload-archive" (hence "git archive --remote") can be built
+ and used on mingw port of Git.
* "gitweb" leaked unescaped control characters from syntax hiliter
outputs.
+ * "gitweb" can be told to give custom string at the end of the HTML
+ HEAD element.
+
* "gitweb" now has its own manual pages.
Unless otherwise noted, all fixes in the 1.7.7.X maintenance track are
included in this release.
- * We used to drop error messages from libcurl on certain kinds of
- errors.
- (merge be22d92eac8 jn/maint-http-error-message later to maint).
-
- * Error report from smart HTTP transport, when the connection was
- broken in the middle of a transfer, showed a useless message on
- a corrupt packet.
- (merge 6cdf022 sp/smart-http-failure later to maint).
-
* HTTP transport did not use pushurl correctly, and also did not tell
what host it is trying to authenticate with when asking for
credentials.
(merge deba493 jk/http-auth later to maint).
- * "git branch -m/-M" advertised to update RENAME_REF ref in the
- commit log message that introduced the feature but not anywhere in
- the documentation, and never did update such a ref anyway. This
- undocumented misfeature that did not exist has been excised.
- (merge b0eab01 jc/maint-remove-renamed-ref later to maint).
+ * "git blame" was aborted if started from an uncommitted content and
+ the path had the textconv filter in effect.
+ (merge 8518088 ss/blame-textconv-fake-working-tree later to maint).
* Adding many refs to the local repository in one go (e.g. "git fetch"
that fetches many tags) and looking up a ref by name in a repository
* Report from "git commit" on untracked files was confused under
core.ignorecase option.
- (merge 2548183b jk/name-hash-dirent later to maint).
-
- * The attribute mechanism did not use case insensitive match when
- core.ignorecase was set.
- (merge 6eba621 bc/attr-ignore-case later to maint).
-
- * "git bisect" did not notice when it failed to update the working tree
- to the next commit to be tested.
- (merge 1acf11717 js/bisect-no-checkout later to maint).
-
- * "git config --bool --get-regexp" failed to separate the variable name
- and its value "true" when the variable is defined without "= true".
- (merge 880e3cc mm/maint-config-explicit-bool-display later to maint).
-
- * "git remote rename $a $b" were not careful to match the remote name
- against $a (i.e. source side of the remote nickname).
- (merge b52d00aed mz/remote-rename later to maint).
-
- * "git diff --[num]stat" used to use the number of lines of context
- different from the default, potentially giving different results from
- "git diff | diffstat" and confusing the users.
- (merge f01cae918 jc/maint-diffstat-numstat-context later to maint).
+ (merge 395c7356 jk/name-hash-dirent later to maint).
* "git merge" did not understand ":/<pattern>" as a way to name a commit.
- * "git mergetool" learned to use its arguments as pathspec, not a path to
- the file that may not even have any conflict.
- (merge 6d9990a jm/mergetool-pathspec later to maint).
-
- * "git pull" and "git rebase" did not work well even when GIT_WORK_TREE is
- set correctly with GIT_DIR if the current directory is outside the working
- tree.
- (merge 035b5bf jk/pull-rebase-with-work-tree later to maint).
-
" "git push" on the receiving end used to call post-receive and post-update
hooks for attempted removal of non-existing refs.
(merge 160b81ed ph/push-to-delete-nothing later to maint).
- * "git send-email" did not honor the configured hostname when restarting
- the HELO/EHLO exchange after switching TLS on.
- (merge 155b940 md/smtp-tls-hello-again later to maint).
-
- * "gitweb" used to produce a non-working link while showing the contents
- of a blob, when JavaScript actions are enabled.
- (merge 2b07ff3ff ps/gitweb-js-with-lineno later to maint).
+ * Help text for "git remote set-url" and "git remote set-branches"
+ were misspelled.
+ (merge c49904e fc/remote-seturl-usage-fix later to maint).
+ (merge 656cdf0 jc/remote-setbranches-usage-fix later to maint).
---
exec >/var/tmp/1
-O=v1.7.7-485-g9ee3d37
+O=v1.7.8-rc1-11-gd7a0129
echo O=$(git describe --always master)
git log --first-parent --oneline --reverse ^$O master
echo
Show whole surrounding functions of changes.
ifndef::git-format-patch[]
+ifndef::git-log[]
--exit-code::
Make the program exit with codes similar to diff(1).
That is, it exits with 1 if there were differences and
--quiet::
Disable all output of the program. Implies `--exit-code`.
+endif::git-log[]
endif::git-format-patch[]
--ext-diff::
+
Can be set using the `GITWEB_SITENAME` at build time. Unset by default.
+$site_html_head_string::
+ HTML snippet to be included in the <head> section of each page.
+ Can be set using `GITWEB_SITE_HTML_HEAD_STRING` at build time.
+ No default value.
+
$site_header::
Name of a file with HTML to be included at the top of each page.
Relative to the directory containing the 'gitweb.cgi' script.
#!/bin/sh
-# This requires a branch named in $head
-# (usually 'man' or 'html', provided by the git.git repository)
-set -e
-head="$1"
-mandir="$2"
-SUBDIRECTORY_OK=t
-USAGE='<refname> <target directory>'
-. "$(git --exec-path)"/git-sh-setup
-cd_to_toplevel
+# This requires git-manpages and/or git-htmldocs repositories
-test -z "$mandir" && usage
-if ! git rev-parse --verify "$head^0" >/dev/null; then
- echo >&2 "head: $head does not exist in the current repository"
- usage
+repository=${1?repository}
+destdir=${2?destination}
+
+head=master GIT_DIR=
+for d in "$repository/.git" "$repository"
+do
+ if GIT_DIR="$d" git rev-parse refs/heads/master >/dev/null 2>&1
+ then
+ GIT_DIR="$d"
+ export GIT_DIR
+ break
+ fi
+done
+
+if test -z "$GIT_DIR"
+then
+ echo >&2 "Neither $repository nor $repository/.git is a repository"
+ exit 1
fi
-GIT_INDEX_FILE=`pwd`/.quick-doc.index
-export GIT_INDEX_FILE
+GIT_WORK_TREE=$(pwd)
+GIT_INDEX_FILE=$(pwd)/.quick-doc.$$
+export GIT_INDEX_FILE GIT_WORK_TREE
rm -f "$GIT_INDEX_FILE"
trap 'rm -f "$GIT_INDEX_FILE"' 0
git read-tree $head
-git checkout-index -a -f --prefix="$mandir"/
+git checkout-index -a -f --prefix="$destdir"/
-if test -n "$GZ"; then
+if test -n "$GZ"
+then
git ls-tree -r --name-only $head |
- xargs printf "$mandir/%s\n" |
+ xargs printf "$destdir/%s\n" |
xargs gzip -f
fi
rm -f "$GIT_INDEX_FILE"
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.7.GIT
+DEF_VER=v1.7.8-rc1
LF='
'
uses some compatibility wrappers to work on AsciiDoc 8. If you have
AsciiDoc 7, try "make ASCIIDOC7=YesPlease".
- Alternatively, pre-formatted documentation is available in
- "html" and "man" branches of the git repository itself. For
- example, you could:
-
- $ mkdir manual && cd manual
- $ git init
- $ git fetch-pack git://git.kernel.org/pub/scm/git/git.git man html |
- while read a b
- do
- echo $a >.git/$b
- done
- $ cp .git/refs/heads/man .git/refs/heads/master
- $ git checkout
-
- to checkout the pre-built man pages. Also in this repository:
-
- $ git checkout html
-
- would instead give you a copy of what you see at:
-
- http://www.kernel.org/pub/software/scm/git/docs/
-
There are also "make quick-install-doc", "make quick-install-man"
and "make quick-install-html" which install preformatted man pages
- and html documentation.
- This does not require asciidoc/xmlto, but it only works from within
- a cloned checkout of git.git with these two extra branches, and will
- not work for the maintainer for obvious chicken-and-egg reasons.
+ and html documentation. To use these build targets, you need to
+ clone two separate git-htmldocs and git-manpages repositories next
+ to the clone of git itself.
It has been reported that docbook-xsl version 1.72 and 1.73 are
buggy; 1.72 misformats manual pages for callouts, and 1.73 needs
LIB_H += compat/obstack.h
LIB_H += compat/win32/pthread.h
LIB_H += compat/win32/syslog.h
-LIB_H += compat/win32/sys/poll.h
+LIB_H += compat/win32/poll.h
LIB_H += compat/win32/dirent.h
LIB_H += connected.h
LIB_H += csum-file.h
NO_PREAD = YesPlease
NEEDS_CRYPTO_WITH_SSL = YesPlease
NO_LIBGEN_H = YesPlease
+ NO_SYS_POLL_H = YesPlease
NO_SYMLINK_HEAD = YesPlease
NO_IPV6 = YesPlease
NO_SETENV = YesPlease
BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
COMPAT_OBJS = compat/msvc.o compat/winansi.o \
compat/win32/pthread.o compat/win32/syslog.o \
- compat/win32/sys/poll.o compat/win32/dirent.o
+ compat/win32/poll.o compat/win32/dirent.o
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
NO_PREAD = YesPlease
NEEDS_CRYPTO_WITH_SSL = YesPlease
NO_LIBGEN_H = YesPlease
+ NO_SYS_POLL_H = YesPlease
NO_SYMLINK_HEAD = YesPlease
NO_SETENV = YesPlease
NO_UNSETENV = YesPlease
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/winansi.o \
compat/win32/pthread.o compat/win32/syslog.o \
- compat/win32/sys/poll.o compat/win32/dirent.o
+ compat/win32/poll.o compat/win32/dirent.o
EXTLIBS += -lws2_32
PTHREAD_LIBS =
X = .exe
const char *exec = "git-upload-archive";
const char *output = NULL;
const char *remote = NULL;
+ int is_remote = 0;
struct option local_opts[] = {
OPT_STRING('o', "output", &output, "file",
"write the archive to this file"),
"retrieve the archive from remote repository <repo>"),
OPT_STRING(0, "exec", &exec, "cmd",
"path to the remote git-upload-archive command"),
+ { OPTION_BOOLEAN, 0, "remote-request", &is_remote, NULL,
+ "indicate we are serving a remote request",
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
OPT_END()
};
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
- return write_archive(argc, argv, prefix, 1, output, 0);
+ return write_archive(argc, argv, prefix, 1, output, is_remote);
}
if (!contents_from || strcmp("-", contents_from)) {
struct stat st;
const char *read_from;
+ char *buf_ptr;
unsigned long buf_len;
if (contents_from) {
switch (st.st_mode & S_IFMT) {
case S_IFREG:
if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
- textconv_object(read_from, mode, null_sha1, &buf.buf, &buf_len))
- buf.len = buf_len;
+ textconv_object(read_from, mode, null_sha1, &buf_ptr, &buf_len))
+ strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
die_errno("cannot open or read '%s'", read_from);
break;
else if (list)
return print_ref_list(kinds, detached, verbose, abbrev,
with_commit, argv);
- else if (rename && (argc == 1))
- rename_branch(head, argv[0], rename > 1);
- else if (rename && (argc == 2))
- rename_branch(argv[0], argv[1], rename > 1);
- else if (argc <= 2) {
+ else if (rename) {
+ if (argc == 1)
+ rename_branch(head, argv[0], rename > 1);
+ else if (argc == 2)
+ rename_branch(argv[0], argv[1], rename > 1);
+ else
+ usage_with_options(builtin_branch_usage, options);
+ } else if (argc <= 2) {
if (kinds != REF_LOCAL_BRANCH)
die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
if (0 <= option_verbosity) {
if (option_bare)
- printf(_("Cloning into bare repository %s...\n"), dir);
+ printf(_("Cloning into bare repository '%s'...\n"), dir);
else
- printf(_("Cloning into %s...\n"), dir);
+ printf(_("Cloning into '%s'...\n"), dir);
}
init_db(option_template, INIT_DB_QUIET);
write_config(&option_config);
return ret;
}
-static int prune_refs(struct transport *transport, struct ref *ref_map)
+static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
{
int result = 0;
- struct ref *ref, *stale_refs = get_stale_heads(transport->remote, ref_map);
+ struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
const char *dangling_msg = dry_run
? _(" (%s will become dangling)\n")
: _(" (%s has become dangling)\n");
free_refs(ref_map);
return 1;
}
- if (prune)
- prune_refs(transport, ref_map);
+ if (prune) {
+ /* If --tags was specified, pretend the user gave us the canonical tags refspec */
+ if (tags == TAGS_SET) {
+ const char *tags_str = "refs/tags/*:refs/tags/*";
+ struct refspec *tags_refspec, *refspec;
+
+ /* Copy the refspec and add the tags to it */
+ refspec = xcalloc(ref_count + 1, sizeof(struct refspec));
+ tags_refspec = parse_fetch_refspec(1, &tags_str);
+ memcpy(refspec, refs, ref_count * sizeof(struct refspec));
+ memcpy(&refspec[ref_count], tags_refspec, sizeof(struct refspec));
+ ref_count++;
+
+ prune_refs(refspec, ref_count, ref_map);
+
+ ref_count--;
+ /* The rest of the strings belong to fetch_one */
+ free_refspec(1, tags_refspec);
+ free(refspec);
+ } else if (ref_count) {
+ prune_refs(refs, ref_count, ref_map);
+ } else {
+ prune_refs(transport->remote->fetch, transport->remote->fetch_refspec_nr, ref_map);
+ }
+ }
free_refs(ref_map);
/* if neither --no-tags nor --tags was specified, do automated tag
atexit(unlock_pack);
refspec = parse_fetch_refspec(ref_nr, refs);
exit_code = do_fetch(transport, refspec, ref_nr);
- free(refspec);
+ free_refspec(ref_nr, refspec);
transport_disconnect(transport);
transport = NULL;
return exit_code;
/* This lock protects all the variables above. */
static pthread_mutex_t grep_mutex;
+static inline void grep_lock(void)
+{
+ if (use_threads)
+ pthread_mutex_lock(&grep_mutex);
+}
+
+static inline void grep_unlock(void)
+{
+ if (use_threads)
+ pthread_mutex_unlock(&grep_mutex);
+}
+
/* Used to serialize calls to read_sha1_file. */
static pthread_mutex_t read_sha1_mutex;
-#define grep_lock() pthread_mutex_lock(&grep_mutex)
-#define grep_unlock() pthread_mutex_unlock(&grep_mutex)
-#define read_sha1_lock() pthread_mutex_lock(&read_sha1_mutex)
-#define read_sha1_unlock() pthread_mutex_unlock(&read_sha1_mutex)
+static inline void read_sha1_lock(void)
+{
+ if (use_threads)
+ pthread_mutex_lock(&read_sha1_mutex);
+}
+
+static inline void read_sha1_unlock(void)
+{
+ if (use_threads)
+ pthread_mutex_unlock(&read_sha1_mutex);
+}
/* Signalled when a new work_item is added to todo. */
static pthread_cond_t cond_add;
{
void *data;
- if (use_threads) {
- read_sha1_lock();
- data = read_sha1_file(sha1, type, size);
- read_sha1_unlock();
- } else {
- data = read_sha1_file(sha1, type, size);
- }
+ read_sha1_lock();
+ data = read_sha1_file(sha1, type, size);
+ read_sha1_unlock();
return data;
}
return 0;
}
-static void add_to_write_order(struct object_entry **wo,
- int *endp,
+static inline void add_to_write_order(struct object_entry **wo,
+ unsigned int *endp,
struct object_entry *e)
{
if (e->filled)
}
static void add_descendants_to_write_order(struct object_entry **wo,
- int *endp,
+ unsigned int *endp,
struct object_entry *e)
{
- struct object_entry *child;
-
- for (child = e->delta_child; child; child = child->delta_sibling)
- add_to_write_order(wo, endp, child);
- for (child = e->delta_child; child; child = child->delta_sibling)
- add_descendants_to_write_order(wo, endp, child);
+ int add_to_order = 1;
+ while (e) {
+ if (add_to_order) {
+ struct object_entry *s;
+ /* add this node... */
+ add_to_write_order(wo, endp, e);
+ /* all its siblings... */
+ for (s = e->delta_sibling; s; s = s->delta_sibling) {
+ add_to_write_order(wo, endp, s);
+ }
+ }
+ /* drop down a level to add left subtree nodes if possible */
+ if (e->delta_child) {
+ add_to_order = 1;
+ e = e->delta_child;
+ } else {
+ add_to_order = 0;
+ /* our sibling might have some children, it is next */
+ if (e->delta_sibling) {
+ e = e->delta_sibling;
+ continue;
+ }
+ /* go back to our parent node */
+ e = e->delta;
+ while (e && !e->delta_sibling) {
+ /* we're on the right side of a subtree, keep
+ * going up until we can go right again */
+ e = e->delta;
+ }
+ if (!e) {
+ /* done- we hit our original root node */
+ return;
+ }
+ /* pass it off to sibling at this level */
+ e = e->delta_sibling;
+ }
+ };
}
static void add_family_to_write_order(struct object_entry **wo,
- int *endp,
+ unsigned int *endp,
struct object_entry *e)
{
struct object_entry *root;
for (root = e; root->delta; root = root->delta)
; /* nothing */
- add_to_write_order(wo, endp, root);
add_descendants_to_write_order(wo, endp, root);
}
static struct object_entry **compute_write_order(void)
{
- int i, wo_end;
+ unsigned int i, wo_end, last_untagged;
struct object_entry **wo = xmalloc(nr_objects * sizeof(*wo));
* Make sure delta_sibling is sorted in the original
* recency order.
*/
- for (i = nr_objects - 1; 0 <= i; i--) {
- struct object_entry *e = &objects[i];
+ for (i = nr_objects; i > 0;) {
+ struct object_entry *e = &objects[--i];
if (!e->delta)
continue;
/* Mark me as the first child */
for_each_tag_ref(mark_tagged, NULL);
/*
- * Give the commits in the original recency order until
+ * Give the objects in the original recency order until
* we see a tagged tip.
*/
for (i = wo_end = 0; i < nr_objects; i++) {
break;
add_to_write_order(wo, &wo_end, &objects[i]);
}
+ last_untagged = i;
/*
* Then fill all the tagged tips.
/*
* And then all remaining commits and tags.
*/
- for (i = 0; i < nr_objects; i++) {
+ for (i = last_untagged; i < nr_objects; i++) {
if (objects[i].type != OBJ_COMMIT &&
objects[i].type != OBJ_TAG)
continue;
/*
* And then all the trees.
*/
- for (i = 0; i < nr_objects; i++) {
+ for (i = last_untagged; i < nr_objects; i++) {
if (objects[i].type != OBJ_TREE)
continue;
add_to_write_order(wo, &wo_end, &objects[i]);
/*
* Finally all the rest in really tight order
*/
- for (i = 0; i < nr_objects; i++)
- add_family_to_write_order(wo, &wo_end, &objects[i]);
+ for (i = last_untagged; i < nr_objects; i++) {
+ if (!objects[i].filled)
+ add_family_to_write_order(wo, &wo_end, &objects[i]);
+ }
+
+ if (wo_end != nr_objects)
+ die("ordered %u objects, expected %"PRIu32, wo_end, nr_objects);
return wo;
}
struct command **cmd_list = cb_data;
struct command *cmd = *cmd_list;
- if (!cmd)
+ if (!cmd || is_null_sha1(cmd->new_sha1))
return -1; /* end of list */
*cmd_list = NULL; /* this returns only one */
hashcpy(sha1, cmd->new_sha1);
struct command **cmd_list = cb_data;
struct command *cmd = *cmd_list;
- if (!cmd)
- return -1; /* end of list */
- *cmd_list = cmd->next;
- hashcpy(sha1, cmd->new_sha1);
- return 0;
+ while (cmd) {
+ if (!is_null_sha1(cmd->new_sha1)) {
+ hashcpy(sha1, cmd->new_sha1);
+ *cmd_list = cmd->next;
+ return 0;
+ }
+ cmd = cmd->next;
+ }
+ *cmd_list = NULL;
+ return -1; /* end of list */
}
static void execute_commands(struct command *commands, const char *unpacker_error)
else
string_list_append(&states->tracked, abbrev_branch(ref->name));
}
- stale_refs = get_stale_heads(states->remote, fetch_map);
+ stale_refs = get_stale_heads(states->remote->fetch,
+ states->remote->fetch_refspec_nr, fetch_map);
for (ref = stale_refs; ref; ref = ref->next) {
struct string_list_item *item =
string_list_append(&states->stale, abbrev_branch(ref->name));
builtin_remote_setbranches_usage, 0);
if (argc == 0) {
error("no remote specified");
- usage_with_options(builtin_remote_seturl_usage, options);
+ usage_with_options(builtin_remote_setbranches_usage, options);
}
argv[argc] = NULL;
"delete URLs"),
OPT_END()
};
- argc = parse_options(argc, argv, NULL, options, builtin_remote_update_usage,
+ argc = parse_options(argc, argv, NULL, options, builtin_remote_seturl_usage,
PARSE_OPT_KEEP_ARGV0);
if (add_mode && delete_mode)
#include "archive.h"
#include "pkt-line.h"
#include "sideband.h"
+#include "run-command.h"
static const char upload_archive_usage[] =
"git upload-archive <repo>";
#define MAX_ARGS (64)
-static int run_upload_archive(int argc, const char **argv, const char *prefix)
+static void prepare_argv(const char **sent_argv, const char **argv)
{
- const char *sent_argv[MAX_ARGS];
const char *arg_cmd = "argument ";
char *p, buf[4096];
int sent_argc;
int len;
- if (argc != 2)
- usage(upload_archive_usage);
-
- if (strlen(argv[1]) + 1 > sizeof(buf))
- die("insanely long repository name");
-
- strcpy(buf, argv[1]); /* enter-repo smudges its argument */
-
- if (!enter_repo(buf, 0))
- die("'%s' does not appear to be a git repository", buf);
-
/* put received options in sent_argv[] */
- sent_argc = 1;
- sent_argv[0] = "git-upload-archive";
+ sent_argc = 2;
+ sent_argv[0] = "archive";
+ sent_argv[1] = "--remote-request";
for (p = buf;;) {
/* This will die if not enough free space in buf */
len = packet_read_line(0, p, (buf + sizeof buf) - p);
*p++ = 0;
}
sent_argv[sent_argc] = NULL;
-
- /* parse all options sent by the client */
- return write_archive(sent_argc, sent_argv, prefix, 0, NULL, 1);
}
__attribute__((format (printf, 1, 2)))
int cmd_upload_archive(int argc, const char **argv, const char *prefix)
{
- pid_t writer;
- int fd1[2], fd2[2];
- /*
- * Set up sideband subprocess.
- *
- * We (parent) monitor and read from child, sending its fd#1 and fd#2
- * multiplexed out to our fd#1. If the child dies, we tell the other
- * end over channel #3.
- */
- if (pipe(fd1) < 0 || pipe(fd2) < 0) {
- int err = errno;
- packet_write(1, "NACK pipe failed on the remote side\n");
- die("upload-archive: %s", strerror(err));
- }
- writer = fork();
- if (writer < 0) {
+ const char *sent_argv[MAX_ARGS];
+ struct child_process cld = { sent_argv };
+ cld.out = cld.err = -1;
+ cld.git_cmd = 1;
+
+ if (argc != 2)
+ usage(upload_archive_usage);
+
+ if (!enter_repo(argv[1], 0))
+ die("'%s' does not appear to be a git repository", argv[1]);
+
+ prepare_argv(sent_argv, argv);
+ if (start_command(&cld)) {
int err = errno;
packet_write(1, "NACK fork failed on the remote side\n");
die("upload-archive: %s", strerror(err));
}
- if (!writer) {
- /* child - connect fd#1 and fd#2 to the pipe */
- dup2(fd1[1], 1);
- dup2(fd2[1], 2);
- close(fd1[1]); close(fd2[1]);
- close(fd1[0]); close(fd2[0]); /* we do not read from pipe */
-
- exit(run_upload_archive(argc, argv, prefix));
- }
/* parent - read from child, multiplex and send out to fd#1 */
- close(fd1[1]); close(fd2[1]); /* we do not write to pipe */
packet_write(1, "ACK\n");
packet_flush(1);
struct pollfd pfd[2];
int status;
- pfd[0].fd = fd1[0];
+ pfd[0].fd = cld.out;
pfd[0].events = POLLIN;
- pfd[1].fd = fd2[0];
+ pfd[1].fd = cld.err;
pfd[1].events = POLLIN;
if (poll(pfd, 2, -1) < 0) {
if (errno != EINTR) {
if (process_input(pfd[0].fd, 1))
continue;
- if (waitpid(writer, &status, 0) < 0)
+ if (waitpid(cld.pid, &status, 0) < 0)
error_clnt("%s", lostchild);
else if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
error_clnt("%s", deadchild);
{ errno = ENOSYS; return -1; }
static inline int fchmod(int fildes, mode_t mode)
{ errno = ENOSYS; return -1; }
-static inline pid_t fork(void)
-{ errno = ENOSYS; return -1; }
static inline unsigned int alarm(unsigned int seconds)
{ return 0; }
static inline int fsync(int fd)
--- /dev/null
+/* Emulation for poll(2)
+ Contributed by Paolo Bonzini.
+
+ Copyright 2001-2003, 2006-2011 Free Software Foundation, Inc.
+
+ This file is part of gnulib.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Tell gcc not to warn about the (nfd < 0) tests, below. */
+#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
+# pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+
+#include <malloc.h>
+
+#include <sys/types.h>
+
+/* Specification. */
+#include <poll.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <assert.h>
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define WIN32_NATIVE
+# if defined (_MSC_VER)
+# define _WIN32_WINNT 0x0502
+# endif
+# include <winsock2.h>
+# include <windows.h>
+# include <io.h>
+# include <stdio.h>
+# include <conio.h>
+#else
+# include <sys/time.h>
+# include <sys/socket.h>
+# include <sys/select.h>
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#include <time.h>
+
+#ifndef INFTIM
+# define INFTIM (-1)
+#endif
+
+/* BeOS does not have MSG_PEEK. */
+#ifndef MSG_PEEK
+# define MSG_PEEK 0
+#endif
+
+#ifdef WIN32_NATIVE
+
+#define IsConsoleHandle(h) (((long) (h) & 3) == 3)
+
+static BOOL
+IsSocketHandle (HANDLE h)
+{
+ WSANETWORKEVENTS ev;
+
+ if (IsConsoleHandle (h))
+ return FALSE;
+
+ /* Under Wine, it seems that getsockopt returns 0 for pipes too.
+ WSAEnumNetworkEvents instead distinguishes the two correctly. */
+ ev.lNetworkEvents = 0xDEADBEEF;
+ WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+ return ev.lNetworkEvents != 0xDEADBEEF;
+}
+
+/* Declare data structures for ntdll functions. */
+typedef struct _FILE_PIPE_LOCAL_INFORMATION {
+ ULONG NamedPipeType;
+ ULONG NamedPipeConfiguration;
+ ULONG MaximumInstances;
+ ULONG CurrentInstances;
+ ULONG InboundQuota;
+ ULONG ReadDataAvailable;
+ ULONG OutboundQuota;
+ ULONG WriteQuotaAvailable;
+ ULONG NamedPipeState;
+ ULONG NamedPipeEnd;
+} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
+
+typedef struct _IO_STATUS_BLOCK
+{
+ union {
+ DWORD Status;
+ PVOID Pointer;
+ } u;
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef enum _FILE_INFORMATION_CLASS {
+ FilePipeLocalInformation = 24
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef DWORD (WINAPI *PNtQueryInformationFile)
+ (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
+
+# ifndef PIPE_BUF
+# define PIPE_BUF 512
+# endif
+
+/* Compute revents values for file handle H. If some events cannot happen
+ for the handle, eliminate them from *P_SOUGHT. */
+
+static int
+win32_compute_revents (HANDLE h, int *p_sought)
+{
+ int i, ret, happened;
+ INPUT_RECORD *irbuffer;
+ DWORD avail, nbuffer;
+ BOOL bRet;
+ IO_STATUS_BLOCK iosb;
+ FILE_PIPE_LOCAL_INFORMATION fpli;
+ static PNtQueryInformationFile NtQueryInformationFile;
+ static BOOL once_only;
+
+ switch (GetFileType (h))
+ {
+ case FILE_TYPE_PIPE:
+ if (!once_only)
+ {
+ NtQueryInformationFile = (PNtQueryInformationFile)
+ GetProcAddress (GetModuleHandle ("ntdll.dll"),
+ "NtQueryInformationFile");
+ once_only = TRUE;
+ }
+
+ happened = 0;
+ if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
+ {
+ if (avail)
+ happened |= *p_sought & (POLLIN | POLLRDNORM);
+ }
+ else if (GetLastError () == ERROR_BROKEN_PIPE)
+ happened |= POLLHUP;
+
+ else
+ {
+ /* It was the write-end of the pipe. Check if it is writable.
+ If NtQueryInformationFile fails, optimistically assume the pipe is
+ writable. This could happen on Win9x, where NtQueryInformationFile
+ is not available, or if we inherit a pipe that doesn't permit
+ FILE_READ_ATTRIBUTES access on the write end (I think this should
+ not happen since WinXP SP2; WINE seems fine too). Otherwise,
+ ensure that enough space is available for atomic writes. */
+ memset (&iosb, 0, sizeof (iosb));
+ memset (&fpli, 0, sizeof (fpli));
+
+ if (!NtQueryInformationFile
+ || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
+ FilePipeLocalInformation)
+ || fpli.WriteQuotaAvailable >= PIPE_BUF
+ || (fpli.OutboundQuota < PIPE_BUF &&
+ fpli.WriteQuotaAvailable == fpli.OutboundQuota))
+ happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
+ }
+ return happened;
+
+ case FILE_TYPE_CHAR:
+ ret = WaitForSingleObject (h, 0);
+ if (!IsConsoleHandle (h))
+ return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
+
+ nbuffer = avail = 0;
+ bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
+ if (bRet)
+ {
+ /* Input buffer. */
+ *p_sought &= POLLIN | POLLRDNORM;
+ if (nbuffer == 0)
+ return POLLHUP;
+ if (!*p_sought)
+ return 0;
+
+ irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
+ bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
+ if (!bRet || avail == 0)
+ return POLLHUP;
+
+ for (i = 0; i < avail; i++)
+ if (irbuffer[i].EventType == KEY_EVENT)
+ return *p_sought;
+ return 0;
+ }
+ else
+ {
+ /* Screen buffer. */
+ *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
+ return *p_sought;
+ }
+
+ default:
+ ret = WaitForSingleObject (h, 0);
+ if (ret == WAIT_OBJECT_0)
+ return *p_sought & ~(POLLPRI | POLLRDBAND);
+
+ return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
+ }
+}
+
+/* Convert fd_sets returned by select into revents values. */
+
+static int
+win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
+{
+ int happened = 0;
+
+ if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
+ happened |= (POLLIN | POLLRDNORM) & sought;
+
+ else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
+ {
+ int r, error;
+
+ char data[64];
+ WSASetLastError (0);
+ r = recv (h, data, sizeof (data), MSG_PEEK);
+ error = WSAGetLastError ();
+ WSASetLastError (0);
+
+ if (r > 0 || error == WSAENOTCONN)
+ happened |= (POLLIN | POLLRDNORM) & sought;
+
+ /* Distinguish hung-up sockets from other errors. */
+ else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
+ || error == WSAECONNABORTED || error == WSAENETRESET)
+ happened |= POLLHUP;
+
+ else
+ happened |= POLLERR;
+ }
+
+ if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
+ happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
+
+ if (lNetworkEvents & FD_OOB)
+ happened |= (POLLPRI | POLLRDBAND) & sought;
+
+ return happened;
+}
+
+#else /* !MinGW */
+
+/* Convert select(2) returned fd_sets into poll(2) revents values. */
+static int
+compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
+{
+ int happened = 0;
+ if (FD_ISSET (fd, rfds))
+ {
+ int r;
+ int socket_errno;
+
+# if defined __MACH__ && defined __APPLE__
+ /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
+ for some kinds of descriptors. Detect if this descriptor is a
+ connected socket, a server socket, or something else using a
+ 0-byte recv, and use ioctl(2) to detect POLLHUP. */
+ r = recv (fd, NULL, 0, MSG_PEEK);
+ socket_errno = (r < 0) ? errno : 0;
+ if (r == 0 || socket_errno == ENOTSOCK)
+ ioctl (fd, FIONREAD, &r);
+# else
+ char data[64];
+ r = recv (fd, data, sizeof (data), MSG_PEEK);
+ socket_errno = (r < 0) ? errno : 0;
+# endif
+ if (r == 0)
+ happened |= POLLHUP;
+
+ /* If the event happened on an unconnected server socket,
+ that's fine. */
+ else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
+ happened |= (POLLIN | POLLRDNORM) & sought;
+
+ /* Distinguish hung-up sockets from other errors. */
+ else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
+ || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
+ happened |= POLLHUP;
+
+ else
+ happened |= POLLERR;
+ }
+
+ if (FD_ISSET (fd, wfds))
+ happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
+
+ if (FD_ISSET (fd, efds))
+ happened |= (POLLPRI | POLLRDBAND) & sought;
+
+ return happened;
+}
+#endif /* !MinGW */
+
+int
+poll (struct pollfd *pfd, nfds_t nfd, int timeout)
+{
+#ifndef WIN32_NATIVE
+ fd_set rfds, wfds, efds;
+ struct timeval tv;
+ struct timeval *ptv;
+ int maxfd, rc;
+ nfds_t i;
+
+# ifdef _SC_OPEN_MAX
+ static int sc_open_max = -1;
+
+ if (nfd < 0
+ || (nfd > sc_open_max
+ && (sc_open_max != -1
+ || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+# else /* !_SC_OPEN_MAX */
+# ifdef OPEN_MAX
+ if (nfd < 0 || nfd > OPEN_MAX)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+# endif /* OPEN_MAX -- else, no check is needed */
+# endif /* !_SC_OPEN_MAX */
+
+ /* EFAULT is not necessary to implement, but let's do it in the
+ simplest case. */
+ if (!pfd)
+ {
+ errno = EFAULT;
+ return -1;
+ }
+
+ /* convert timeout number into a timeval structure */
+ if (timeout == 0)
+ {
+ ptv = &tv;
+ ptv->tv_sec = 0;
+ ptv->tv_usec = 0;
+ }
+ else if (timeout > 0)
+ {
+ ptv = &tv;
+ ptv->tv_sec = timeout / 1000;
+ ptv->tv_usec = (timeout % 1000) * 1000;
+ }
+ else if (timeout == INFTIM)
+ /* wait forever */
+ ptv = NULL;
+ else
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* create fd sets and determine max fd */
+ maxfd = -1;
+ FD_ZERO (&rfds);
+ FD_ZERO (&wfds);
+ FD_ZERO (&efds);
+ for (i = 0; i < nfd; i++)
+ {
+ if (pfd[i].fd < 0)
+ continue;
+
+ if (pfd[i].events & (POLLIN | POLLRDNORM))
+ FD_SET (pfd[i].fd, &rfds);
+
+ /* see select(2): "the only exceptional condition detectable
+ is out-of-band data received on a socket", hence we push
+ POLLWRBAND events onto wfds instead of efds. */
+ if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
+ FD_SET (pfd[i].fd, &wfds);
+ if (pfd[i].events & (POLLPRI | POLLRDBAND))
+ FD_SET (pfd[i].fd, &efds);
+ if (pfd[i].fd >= maxfd
+ && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
+ | POLLRDNORM | POLLRDBAND
+ | POLLWRNORM | POLLWRBAND)))
+ {
+ maxfd = pfd[i].fd;
+ if (maxfd > FD_SETSIZE)
+ {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ }
+ }
+
+ /* examine fd sets */
+ rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
+ if (rc < 0)
+ return rc;
+
+ /* establish results */
+ rc = 0;
+ for (i = 0; i < nfd; i++)
+ if (pfd[i].fd < 0)
+ pfd[i].revents = 0;
+ else
+ {
+ int happened = compute_revents (pfd[i].fd, pfd[i].events,
+ &rfds, &wfds, &efds);
+ if (happened)
+ {
+ pfd[i].revents = happened;
+ rc++;
+ }
+ }
+
+ return rc;
+#else
+ static struct timeval tv0;
+ static HANDLE hEvent;
+ WSANETWORKEVENTS ev;
+ HANDLE h, handle_array[FD_SETSIZE + 2];
+ DWORD ret, wait_timeout, nhandles;
+ fd_set rfds, wfds, xfds;
+ BOOL poll_again;
+ MSG msg;
+ int rc = 0;
+ nfds_t i;
+
+ if (nfd < 0 || timeout < -1)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!hEvent)
+ hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
+
+restart:
+ handle_array[0] = hEvent;
+ nhandles = 1;
+ FD_ZERO (&rfds);
+ FD_ZERO (&wfds);
+ FD_ZERO (&xfds);
+
+ /* Classify socket handles and create fd sets. */
+ for (i = 0; i < nfd; i++)
+ {
+ int sought = pfd[i].events;
+ pfd[i].revents = 0;
+ if (pfd[i].fd < 0)
+ continue;
+ if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
+ | POLLPRI | POLLRDBAND)))
+ continue;
+
+ h = (HANDLE) _get_osfhandle (pfd[i].fd);
+ assert (h != NULL);
+ if (IsSocketHandle (h))
+ {
+ int requested = FD_CLOSE;
+
+ /* see above; socket handles are mapped onto select. */
+ if (sought & (POLLIN | POLLRDNORM))
+ {
+ requested |= FD_READ | FD_ACCEPT;
+ FD_SET ((SOCKET) h, &rfds);
+ }
+ if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
+ {
+ requested |= FD_WRITE | FD_CONNECT;
+ FD_SET ((SOCKET) h, &wfds);
+ }
+ if (sought & (POLLPRI | POLLRDBAND))
+ {
+ requested |= FD_OOB;
+ FD_SET ((SOCKET) h, &xfds);
+ }
+
+ if (requested)
+ WSAEventSelect ((SOCKET) h, hEvent, requested);
+ }
+ else
+ {
+ /* Poll now. If we get an event, do not poll again. Also,
+ screen buffer handles are waitable, and they'll block until
+ a character is available. win32_compute_revents eliminates
+ bits for the "wrong" direction. */
+ pfd[i].revents = win32_compute_revents (h, &sought);
+ if (sought)
+ handle_array[nhandles++] = h;
+ if (pfd[i].revents)
+ timeout = 0;
+ }
+ }
+
+ if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
+ {
+ /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
+ no need to call select again. */
+ poll_again = FALSE;
+ wait_timeout = 0;
+ }
+ else
+ {
+ poll_again = TRUE;
+ if (timeout == INFTIM)
+ wait_timeout = INFINITE;
+ else
+ wait_timeout = timeout;
+ }
+
+ for (;;)
+ {
+ ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
+ wait_timeout, QS_ALLINPUT);
+
+ if (ret == WAIT_OBJECT_0 + nhandles)
+ {
+ /* new input of some other kind */
+ BOOL bRet;
+ while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+ }
+ else
+ break;
+ }
+
+ if (poll_again)
+ select (0, &rfds, &wfds, &xfds, &tv0);
+
+ /* Place a sentinel at the end of the array. */
+ handle_array[nhandles] = NULL;
+ nhandles = 1;
+ for (i = 0; i < nfd; i++)
+ {
+ int happened;
+
+ if (pfd[i].fd < 0)
+ continue;
+ if (!(pfd[i].events & (POLLIN | POLLRDNORM |
+ POLLOUT | POLLWRNORM | POLLWRBAND)))
+ continue;
+
+ h = (HANDLE) _get_osfhandle (pfd[i].fd);
+ if (h != handle_array[nhandles])
+ {
+ /* It's a socket. */
+ WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+ WSAEventSelect ((SOCKET) h, 0, 0);
+
+ /* If we're lucky, WSAEnumNetworkEvents already provided a way
+ to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
+ if (FD_ISSET ((SOCKET) h, &rfds)
+ && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
+ ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
+ if (FD_ISSET ((SOCKET) h, &wfds))
+ ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
+ if (FD_ISSET ((SOCKET) h, &xfds))
+ ev.lNetworkEvents |= FD_OOB;
+
+ happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
+ ev.lNetworkEvents);
+ }
+ else
+ {
+ /* Not a socket. */
+ int sought = pfd[i].events;
+ happened = win32_compute_revents (h, &sought);
+ nhandles++;
+ }
+
+ if ((pfd[i].revents |= happened) != 0)
+ rc++;
+ }
+
+ if (!rc && timeout == INFTIM)
+ {
+ SwitchToThread();
+ goto restart;
+ }
+
+ return rc;
+#endif
+}
--- /dev/null
+/* Header for poll(2) emulation
+ Contributed by Paolo Bonzini.
+
+ Copyright 2001, 2002, 2003, 2007, 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of gnulib.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _GL_POLL_H
+#define _GL_POLL_H
+
+/* fake a poll(2) environment */
+#define POLLIN 0x0001 /* any readable data available */
+#define POLLPRI 0x0002 /* OOB/Urgent readable data */
+#define POLLOUT 0x0004 /* file descriptor is writeable */
+#define POLLERR 0x0008 /* some poll error occurred */
+#define POLLHUP 0x0010 /* file descriptor was "hung up" */
+#define POLLNVAL 0x0020 /* requested events "invalid" */
+#define POLLRDNORM 0x0040
+#define POLLRDBAND 0x0080
+#define POLLWRNORM 0x0100
+#define POLLWRBAND 0x0200
+
+struct pollfd
+{
+ int fd; /* which file descriptor to poll */
+ short events; /* events we are interested in */
+ short revents; /* events found on return */
+};
+
+typedef unsigned long nfds_t;
+
+extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout);
+
+/* Define INFTIM only if doing so conforms to POSIX. */
+#if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE)
+#define INFTIM (-1)
+#endif
+
+#endif /* _GL_POLL_H */
+++ /dev/null
-/* Emulation for poll(2)
- Contributed by Paolo Bonzini.
-
- Copyright 2001-2003, 2006-2010 Free Software Foundation, Inc.
-
- This file is part of gnulib.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
-
-/* Tell gcc not to warn about the (nfd < 0) tests, below. */
-#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
-# pragma GCC diagnostic ignored "-Wtype-limits"
-#endif
-
-#include <malloc.h>
-
-#include <sys/types.h>
-#include "poll.h"
-#include <errno.h>
-#include <limits.h>
-#include <assert.h>
-
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-# define WIN32_NATIVE
-# if defined (_MSC_VER)
-# define _WIN32_WINNT 0x0502
-# endif
-# include <winsock2.h>
-# include <windows.h>
-# include <io.h>
-# include <stdio.h>
-# include <conio.h>
-#else
-# include <sys/time.h>
-# include <sys/socket.h>
-# include <sys/select.h>
-# include <unistd.h>
-#endif
-
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_FILIO_H
-# include <sys/filio.h>
-#endif
-
-#include <time.h>
-
-#ifndef INFTIM
-# define INFTIM (-1)
-#endif
-
-/* BeOS does not have MSG_PEEK. */
-#ifndef MSG_PEEK
-# define MSG_PEEK 0
-#endif
-
-#ifdef WIN32_NATIVE
-
-#define IsConsoleHandle(h) (((long) (h) & 3) == 3)
-
-static BOOL
-IsSocketHandle (HANDLE h)
-{
- WSANETWORKEVENTS ev;
-
- if (IsConsoleHandle (h))
- return FALSE;
-
- /* Under Wine, it seems that getsockopt returns 0 for pipes too.
- WSAEnumNetworkEvents instead distinguishes the two correctly. */
- ev.lNetworkEvents = 0xDEADBEEF;
- WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
- return ev.lNetworkEvents != 0xDEADBEEF;
-}
-
-/* Declare data structures for ntdll functions. */
-typedef struct _FILE_PIPE_LOCAL_INFORMATION {
- ULONG NamedPipeType;
- ULONG NamedPipeConfiguration;
- ULONG MaximumInstances;
- ULONG CurrentInstances;
- ULONG InboundQuota;
- ULONG ReadDataAvailable;
- ULONG OutboundQuota;
- ULONG WriteQuotaAvailable;
- ULONG NamedPipeState;
- ULONG NamedPipeEnd;
-} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
-
-typedef struct _IO_STATUS_BLOCK
-{
- union {
- DWORD Status;
- PVOID Pointer;
- } u;
- ULONG_PTR Information;
-} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
-
-typedef enum _FILE_INFORMATION_CLASS {
- FilePipeLocalInformation = 24
-} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
-
-typedef DWORD (WINAPI *PNtQueryInformationFile)
- (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
-
-# ifndef PIPE_BUF
-# define PIPE_BUF 512
-# endif
-
-/* Compute revents values for file handle H. If some events cannot happen
- for the handle, eliminate them from *P_SOUGHT. */
-
-static int
-win32_compute_revents (HANDLE h, int *p_sought)
-{
- int i, ret, happened;
- INPUT_RECORD *irbuffer;
- DWORD avail, nbuffer;
- BOOL bRet;
- IO_STATUS_BLOCK iosb;
- FILE_PIPE_LOCAL_INFORMATION fpli;
- static PNtQueryInformationFile NtQueryInformationFile;
- static BOOL once_only;
-
- switch (GetFileType (h))
- {
- case FILE_TYPE_PIPE:
- if (!once_only)
- {
- NtQueryInformationFile = (PNtQueryInformationFile)
- GetProcAddress (GetModuleHandle ("ntdll.dll"),
- "NtQueryInformationFile");
- once_only = TRUE;
- }
-
- happened = 0;
- if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
- {
- if (avail)
- happened |= *p_sought & (POLLIN | POLLRDNORM);
- }
- else if (GetLastError () == ERROR_BROKEN_PIPE)
- happened |= POLLHUP;
-
- else
- {
- /* It was the write-end of the pipe. Check if it is writable.
- If NtQueryInformationFile fails, optimistically assume the pipe is
- writable. This could happen on Win9x, where NtQueryInformationFile
- is not available, or if we inherit a pipe that doesn't permit
- FILE_READ_ATTRIBUTES access on the write end (I think this should
- not happen since WinXP SP2; WINE seems fine too). Otherwise,
- ensure that enough space is available for atomic writes. */
- memset (&iosb, 0, sizeof (iosb));
- memset (&fpli, 0, sizeof (fpli));
-
- if (!NtQueryInformationFile
- || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
- FilePipeLocalInformation)
- || fpli.WriteQuotaAvailable >= PIPE_BUF
- || (fpli.OutboundQuota < PIPE_BUF &&
- fpli.WriteQuotaAvailable == fpli.OutboundQuota))
- happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
- }
- return happened;
-
- case FILE_TYPE_CHAR:
- ret = WaitForSingleObject (h, 0);
- if (!IsConsoleHandle (h))
- return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
-
- nbuffer = avail = 0;
- bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
- if (bRet)
- {
- /* Input buffer. */
- *p_sought &= POLLIN | POLLRDNORM;
- if (nbuffer == 0)
- return POLLHUP;
- if (!*p_sought)
- return 0;
-
- irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
- bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
- if (!bRet || avail == 0)
- return POLLHUP;
-
- for (i = 0; i < avail; i++)
- if (irbuffer[i].EventType == KEY_EVENT)
- return *p_sought;
- return 0;
- }
- else
- {
- /* Screen buffer. */
- *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
- return *p_sought;
- }
-
- default:
- ret = WaitForSingleObject (h, 0);
- if (ret == WAIT_OBJECT_0)
- return *p_sought & ~(POLLPRI | POLLRDBAND);
-
- return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
- }
-}
-
-/* Convert fd_sets returned by select into revents values. */
-
-static int
-win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
-{
- int happened = 0;
-
- if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
- happened |= (POLLIN | POLLRDNORM) & sought;
-
- else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
- {
- int r, error;
-
- char data[64];
- WSASetLastError (0);
- r = recv (h, data, sizeof (data), MSG_PEEK);
- error = WSAGetLastError ();
- WSASetLastError (0);
-
- if (r > 0 || error == WSAENOTCONN)
- happened |= (POLLIN | POLLRDNORM) & sought;
-
- /* Distinguish hung-up sockets from other errors. */
- else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
- || error == WSAECONNABORTED || error == WSAENETRESET)
- happened |= POLLHUP;
-
- else
- happened |= POLLERR;
- }
-
- if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
- happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
-
- if (lNetworkEvents & FD_OOB)
- happened |= (POLLPRI | POLLRDBAND) & sought;
-
- return happened;
-}
-
-#else /* !MinGW */
-
-/* Convert select(2) returned fd_sets into poll(2) revents values. */
-static int
-compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
-{
- int happened = 0;
- if (FD_ISSET (fd, rfds))
- {
- int r;
- int socket_errno;
-
-# if defined __MACH__ && defined __APPLE__
- /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
- for some kinds of descriptors. Detect if this descriptor is a
- connected socket, a server socket, or something else using a
- 0-byte recv, and use ioctl(2) to detect POLLHUP. */
- r = recv (fd, NULL, 0, MSG_PEEK);
- socket_errno = (r < 0) ? errno : 0;
- if (r == 0 || socket_errno == ENOTSOCK)
- ioctl (fd, FIONREAD, &r);
-# else
- char data[64];
- r = recv (fd, data, sizeof (data), MSG_PEEK);
- socket_errno = (r < 0) ? errno : 0;
-# endif
- if (r == 0)
- happened |= POLLHUP;
-
- /* If the event happened on an unconnected server socket,
- that's fine. */
- else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
- happened |= (POLLIN | POLLRDNORM) & sought;
-
- /* Distinguish hung-up sockets from other errors. */
- else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
- || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
- happened |= POLLHUP;
-
- else
- happened |= POLLERR;
- }
-
- if (FD_ISSET (fd, wfds))
- happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
-
- if (FD_ISSET (fd, efds))
- happened |= (POLLPRI | POLLRDBAND) & sought;
-
- return happened;
-}
-#endif /* !MinGW */
-
-int
-poll (pfd, nfd, timeout)
- struct pollfd *pfd;
- nfds_t nfd;
- int timeout;
-{
-#ifndef WIN32_NATIVE
- fd_set rfds, wfds, efds;
- struct timeval tv;
- struct timeval *ptv;
- int maxfd, rc;
- nfds_t i;
-
-# ifdef _SC_OPEN_MAX
- static int sc_open_max = -1;
-
- if (nfd < 0
- || (nfd > sc_open_max
- && (sc_open_max != -1
- || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
- {
- errno = EINVAL;
- return -1;
- }
-# else /* !_SC_OPEN_MAX */
-# ifdef OPEN_MAX
- if (nfd < 0 || nfd > OPEN_MAX)
- {
- errno = EINVAL;
- return -1;
- }
-# endif /* OPEN_MAX -- else, no check is needed */
-# endif /* !_SC_OPEN_MAX */
-
- /* EFAULT is not necessary to implement, but let's do it in the
- simplest case. */
- if (!pfd)
- {
- errno = EFAULT;
- return -1;
- }
-
- /* convert timeout number into a timeval structure */
- if (timeout == 0)
- {
- ptv = &tv;
- ptv->tv_sec = 0;
- ptv->tv_usec = 0;
- }
- else if (timeout > 0)
- {
- ptv = &tv;
- ptv->tv_sec = timeout / 1000;
- ptv->tv_usec = (timeout % 1000) * 1000;
- }
- else if (timeout == INFTIM)
- /* wait forever */
- ptv = NULL;
- else
- {
- errno = EINVAL;
- return -1;
- }
-
- /* create fd sets and determine max fd */
- maxfd = -1;
- FD_ZERO (&rfds);
- FD_ZERO (&wfds);
- FD_ZERO (&efds);
- for (i = 0; i < nfd; i++)
- {
- if (pfd[i].fd < 0)
- continue;
-
- if (pfd[i].events & (POLLIN | POLLRDNORM))
- FD_SET (pfd[i].fd, &rfds);
-
- /* see select(2): "the only exceptional condition detectable
- is out-of-band data received on a socket", hence we push
- POLLWRBAND events onto wfds instead of efds. */
- if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
- FD_SET (pfd[i].fd, &wfds);
- if (pfd[i].events & (POLLPRI | POLLRDBAND))
- FD_SET (pfd[i].fd, &efds);
- if (pfd[i].fd >= maxfd
- && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
- | POLLRDNORM | POLLRDBAND
- | POLLWRNORM | POLLWRBAND)))
- {
- maxfd = pfd[i].fd;
- if (maxfd > FD_SETSIZE)
- {
- errno = EOVERFLOW;
- return -1;
- }
- }
- }
-
- /* examine fd sets */
- rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
- if (rc < 0)
- return rc;
-
- /* establish results */
- rc = 0;
- for (i = 0; i < nfd; i++)
- if (pfd[i].fd < 0)
- pfd[i].revents = 0;
- else
- {
- int happened = compute_revents (pfd[i].fd, pfd[i].events,
- &rfds, &wfds, &efds);
- if (happened)
- {
- pfd[i].revents = happened;
- rc++;
- }
- }
-
- return rc;
-#else
- static struct timeval tv0;
- static HANDLE hEvent;
- WSANETWORKEVENTS ev;
- HANDLE h, handle_array[FD_SETSIZE + 2];
- DWORD ret, wait_timeout, nhandles;
- fd_set rfds, wfds, xfds;
- BOOL poll_again;
- MSG msg;
- int rc = 0;
- nfds_t i;
-
- if (nfd < 0 || timeout < -1)
- {
- errno = EINVAL;
- return -1;
- }
-
- if (!hEvent)
- hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
-
- handle_array[0] = hEvent;
- nhandles = 1;
- FD_ZERO (&rfds);
- FD_ZERO (&wfds);
- FD_ZERO (&xfds);
-
- /* Classify socket handles and create fd sets. */
- for (i = 0; i < nfd; i++)
- {
- int sought = pfd[i].events;
- pfd[i].revents = 0;
- if (pfd[i].fd < 0)
- continue;
- if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
- | POLLPRI | POLLRDBAND)))
- continue;
-
- h = (HANDLE) _get_osfhandle (pfd[i].fd);
- assert (h != NULL);
- if (IsSocketHandle (h))
- {
- int requested = FD_CLOSE;
-
- /* see above; socket handles are mapped onto select. */
- if (sought & (POLLIN | POLLRDNORM))
- {
- requested |= FD_READ | FD_ACCEPT;
- FD_SET ((SOCKET) h, &rfds);
- }
- if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
- {
- requested |= FD_WRITE | FD_CONNECT;
- FD_SET ((SOCKET) h, &wfds);
- }
- if (sought & (POLLPRI | POLLRDBAND))
- {
- requested |= FD_OOB;
- FD_SET ((SOCKET) h, &xfds);
- }
-
- if (requested)
- WSAEventSelect ((SOCKET) h, hEvent, requested);
- }
- else
- {
- /* Poll now. If we get an event, do not poll again. Also,
- screen buffer handles are waitable, and they'll block until
- a character is available. win32_compute_revents eliminates
- bits for the "wrong" direction. */
- pfd[i].revents = win32_compute_revents (h, &sought);
- if (sought)
- handle_array[nhandles++] = h;
- if (pfd[i].revents)
- timeout = 0;
- }
- }
-
- if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
- {
- /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
- no need to call select again. */
- poll_again = FALSE;
- wait_timeout = 0;
- }
- else
- {
- poll_again = TRUE;
- if (timeout == INFTIM)
- wait_timeout = INFINITE;
- else
- wait_timeout = timeout;
- }
-
- for (;;)
- {
- ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
- wait_timeout, QS_ALLINPUT);
-
- if (ret == WAIT_OBJECT_0 + nhandles)
- {
- /* new input of some other kind */
- BOOL bRet;
- while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
- {
- TranslateMessage (&msg);
- DispatchMessage (&msg);
- }
- }
- else
- break;
- }
-
- if (poll_again)
- select (0, &rfds, &wfds, &xfds, &tv0);
-
- /* Place a sentinel at the end of the array. */
- handle_array[nhandles] = NULL;
- nhandles = 1;
- for (i = 0; i < nfd; i++)
- {
- int happened;
-
- if (pfd[i].fd < 0)
- continue;
- if (!(pfd[i].events & (POLLIN | POLLRDNORM |
- POLLOUT | POLLWRNORM | POLLWRBAND)))
- continue;
-
- h = (HANDLE) _get_osfhandle (pfd[i].fd);
- if (h != handle_array[nhandles])
- {
- /* It's a socket. */
- WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
- WSAEventSelect ((SOCKET) h, 0, 0);
-
- /* If we're lucky, WSAEnumNetworkEvents already provided a way
- to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
- if (FD_ISSET ((SOCKET) h, &rfds)
- && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
- ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
- if (FD_ISSET ((SOCKET) h, &wfds))
- ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
- if (FD_ISSET ((SOCKET) h, &xfds))
- ev.lNetworkEvents |= FD_OOB;
-
- happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
- ev.lNetworkEvents);
- }
- else
- {
- /* Not a socket. */
- int sought = pfd[i].events;
- happened = win32_compute_revents (h, &sought);
- nhandles++;
- }
-
- if ((pfd[i].revents |= happened) != 0)
- rc++;
- }
-
- return rc;
-#endif
-}
+++ /dev/null
-/* Header for poll(2) emulation
- Contributed by Paolo Bonzini.
-
- Copyright 2001, 2002, 2003, 2007, 2009, 2010 Free Software Foundation, Inc.
-
- This file is part of gnulib.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
-
-#ifndef _GL_POLL_H
-#define _GL_POLL_H
-
-/* fake a poll(2) environment */
-#define POLLIN 0x0001 /* any readable data available */
-#define POLLPRI 0x0002 /* OOB/Urgent readable data */
-#define POLLOUT 0x0004 /* file descriptor is writeable */
-#define POLLERR 0x0008 /* some poll error occurred */
-#define POLLHUP 0x0010 /* file descriptor was "hung up" */
-#define POLLNVAL 0x0020 /* requested events "invalid" */
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-
-struct pollfd
-{
- int fd; /* which file descriptor to poll */
- short events; /* events we are interested in */
- short revents; /* events found on return */
-};
-
-typedef unsigned long nfds_t;
-
-extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout);
-
-/* Define INFTIM only if doing so conforms to POSIX. */
-#if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE)
-#define INFTIM (-1)
-#endif
-
-#endif /* _GL_POLL_H */
_gitk
}
+__git_match_ctag() {
+ awk "/^${1////\\/}/ { print \$1 }" "$2"
+}
+
_git_grep ()
{
__git_has_doubledash && return
;;
esac
+ case "$cword,$prev" in
+ 2,*|*,-*)
+ if test -r tags; then
+ __gitcomp "$(__git_match_ctag "$cur" tags)"
+ return
+ fi
+ ;;
+ esac
+
__gitcomp "$(__git_refs)"
}
--- /dev/null
+diff-highlight
+==============
+
+Line oriented diffs are great for reviewing code, because for most
+hunks, you want to see the old and the new segments of code next to each
+other. Sometimes, though, when an old line and a new line are very
+similar, it's hard to immediately see the difference.
+
+You can use "--color-words" to highlight only the changed portions of
+lines. However, this can often be hard to read for code, as it loses
+the line structure, and you end up with oddly formatted bits.
+
+Instead, this script post-processes the line-oriented diff, finds pairs
+of lines, and highlights the differing segments. It's currently very
+simple and stupid about doing these tasks. In particular:
+
+ 1. It will only highlight a pair of lines if they are the only two
+ lines in a hunk. It could instead try to match up "before" and
+ "after" lines for a given hunk into pairs of similar lines.
+ However, this may end up visually distracting, as the paired
+ lines would have other highlighted lines in between them. And in
+ practice, the lines which most need attention called to their
+ small, hard-to-see changes are touching only a single line.
+
+ 2. It will find the common prefix and suffix of two lines, and
+ consider everything in the middle to be "different". It could
+ instead do a real diff of the characters between the two lines and
+ find common subsequences. However, the point of the highlight is to
+ call attention to a certain area. Even if some small subset of the
+ highlighted area actually didn't change, that's OK. In practice it
+ ends up being more readable to just have a single blob on the line
+ showing the interesting bit.
+
+The goal of the script is therefore not to be exact about highlighting
+changes, but to call attention to areas of interest without being
+visually distracting. Non-diff lines and existing diff coloration is
+preserved; the intent is that the output should look exactly the same as
+the input, except for the occasional highlight.
+
+Use
+---
+
+You can try out the diff-highlight program with:
+
+---------------------------------------------
+git log -p --color | /path/to/diff-highlight
+---------------------------------------------
+
+If you want to use it all the time, drop it in your $PATH and put the
+following in your git configuration:
+
+---------------------------------------------
+[pager]
+ log = diff-highlight | less
+ show = diff-highlight | less
+ diff = diff-highlight | less
+---------------------------------------------
--- /dev/null
+#!/usr/bin/perl
+
+# Highlight by reversing foreground and background. You could do
+# other things like bold or underline if you prefer.
+my $HIGHLIGHT = "\x1b[7m";
+my $UNHIGHLIGHT = "\x1b[27m";
+my $COLOR = qr/\x1b\[[0-9;]*m/;
+
+my @window;
+
+while (<>) {
+ # We highlight only single-line changes, so we need
+ # a 4-line window to make a decision on whether
+ # to highlight.
+ push @window, $_;
+ next if @window < 4;
+ if ($window[0] =~ /^$COLOR*(\@| )/ &&
+ $window[1] =~ /^$COLOR*-/ &&
+ $window[2] =~ /^$COLOR*\+/ &&
+ $window[3] !~ /^$COLOR*\+/) {
+ print shift @window;
+ show_pair(shift @window, shift @window);
+ }
+ else {
+ print shift @window;
+ }
+
+ # Most of the time there is enough output to keep things streaming,
+ # but for something like "git log -Sfoo", you can get one early
+ # commit and then many seconds of nothing. We want to show
+ # that one commit as soon as possible.
+ #
+ # Since we can receive arbitrary input, there's no optimal
+ # place to flush. Flushing on a blank line is a heuristic that
+ # happens to match git-log output.
+ if (!length) {
+ local $| = 1;
+ }
+}
+
+# Special case a single-line hunk at the end of file.
+if (@window == 3 &&
+ $window[0] =~ /^$COLOR*(\@| )/ &&
+ $window[1] =~ /^$COLOR*-/ &&
+ $window[2] =~ /^$COLOR*\+/) {
+ print shift @window;
+ show_pair(shift @window, shift @window);
+}
+
+# And then flush any remaining lines.
+while (@window) {
+ print shift @window;
+}
+
+exit 0;
+
+sub show_pair {
+ my @a = split_line(shift);
+ my @b = split_line(shift);
+
+ # Find common prefix, taking care to skip any ansi
+ # color codes.
+ my $seen_plusminus;
+ my ($pa, $pb) = (0, 0);
+ while ($pa < @a && $pb < @b) {
+ if ($a[$pa] =~ /$COLOR/) {
+ $pa++;
+ }
+ elsif ($b[$pb] =~ /$COLOR/) {
+ $pb++;
+ }
+ elsif ($a[$pa] eq $b[$pb]) {
+ $pa++;
+ $pb++;
+ }
+ elsif (!$seen_plusminus && $a[$pa] eq '-' && $b[$pb] eq '+') {
+ $seen_plusminus = 1;
+ $pa++;
+ $pb++;
+ }
+ else {
+ last;
+ }
+ }
+
+ # Find common suffix, ignoring colors.
+ my ($sa, $sb) = ($#a, $#b);
+ while ($sa >= $pa && $sb >= $pb) {
+ if ($a[$sa] =~ /$COLOR/) {
+ $sa--;
+ }
+ elsif ($b[$sb] =~ /$COLOR/) {
+ $sb--;
+ }
+ elsif ($a[$sa] eq $b[$sb]) {
+ $sa--;
+ $sb--;
+ }
+ else {
+ last;
+ }
+ }
+
+ print highlight(\@a, $pa, $sa);
+ print highlight(\@b, $pb, $sb);
+}
+
+sub split_line {
+ local $_ = shift;
+ return map { /$COLOR/ ? $_ : (split //) }
+ split /($COLOR*)/;
+}
+
+sub highlight {
+ my ($line, $prefix, $suffix) = @_;
+
+ return join('',
+ @{$line}[0..($prefix-1)],
+ $HIGHLIGHT,
+ @{$line}[$prefix..$suffix],
+ $UNHIGHLIGHT,
+ @{$line}[($suffix+1)..$#$line]
+ );
+}
text = p4_read_pipe(['print', '-q', '-o', '-', file['depotFile']])
contents = [ text ]
+ if type_base == "apple":
+ # Apple filetype files will be streamed as a concatenation of
+ # its appledouble header and the contents. This is useless
+ # on both macs and non-macs. If using "print -q -o xx", it
+ # will create "xx" with the data, and "%xx" with the header.
+ # This is also not very useful.
+ #
+ # Ideally, someday, this script can learn how to generate
+ # appledouble files directly and import those to git, but
+ # non-mac machines can never find a use for apple filetype.
+ print "\nIgnoring apple filetype file %s" % file['depotFile']
+ return
+
# Perhaps windows wants unicode, utf16 newlines translated too;
# but this is not doing it.
if self.isWindows and type_base == "text":
--- /dev/null
+git-jump
+========
+
+Git-jump is a script for helping you jump to "interesting" parts of your
+project in your editor. It works by outputting a set of interesting
+spots in the "quickfix" format, which editors like vim can use as a
+queue of places to visit (this feature is usually used to jump to errors
+produced by a compiler). For example, given a diff like this:
+
+------------------------------------
+diff --git a/foo.c b/foo.c
+index a655540..5a59044 100644
+--- a/foo.c
++++ b/foo.c
+@@ -1,3 +1,3 @@
+ int main(void) {
+- printf("hello word!\n");
++ printf("hello world!\n");
+ }
+-----------------------------------
+
+git-jump will feed this to the editor:
+
+-----------------------------------
+foo.c:2: printf("hello word!\n");
+-----------------------------------
+
+Obviously this trivial case isn't that interesting; you could just open
+`foo.c` yourself. But when you have many changes scattered across a
+project, you can use the editor's support to "jump" from point to point.
+
+Git-jump can generate three types of interesting lists:
+
+ 1. The beginning of any diff hunks.
+
+ 2. The beginning of any merge conflict markers.
+
+ 3. Any grep matches.
+
+
+Using git-jump
+--------------
+
+To use it, just drop git-jump in your PATH, and then invoke it like
+this:
+
+--------------------------------------------------
+# jump to changes not yet staged for commit
+git jump diff
+
+# jump to changes that are staged for commit; you can give
+# arbitrary diff options
+git jump diff --cached
+
+# jump to merge conflicts
+git jump merge
+
+# jump to all instances of foo_bar
+git jump grep foo_bar
+
+# same as above, but case-insensitive; you can give
+# arbitrary grep options
+git jump grep -i foo_bar
+--------------------------------------------------
+
+
+Related Programs
+----------------
+
+You can accomplish some of the same things with individual tools. For
+example, you can use `git mergetool` to start vimdiff on each unmerged
+file. `git jump merge` is for the vim-wielding luddite who just wants to
+jump straight to the conflict text with no fanfare.
+
+As of git v1.7.2, `git grep` knows the `--open-files-in-pager` option,
+which does something similar to `git jump grep`. However, it is limited
+to positioning the cursor to the correct line in only the first file,
+leaving you to locate subsequent hits in that file or other files using
+the editor or pager. By contrast, git-jump provides the editor with a
+complete list of files and line numbers for each match.
+
+
+Limitations
+-----------
+
+This scripts was written and tested with vim. Given that the quickfix
+format is the same as what gcc produces, I expect emacs users have a
+similar feature for iterating through the list, but I know nothing about
+how to activate it.
+
+The shell snippets to generate the quickfix lines will almost certainly
+choke on filenames with exotic characters (like newlines).
--- /dev/null
+#!/bin/sh
+
+usage() {
+ cat <<\EOF
+usage: git jump <mode> [<args>]
+
+Jump to interesting elements in an editor.
+The <mode> parameter is one of:
+
+diff: elements are diff hunks. Arguments are given to diff.
+
+merge: elements are merge conflicts. Arguments are ignored.
+
+grep: elements are grep hits. Arguments are given to grep.
+EOF
+}
+
+open_editor() {
+ editor=`git var GIT_EDITOR`
+ eval "$editor -q \$1"
+}
+
+mode_diff() {
+ git diff --relative "$@" |
+ perl -ne '
+ if (m{^\+\+\+ b/(.*)}) { $file = $1; next }
+ defined($file) or next;
+ if (m/^@@ .*\+(\d+)/) { $line = $1; next }
+ defined($line) or next;
+ if (/^ /) { $line++; next }
+ if (/^[-+]\s*(.*)/) {
+ print "$file:$line: $1\n";
+ $line = undef;
+ }
+ '
+}
+
+mode_merge() {
+ git ls-files -u |
+ perl -pe 's/^.*?\t//' |
+ sort -u |
+ while IFS= read fn; do
+ grep -Hn '^<<<<<<<' "$fn"
+ done
+}
+
+# Grep -n generates nice quickfix-looking lines by itself,
+# but let's clean up extra whitespace, so they look better if the
+# editor shows them to us in the status bar.
+mode_grep() {
+ git grep -n "$@" |
+ perl -pe '
+ s/[ \t]+/ /g;
+ s/^ *//;
+ '
+}
+
+if test $# -lt 1; then
+ usage >&2
+ exit 1
+fi
+mode=$1; shift
+
+trap 'rm -f "$tmp"' 0 1 2 3 15
+tmp=`mktemp -t git-jump.XXXXXX` || exit 1
+type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }
+"mode_$mode" "$@" >"$tmp"
+test -s "$tmp" || exit 0
+open_editor "$tmp"
my $wiki_name = $url;
$wiki_name =~ s/[^\/]*:\/\///;
+# If URL is like http://user:password@example.com/, we clearly don't
+# want the password in $wiki_name. While we're there, also remove user
+# and '@' sign, to avoid author like MWUser@HTTPUser@host.com
+$wiki_name =~ s/^.*@//;
# Commands parser
my $entry;
re=$(printf '%s\n' "$1" | sed -e 's/[].[^$\\*]/\\&/g')
name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
- test -z "$name" &&
- die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
- echo "$name"
+ test -z "$name" &&
+ die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
+ echo "$name"
}
#
gitdir=
gitdir_base=
- name=$(module_name "$path")
+ name=$(module_name "$path" 2>/dev/null)
base_path=$(dirname "$path")
gitdir=$(git rev-parse --git-dir)
fatal "merge commit $d has ancestor $parent, but that change "
."does not have git-svn metadata!";
}
- unless ($branchurl =~ /^$rooturl(.*)/) {
+ unless ($branchurl =~ /^\Q$rooturl\E(.*)/) {
fatal "commit $parent git-svn metadata changed mid-run!";
}
my $branchpath = $1;
."has uuid $uuid!";
}
- unless ($branchurl =~ /^$rooturl(.*)/) {
+ unless ($branchurl =~ /^\Q$rooturl\E(.*)/) {
# This branch is very strange indeed.
fatal "merge parent $parent for $d is on branch "
."$branchurl, which is not under the "
Points to an .html file which is included on the gitweb project
overview page ('projects_list' view), if it exists. Relative to
gitweb.cgi script. [Default: indextext.html]
+ * GITWEB_SITE_HTML_HEAD_STRING
+ html snippet to include in the <head> section of each page. [No default]
* GITWEB_SITE_HEADER
Filename of html text to include at top of each page. Relative to
gitweb.cgi script. [No default]
GITWEB_LOGO = static/git-logo.png
GITWEB_FAVICON = static/git-favicon.png
GITWEB_JS = static/gitweb.js
+GITWEB_SITE_HTML_HEAD_STRING =
GITWEB_SITE_HEADER =
GITWEB_SITE_FOOTER =
HIGHLIGHT_BIN = highlight
-e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
-e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
-e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
+ -e 's|++GITWEB_SITE_HTML_HEAD_STRING++|$(GITWEB_SITE_HTML_HEAD_STRING)|g' \
-e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
-e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
-e 's|++HIGHLIGHT_BIN++|$(HIGHLIGHT_BIN)|g'
### Cleaning rules
clean:
- $(RM) gitweb.cgi static/gitweb.min.js static/gitweb.min.css GITWEB-BUILD-OPTIONS
+ $(RM) gitweb.cgi static/gitweb.js \
+ static/gitweb.min.js static/gitweb.min.css \
+ GITWEB-BUILD-OPTIONS
.PHONY: all clean install test test-installed .FORCE-GIT-VERSION-FILE FORCE
our $site_name = "++GITWEB_SITENAME++"
|| ($ENV{'SERVER_NAME'} || "Untitled") . " Git";
+# html snippet to include in the <head> section of each page
+our $site_html_head_string = "++GITWEB_SITE_HTML_HEAD_STRING++";
# filename of html text to include at top of each page
our $site_header = "++GITWEB_SITE_HEADER++";
# html text to include at home page
$path =~ s/\.git$//; # forks of 'repo.git' are in 'repo/' directory
next if ($path =~ m!/$!); # skip non-bare repositories, e.g. 'repo/.git'
next unless ($path); # skip '.git' repository: tests, git-instaweb
- next unless (-d $path); # containing directory exists
+ next unless (-d "$projectroot/$path"); # containing directory exists
$pr->{'forks'} = []; # there can be 0 or more forks of project
# add to trie
print "<base href=\"".esc_url($base_url)."\" />\n";
}
print_header_links($status);
+
+ if (defined $site_html_head_string) {
+ print to_utf8($site_html_head_string);
+ }
+
print "</head>\n" .
"<body>\n";
curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
#endif
- init_curl_http_auth(result);
-
if (ssl_cert != NULL)
curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
if (has_cert_password())
else if (missing_target(&results))
ret = HTTP_MISSING_TARGET;
else if (results.http_code == 401) {
- if (user_name) {
+ if (user_name && user_pass) {
ret = HTTP_NOAUTH;
} else {
/*
* but that is non-portable. Using git_getpass() can at least be stubbed
* on other platforms with a different implementation if/when necessary.
*/
- user_name = xstrdup(git_getpass_with_description("Username", description));
+ if (!user_name)
+ user_name = xstrdup(git_getpass_with_description("Username", description));
init_curl_http_auth(slot->curl);
ret = HTTP_REAUTH;
}
if (ce->ce_flags & CE_HASHED)
return;
ce->ce_flags |= CE_HASHED;
- ce->next = NULL;
+ ce->next = ce->dir_next = NULL;
hash = hash_name(ce->name, ce_namelen(ce));
pos = insert_hash(hash, ce, &istate->name_hash);
if (pos) {
(exception is thrown otherwise), in array context returns allows the
variable to be set multiple times and returns all the values.
-This currently wraps command('config') so it is not so fast.
-
=cut
sub config {
- my ($self, $var) = _maybe_self(@_);
-
- try {
- my @cmd = ('config');
- unshift @cmd, $self if $self;
- if (wantarray) {
- return command(@cmd, '--get-all', $var);
- } else {
- return command_oneline(@cmd, '--get', $var);
- }
- } catch Git::Error::Command with {
- my $E = shift;
- if ($E->value() == 1) {
- # Key not found.
- return;
- } else {
- throw $E;
- }
- };
+ return _config_common({}, @_);
}
is usable as a boolean in perl (and C<undef> if it's not defined,
of course).
-This currently wraps command('config') so it is not so fast.
-
=cut
sub config_bool {
- my ($self, $var) = _maybe_self(@_);
+ my $val = scalar _config_common({'kind' => '--bool'}, @_);
- try {
- my @cmd = ('config', '--bool', '--get', $var);
- unshift @cmd, $self if $self;
- my $val = command_oneline(@cmd);
- return undef unless defined $val;
+ # Do not rewrite this as return (defined $val && $val eq 'true')
+ # as some callers do care what kind of falsehood they receive.
+ if (!defined $val) {
+ return undef;
+ } else {
return $val eq 'true';
- } catch Git::Error::Command with {
- my $E = shift;
- if ($E->value() == 1) {
- # Key not found.
- return undef;
- } else {
- throw $E;
- }
- };
+ }
}
Retrieve the path configuration C<VARIABLE>. The return value
is an expanded path or C<undef> if it's not defined.
-This currently wraps command('config') so it is not so fast.
-
=cut
sub config_path {
- my ($self, $var) = _maybe_self(@_);
-
- try {
- my @cmd = ('config', '--path');
- unshift @cmd, $self if $self;
- if (wantarray) {
- return command(@cmd, '--get-all', $var);
- } else {
- return command_oneline(@cmd, '--get', $var);
- }
- } catch Git::Error::Command with {
- my $E = shift;
- if ($E->value() == 1) {
- # Key not found.
- return undef;
- } else {
- throw $E;
- }
- };
+ return _config_common({'kind' => '--path'}, @_);
}
+
=item config_int ( VARIABLE )
Retrieve the integer configuration C<VARIABLE>. The return value
by 1024, 1048576 (1024^2), or 1073741824 (1024^3) prior to output.
It would return C<undef> if configuration variable is not defined,
-This currently wraps command('config') so it is not so fast.
-
=cut
sub config_int {
+ return scalar _config_common({'kind' => '--int'}, @_);
+}
+
+# Common subroutine to implement bulk of what the config* family of methods
+# do. This curently wraps command('config') so it is not so fast.
+sub _config_common {
+ my ($opts) = shift @_;
my ($self, $var) = _maybe_self(@_);
try {
- my @cmd = ('config', '--int', '--get', $var);
+ my @cmd = ('config', $opts->{'kind'} ? $opts->{'kind'} : ());
unshift @cmd, $self if $self;
- return command_oneline(@cmd);
+ if (wantarray) {
+ return command(@cmd, '--get-all', $var);
+ } else {
+ return command_oneline(@cmd, '--get', $var);
+ }
} catch Git::Error::Command with {
my $E = shift;
if ($E->value() == 1) {
# Key not found.
- return undef;
+ return;
} else {
throw $E;
}
{
struct format_commit_context context;
static const char utf8[] = "UTF-8";
- const char *enc;
const char *output_enc = pretty_ctx->output_encoding;
memset(&context, 0, sizeof(context));
context.wrap_start = sb->len;
context.message = commit->buffer;
if (output_enc) {
- enc = get_header(commit, "encoding");
- enc = enc ? enc : utf8;
- if (strcmp(enc, output_enc))
+ char *enc = get_header(commit, "encoding");
+ if (strcmp(enc ? enc : utf8, output_enc)) {
context.message = logmsg_reencode(commit, output_enc);
+ if (!context.message)
+ context.message = commit->buffer;
+ }
+ free(enc);
}
strbuf_expand(sb, format, format_commit_item, &context);
static inline size_t estimate_cache_size(size_t ondisk_size, unsigned int entries)
{
- long per_entry;
-
- per_entry = sizeof(struct cache_entry) - sizeof(struct ondisk_cache_entry);
+ size_t fix_size_mem = offsetof(struct cache_entry, name);
+ size_t fix_size_dsk = offsetof(struct ondisk_cache_entry, name);
+ long per_entry = (fix_size_mem - fix_size_dsk + 7) & ~7;
/*
* Alignment can cause differences. This should be "alignof", but
return ret;
}
-char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
- const char *name)
+static int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
{
int i;
- char *ret = NULL;
- for (i = 0; i < nr_refspec; i++) {
- struct refspec *refspec = refspecs + i;
- if (refspec->pattern) {
- if (match_name_with_pattern(refspec->src, name,
- refspec->dst, &ret))
- return ret;
- } else if (!strcmp(refspec->src, name))
- return xstrdup(refspec->dst);
- }
- return NULL;
-}
+ int find_src = !query->src;
-int remote_find_tracking(struct remote *remote, struct refspec *refspec)
-{
- int find_src = refspec->src == NULL;
- char *needle, **result;
- int i;
+ if (find_src && !query->dst)
+ return error("query_refspecs: need either src or dst");
- if (find_src) {
- if (!refspec->dst)
- return error("find_tracking: need either src or dst");
- needle = refspec->dst;
- result = &refspec->src;
- } else {
- needle = refspec->src;
- result = &refspec->dst;
- }
+ for (i = 0; i < ref_count; i++) {
+ struct refspec *refspec = &refs[i];
+ const char *key = find_src ? refspec->dst : refspec->src;
+ const char *value = find_src ? refspec->src : refspec->dst;
+ const char *needle = find_src ? query->dst : query->src;
+ char **result = find_src ? &query->src : &query->dst;
- for (i = 0; i < remote->fetch_refspec_nr; i++) {
- struct refspec *fetch = &remote->fetch[i];
- const char *key = find_src ? fetch->dst : fetch->src;
- const char *value = find_src ? fetch->src : fetch->dst;
- if (!fetch->dst)
+ if (!refspec->dst)
continue;
- if (fetch->pattern) {
+ if (refspec->pattern) {
if (match_name_with_pattern(key, needle, value, result)) {
- refspec->force = fetch->force;
+ query->force = refspec->force;
return 0;
}
} else if (!strcmp(needle, key)) {
*result = xstrdup(value);
- refspec->force = fetch->force;
+ query->force = refspec->force;
return 0;
}
}
return -1;
}
+char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
+ const char *name)
+{
+ struct refspec query;
+
+ memset(&query, 0, sizeof(struct refspec));
+ query.src = (char *)name;
+
+ if (query_refspecs(refspecs, nr_refspec, &query))
+ return NULL;
+
+ return query.dst;
+}
+
+int remote_find_tracking(struct remote *remote, struct refspec *refspec)
+{
+ return query_refspecs(remote->fetch, remote->fetch_refspec_nr, refspec);
+}
+
static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
const char *name)
{
}
struct stale_heads_info {
- struct remote *remote;
struct string_list *ref_names;
struct ref **stale_refs_tail;
+ struct refspec *refs;
+ int ref_count;
};
static int get_stale_heads_cb(const char *refname,
const unsigned char *sha1, int flags, void *cb_data)
{
struct stale_heads_info *info = cb_data;
- struct refspec refspec;
- memset(&refspec, 0, sizeof(refspec));
- refspec.dst = (char *)refname;
- if (!remote_find_tracking(info->remote, &refspec)) {
- if (!((flags & REF_ISSYMREF) ||
- string_list_has_string(info->ref_names, refspec.src))) {
- struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail);
- hashcpy(ref->new_sha1, sha1);
- }
+ struct refspec query;
+ memset(&query, 0, sizeof(struct refspec));
+ query.dst = (char *)refname;
+
+ if (query_refspecs(info->refs, info->ref_count, &query))
+ return 0; /* No matches */
+
+ /*
+ * If we did find a suitable refspec and it's not a symref and
+ * it's not in the list of refs that currently exist in that
+ * remote we consider it to be stale.
+ */
+ if (!((flags & REF_ISSYMREF) ||
+ string_list_has_string(info->ref_names, query.src))) {
+ struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail);
+ hashcpy(ref->new_sha1, sha1);
}
+
+ free(query.src);
return 0;
}
-struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map)
+struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map)
{
struct ref *ref, *stale_refs = NULL;
struct string_list ref_names = STRING_LIST_INIT_NODUP;
struct stale_heads_info info;
- info.remote = remote;
info.ref_names = &ref_names;
info.stale_refs_tail = &stale_refs;
+ info.refs = refs;
+ info.ref_count = ref_count;
for (ref = fetch_map; ref; ref = ref->next)
string_list_append(&ref_names, ref->name);
sort_string_list(&ref_names);
int all);
/* Return refs which no longer exist on remote */
-struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map);
+struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map);
#endif
our \$project_maxdepth = 8;
our \$home_link_str = 'projects';
our \$site_name = '[localhost]';
+our \$site_html_head_string = '';
our \$site_header = '';
our \$site_footer = '';
our \$home_text = 'indextext.html';
git branch -d l/m &&
git branch l'
+test_expect_success \
+ 'git branch -m dumps usage' \
+ 'test_expect_code 129 git branch -m 2>err &&
+ grep "[Uu]sage: git branch" err'
+
test_expect_success \
'git branch -m m m/m should work' \
'git branch -l m &&
'git archive --output=b4.tar HEAD &&
test_cmp b.tar b4.tar'
-test_expect_success NOT_MINGW 'git archive --remote' \
+test_expect_success 'git archive --remote' \
'git archive --remote=. HEAD >b5.tar &&
test_cmp b.tar b5.tar'
grep "^bar\$" output
'
-test_expect_success NOT_MINGW 'archive --list shows only enabled remote filters' '
+test_expect_success 'archive --list shows only enabled remote filters' '
git archive --list --remote=. >output &&
! grep "^tar\.foo\$" output &&
grep "^bar\$" output
test_cmp b.tar config-implicittar.foo
'
-test_expect_success NOT_MINGW 'only enabled filters are available remotely' '
+test_expect_success 'only enabled filters are available remotely' '
test_must_fail git archive --remote=. --format=tar.foo HEAD \
>remote.tar.foo &&
git archive --remote=. --format=bar >remote.bar HEAD &&
test_cmp b.tar j.tar
'
-test_expect_success GZIP,NOT_MINGW 'remote tar.gz is allowed by default' '
+test_expect_success GZIP 'remote tar.gz is allowed by default' '
git archive --remote=. --format=tar.gz HEAD >remote.tar.gz &&
test_cmp j.tgz remote.tar.gz
'
-test_expect_success GZIP,NOT_MINGW 'remote tar.gz can be disabled' '
+test_expect_success GZIP 'remote tar.gz can be disabled' '
git config tar.tar.gz.remote false &&
test_must_fail git archive --remote=. --format=tar.gz HEAD \
>remote.tar.gz
cut -f -2 .git/FETCH_HEAD >actual &&
test_cmp expected actual'
+test_expect_success 'fetch --prune on its own works as expected' '
+ cd "$D" &&
+ git clone . prune &&
+ cd prune &&
+ git fetch origin refs/heads/master:refs/remotes/origin/extrabranch &&
+
+ git fetch --prune origin &&
+ test_must_fail git rev-parse origin/extrabranch
+'
+
+test_expect_success 'fetch --prune with a branch name keeps branches' '
+ cd "$D" &&
+ git clone . prune-branch &&
+ cd prune-branch &&
+ git fetch origin refs/heads/master:refs/remotes/origin/extrabranch &&
+
+ git fetch --prune origin master &&
+ git rev-parse origin/extrabranch
+'
+
+test_expect_success 'fetch --prune with a namespace keeps other namespaces' '
+ cd "$D" &&
+ git clone . prune-namespace &&
+ cd prune-namespace &&
+
+ git fetch --prune origin refs/heads/a/*:refs/remotes/origin/a/* &&
+ git rev-parse origin/master
+'
+
+test_expect_success 'fetch --prune --tags does not delete the remote-tracking branches' '
+ cd "$D" &&
+ git clone . prune-tags &&
+ cd prune-tags &&
+ git fetch origin refs/heads/master:refs/tags/sometag &&
+
+ git fetch --prune --tags origin &&
+ git rev-parse origin/master &&
+ test_must_fail git rev-parse somebranch
+'
+
+test_expect_success 'fetch --prune --tags with branch does not delete other remote-tracking branches' '
+ cd "$D" &&
+ git clone . prune-tags-branch &&
+ cd prune-tags-branch &&
+ git fetch origin refs/heads/master:refs/remotes/origin/extrabranch &&
+
+ git fetch --prune --tags origin master &&
+ git rev-parse origin/extrabranch
+'
+
test_expect_success 'fetch tags when there is no tags' '
cd "$D" &&
cp .git/BISECT_START saved &&
test_must_fail git bisect start $HASH4 foo -- &&
git branch > branch.output &&
- grep "* (no branch)" branch.output > /dev/null &&
+ test_i18ngrep "* (no branch)" branch.output > /dev/null &&
test_cmp saved .git/BISECT_START
'
test_expect_success 'bisect start: no ".git/BISECT_START" if mistaken rev' '
# untracked
EOF
git status --ignored >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
test_expect_success 'status with gitignore (nothing untracked)' '
# untracked
EOF
git status --ignored >output &&
- test_cmp expect output
+ test_i18ncmp expect output
'
rm -f .gitignore
--- /dev/null
+#!/bin/sh
+
+test_description='git status with certain file name lengths'
+
+. ./test-lib.sh
+
+files="0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z"
+
+check() {
+ len=$1
+ prefix=$2
+
+ for i in $files
+ do
+ : >$prefix$i
+ done
+
+ test_expect_success "status, filename length $len" "
+ git add $prefix* &&
+ git status
+ "
+ rm $prefix* .git/index
+}
+
+check 1
+check 2 p
+check 3 px
+check 4 pre
+check 5 pref
+check 6 prefi
+check 7 prefix
+check 8 prefix-
+check 9 prefix-p
+check 10 prefix-pr
+check 11 prefix-pre
+check 12 prefix-pref
+check 13 prefix-prefi
+check 14 prefix-prefix
+check 15 prefix-prefix-
+check 16 prefix-prefix-p
+check 17 prefix-prefix-pr
+check 18 prefix-prefix-pre
+check 19 prefix-prefix-pref
+check 20 prefix-prefix-prefi
+check 21 prefix-prefix-prefix
+check 22 prefix-prefix-prefix-
+check 23 prefix-prefix-prefix-p
+check 24 prefix-prefix-prefix-pr
+
+test_done
chmod +x helper
test_expect_success 'setup ' '
+ echo "bin: test number 0" >zero.bin &&
echo "bin: test 1" >one.bin &&
echo "bin: test number 2" >two.bin &&
if test_have_prereq SYMLINKS; then
test_expect_success 'setup textconv filters' '
echo "*.bin diff=test" >.gitattributes &&
+ echo "zero.bin eol=crlf" >>.gitattributes &&
git config diff.test.textconv ./helper &&
git config diff.test.cachetextconv false
'
test_cmp expected result
'
+test_expect_success 'blame --textconv with local changes' '
+ test_when_finished "git checkout zero.bin" &&
+ printf "bin: updated number 0\015" >zero.bin &&
+ git blame --textconv zero.bin >blame &&
+ expect="(Not Committed Yet ....-..-.. ..:..:.. +0000 1)" &&
+ expect="$expect converted: updated number 0" &&
+ expr "$(find_blame <blame)" : "^$expect"
+'
+
test_expect_success 'setup +cachetextconv' '
git config diff.test.cachetextconv true
'
git config --add test.booltrue true &&
git config --add test.boolfalse no &&
git config --add test.boolother other &&
- git config --add test.int 2k
+ git config --add test.int 2k &&
+ git config --add test.path "~/foo" &&
+ git config --add test.pathexpanded "$HOME/foo" &&
+ git config --add test.pathmulti foo &&
+ git config --add test.pathmulti bar
'
# The external test will outputs its own plan
is($r->config_int("test.nonexistent"), undef, "config_int: nonexistent");
ok($r->config_bool("test.booltrue"), "config_bool: true");
ok(!$r->config_bool("test.boolfalse"), "config_bool: false");
+is($r->config_path("test.path"), $r->config("test.pathexpanded"),
+ "config_path: ~/foo expansion");
+is_deeply([$r->config_path("test.pathmulti")], ["foo", "bar"],
+ "config_path: multiple values");
our $ansi_green = "\x1b[32m";
is($r->get_color("color.test.slot1", "red"), $ansi_green, "get_color");
# Cannot test $r->get_colorbool("color.foo")) because we do not
)
'
+build_gendouble() {
+ cat >gendouble.py <<-\EOF
+ import sys
+ import struct
+ import array
+
+ s = array.array("c", '\0' * 26)
+ struct.pack_into(">L", s, 0, 0x00051607) # AppleDouble
+ struct.pack_into(">L", s, 4, 0x00020000) # version 2
+ s.tofile(sys.stdout)
+ EOF
+}
+
+test_expect_success 'ignore apple' '
+ test_when_finished rm -f gendouble.py &&
+ build_gendouble &&
+ (
+ cd "$cli" &&
+ test-genrandom apple 1024 >double.png &&
+ "$PYTHON_PATH" "$TRASH_DIRECTORY/gendouble.py" >%double.png &&
+ p4 add -t apple double.png &&
+ p4 submit -d appledouble
+ ) &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --dest="$git" //depot@all &&
+ (
+ cd "$git" &&
+ test ! -f double.png
+ )
+'
+
test_expect_success 'kill p4d' '
kill_p4d
'
# If you want to allow non-ascii filenames set this variable to true.
allownonascii=$(git config hooks.allownonascii)
+# Redirect output to stderr.
+exec 1>&2
+
# Cross platform projects tend to avoid non-ascii filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
- test "$(git diff --cached --name-only --diff-filter=A -z $against |
- LC_ALL=C tr -d '[ -~]\0')"
+ test $(git diff --cached --name-only --diff-filter=A -z $against |
+ LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
echo "Error: Attempt to add a non-ascii file name."
echo
exit 1
fi
+# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --