aboutsummaryrefslogtreecommitdiff
diff refs
from: back
to: back
| flip
diff options
context:
space:
mode:
-rw-r--r--.gitignore11
-rw-r--r--.gitmodules3
-rw-r--r--.mailmap10
-rw-r--r--AUTHORS13
-rw-r--r--COPYING339
-rw-r--r--Makefile184
-rw-r--r--README99
-rw-r--r--cache.c475
-rw-r--r--cache.h37
-rw-r--r--cgit.c1326
-rw-r--r--cgit.css908
-rw-r--r--cgit.h403
-rw-r--r--cgit.js68
-rw-r--r--cgit.mk141
-rw-r--r--cgit.pngbin1366 -> 0 bytes
-rw-r--r--cgitrc.5.txt1022
-rw-r--r--cmd.c208
-rw-r--r--cmd.h16
-rw-r--r--config.c73
-rw-r--r--configfile.c90
-rw-r--r--configfile.h10
-rwxr-xr-xcontrib/hooks/post-receive.agefile19
-rw-r--r--favicon.icobin1078 -> 0 bytes
-rw-r--r--filter.c457
-rwxr-xr-xfilters/about-formatting.sh27
-rwxr-xr-xfilters/commit-links.sh28
-rw-r--r--filters/email-gravatar.lua35
-rwxr-xr-xfilters/email-gravatar.py39
-rw-r--r--filters/email-libravatar.lua36
-rw-r--r--filters/file-authentication.lua359
-rw-r--r--filters/gentoo-ldap-authentication.lua360
-rwxr-xr-xfilters/html-converters/man2html4
-rwxr-xr-xfilters/html-converters/md2html304
-rwxr-xr-xfilters/html-converters/rst2html2
-rwxr-xr-xfilters/html-converters/txt2html4
-rw-r--r--filters/owner-example.lua17
-rw-r--r--filters/simple-authentication.lua314
-rwxr-xr-xfilters/syntax-highlighting.py55
-rwxr-xr-xfilters/syntax-highlighting.sh121
-rwxr-xr-xgen-version.sh20
m---------git0
-rw-r--r--git.h399
-rw-r--r--html.c306
-rw-r--r--html.h37
-rw-r--r--parsing.c227
-rw-r--r--robots.txt4
-rw-r--r--scan-tree.c269
-rw-r--r--scan-tree.h2
-rw-r--r--shared.c595
-rw-r--r--tests/.gitignore2
-rw-r--r--tests/Makefile17
-rw-r--r--tests/filters/dump.lua17
-rwxr-xr-xtests/filters/dump.sh4
-rwxr-xr-xtests/setup.sh180
-rwxr-xr-xtests/t0001-validate-git-versions.sh45
-rwxr-xr-xtests/t0010-validate-html.sh40
-rwxr-xr-xtests/t0020-validate-cache.sh78
-rwxr-xr-xtests/t0101-index.sh17
-rwxr-xr-xtests/t0102-summary.sh25
-rwxr-xr-xtests/t0103-log.sh24
-rwxr-xr-xtests/t0104-tree.sh32
-rwxr-xr-xtests/t0105-commit.sh36
-rwxr-xr-xtests/t0106-diff.sh19
-rwxr-xr-xtests/t0107-snapshot.sh205
-rwxr-xr-xtests/t0108-patch.sh62
-rwxr-xr-xtests/t0109-gitconfig.sh48
-rwxr-xr-xtests/t0110-rawdiff.sh42
-rwxr-xr-xtests/t0111-filter.sh46
-rwxr-xr-xtests/valgrind/bin/cgit12
-rw-r--r--ui-atom.c159
-rw-r--r--ui-atom.h6
-rw-r--r--ui-blame.c317
-rw-r--r--ui-blame.h6
-rw-r--r--ui-blob.c184
-rw-r--r--ui-blob.h8
-rw-r--r--ui-clone.c138
-rw-r--r--ui-clone.h8
-rw-r--r--ui-commit.c150
-rw-r--r--ui-commit.h6
-rw-r--r--ui-diff.c503
-rw-r--r--ui-diff.h15
-rw-r--r--ui-log.c553
-rw-r--r--ui-log.h9
-rw-r--r--ui-patch.c100
-rw-r--r--ui-patch.h7
-rw-r--r--ui-plain.c209
-rw-r--r--ui-plain.h6
-rw-r--r--ui-refs.c224
-rw-r--r--ui-refs.h8
-rw-r--r--ui-repolist.c379
-rw-r--r--ui-repolist.h7
-rw-r--r--ui-shared.c1265
-rw-r--r--ui-shared.h88
-rw-r--r--ui-snapshot.c318
-rw-r--r--ui-snapshot.h7
-rw-r--r--ui-ssdiff.c420
-rw-r--r--ui-ssdiff.h25
-rw-r--r--ui-stats.c435
-rw-r--r--ui-stats.h28
-rw-r--r--ui-summary.c148
-rw-r--r--ui-summary.h7
-rw-r--r--ui-tag.c122
-rw-r--r--ui-tag.h6
-rw-r--r--ui-tree.c407
-rw-r--r--ui-tree.h6
105 files changed, 866 insertions, 15845 deletions
diff --git a/.gitignore b/.gitignore
index 661df34..4eaec97 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,3 @@
# Files I don't care to see in git-status/commit
-/cgit
-cgit.conf
-CGIT-CFLAGS
-VERSION
-cgitrc.5
-cgitrc.5.fo
-cgitrc.5.html
-cgitrc.5.pdf
-cgitrc.5.xml
+cgit
*.o
-*.d
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 5c6ecb4..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "git"]
- url = https://git.kernel.org/pub/scm/git/git.git
- path = git
diff --git a/.mailmap b/.mailmap
deleted file mode 100644
index 03b5479..0000000
--- a/.mailmap
+++ /dev/null
@@ -1,10 +0,0 @@
-Florian Pritz <bluewind@xinu.at> <bluewind@xssn.at>
-Harley Laue <losinggeneration@gmail.com> <losinggeneration@aim.com>
-John Keeping <john@keeping.me.uk> <john@metanate.com>
-Lars Hjemli <hjemli@gmail.com> <larsh@hal-2004.(none)>
-Lars Hjemli <hjemli@gmail.com> <larsh@hatman.(none)>
-Lars Hjemli <hjemli@gmail.com> <larsh@slackbox.hjemli.net>
-Lars Hjemli <hjemli@gmail.com> <larsh@slaptop.hjemli.net>
-Lukas Fleischer <lfleischer@lfos.de> <cgit@cryptocrack.de>
-Lukas Fleischer <lfleischer@lfos.de> <info@cryptocrack.de>
-Stefan Bühler <source@stbuehler.de> <lighttpd@stbuehler.de>
diff --git a/AUTHORS b/AUTHORS
deleted file mode 100644
index 031de33..0000000
--- a/AUTHORS
+++ /dev/null
@@ -1,13 +0,0 @@
-Maintainer:
- Jason A. Donenfeld <Jason@zx2c4.com>
-
-Contributors:
- Jason A. Donenfeld <Jason@zx2c4.com>
- Lukas Fleischer <cgit@cryptocrack.de>
- Johan Herland <johan@herland.net>
- Lars Hjemli <hjemli@gmail.com>
- Ferry Huberts <ferry.huberts@pelagic.nl>
- John Keeping <john@keeping.me.uk>
-
-Previous Maintainer:
- Lars Hjemli <hjemli@gmail.com>
diff --git a/COPYING b/COPYING
deleted file mode 100644
index d159169..0000000
--- a/COPYING
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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 of the License, 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.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/Makefile b/Makefile
index 9d39bf4..4e72b07 100644
--- a/Makefile
+++ b/Makefile
@@ -1,180 +1,20 @@
-all::
-CGIT_VERSION = v1.3.1
-CGIT_SCRIPT_NAME = cgit.cgi
-CGIT_SCRIPT_PATH = /var/www/htdocs/cgit
-CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH)
-CGIT_CONFIG = /etc/cgitrc
-CACHE_ROOT = /var/cache/cgit
-prefix = /usr/local
-libdir = $(prefix)/lib
-filterdir = $(libdir)/cgit/filters
-docdir = $(prefix)/share/doc/cgit
-htmldir = $(docdir)
-pdfdir = $(docdir)
-mandir = $(prefix)/share/man
-SHA1_HEADER = <openssl/sha.h>
-GIT_VER = 2.54.0
-GIT_URL = https://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.xz
-INSTALL = install
-COPYTREE = cp -r
-MAN5_TXT = $(wildcard *.5.txt)
-MAN_TXT = $(MAN5_TXT)
-DOC_MAN5 = $(patsubst %.txt,%,$(MAN5_TXT))
-DOC_HTML = $(patsubst %.txt,%.html,$(MAN_TXT))
-DOC_PDF = $(patsubst %.txt,%.pdf,$(MAN_TXT))
+INSTALL_BIN = /var/www/htdocs/cgit.cgi
+INSTALL_CSS = /var/www/htdocs/cgit.css
-ASCIIDOC = asciidoc
-ASCIIDOC_EXTRA =
-ASCIIDOC_HTML = xhtml11
-ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA)
-TXT_TO_HTML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_HTML)
+EXTLIBS = ../git/libgit.a ../git/xdiff/lib.a -lz -lcrypto
+OBJECTS = cgit.o config.o html.o
-# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
-# do not support the 'size specifiers' introduced by C99, namely ll, hh,
-# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
-# some C compilers supported these specifiers prior to C99 as an extension.
-#
-# Define HAVE_LINUX_SENDFILE to use sendfile()
-
-#-include config.mak
-
--include git/config.mak.uname
-#
-# Let the user override the above settings.
-#
--include cgit.conf
-
-export CGIT_VERSION CGIT_SCRIPT_NAME CGIT_SCRIPT_PATH CGIT_DATA_PATH CGIT_CONFIG CACHE_ROOT
-
-#
-# Define a way to invoke make in subdirs quietly, shamelessly ripped
-# from git.git
-#
-QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
-QUIET_SUBDIR1 =
-
-ifneq ($(findstring w,$(MAKEFLAGS)),w)
-PRINT_DIR = --no-print-directory
-else # "make -w"
-NO_SUBDIR = :
-endif
-
-ifndef V
- QUIET_SUBDIR0 = +@subdir=
- QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
- $(MAKE) $(PRINT_DIR) -C $$subdir
- QUIET_TAGS = @echo ' ' TAGS $@;
- export V
-endif
-
-.SUFFIXES:
-
-all:: cgit
-
-cgit:
- $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) -f ../cgit.mk ../cgit $(EXTRA_GIT_TARGETS) NO_CURL=1
-
-sparse:
- $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) -f ../cgit.mk NO_CURL=1 cgit-sparse
-
-test:
- @$(MAKE) --no-print-directory cgit EXTRA_GIT_TARGETS=all
- $(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all
+all: cgit
install: all
- $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_SCRIPT_PATH)
- $(INSTALL) -m 0755 cgit $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
- $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_DATA_PATH)
- $(INSTALL) -m 0644 cgit.css $(DESTDIR)$(CGIT_DATA_PATH)/cgit.css
- $(INSTALL) -m 0644 cgit.js $(DESTDIR)$(CGIT_DATA_PATH)/cgit.js
- $(INSTALL) -m 0644 cgit.png $(DESTDIR)$(CGIT_DATA_PATH)/cgit.png
- $(INSTALL) -m 0644 favicon.ico $(DESTDIR)$(CGIT_DATA_PATH)/favicon.ico
- $(INSTALL) -m 0644 robots.txt $(DESTDIR)$(CGIT_DATA_PATH)/robots.txt
- $(INSTALL) -m 0755 -d $(DESTDIR)$(filterdir)
- $(COPYTREE) filters/* $(DESTDIR)$(filterdir)
-
-install-doc: install-man install-html install-pdf
-
-install-man: doc-man
- $(INSTALL) -m 0755 -d $(DESTDIR)$(mandir)/man5
- $(INSTALL) -m 0644 $(DOC_MAN5) $(DESTDIR)$(mandir)/man5
-
-install-html: doc-html
- $(INSTALL) -m 0755 -d $(DESTDIR)$(htmldir)
- $(INSTALL) -m 0644 $(DOC_HTML) $(DESTDIR)$(htmldir)
-
-install-pdf: doc-pdf
- $(INSTALL) -m 0755 -d $(DESTDIR)$(pdfdir)
- $(INSTALL) -m 0644 $(DOC_PDF) $(DESTDIR)$(pdfdir)
-
-define rm_f
-rm -f $(1)
-
-endef
-
-uninstall:
- rm -f $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
- rm -f $(DESTDIR)$(CGIT_DATA_PATH)/cgit.css
- rm -f $(DESTDIR)$(CGIT_DATA_PATH)/cgit.js
- rm -f $(DESTDIR)$(CGIT_DATA_PATH)/cgit.png
- rm -f $(DESTDIR)$(CGIT_DATA_PATH)/favicon.ico
- rm -f $(DESTDIR)$(CGIT_DATA_PATH)/robots.txt
- $(foreach file,$(patsubst filters/%,%,$(shell find filters/ ! -type d)), \
- $(call rm_f,$(DESTDIR)$(filterdir)/$(file)))
-
-uninstall-doc: uninstall-man uninstall-html uninstall-pdf
-
-uninstall-man:
- @for i in $(DOC_MAN5); do \
- rm -fv $(DESTDIR)$(mandir)/man5/$$i; \
- done
-
-uninstall-html:
- @for i in $(DOC_HTML); do \
- rm -fv $(DESTDIR)$(htmldir)/$$i; \
- done
-
-uninstall-pdf:
- @for i in $(DOC_PDF); do \
- rm -fv $(DESTDIR)$(pdfdir)/$$i; \
- done
-
-doc: doc-man doc-html doc-pdf
-doc-man: doc-man5
-doc-man5: $(DOC_MAN5)
-doc-html: $(DOC_HTML)
-doc-pdf: $(DOC_PDF)
-
-%.5 : %.5.txt
- a2x -f manpage $<
-
-$(DOC_HTML): %.html : %.txt
- $(TXT_TO_HTML) -o $@+ $< && \
- mv $@+ $@
-
-$(DOC_PDF): %.pdf : %.txt
- a2x -f pdf cgitrc.5.txt
-
-clean: clean-doc
- $(RM) cgit VERSION CGIT-CFLAGS *.o tags
- $(RM) -r .deps
-
-cleanall: clean
- $(MAKE) -C git clean
-
-clean-doc:
- $(RM) cgitrc.5 cgitrc.5.html cgitrc.5.pdf cgitrc.5.xml cgitrc.5.fo
+ install cgit $(INSTALL_BIN)
+ install cgit.css $(INSTALL_CSS)
-get-git:
- curl -L $(GIT_URL) | tar -xJf - && rm -rf git && mv git-$(GIT_VER) git
+clean:
+ rm -f cgit *.o
-tags:
- $(QUIET_TAGS)find . -name '*.[ch]' | xargs ctags
+cgit: $(OBJECTS)
+ $(CC) -o cgit $(OBJECTS) $(EXTLIBS)
-.PHONY: all cgit git get-git
-.PHONY: clean clean-doc cleanall
-.PHONY: doc doc-html doc-man doc-pdf
-.PHONY: install install-doc install-html install-man install-pdf
-.PHONY: tags test
-.PHONY: uninstall uninstall-doc uninstall-html uninstall-man uninstall-pdf
+$(OBJECTS): cgit.h git.h
diff --git a/README b/README
deleted file mode 100644
index 7a6b4a4..0000000
--- a/README
+++ /dev/null
@@ -1,99 +0,0 @@
-cgit - CGI for Git
-==================
-
-This is an attempt to create a fast web interface for the Git SCM, using a
-built-in cache to decrease server I/O pressure.
-
-Installation
-------------
-
-Building cgit involves building a proper version of Git. How to do this
-depends on how you obtained the cgit sources:
-
-a) If you're working in a cloned cgit repository, you first need to
-initialize and update the Git submodule:
-
- $ git submodule init # register the Git submodule in .git/config
- $ $EDITOR .git/config # if you want to specify a different url for git
- $ git submodule update # clone/fetch and checkout correct git version
-
-b) If you're building from a cgit tarball, you can download a proper git
-version like this:
-
- $ make get-git
-
-When either a) or b) has been performed, you can build and install cgit like
-this:
-
- $ make
- $ sudo make install
-
-This will install `cgit.cgi` and `cgit.css` into `/var/www/htdocs/cgit`. You
-can configure this location (and a few other things) by providing a `cgit.conf`
-file (see the Makefile for details).
-
-If you'd like to compile without Lua support, you may use:
-
- $ make NO_LUA=1
-
-And if you'd like to specify a Lua implementation, you may use:
-
- $ make LUA_PKGCONFIG=lua5.1
-
-If this is not specified, the Lua implementation will be auto-detected,
-preferring LuaJIT if many are present. Acceptable values are generally "lua",
-"luajit", "lua5.1", and "lua5.2".
-
-
-Dependencies
-------------
-
-* libzip
-* libcrypto (OpenSSL)
-* libssl (OpenSSL)
-* optional: luajit or lua, most reliably used when pkg-config is available
-
-Apache configuration
---------------------
-
-A new `Directory` section must probably be added for cgit, possibly something
-like this:
-
- <Directory "/var/www/htdocs/cgit/">
- AllowOverride None
- Options +ExecCGI
- Order allow,deny
- Allow from all
- </Directory>
-
-
-Runtime configuration
----------------------
-
-The file `/etc/cgitrc` is read by cgit before handling a request. In addition
-to runtime parameters, this file may also contain a list of repositories
-displayed by cgit (see `cgitrc.5.txt` for further details).
-
-The cache
----------
-
-When cgit is invoked it looks for a cache file matching the request and
-returns it to the client. If no such cache file exists (or if it has expired),
-the content for the request is written into the proper cache file before the
-file is returned.
-
-If the cache file has expired but cgit is unable to obtain a lock for it, the
-stale cache file is returned to the client. This is done to favour page
-throughput over page freshness.
-
-The generated content contains the complete response to the client, including
-the HTTP headers `Modified` and `Expires`.
-
-Online presence
----------------
-
-* The cgit homepage is hosted by cgit at <https://git.zx2c4.com/cgit/about/>
-
-* Patches, bug reports, discussions and support should go to the cgit
- mailing list: <cgit@lists.zx2c4.com>. To sign up, visit
- <https://lists.zx2c4.com/mailman/listinfo/cgit>
diff --git a/cache.c b/cache.c
deleted file mode 100644
index e70af13..0000000
--- a/cache.c
+++ /dev/null
@@ -1,475 +0,0 @@
-/* cache.c: cache management
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- *
- *
- * The cache is just a directory structure where each file is a cache slot,
- * and each filename is based on the hash of some key (e.g. the cgit url).
- * Each file contains the full key followed by the cached content for that
- * key.
- *
- */
-
-#include "cgit.h"
-#include "cache.h"
-#include "html.h"
-#ifdef HAVE_LINUX_SENDFILE
-#include <sys/sendfile.h>
-#endif
-
-#define CACHE_BUFSIZE (1024 * 4)
-
-struct cache_slot {
- const char *key;
- size_t keylen;
- int ttl;
- cache_fill_fn fn;
- int cache_fd;
- int lock_fd;
- int stdout_fd;
- const char *cache_name;
- const char *lock_name;
- int match;
- struct stat cache_st;
- int bufsize;
- char buf[CACHE_BUFSIZE];
-};
-
-/* Open an existing cache slot and fill the cache buffer with
- * (part of) the content of the cache file. Return 0 on success
- * and errno otherwise.
- */
-static int open_slot(struct cache_slot *slot)
-{
- char *bufz;
- ssize_t bufkeylen = -1;
-
- slot->cache_fd = open(slot->cache_name, O_RDONLY);
- if (slot->cache_fd == -1)
- return errno;
-
- if (fstat(slot->cache_fd, &slot->cache_st))
- return errno;
-
- slot->bufsize = xread(slot->cache_fd, slot->buf, sizeof(slot->buf));
- if (slot->bufsize < 0)
- return errno;
-
- bufz = memchr(slot->buf, 0, slot->bufsize);
- if (bufz)
- bufkeylen = bufz - slot->buf;
-
- if (slot->key)
- slot->match = bufkeylen == slot->keylen &&
- !memcmp(slot->key, slot->buf, bufkeylen + 1);
-
- return 0;
-}
-
-/* Close the active cache slot */
-static int close_slot(struct cache_slot *slot)
-{
- int err = 0;
- if (slot->cache_fd > 0) {
- if (close(slot->cache_fd))
- err = errno;
- else
- slot->cache_fd = -1;
- }
- return err;
-}
-
-/* Print the content of the active cache slot (but skip the key). */
-static int print_slot(struct cache_slot *slot)
-{
- off_t off;
-#ifdef HAVE_LINUX_SENDFILE
- off_t size;
-#endif
-
- off = slot->keylen + 1;
-
-#ifdef HAVE_LINUX_SENDFILE
- size = slot->cache_st.st_size;
-
- do {
- ssize_t ret;
- ret = sendfile(STDOUT_FILENO, slot->cache_fd, &off, size - off);
- if (ret < 0) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- /* Fall back to read/write on EINVAL or ENOSYS */
- if (errno == EINVAL || errno == ENOSYS)
- break;
- return errno;
- }
- if (off == size)
- return 0;
- } while (1);
-#endif
-
- if (lseek(slot->cache_fd, off, SEEK_SET) != off)
- return errno;
-
- do {
- ssize_t ret;
- ret = xread(slot->cache_fd, slot->buf, sizeof(slot->buf));
- if (ret < 0)
- return errno;
- if (ret == 0)
- return 0;
- if (write_in_full(STDOUT_FILENO, slot->buf, ret) < 0)
- return errno;
- } while (1);
-}
-
-/* Check if the slot has expired */
-static int is_expired(struct cache_slot *slot)
-{
- if (slot->ttl < 0)
- return 0;
- else
- return slot->cache_st.st_mtime + slot->ttl * 60 < time(NULL);
-}
-
-/* Check if the slot has been modified since we opened it.
- * NB: If stat() fails, we pretend the file is modified.
- */
-static int is_modified(struct cache_slot *slot)
-{
- struct stat st;
-
- if (stat(slot->cache_name, &st))
- return 1;
- return (st.st_ino != slot->cache_st.st_ino ||
- st.st_mtime != slot->cache_st.st_mtime ||
- st.st_size != slot->cache_st.st_size);
-}
-
-/* Close an open lockfile */
-static int close_lock(struct cache_slot *slot)
-{
- int err = 0;
- if (slot->lock_fd > 0) {
- if (close(slot->lock_fd))
- err = errno;
- else
- slot->lock_fd = -1;
- }
- return err;
-}
-
-/* Create a lockfile used to store the generated content for a cache
- * slot, and write the slot key + \0 into it.
- * Returns 0 on success and errno otherwise.
- */
-static int lock_slot(struct cache_slot *slot)
-{
- struct flock lock = {
- .l_type = F_WRLCK,
- .l_whence = SEEK_SET,
- .l_start = 0,
- .l_len = 0,
- };
-
- slot->lock_fd = open(slot->lock_name, O_RDWR | O_CREAT,
- S_IRUSR | S_IWUSR);
- if (slot->lock_fd == -1)
- return errno;
- if (fcntl(slot->lock_fd, F_SETLK, &lock) < 0) {
- int saved_errno = errno;
- close(slot->lock_fd);
- slot->lock_fd = -1;
- return saved_errno;
- }
- if (ftruncate(slot->lock_fd, 0) < 0)
- return errno;
- if (xwrite(slot->lock_fd, slot->key, slot->keylen + 1) < 0)
- return errno;
- return 0;
-}
-
-/* Release the current lockfile. If `replace_old_slot` is set the
- * lockfile replaces the old cache slot, otherwise the lockfile is
- * just deleted.
- */
-static int unlock_slot(struct cache_slot *slot, int replace_old_slot)
-{
- int err;
-
- if (replace_old_slot)
- err = rename(slot->lock_name, slot->cache_name);
- else
- err = unlink(slot->lock_name);
-
- /* Restore stdout and close the temporary FD. */
- if (slot->stdout_fd >= 0) {
- dup2(slot->stdout_fd, STDOUT_FILENO);
- close(slot->stdout_fd);
- slot->stdout_fd = -1;
- }
-
- if (err)
- return errno;
-
- return 0;
-}
-
-/* Generate the content for the current cache slot by redirecting
- * stdout to the lock-fd and invoking the callback function
- */
-static int fill_slot(struct cache_slot *slot)
-{
- /* Preserve stdout */
- slot->stdout_fd = dup(STDOUT_FILENO);
- if (slot->stdout_fd == -1)
- return errno;
-
- /* Redirect stdout to lockfile */
- if (dup2(slot->lock_fd, STDOUT_FILENO) == -1)
- return errno;
-
- /* Generate cache content */
- slot->fn();
-
- /* Make sure any buffered data is flushed to the file */
- if (fflush(stdout))
- return errno;
-
- /* update stat info */
- if (fstat(slot->lock_fd, &slot->cache_st))
- return errno;
-
- return 0;
-}
-
-/* Crude implementation of 32-bit FNV-1 hash algorithm,
- * see http://www.isthe.com/chongo/tech/comp/fnv/ for details
- * about the magic numbers.
- */
-#define FNV_OFFSET 0x811c9dc5
-#define FNV_PRIME 0x01000193
-
-unsigned long hash_str(const char *str)
-{
- unsigned long h = FNV_OFFSET;
- unsigned char *s = (unsigned char *)str;
-
- if (!s)
- return h;
-
- while (*s) {
- h *= FNV_PRIME;
- h ^= *s++;
- }
- return h;
-}
-
-static int process_slot(struct cache_slot *slot)
-{
- int err;
-
- err = open_slot(slot);
- if (!err && slot->match) {
- if (is_expired(slot)) {
- if (!lock_slot(slot)) {
- /* If the cachefile has been replaced between
- * `open_slot` and `lock_slot`, we'll just
- * serve the stale content from the original
- * cachefile. This way we avoid pruning the
- * newly generated slot. The same code-path
- * is chosen if fill_slot() fails for some
- * reason.
- *
- * TODO? check if the new slot contains the
- * same key as the old one, since we would
- * prefer to serve the newest content.
- * This will require us to open yet another
- * file-descriptor and read and compare the
- * key from the new file, so for now we're
- * lazy and just ignore the new file.
- */
- if (is_modified(slot) || fill_slot(slot)) {
- unlock_slot(slot, 0);
- close_lock(slot);
- } else {
- close_slot(slot);
- unlock_slot(slot, 1);
- slot->cache_fd = slot->lock_fd;
- }
- }
- }
- if ((err = print_slot(slot)) != 0) {
- cache_log("[cgit] error printing cache %s: %s (%d)\n",
- slot->cache_name,
- strerror(err),
- err);
- }
- close_slot(slot);
- return err;
- }
-
- /* If the cache slot does not exist (or its key doesn't match the
- * current key), lets try to create a new cache slot for this
- * request. If this fails (for whatever reason), lets just generate
- * the content without caching it and fool the caller to believe
- * everything worked out (but print a warning on stdout).
- */
-
- close_slot(slot);
- if ((err = lock_slot(slot)) != 0) {
- cache_log("[cgit] Unable to lock slot %s: %s (%d)\n",
- slot->lock_name, strerror(err), err);
- slot->fn();
- return 0;
- }
-
- if ((err = fill_slot(slot)) != 0) {
- cache_log("[cgit] Unable to fill slot %s: %s (%d)\n",
- slot->lock_name, strerror(err), err);
- unlock_slot(slot, 0);
- close_lock(slot);
- slot->fn();
- return 0;
- }
- // We've got a valid cache slot in the lock file, which
- // is about to replace the old cache slot. But if we
- // release the lockfile and then try to open the new cache
- // slot, we might get a race condition with a concurrent
- // writer for the same cache slot (with a different key).
- // Lets avoid such a race by just printing the content of
- // the lock file.
- slot->cache_fd = slot->lock_fd;
- unlock_slot(slot, 1);
- if ((err = print_slot(slot)) != 0) {
- cache_log("[cgit] error printing cache %s: %s (%d)\n",
- slot->cache_name,
- strerror(err),
- err);
- }
- close_slot(slot);
- return err;
-}
-
-/* Print cached content to stdout, generate the content if necessary. */
-int cache_process(int size, const char *path, const char *key, int ttl,
- cache_fill_fn fn)
-{
- unsigned long hash;
- int i;
- struct strbuf filename = STRBUF_INIT;
- struct strbuf lockname = STRBUF_INIT;
- struct cache_slot slot;
- int result;
-
- /* If the cache is disabled, just generate the content */
- if (size <= 0 || ttl == 0) {
- fn();
- return 0;
- }
-
- /* Verify input, calculate filenames */
- if (!path) {
- cache_log("[cgit] Cache path not specified, caching is disabled\n");
- fn();
- return 0;
- }
- if (!key)
- key = "";
- hash = hash_str(key) % size;
- strbuf_addstr(&filename, path);
- strbuf_ensure_end(&filename, '/');
- for (i = 0; i < 8; i++) {
- strbuf_addf(&filename, "%x", (unsigned char)(hash & 0xf));
- hash >>= 4;
- }
- strbuf_addbuf(&lockname, &filename);
- strbuf_addstr(&lockname, ".lock");
- slot.fn = fn;
- slot.ttl = ttl;
- slot.stdout_fd = -1;
- slot.cache_name = filename.buf;
- slot.lock_name = lockname.buf;
- slot.key = key;
- slot.keylen = strlen(key);
- result = process_slot(&slot);
-
- strbuf_release(&filename);
- strbuf_release(&lockname);
- return result;
-}
-
-/* Return a strftime formatted date/time
- * NB: the result from this function is to shared memory
- */
-static char *sprintftime(const char *format, time_t time)
-{
- static char buf[64];
- struct tm tm;
-
- if (!time)
- return NULL;
- gmtime_r(&time, &tm);
- strftime(buf, sizeof(buf)-1, format, &tm);
- return buf;
-}
-
-int cache_ls(const char *path)
-{
- DIR *dir;
- struct dirent *ent;
- int err = 0;
- struct cache_slot slot = { NULL };
- struct strbuf fullname = STRBUF_INIT;
- size_t prefixlen;
-
- if (!path) {
- cache_log("[cgit] cache path not specified\n");
- return -1;
- }
- dir = opendir(path);
- if (!dir) {
- err = errno;
- cache_log("[cgit] unable to open path %s: %s (%d)\n",
- path, strerror(err), err);
- return err;
- }
- strbuf_addstr(&fullname, path);
- strbuf_ensure_end(&fullname, '/');
- prefixlen = fullname.len;
- while ((ent = readdir(dir)) != NULL) {
- if (strlen(ent->d_name) != 8)
- continue;
- strbuf_setlen(&fullname, prefixlen);
- strbuf_addstr(&fullname, ent->d_name);
- slot.cache_name = fullname.buf;
- if ((err = open_slot(&slot)) != 0) {
- cache_log("[cgit] unable to open path %s: %s (%d)\n",
- fullname.buf, strerror(err), err);
- continue;
- }
- htmlf("%s %s %10"PRIuMAX" %s\n",
- fullname.buf,
- sprintftime("%Y-%m-%d %H:%M:%S",
- slot.cache_st.st_mtime),
- (uintmax_t)slot.cache_st.st_size,
- slot.buf);
- close_slot(&slot);
- }
- closedir(dir);
- strbuf_release(&fullname);
- return 0;
-}
-
-/* Print a message to stdout */
-void cache_log(const char *format, ...)
-{
- va_list args;
- va_start(args, format);
- vfprintf(stderr, format, args);
- va_end(args);
-}
-
diff --git a/cache.h b/cache.h
deleted file mode 100644
index 470da4f..0000000
--- a/cache.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Since git has it's own cache.h which we include,
- * lets test on CGIT_CACHE_H to avoid confusion
- */
-
-#ifndef CGIT_CACHE_H
-#define CGIT_CACHE_H
-
-typedef void (*cache_fill_fn)(void);
-
-
-/* Print cached content to stdout, generate the content if necessary.
- *
- * Parameters
- * size max number of cache files
- * path directory used to store cache files
- * key the key used to lookup cache files
- * ttl max cache time in seconds for this key
- * fn content generator function for this key
- *
- * Return value
- * 0 indicates success, everything else is an error
- */
-extern int cache_process(int size, const char *path, const char *key, int ttl,
- cache_fill_fn fn);
-
-
-/* List info about all cache entries on stdout */
-extern int cache_ls(const char *path);
-
-/* Print a message to stdout */
-__attribute__((format (printf,1,2)))
-extern void cache_log(const char *format, ...);
-
-extern unsigned long hash_str(const char *str);
-
-#endif /* CGIT_CACHE_H */
diff --git a/cgit.c b/cgit.c
index ca318e8..4c14f77 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,1118 +1,410 @@
-/* cgit.c: cgi for the git scm
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
+#include "cgit.h"
-#define USE_THE_REPOSITORY_VARIABLE
+static const char cgit_doctype[] =
+"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
+" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
-#include "cgit.h"
-#include "cache.h"
-#include "cmd.h"
-#include "configfile.h"
-#include "html.h"
-#include "ui-shared.h"
-#include "ui-stats.h"
-#include "ui-blob.h"
-#include "ui-summary.h"
-#include "scan-tree.h"
+static const char cgit_error[] =
+"<div class='error'>%s</div>";
-const char *cgit_version = CGIT_VERSION;
+static const char cgit_lib_error[] =
+"<div class='error'>%s: %s</div>";
-__attribute__((constructor))
-static void constructor_environment()
-{
- /* Do not look in /etc/ for gitconfig and gitattributes. */
- setenv("GIT_CONFIG_NOSYSTEM", "1", 1);
- setenv("GIT_ATTR_NOSYSTEM", "1", 1);
- unsetenv("HOME");
- unsetenv("XDG_CONFIG_HOME");
-}
-static void add_mimetype(const char *name, const char *value)
-{
- struct string_list_item *item;
+char *cgit_root = "/var/git";
+char *cgit_root_title = "Git repository browser";
+char *cgit_css = "/cgit.css";
+char *cgit_logo = "/git-logo.png";
+char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/";
+char *cgit_virtual_root = NULL;
- item = string_list_insert(&ctx.cfg.mimetypes, name);
- item->util = xstrdup(value);
-}
+char *cgit_repo_name = NULL;
+char *cgit_repo_desc = NULL;
+char *cgit_repo_owner = NULL;
-static void process_cached_repolist(const char *path);
+char *cgit_query_repo = NULL;
+char *cgit_query_page = NULL;
+char *cgit_query_head = NULL;
-void cgit_repo_config(struct cgit_repo *repo, const char *name, const char *value)
+int cgit_parse_query(char *txt, configfn fn)
{
- const char *path;
- struct string_list_item *item;
+ char *t = txt, *value = NULL, c;
- if (!strcmp(name, "name"))
- repo->name = strdup_first_line(value);
- else if (!strcmp(name, "clone-url"))
- repo->clone_url = strdup_first_line(value);
- else if (!strcmp(name, "desc"))
- repo->desc = strdup_first_line(value);
- else if (!strcmp(name, "owner"))
- repo->owner = strdup_first_line(value);
- else if (!strcmp(name, "homepage"))
- repo->homepage = strdup_first_line(value);
- else if (!strcmp(name, "defbranch"))
- repo->defbranch = strdup_first_line(value);
- else if (!strcmp(name, "extra-head-content"))
- repo->extra_head_content = strdup_first_line(value);
- else if (!strcmp(name, "snapshots"))
- repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value);
- else if (!strcmp(name, "enable-blame"))
- repo->enable_blame = atoi(value);
- else if (!strcmp(name, "enable-commit-graph"))
- repo->enable_commit_graph = atoi(value);
- else if (!strcmp(name, "enable-follow-links"))
- repo->enable_follow_links = atoi(value);
- else if (!strcmp(name, "enable-log-filecount"))
- repo->enable_log_filecount = atoi(value);
- else if (!strcmp(name, "enable-log-linecount"))
- repo->enable_log_linecount = atoi(value);
- else if (!strcmp(name, "enable-remote-branches"))
- repo->enable_remote_branches = atoi(value);
- else if (!strcmp(name, "enable-subject-links"))
- repo->enable_subject_links = atoi(value);
- else if (!strcmp(name, "enable-html-serving"))
- repo->enable_html_serving = atoi(value);
- else if (!strcmp(name, "branch-sort")) {
- if (!strcmp(value, "age"))
- repo->branch_sort = 1;
- if (!strcmp(value, "name"))
- repo->branch_sort = 0;
- } else if (!strcmp(name, "commit-sort")) {
- if (!strcmp(value, "date"))
- repo->commit_sort = 1;
- if (!strcmp(value, "topo"))
- repo->commit_sort = 2;
- } else if (!strcmp(name, "max-stats"))
- repo->max_stats = cgit_find_stats_period(value, NULL);
- else if (!strcmp(name, "module-link"))
- repo->module_link= strdup_first_line(value);
- else if (skip_prefix(name, "module-link.", &path)) {
- item = string_list_append(&repo->submodules, strdup_first_line(path));
- item->util = strdup_first_line(value);
- } else if (!strcmp(name, "section"))
- repo->section = strdup_first_line(value);
- else if (!strcmp(name, "snapshot-prefix"))
- repo->snapshot_prefix = strdup_first_line(value);
- else if (!strcmp(name, "readme") && value != NULL) {
- if (repo->readme.items == ctx.cfg.readme.items)
- memset(&repo->readme, 0, sizeof(repo->readme));
- string_list_append(&repo->readme, strdup_first_line(value));
- } else if (!strcmp(name, "logo") && value != NULL)
- repo->logo = strdup_first_line(value);
- else if (!strcmp(name, "logo-link") && value != NULL)
- repo->logo_link = strdup_first_line(value);
- else if (!strcmp(name, "hide"))
- repo->hide = atoi(value);
- else if (!strcmp(name, "ignore"))
- repo->ignore = atoi(value);
- else if (ctx.cfg.enable_filter_overrides) {
- if (!strcmp(name, "about-filter"))
- repo->about_filter = cgit_new_filter(value, ABOUT);
- else if (!strcmp(name, "commit-filter"))
- repo->commit_filter = cgit_new_filter(value, COMMIT);
- else if (!strcmp(name, "source-filter"))
- repo->source_filter = cgit_new_filter(value, SOURCE);
- else if (!strcmp(name, "email-filter"))
- repo->email_filter = cgit_new_filter(value, EMAIL);
- else if (!strcmp(name, "owner-filter"))
- repo->owner_filter = cgit_new_filter(value, OWNER);
+ if (!txt)
+ return 0;
+
+ while((c=*t) != '\0') {
+ if (c=='=') {
+ *t = '\0';
+ value = t+1;
+ } else if (c=='&') {
+ *t = '\0';
+ (*fn)(txt, value);
+ txt = t+1;
+ value = NULL;
+ }
+ t++;
}
+ if (t!=txt)
+ (*fn)(txt, value);
+ return 0;
}
-static void config_cb(const char *name, const char *value)
+void cgit_global_config_cb(const char *name, const char *value)
{
- const char *arg;
-
- if (!strcmp(name, "section"))
- ctx.cfg.section = strdup_first_line(value);
- else if (!strcmp(name, "repo.url"))
- ctx.repo = cgit_add_repo(value);
- else if (ctx.repo && !strcmp(name, "repo.path"))
- ctx.repo->path = trim_end(value, '/');
- else if (ctx.repo && skip_prefix(name, "repo.", &arg))
- cgit_repo_config(ctx.repo, arg, value);
- else if (!strcmp(name, "readme"))
- string_list_append(&ctx.cfg.readme, strdup_first_line(value));
+ if (!strcmp(name, "root"))
+ cgit_root = xstrdup(value);
else if (!strcmp(name, "root-title"))
- ctx.cfg.root_title = strdup_first_line(value);
- else if (!strcmp(name, "root-desc"))
- ctx.cfg.root_desc = strdup_first_line(value);
- else if (!strcmp(name, "root-readme"))
- ctx.cfg.root_readme = strdup_first_line(value);
+ cgit_root_title = xstrdup(value);
else if (!strcmp(name, "css"))
- string_list_append(&ctx.cfg.css, strdup_first_line(value));
- else if (!strcmp(name, "js"))
- string_list_append(&ctx.cfg.js, strdup_first_line(value));
- else if (!strcmp(name, "favicon"))
- ctx.cfg.favicon = strdup_first_line(value);
- else if (!strcmp(name, "footer"))
- ctx.cfg.footer = strdup_first_line(value);
- else if (!strcmp(name, "head-include"))
- ctx.cfg.head_include = strdup_first_line(value);
- else if (!strcmp(name, "header"))
- ctx.cfg.header = strdup_first_line(value);
+ cgit_css = xstrdup(value);
else if (!strcmp(name, "logo"))
- ctx.cfg.logo = strdup_first_line(value);
+ cgit_logo = xstrdup(value);
else if (!strcmp(name, "logo-link"))
- ctx.cfg.logo_link = strdup_first_line(value);
- else if (!strcmp(name, "module-link"))
- ctx.cfg.module_link = strdup_first_line(value);
- else if (!strcmp(name, "strict-export"))
- ctx.cfg.strict_export = strdup_first_line(value);
+ cgit_logo_link = xstrdup(value);
else if (!strcmp(name, "virtual-root"))
- ctx.cfg.virtual_root = ensure_end(value, '/');
- else if (!strcmp(name, "noplainemail"))
- ctx.cfg.noplainemail = atoi(value);
- else if (!strcmp(name, "noheader"))
- ctx.cfg.noheader = atoi(value);
- else if (!strcmp(name, "snapshots"))
- ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
- else if (!strcmp(name, "enable-filter-overrides"))
- ctx.cfg.enable_filter_overrides = atoi(value);
- else if (!strcmp(name, "enable-follow-links"))
- ctx.cfg.enable_follow_links = atoi(value);
- else if (!strcmp(name, "enable-http-clone"))
- ctx.cfg.enable_http_clone = atoi(value);
- else if (!strcmp(name, "enable-index-links"))
- ctx.cfg.enable_index_links = atoi(value);
- else if (!strcmp(name, "enable-index-owner"))
- ctx.cfg.enable_index_owner = atoi(value);
- else if (!strcmp(name, "enable-blame"))
- ctx.cfg.enable_blame = atoi(value);
- else if (!strcmp(name, "enable-commit-graph"))
- ctx.cfg.enable_commit_graph = atoi(value);
- else if (!strcmp(name, "enable-log-filecount"))
- ctx.cfg.enable_log_filecount = atoi(value);
- else if (!strcmp(name, "enable-log-linecount"))
- ctx.cfg.enable_log_linecount = atoi(value);
- else if (!strcmp(name, "enable-remote-branches"))
- ctx.cfg.enable_remote_branches = atoi(value);
- else if (!strcmp(name, "enable-subject-links"))
- ctx.cfg.enable_subject_links = atoi(value);
- else if (!strcmp(name, "enable-html-serving"))
- ctx.cfg.enable_html_serving = atoi(value);
- else if (!strcmp(name, "enable-tree-linenumbers"))
- ctx.cfg.enable_tree_linenumbers = atoi(value);
- else if (!strcmp(name, "enable-git-config"))
- ctx.cfg.enable_git_config = atoi(value);
- else if (!strcmp(name, "max-stats"))
- ctx.cfg.max_stats = cgit_find_stats_period(value, NULL);
- else if (!strcmp(name, "cache-size"))
- ctx.cfg.cache_size = atoi(value);
- else if (!strcmp(name, "cache-root"))
- ctx.cfg.cache_root = strdup_first_line(expand_macros(value));
- else if (!strcmp(name, "cache-root-ttl"))
- ctx.cfg.cache_root_ttl = atoi(value);
- else if (!strcmp(name, "cache-repo-ttl"))
- ctx.cfg.cache_repo_ttl = atoi(value);
- else if (!strcmp(name, "cache-scanrc-ttl"))
- ctx.cfg.cache_scanrc_ttl = atoi(value);
- else if (!strcmp(name, "cache-static-ttl"))
- ctx.cfg.cache_static_ttl = atoi(value);
- else if (!strcmp(name, "cache-dynamic-ttl"))
- ctx.cfg.cache_dynamic_ttl = atoi(value);
- else if (!strcmp(name, "cache-about-ttl"))
- ctx.cfg.cache_about_ttl = atoi(value);
- else if (!strcmp(name, "cache-snapshot-ttl"))
- ctx.cfg.cache_snapshot_ttl = atoi(value);
- else if (!strcmp(name, "case-sensitive-sort"))
- ctx.cfg.case_sensitive_sort = atoi(value);
- else if (!strcmp(name, "about-filter"))
- ctx.cfg.about_filter = cgit_new_filter(value, ABOUT);
- else if (!strcmp(name, "commit-filter"))
- ctx.cfg.commit_filter = cgit_new_filter(value, COMMIT);
- else if (!strcmp(name, "email-filter"))
- ctx.cfg.email_filter = cgit_new_filter(value, EMAIL);
- else if (!strcmp(name, "owner-filter"))
- ctx.cfg.owner_filter = cgit_new_filter(value, OWNER);
- else if (!strcmp(name, "auth-filter"))
- ctx.cfg.auth_filter = cgit_new_filter(value, AUTH);
- else if (!strcmp(name, "embedded"))
- ctx.cfg.embedded = atoi(value);
- else if (!strcmp(name, "max-atom-items"))
- ctx.cfg.max_atom_items = atoi(value);
- else if (!strcmp(name, "max-message-length"))
- ctx.cfg.max_msg_len = atoi(value);
- else if (!strcmp(name, "max-repodesc-length"))
- ctx.cfg.max_repodesc_len = atoi(value);
- else if (!strcmp(name, "max-blob-size"))
- ctx.cfg.max_blob_size = atoi(value);
- else if (!strcmp(name, "max-repo-count")) {
- ctx.cfg.max_repo_count = atoi(value);
- if (ctx.cfg.max_repo_count <= 0)
- ctx.cfg.max_repo_count = INT_MAX;
- } else if (!strcmp(name, "max-commit-count"))
- ctx.cfg.max_commit_count = atoi(value);
- else if (!strcmp(name, "project-list"))
- ctx.cfg.project_list = strdup_first_line(expand_macros(value));
- else if (!strcmp(name, "scan-path"))
- if (ctx.cfg.cache_size)
- process_cached_repolist(expand_macros(value));
- else if (ctx.cfg.project_list)
- scan_projects(expand_macros(value),
- ctx.cfg.project_list);
- else
- scan_tree(expand_macros(value));
- else if (!strcmp(name, "scan-hidden-path"))
- ctx.cfg.scan_hidden_path = atoi(value);
- else if (!strcmp(name, "section-from-path"))
- ctx.cfg.section_from_path = atoi(value);
- else if (!strcmp(name, "repository-sort"))
- ctx.cfg.repository_sort = strdup_first_line(value);
- else if (!strcmp(name, "section-sort"))
- ctx.cfg.section_sort = atoi(value);
- else if (!strcmp(name, "source-filter"))
- ctx.cfg.source_filter = cgit_new_filter(value, SOURCE);
- else if (!strcmp(name, "summary-log"))
- ctx.cfg.summary_log = atoi(value);
- else if (!strcmp(name, "summary-branches"))
- ctx.cfg.summary_branches = atoi(value);
- else if (!strcmp(name, "summary-tags"))
- ctx.cfg.summary_tags = atoi(value);
- else if (!strcmp(name, "side-by-side-diffs"))
- ctx.cfg.difftype = atoi(value) ? DIFF_SSDIFF : DIFF_UNIFIED;
- else if (!strcmp(name, "agefile"))
- ctx.cfg.agefile = strdup_first_line(value);
- else if (!strcmp(name, "mimetype-file"))
- ctx.cfg.mimetype_file = strdup_first_line(value);
- else if (!strcmp(name, "renamelimit"))
- ctx.cfg.renamelimit = atoi(value);
- else if (!strcmp(name, "remove-suffix"))
- ctx.cfg.remove_suffix = atoi(value);
- else if (!strcmp(name, "robots"))
- ctx.cfg.robots = strdup_first_line(value);
- else if (!strcmp(name, "clone-prefix"))
- ctx.cfg.clone_prefix = strdup_first_line(value);
- else if (!strcmp(name, "clone-url"))
- ctx.cfg.clone_url = strdup_first_line(value);
- else if (!strcmp(name, "local-time"))
- ctx.cfg.local_time = atoi(value);
- else if (!strcmp(name, "commit-sort")) {
- if (!strcmp(value, "date"))
- ctx.cfg.commit_sort = 1;
- if (!strcmp(value, "topo"))
- ctx.cfg.commit_sort = 2;
- } else if (!strcmp(name, "branch-sort")) {
- if (!strcmp(value, "age"))
- ctx.cfg.branch_sort = 1;
- if (!strcmp(value, "name"))
- ctx.cfg.branch_sort = 0;
- } else if (skip_prefix(name, "mimetype.", &arg))
- add_mimetype(arg, value);
- else if (!strcmp(name, "include"))
- parse_configfile(expand_macros(value), config_cb);
+ cgit_virtual_root = xstrdup(value);
}
-static void querystring_cb(const char *name, const char *value)
+void cgit_repo_config_cb(const char *name, const char *value)
{
- if (!value)
- value = "";
-
- if (!strcmp(name,"r")) {
- ctx.qry.repo = xstrdup(value);
- ctx.repo = cgit_get_repoinfo(value);
- } else if (!strcmp(name, "p")) {
- ctx.qry.page = xstrdup(value);
- } else if (!strcmp(name, "url")) {
- if (*value == '/')
- value++;
- ctx.qry.url = xstrdup(value);
- cgit_parse_url(value);
- } else if (!strcmp(name, "qt")) {
- ctx.qry.grep = xstrdup(value);
- } else if (!strcmp(name, "q")) {
- ctx.qry.search = xstrdup(value);
- } else if (!strcmp(name, "h")) {
- ctx.qry.head = xstrdup(value);
- ctx.qry.has_symref = 1;
- } else if (!strcmp(name, "id")) {
- ctx.qry.oid = xstrdup(value);
- ctx.qry.has_oid = 1;
- } else if (!strcmp(name, "id2")) {
- ctx.qry.oid2 = xstrdup(value);
- ctx.qry.has_oid = 1;
- } else if (!strcmp(name, "ofs")) {
- ctx.qry.ofs = atoi(value);
- } else if (!strcmp(name, "path")) {
- ctx.qry.path = trim_end(value, '/');
- } else if (!strcmp(name, "name")) {
- ctx.qry.name = xstrdup(value);
- } else if (!strcmp(name, "s")) {
- ctx.qry.sort = xstrdup(value);
- } else if (!strcmp(name, "showmsg")) {
- ctx.qry.showmsg = atoi(value);
- } else if (!strcmp(name, "period")) {
- ctx.qry.period = xstrdup(value);
- } else if (!strcmp(name, "dt")) {
- ctx.qry.difftype = atoi(value);
- ctx.qry.has_difftype = 1;
- } else if (!strcmp(name, "ss")) {
- /* No longer generated, but there may be links out there. */
- ctx.qry.difftype = atoi(value) ? DIFF_SSDIFF : DIFF_UNIFIED;
- ctx.qry.has_difftype = 1;
- } else if (!strcmp(name, "all")) {
- ctx.qry.show_all = atoi(value);
- } else if (!strcmp(name, "context")) {
- ctx.qry.context = atoi(value);
- } else if (!strcmp(name, "ignorews")) {
- ctx.qry.ignorews = atoi(value);
- } else if (!strcmp(name, "follow")) {
- ctx.qry.follow = atoi(value);
- }
+ if (!strcmp(name, "name"))
+ cgit_repo_name = xstrdup(value);
+ else if (!strcmp(name, "desc"))
+ cgit_repo_desc = xstrdup(value);
+ else if (!strcmp(name, "owner"))
+ cgit_repo_owner = xstrdup(value);
}
-static void prepare_context(void)
+void cgit_querystring_cb(const char *name, const char *value)
{
- memset(&ctx, 0, sizeof(ctx));
- ctx.cfg.agefile = "info/web/last-modified";
- ctx.cfg.cache_size = 0;
- ctx.cfg.cache_max_create_time = 5;
- ctx.cfg.cache_root = CGIT_CACHE_ROOT;
- ctx.cfg.cache_about_ttl = 15;
- ctx.cfg.cache_snapshot_ttl = 5;
- ctx.cfg.cache_repo_ttl = 5;
- ctx.cfg.cache_root_ttl = 5;
- ctx.cfg.cache_scanrc_ttl = 15;
- ctx.cfg.cache_dynamic_ttl = 5;
- ctx.cfg.cache_static_ttl = -1;
- ctx.cfg.case_sensitive_sort = 1;
- ctx.cfg.branch_sort = 0;
- ctx.cfg.commit_sort = 0;
- ctx.cfg.logo = "/cgit.png";
- ctx.cfg.favicon = "/favicon.ico";
- ctx.cfg.local_time = 0;
- ctx.cfg.enable_http_clone = 1;
- ctx.cfg.enable_index_owner = 1;
- ctx.cfg.enable_tree_linenumbers = 1;
- ctx.cfg.enable_git_config = 0;
- ctx.cfg.max_repo_count = 50;
- ctx.cfg.max_commit_count = 50;
- ctx.cfg.max_lock_attempts = 5;
- ctx.cfg.max_msg_len = 80;
- ctx.cfg.max_repodesc_len = 80;
- ctx.cfg.max_blob_size = 0;
- ctx.cfg.max_stats = 0;
- ctx.cfg.project_list = NULL;
- ctx.cfg.renamelimit = -1;
- ctx.cfg.remove_suffix = 0;
- ctx.cfg.robots = "index, nofollow";
- ctx.cfg.root_title = "Git repository browser";
- ctx.cfg.root_desc = "a fast webinterface for the git dscm";
- ctx.cfg.scan_hidden_path = 0;
- ctx.cfg.script_name = CGIT_SCRIPT_NAME;
- ctx.cfg.section = "";
- ctx.cfg.repository_sort = "name";
- ctx.cfg.section_sort = 1;
- ctx.cfg.summary_branches = 10;
- ctx.cfg.summary_log = 10;
- ctx.cfg.summary_tags = 10;
- ctx.cfg.max_atom_items = 10;
- ctx.cfg.difftype = DIFF_UNIFIED;
- ctx.env.cgit_config = getenv("CGIT_CONFIG");
- ctx.env.http_host = getenv("HTTP_HOST");
- ctx.env.https = getenv("HTTPS");
- ctx.env.no_http = getenv("NO_HTTP");
- ctx.env.path_info = getenv("PATH_INFO");
- ctx.env.query_string = getenv("QUERY_STRING");
- ctx.env.request_method = getenv("REQUEST_METHOD");
- ctx.env.script_name = getenv("SCRIPT_NAME");
- ctx.env.server_name = getenv("SERVER_NAME");
- ctx.env.server_port = getenv("SERVER_PORT");
- ctx.env.http_cookie = getenv("HTTP_COOKIE");
- ctx.env.http_referer = getenv("HTTP_REFERER");
- ctx.env.content_length = getenv("CONTENT_LENGTH") ? strtoul(getenv("CONTENT_LENGTH"), NULL, 10) : 0;
- ctx.env.authenticated = 0;
- ctx.page.mimetype = "text/html";
- ctx.page.charset = PAGE_ENCODING;
- ctx.page.filename = NULL;
- ctx.page.size = 0;
- ctx.page.modified = time(NULL);
- ctx.page.expires = ctx.page.modified;
- ctx.page.etag = NULL;
- string_list_init_dup(&ctx.cfg.mimetypes);
- if (ctx.env.script_name)
- ctx.cfg.script_name = xstrdup(ctx.env.script_name);
- if (ctx.env.query_string)
- ctx.qry.raw = xstrdup(ctx.env.query_string);
- if (!ctx.env.cgit_config)
- ctx.env.cgit_config = CGIT_CONFIG;
+ if (!strcmp(name,"r"))
+ cgit_query_repo = xstrdup(value);
+ else if (!strcmp(name, "p"))
+ cgit_query_page = xstrdup(value);
+ else if (!strcmp(name, "h"))
+ cgit_query_head = xstrdup(value);
}
-struct refmatch {
- char *req_ref;
- char *first_ref;
- int match;
-};
-
-static int find_current_ref(const struct reference *ref, void *cb_data)
+char *cgit_repourl(const char *reponame)
{
- struct refmatch *info;
-
- info = (struct refmatch *)cb_data;
- if (!strcmp(ref->name, info->req_ref))
- info->match = 1;
- if (!info->first_ref)
- info->first_ref = xstrdup(ref->name);
- return info->match;
+ if (cgit_virtual_root) {
+ return fmt("%s/%s/", cgit_virtual_root, reponame);
+ } else {
+ return fmt("?r=%s", reponame);
+ }
}
-static void free_refmatch_inner(struct refmatch *info)
+char *cgit_pageurl(const char *reponame, const char *pagename,
+ const char *query)
{
- if (info->first_ref)
- free(info->first_ref);
+ if (cgit_virtual_root) {
+ return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame,
+ pagename, query);
+ } else {
+ return fmt("?r=%s&p=%s&%s", reponame, pagename, query);
+ }
}
-static char *find_default_branch(struct cgit_repo *repo)
+static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1,
+ int flags, void *cb_data)
{
- struct refmatch info;
- char *ref;
-
- info.req_ref = repo->defbranch;
- info.first_ref = NULL;
- info.match = 0;
- refs_for_each_branch_ref(get_main_ref_store(the_repository),
- find_current_ref, &info);
- if (info.match)
- ref = info.req_ref;
- else
- ref = info.first_ref;
- if (ref)
- ref = xstrdup(ref);
- free_refmatch_inner(&info);
+ struct commit *commit;
+ char buf[256], *url;
- return ref;
+ commit = lookup_commit(sha1);
+ if (commit && !parse_commit(commit)){
+ html("<tr><td>");
+ url = cgit_pageurl(cgit_query_repo, "log",
+ fmt("h=%s", refname));
+ html_link_open(url, NULL, NULL);
+ strncpy(buf, refname, sizeof(buf));
+ html_txt(buf);
+ html_link_close();
+ html("</td><td>");
+ pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, buf,
+ sizeof(buf), 0, NULL, NULL, 0);
+ html_txt(buf);
+ html("</td></tr>\n");
+ } else {
+ html("<tr><td>");
+ html_txt(buf);
+ html("</td><td>");
+ htmlf("*** bad ref %s", sha1_to_hex(sha1));
+ html("</td></tr>\n");
+ }
+ return 0;
}
-static char *guess_defbranch(void)
+static void cgit_print_docstart(char *title)
{
- const char *ref, *refname;
- struct object_id oid;
-
- ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
- "HEAD", 0, &oid, NULL);
- if (!ref || !skip_prefix(ref, "refs/heads/", &refname))
- return "master";
- return xstrdup(refname);
+ html("Content-Type: text/html; charset=utf-8\n");
+ html("\n");
+ html(cgit_doctype);
+ html("<html>\n");
+ html("<head>\n");
+ html("<title>");
+ html_txt(title);
+ html("</title>\n");
+ html("<link rel='stylesheet' type='text/css' href='");
+ html_attr(cgit_css);
+ html("'/>\n");
+ html("</head>\n");
+ html("<body>\n");
}
-/* The caller must free filename and ref after calling this. */
-static inline void parse_readme(const char *readme, char **filename, char **ref, struct cgit_repo *repo)
-{
- const char *colon;
-
- *filename = NULL;
- *ref = NULL;
-
- if (!readme || !readme[0])
- return;
-
- /* Check if the readme is tracked in the git repo. */
- colon = strchr(readme, ':');
- if (colon && strlen(colon) > 1) {
- /* If it starts with a colon, we want to use head given
- * from query or the default branch */
- if (colon == readme && ctx.qry.head)
- *ref = xstrdup(ctx.qry.head);
- else if (colon == readme && repo->defbranch)
- *ref = xstrdup(repo->defbranch);
- else
- *ref = xstrndup(readme, colon - readme);
- readme = colon + 1;
- }
-
- /* Prepend repo path to relative readme path unless tracked. */
- if (!(*ref) && readme[0] != '/')
- *filename = fmtalloc("%s/%s", repo->path, readme);
- else
- *filename = xstrdup(readme);
-}
-static void choose_readme(struct cgit_repo *repo)
+static void cgit_print_docend()
{
- int found;
- char *filename, *ref;
- struct string_list_item *entry;
-
- if (!repo->readme.nr)
- return;
-
- found = 0;
- for_each_string_list_item(entry, &repo->readme) {
- parse_readme(entry->string, &filename, &ref, repo);
- if (!filename) {
- free(filename);
- free(ref);
- continue;
- }
- if (ref) {
- if (cgit_ref_path_exists(filename, ref, 1)) {
- found = 1;
- break;
- }
- }
- else if (!access(filename, R_OK)) {
- found = 1;
- break;
- }
- free(filename);
- free(ref);
- }
- repo->readme.strdup_strings = 1;
- string_list_clear(&repo->readme, 0);
- repo->readme.strdup_strings = 0;
- if (found)
- string_list_append(&repo->readme, filename)->util = ref;
+ html("</body>\n</html>\n");
}
-static void print_no_repo_clone_urls(const char *url)
+static void cgit_print_pageheader(char *title)
{
- html("<tr><td><a rel='vcs-git' href='");
- html_url_path(url);
- html("' title='");
- html_attr(ctx.repo->name);
- html(" Git repository'>");
- html_txt(url);
- html("</a></td></tr>\n");
+ html("<div id='header'>");
+ htmlf("<a href='%s'>", cgit_logo_link);
+ htmlf("<img id='logo' src='%s'/>\n", cgit_logo);
+ htmlf("</a>");
+ html_txt(title);
+ html("</div>");
}
-static void prepare_repo_env(int *nongit)
+static void cgit_print_repolist()
{
- /* The path to the git repository. */
- setenv("GIT_DIR", ctx.repo->path, 1);
-
- /* Setup the git directory and initialize the notes system. Both of these
- * load local configuration from the git repository, so we do them both while
- * the HOME variables are unset. */
- setup_git_directory_gently(nongit);
- load_display_notes(NULL);
-}
+ DIR *d;
+ struct dirent *de;
+ struct stat st;
+ char *name;
-static int prepare_repo_cmd(int nongit)
-{
- struct object_id oid;
- int rc;
+ cgit_print_docstart(cgit_root_title);
+ cgit_print_pageheader(cgit_root_title);
- if (nongit) {
- const char *name = ctx.repo->name;
- rc = errno;
- ctx.page.title = fmtalloc("%s - %s", ctx.cfg.root_title,
- "config error");
- ctx.repo = NULL;
- cgit_print_http_headers();
- cgit_print_docstart();
- cgit_print_pageheader();
- cgit_print_error("Failed to open %s: %s", name,
- rc ? strerror(rc) : "Not a valid git repository");
+ if (!(d = opendir("."))) {
+ htmlf(cgit_lib_error, "Unable to scan repository directory",
+ strerror(errno));
cgit_print_docend();
- return 1;
+ return;
}
- ctx.page.title = fmtalloc("%s - %s", ctx.repo->name, ctx.repo->desc);
-
- if (!ctx.repo->defbranch)
- ctx.repo->defbranch = guess_defbranch();
- if (!ctx.qry.head) {
- ctx.qry.nohead = 1;
- ctx.qry.head = find_default_branch(ctx.repo);
- }
+ html("<h2>Repositories</h2>\n");
+ html("<table class='list'>");
+ html("<tr><th>Name</th><th>Description</th><th>Owner</th></tr>\n");
+ while ((de = readdir(d)) != NULL) {
+ if (de->d_name[0] == '.')
+ continue;
+ if (stat(de->d_name, &st) < 0)
+ continue;
+ if (!S_ISDIR(st.st_mode))
+ continue;
- if (!ctx.qry.head) {
- cgit_print_http_headers();
- cgit_print_docstart();
- cgit_print_pageheader();
- cgit_print_error("Repository seems to be empty");
- if (!strcmp(ctx.qry.page, "summary")) {
- html("<table class='list'><tr class='nohover'><td>&nbsp;</td></tr><tr class='nohover'><th class='left'>Clone</th></tr>\n");
- cgit_prepare_repo_env(ctx.repo);
- cgit_add_clone_urls(print_no_repo_clone_urls);
- html("</table>\n");
- }
- cgit_print_docend();
- return 1;
- }
+ cgit_repo_name = cgit_repo_desc = cgit_repo_owner = NULL;
+ name = fmt("%s/.git/info/cgit", de->d_name);
+ if (cgit_read_config(name, cgit_repo_config_cb))
+ continue;
- if (repo_get_oid(the_repository, ctx.qry.head, &oid)) {
- char *old_head = ctx.qry.head;
- ctx.qry.head = xstrdup(ctx.repo->defbranch);
- cgit_print_error_page(404, "Not found",
- "Invalid branch: %s", old_head);
- free(old_head);
- return 1;
+ html("<tr><td>");
+ html_link_open(cgit_repourl(de->d_name), NULL, NULL);
+ html_txt(cgit_repo_name);
+ html_link_close();
+ html("</td><td>");
+ html_txt(cgit_repo_desc);
+ html("</td><td>");
+ html_txt(cgit_repo_owner);
+ html("</td></tr>\n");
}
- string_list_sort(&ctx.repo->submodules);
- cgit_prepare_repo_env(ctx.repo);
- choose_readme(ctx.repo);
- return 0;
+ closedir(d);
+ html("</table>");
+ cgit_print_docend();
}
-static inline void open_auth_filter(const char *function)
+static void cgit_print_branches()
{
- cgit_open_filter(ctx.cfg.auth_filter, function,
- ctx.env.http_cookie ? ctx.env.http_cookie : "",
- ctx.env.request_method ? ctx.env.request_method : "",
- ctx.env.query_string ? ctx.env.query_string : "",
- ctx.env.http_referer ? ctx.env.http_referer : "",
- ctx.env.path_info ? ctx.env.path_info : "",
- ctx.env.http_host ? ctx.env.http_host : "",
- ctx.env.https ? ctx.env.https : "",
- ctx.qry.repo ? ctx.qry.repo : "",
- ctx.qry.page ? ctx.qry.page : "",
- cgit_currentfullurl(),
- cgit_loginurl());
+ html("<table class='list'>");
+ html("<tr><th>Branch name</th><th>Head commit</th></tr>\n");
+ for_each_branch_ref(cgit_print_branch_cb, NULL);
+ html("</table>");
}
-/* We intentionally keep this rather small, instead of looping and
- * feeding it to the filter a couple bytes at a time. This way, the
- * filter itself does not need to handle any denial of service or
- * buffer bloat issues. If this winds up being too small, people
- * will complain on the mailing list, and we'll increase it as needed. */
-#define MAX_AUTHENTICATION_POST_BYTES 4096
-/* The filter is expected to spit out "Status: " and all headers. */
-static inline void authenticate_post(void)
+static int get_one_line(char *txt)
{
- char buffer[MAX_AUTHENTICATION_POST_BYTES];
- ssize_t len;
+ char *t;
- open_auth_filter("authenticate-post");
- len = ctx.env.content_length;
- if (len > MAX_AUTHENTICATION_POST_BYTES)
- len = MAX_AUTHENTICATION_POST_BYTES;
- if ((len = read(STDIN_FILENO, buffer, len)) < 0)
- die_errno("Could not read POST from stdin");
- if (write(STDOUT_FILENO, buffer, len) < 0)
- die_errno("Could not write POST to stdout");
- cgit_close_filter(ctx.cfg.auth_filter);
- exit(0);
+ for(t=txt; *t != '\n' && t != '\0'; t++)
+ ;
+ *t = '\0';
+ return t-txt-1;
}
-static inline void authenticate_cookie(void)
+static void cgit_print_commit_shortlog(struct commit *commit)
{
- /* If we don't have an auth_filter, consider all cookies valid, and thus return early. */
- if (!ctx.cfg.auth_filter) {
- ctx.env.authenticated = 1;
- return;
- }
+ char *h, *t, *p;
+ char *tree = NULL, *author = NULL, *subject = NULL;
+ int len;
+ time_t sec;
+ struct tm *time;
+ char buf[32];
- /* If we're having something POST'd to /login, we're authenticating POST,
- * instead of the cookie, so call authenticate_post and bail out early.
- * This pattern here should match /?p=login with POST. */
- if (ctx.env.request_method && ctx.qry.page && !ctx.repo && \
- !strcmp(ctx.env.request_method, "POST") && !strcmp(ctx.qry.page, "login")) {
- authenticate_post();
- return;
- }
+ h = t = commit->buffer;
+
+ if (strncmp(h, "tree ", 5))
+ die("Bad commit format: %s",
+ sha1_to_hex(commit->object.sha1));
+
+ len = get_one_line(h);
+ tree = h+5;
+ h += len + 2;
- /* If we've made it this far, we're authenticating the cookie for real, so do that. */
- open_auth_filter("authenticate-cookie");
- ctx.env.authenticated = cgit_close_filter(ctx.cfg.auth_filter);
-}
+ while (!strncmp(h, "parent ", 7))
+ h += get_one_line(h) + 2;
+
+ if (!strncmp(h, "author ", 7)) {
+ author = h+7;
+ h += get_one_line(h) + 2;
+ t = author;
+ while(t!=h && *t!='<')
+ t++;
+ *t='\0';
+ p = t;
+ while(--t!=author && *t==' ')
+ *t='\0';
+ while(++p!=h && *p!='>')
+ ;
+ while(++p!=h && !isdigit(*p))
+ ;
-static void process_request(void)
-{
- struct cgit_cmd *cmd;
- int nongit = 0;
-
- /* If we're not yet authenticated, no matter what page we're on,
- * display the authentication body from the auth_filter. This should
- * never be cached. */
- if (!ctx.env.authenticated) {
- ctx.page.title = "Authentication Required";
- cgit_print_http_headers();
- cgit_print_docstart();
- cgit_print_pageheader();
- open_auth_filter("body");
- cgit_close_filter(ctx.cfg.auth_filter);
- cgit_print_docend();
- return;
- }
-
- if (ctx.repo)
- prepare_repo_env(&nongit);
-
- cmd = cgit_get_cmd();
- if (!cmd) {
- ctx.page.title = "cgit error";
- cgit_print_error_page(404, "Not found", "Invalid request");
- return;
+ t = p;
+ while(++p && isdigit(*p))
+ ;
+ *p = '\0';
+ sec = atoi(t);
+ time = gmtime(&sec);
}
- if (!ctx.cfg.enable_http_clone && cmd->is_clone) {
- ctx.page.title = "cgit error";
- cgit_print_error_page(404, "Not found", "Invalid request");
- return;
- }
-
- if (cmd->want_repo && !ctx.repo) {
- cgit_print_error_page(400, "Bad request",
- "No repository selected");
- return;
- }
-
- /* If cmd->want_vpath is set, assume ctx.qry.path contains a "virtual"
- * in-project path limit to be made available at ctx.qry.vpath.
- * Otherwise, no path limit is in effect (ctx.qry.vpath = NULL).
- */
- ctx.qry.vpath = cmd->want_vpath ? ctx.qry.path : NULL;
+ while((len = get_one_line(h)) > 0)
+ h += len+2;
- if (ctx.repo && prepare_repo_cmd(nongit))
- return;
+ h++;
+ len = get_one_line(h);
- cmd->fn();
-}
+ subject = h;
-static int cmp_repos(const void *a, const void *b)
-{
- const struct cgit_repo *ra = a, *rb = b;
- return strcmp(ra->url, rb->url);
+ html("<tr><td>");
+ strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", time);
+ html_txt(buf);
+ html("</td><td>");
+ char *qry = fmt("h=%s", sha1_to_hex(commit->object.sha1));
+ char *url = cgit_pageurl(cgit_query_repo, "view", qry);
+ html_link_open(url, NULL, NULL);
+ html_txt(subject);
+ html_link_close();
+ html("</td><td>");
+ html_txt(author);
+ html("</td></tr>\n");
}
-static char *build_snapshot_setting(int bitmap)
+static void cgit_print_log(const char *tip, int ofs, int cnt)
{
- const struct cgit_snapshot_format *f;
- struct strbuf result = STRBUF_INIT;
-
- for (f = cgit_snapshot_formats; f->suffix; f++) {
- if (cgit_snapshot_format_bit(f) & bitmap) {
- if (result.len)
- strbuf_addch(&result, ' ');
- strbuf_addstr(&result, f->suffix);
- }
- }
- return strbuf_detach(&result, NULL);
-}
+ struct rev_info rev;
+ struct commit *commit;
+ const char *argv[2] = {NULL, tip};
+ int n = 0;
+
+ init_revisions(&rev, NULL);
+ rev.abbrev = DEFAULT_ABBREV;
+ rev.commit_format = CMIT_FMT_DEFAULT;
+ rev.verbose_header = 1;
+ rev.show_root_diff = 0;
+ setup_revisions(2, argv, &rev, NULL);
+ prepare_revision_walk(&rev);
-static void print_repo(FILE *f, struct cgit_repo *repo)
-{
- struct string_list_item *item;
- fprintf(f, "repo.url=%s\n", repo->url);
- fprintf(f, "repo.name=%s\n", repo->name);
- fprintf(f, "repo.path=%s\n", repo->path);
- if (repo->owner)
- fprintf(f, "repo.owner=%s\n", repo->owner);
- if (repo->desc)
- fprintf(f, "repo.desc=%s\n", repo->desc);
- for_each_string_list_item(item, &repo->readme) {
- if (item->util)
- fprintf(f, "repo.readme=%s:%s\n", (char *)item->util, item->string);
- else
- fprintf(f, "repo.readme=%s\n", item->string);
- }
- if (repo->defbranch)
- fprintf(f, "repo.defbranch=%s\n", repo->defbranch);
- if (repo->extra_head_content)
- fprintf(f, "repo.extra-head-content=%s\n", repo->extra_head_content);
- if (repo->module_link)
- fprintf(f, "repo.module-link=%s\n", repo->module_link);
- if (repo->section)
- fprintf(f, "repo.section=%s\n", repo->section);
- if (repo->homepage)
- fprintf(f, "repo.homepage=%s\n", repo->homepage);
- if (repo->clone_url)
- fprintf(f, "repo.clone-url=%s\n", repo->clone_url);
- fprintf(f, "repo.enable-blame=%d\n",
- repo->enable_blame);
- fprintf(f, "repo.enable-commit-graph=%d\n",
- repo->enable_commit_graph);
- fprintf(f, "repo.enable-follow-links=%d\n",
- repo->enable_follow_links);
- fprintf(f, "repo.enable-log-filecount=%d\n",
- repo->enable_log_filecount);
- fprintf(f, "repo.enable-log-linecount=%d\n",
- repo->enable_log_linecount);
- if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter)
- cgit_fprintf_filter(repo->about_filter, f, "repo.about-filter=");
- if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter)
- cgit_fprintf_filter(repo->commit_filter, f, "repo.commit-filter=");
- if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter)
- cgit_fprintf_filter(repo->source_filter, f, "repo.source-filter=");
- if (repo->email_filter && repo->email_filter != ctx.cfg.email_filter)
- cgit_fprintf_filter(repo->email_filter, f, "repo.email-filter=");
- if (repo->owner_filter && repo->owner_filter != ctx.cfg.owner_filter)
- cgit_fprintf_filter(repo->owner_filter, f, "repo.owner-filter=");
- if (repo->snapshots != ctx.cfg.snapshots) {
- char *tmp = build_snapshot_setting(repo->snapshots);
- fprintf(f, "repo.snapshots=%s\n", tmp ? tmp : "");
- free(tmp);
- }
- if (repo->snapshot_prefix)
- fprintf(f, "repo.snapshot-prefix=%s\n", repo->snapshot_prefix);
- if (repo->max_stats != ctx.cfg.max_stats)
- fprintf(f, "repo.max-stats=%s\n",
- cgit_find_stats_periodname(repo->max_stats));
- if (repo->logo)
- fprintf(f, "repo.logo=%s\n", repo->logo);
- if (repo->logo_link)
- fprintf(f, "repo.logo-link=%s\n", repo->logo_link);
- fprintf(f, "repo.enable-remote-branches=%d\n", repo->enable_remote_branches);
- fprintf(f, "repo.enable-subject-links=%d\n", repo->enable_subject_links);
- fprintf(f, "repo.enable-html-serving=%d\n", repo->enable_html_serving);
- if (repo->branch_sort == 1)
- fprintf(f, "repo.branch-sort=age\n");
- if (repo->commit_sort) {
- if (repo->commit_sort == 1)
- fprintf(f, "repo.commit-sort=date\n");
- else if (repo->commit_sort == 2)
- fprintf(f, "repo.commit-sort=topo\n");
+ html("<h2>Log</h2>");
+ html("<table class='list'>");
+ html("<tr><th>Date</th><th>Message</th><th>Author</th></tr>\n");
+ while ((commit = get_revision(&rev)) != NULL && n++ < 100) {
+ cgit_print_commit_shortlog(commit);
+ free(commit->buffer);
+ commit->buffer = NULL;
+ free_commit_list(commit->parents);
+ commit->parents = NULL;
}
- fprintf(f, "repo.hide=%d\n", repo->hide);
- fprintf(f, "repo.ignore=%d\n", repo->ignore);
- fprintf(f, "\n");
+ html("</table>\n");
}
-static void print_repolist(FILE *f, struct cgit_repolist *list, int start)
+static void cgit_print_repo_summary()
{
- int i;
-
- for (i = start; i < list->count; i++)
- print_repo(f, &list->repos[i]);
+ html("<h2>");
+ html_txt("Repo summary page");
+ html("</h2>");
+ cgit_print_branches();
}
-/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc'
- * and return 0 on success.
- */
-static int generate_cached_repolist(const char *path, const char *cached_rc)
+static void cgit_print_object(char *hex)
{
- struct strbuf locked_rc = STRBUF_INIT;
- int result = 0;
- int idx;
- FILE *f;
+ unsigned char sha1[20];
+ //struct object *object;
+ char type[20];
+ unsigned char *buf;
+ unsigned long size;
- strbuf_addf(&locked_rc, "%s.lock", cached_rc);
- f = fopen(locked_rc.buf, "wx");
- if (!f) {
- /* Inform about the error unless the lockfile already existed,
- * since that only means we've got concurrent requests.
- */
- result = errno;
- if (result != EEXIST)
- fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n",
- locked_rc.buf, strerror(result), result);
- goto out;
+ if (get_sha1_hex(hex, sha1)){
+ htmlf(cgit_error, "Bad hex value");
+ return;
}
- idx = cgit_repolist.count;
- if (ctx.cfg.project_list)
- scan_projects(path, ctx.cfg.project_list);
- else
- scan_tree(path);
- print_repolist(f, &cgit_repolist, idx);
- if (rename(locked_rc.buf, cached_rc))
- fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n",
- locked_rc.buf, cached_rc, strerror(errno), errno);
- fclose(f);
-out:
- strbuf_release(&locked_rc);
- return result;
-}
-
-static void process_cached_repolist(const char *path)
-{
- struct stat st;
- struct strbuf cached_rc = STRBUF_INIT;
- time_t age;
- unsigned long hash;
- hash = hash_str(path);
- if (ctx.cfg.project_list)
- hash += hash_str(ctx.cfg.project_list);
- strbuf_addf(&cached_rc, "%s/rc-%8lx", ctx.cfg.cache_root, hash);
-
- if (stat(cached_rc.buf, &st)) {
- /* Nothing is cached, we need to scan without forking. And
- * if we fail to generate a cached repolist, we need to
- * invoke scan_tree manually.
- */
- if (generate_cached_repolist(path, cached_rc.buf)) {
- if (ctx.cfg.project_list)
- scan_projects(path, ctx.cfg.project_list);
- else
- scan_tree(path);
- }
- goto out;
+ if (sha1_object_info(sha1, type, NULL)){
+ htmlf(cgit_error, "Bad object name");
+ return;
}
- parse_configfile(cached_rc.buf, config_cb);
-
- /* If the cached configfile hasn't expired, lets exit now */
- age = time(NULL) - st.st_mtime;
- if (age <= (ctx.cfg.cache_scanrc_ttl * 60))
- goto out;
-
- /* The cached repolist has been parsed, but it was old. So lets
- * rescan the specified path and generate a new cached repolist
- * in a child-process to avoid latency for the current request.
- */
- if (fork())
- goto out;
+ buf = read_sha1_file(sha1, type, &size);
+ if (!buf) {
+ htmlf(cgit_error, "Error reading object");
+ return;
+ }
- exit(generate_cached_repolist(path, cached_rc.buf));
-out:
- strbuf_release(&cached_rc);
+ buf[size] = '\0';
+ html("<h2>Object view</h2>");
+ htmlf("sha1=%s<br/>type=%s<br/>size=%i<br/>", hex, type, size);
+ html("<pre>");
+ html_txt(buf);
+ html("</pre>");
}
-static void cgit_parse_args(int argc, const char **argv)
+static void cgit_print_repo_page()
{
- int i;
- const char *arg;
- int scan = 0;
-
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "--version")) {
- printf("CGit %s | https://git.zx2c4.com/cgit/\n\nCompiled in features:\n", CGIT_VERSION);
-#ifdef NO_LUA
- printf("[-] ");
-#else
- printf("[+] ");
-#endif
- printf("Lua scripting\n");
-#ifndef HAVE_LINUX_SENDFILE
- printf("[-] ");
-#else
- printf("[+] ");
-#endif
- printf("Linux sendfile() usage\n");
-
- exit(0);
- }
- if (skip_prefix(argv[i], "--cache=", &arg)) {
- ctx.cfg.cache_root = xstrdup(arg);
- } else if (!strcmp(argv[i], "--nohttp")) {
- ctx.env.no_http = "1";
- } else if (skip_prefix(argv[i], "--query=", &arg)) {
- ctx.qry.raw = xstrdup(arg);
- } else if (skip_prefix(argv[i], "--repo=", &arg)) {
- ctx.qry.repo = xstrdup(arg);
- } else if (skip_prefix(argv[i], "--page=", &arg)) {
- ctx.qry.page = xstrdup(arg);
- } else if (skip_prefix(argv[i], "--head=", &arg)) {
- ctx.qry.head = xstrdup(arg);
- ctx.qry.has_symref = 1;
- } else if (skip_prefix(argv[i], "--oid=", &arg)) {
- ctx.qry.oid = xstrdup(arg);
- ctx.qry.has_oid = 1;
- } else if (skip_prefix(argv[i], "--ofs=", &arg)) {
- ctx.qry.ofs = atoi(arg);
- } else if (skip_prefix(argv[i], "--scan-tree=", &arg) ||
- skip_prefix(argv[i], "--scan-path=", &arg)) {
- /*
- * HACK: The global snapshot bit mask defines the set
- * of allowed snapshot formats, but the config file
- * hasn't been parsed yet so the mask is currently 0.
- * By setting all bits high before scanning we make
- * sure that any in-repo cgitrc snapshot setting is
- * respected by scan_tree().
- *
- * NOTE: We assume that there aren't more than 8
- * different snapshot formats supported by cgit...
- */
- ctx.cfg.snapshots = 0xFF;
- scan++;
- scan_tree(arg);
- }
+ if (chdir(cgit_query_repo) ||
+ cgit_read_config(".git/info/cgit", cgit_repo_config_cb)) {
+ char *title = fmt("%s - %s", cgit_root_title, "Bad request");
+ cgit_print_docstart(title);
+ cgit_print_pageheader(title);
+ htmlf(cgit_lib_error, "Unable to scan repository",
+ strerror(errno));
+ cgit_print_docend();
+ return;
}
- if (scan) {
- qsort(cgit_repolist.repos, cgit_repolist.count,
- sizeof(struct cgit_repo), cmp_repos);
- print_repolist(stdout, &cgit_repolist, 0);
- exit(0);
+
+ char *title = fmt("%s - %s", cgit_repo_name, cgit_repo_desc);
+ cgit_print_docstart(title);
+ cgit_print_pageheader(title);
+ if (!cgit_query_page)
+ cgit_print_repo_summary();
+ else if (!strcmp(cgit_query_page, "log")) {
+ cgit_print_log(cgit_query_head, 0, 100);
+ } else if (!strcmp(cgit_query_page, "view")) {
+ cgit_print_object(cgit_query_head);
}
+ cgit_print_docend();
}
-static int calc_ttl(void)
+int main(int argc, const char **argv)
{
- if (!ctx.repo)
- return ctx.cfg.cache_root_ttl;
-
- if (!ctx.qry.page)
- return ctx.cfg.cache_repo_ttl;
-
- if (!strcmp(ctx.qry.page, "about"))
- return ctx.cfg.cache_about_ttl;
-
- if (!strcmp(ctx.qry.page, "snapshot"))
- return ctx.cfg.cache_snapshot_ttl;
-
- if (ctx.qry.has_oid)
- return ctx.cfg.cache_static_ttl;
-
- if (ctx.qry.has_symref)
- return ctx.cfg.cache_dynamic_ttl;
+ if (cgit_read_config("/etc/cgitrc", cgit_global_config_cb))
+ die("Error reading config: %d %s", errno, strerror(errno));
- return ctx.cfg.cache_repo_ttl;
-}
-
-static NORETURN void cgit_die_routine(const char *msg, va_list params)
-{
- cgit_vprint_error_page(400, "Bad request", msg, params);
- exit(0);
-}
-
-int cmd_main(int argc, const char **argv)
-{
- const char *path;
- int err, ttl;
-
- cgit_init_filters();
- atexit(cgit_cleanup_filters);
- set_die_routine(cgit_die_routine);
-
- prepare_context();
- cgit_repolist.length = 0;
- cgit_repolist.count = 0;
- cgit_repolist.repos = NULL;
-
- cgit_parse_args(argc, argv);
- parse_configfile(expand_macros(ctx.env.cgit_config), config_cb);
- ctx.repo = NULL;
- http_parse_querystring(ctx.qry.raw, querystring_cb);
-
- /* If virtual-root isn't specified in cgitrc, lets pretend
- * that virtual-root equals SCRIPT_NAME, minus any possibly
- * trailing slashes.
- */
- if (!ctx.cfg.virtual_root && ctx.cfg.script_name)
- ctx.cfg.virtual_root = ensure_end(ctx.cfg.script_name, '/');
-
- /* If no url parameter is specified on the querystring, lets
- * use PATH_INFO as url. This allows cgit to work with virtual
- * urls without the need for rewriterules in the webserver (as
- * long as PATH_INFO is included in the cache lookup key).
- */
- path = ctx.env.path_info;
- if (!ctx.qry.url && path) {
- if (path[0] == '/')
- path++;
- ctx.qry.url = xstrdup(path);
- if (ctx.qry.raw) {
- char *newqry = fmtalloc("%s?%s", path, ctx.qry.raw);
- free(ctx.qry.raw);
- ctx.qry.raw = newqry;
- } else
- ctx.qry.raw = xstrdup(ctx.qry.url);
- cgit_parse_url(ctx.qry.url);
- }
-
- /* Before we go any further, we set ctx.env.authenticated by checking to see
- * if the supplied cookie is valid. All cookies are valid if there is no
- * auth_filter. If there is an auth_filter, the filter decides. */
- authenticate_cookie();
-
- ttl = calc_ttl();
- if (ttl < 0)
- ctx.page.expires += 10 * 365 * 24 * 60 * 60; /* 10 years */
+ chdir(cgit_root);
+ cgit_parse_query(getenv("QUERY_STRING"), cgit_querystring_cb);
+ if (cgit_query_repo)
+ cgit_print_repo_page();
else
- ctx.page.expires += ttl * 60;
- if (!ctx.env.authenticated || (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")))
- ctx.cfg.cache_size = 0;
- err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root,
- ctx.qry.raw, ttl, process_request);
- cgit_cleanup_filters();
- if (err)
- cgit_print_error("Error processing page: %s (%d)",
- strerror(err), err);
- return err;
+ cgit_print_repolist();
+ return 0;
}
diff --git a/cgit.css b/cgit.css
index d10a24d..3ed0c22 100644
--- a/cgit.css
+++ b/cgit.css
@@ -1,909 +1,63 @@
-div#cgit {
- padding: 0em;
- margin: 0em;
- font-family: sans-serif;
- font-size: 10pt;
- color: #333;
+body {
+ font-family: arial;
+ font-size: normal;
background: white;
- padding: 4px;
-}
-
-div#cgit a {
- color: blue;
- text-decoration: none;
-}
-
-div#cgit a:hover {
- text-decoration: underline;
-}
-
-div#cgit table {
- border-collapse: collapse;
-}
-
-div#cgit table#header {
- width: 100%;
- margin-bottom: 1em;
-}
-
-div#cgit table#header td.logo {
- width: 96px;
- vertical-align: top;
-}
-
-div#cgit table#header td.main {
- font-size: 250%;
- padding-left: 10px;
- white-space: nowrap;
-}
-
-div#cgit table#header td.main a {
- color: #000;
-}
-
-div#cgit table#header td.form {
- text-align: right;
- vertical-align: bottom;
- padding-right: 1em;
- padding-bottom: 2px;
- white-space: nowrap;
-}
-
-div#cgit table#header td.form form,
-div#cgit table#header td.form input,
-div#cgit table#header td.form select {
- font-size: 90%;
-}
-
-div#cgit table#header td.sub {
- color: #777;
- border-top: solid 1px #ccc;
- padding-left: 10px;
-}
-
-div#cgit table.tabs {
- border-bottom: solid 3px #ccc;
- border-collapse: collapse;
- margin-top: 2em;
- margin-bottom: 0px;
- width: 100%;
-}
-
-div#cgit table.tabs td {
- padding: 0px 1em;
- vertical-align: bottom;
-}
-
-div#cgit table.tabs td a {
- padding: 2px 0.75em;
- color: #777;
- font-size: 110%;
-}
-
-div#cgit table.tabs td a.active {
- color: #000;
- background-color: #ccc;
-}
-
-div#cgit table.tabs a[href^="http://"]:after, div#cgit table.tabs a[href^="https://"]:after {
- content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhcJDQY+gm2TAAAAHWlUWHRDb21tZW50AAAAAABDcmVhdGVkIHdpdGggR0lNUGQuZQcAAABbSURBVAhbY2BABs4MU4CwhYHBh2Erww4wrGFQZHjI8B8IgUIscJWyDHcggltQhI4zGDCcRwhChPggHIggP1QoAVmQkSETrGoHsiAEsACtBYN0oDAMbgU6EBcAAL2eHUt4XUU4AAAAAElFTkSuQmCC);
- opacity: 0.5;
- margin: 0 0 0 5px;
-}
-
-div#cgit table.tabs td.form {
- text-align: right;
-}
-
-div#cgit table.tabs td.form form {
- padding-bottom: 2px;
- font-size: 90%;
- white-space: nowrap;
-}
-
-div#cgit table.tabs td.form input,
-div#cgit table.tabs td.form select {
- font-size: 90%;
-}
-
-div#cgit div.path {
- margin: 0px;
- padding: 5px 2em 2px 2em;
- color: #000;
- background-color: #eee;
-}
-
-div#cgit div.content {
- margin: 0px;
- padding: 2em;
- border-bottom: solid 3px #ccc;
-}
-
-
-div#cgit table.list {
- width: 100%;
- border: none;
- border-collapse: collapse;
-}
-
-div#cgit table.list tr {
- background: white;
-}
-
-div#cgit table.list tr.logheader {
- background: #eee;
-}
-
-div#cgit table.list tr:nth-child(even) {
- background: #f7f7f7;
-}
-
-div#cgit table.list tr:nth-child(odd) {
- background: white;
-}
-
-div#cgit table.list tr:hover {
- background: #eee;
-}
-
-div#cgit table.list tr.nohover {
- background: white;
-}
-
-div#cgit table.list tr.nohover:hover {
- background: white;
-}
-
-div#cgit table.list tr.nohover-highlight:hover:nth-child(even) {
- background: #f7f7f7;
-}
-
-div#cgit table.list tr.nohover-highlight:hover:nth-child(odd) {
- background: white;
-}
-
-div#cgit table.list th {
- font-weight: bold;
- /* color: #888;
- border-top: dashed 1px #888;
- border-bottom: dashed 1px #888;
- */
- padding: 0.1em 0.5em 0.05em 0.5em;
- vertical-align: baseline;
-}
-
-div#cgit table.list td {
- border: none;
- padding: 0.1em 0.5em 0.1em 0.5em;
-}
-
-div#cgit table.list td.commitgraph {
- font-family: monospace;
- white-space: pre;
-}
-
-div#cgit table.list td.commitgraph .column1 {
- color: #a00;
-}
-
-div#cgit table.list td.commitgraph .column2 {
- color: #0a0;
-}
-
-div#cgit table.list td.commitgraph .column3 {
- color: #aa0;
-}
-
-div#cgit table.list td.commitgraph .column4 {
- color: #00a;
-}
-
-div#cgit table.list td.commitgraph .column5 {
- color: #a0a;
-}
-
-div#cgit table.list td.commitgraph .column6 {
- color: #0aa;
-}
-
-div#cgit table.list td.logsubject {
- font-family: monospace;
- font-weight: bold;
-}
-
-div#cgit table.list td.logmsg {
- font-family: monospace;
- white-space: pre;
- padding: 0 0.5em;
-}
-
-div#cgit table.list td a {
- color: black;
-}
-
-div#cgit table.list td a.ls-dir {
- font-weight: bold;
- color: #00f;
-}
-
-div#cgit table.list td a:hover {
- color: #00f;
-}
-
-div#cgit img {
- border: none;
-}
-
-div#cgit input#switch-btn {
- margin: 2px 0px 0px 0px;
-}
-
-div#cgit td#sidebar input.txt {
- width: 100%;
- margin: 2px 0px 0px 0px;
-}
-
-div#cgit table#grid {
- margin: 0px;
-}
-
-div#cgit td#content {
- vertical-align: top;
- padding: 1em 2em 1em 1em;
- border: none;
-}
-
-div#cgit div#summary {
- vertical-align: top;
- margin-bottom: 1em;
-}
-
-div#cgit table#downloads {
- float: right;
- border-collapse: collapse;
- border: solid 1px #777;
- margin-left: 0.5em;
- margin-bottom: 0.5em;
-}
-
-div#cgit table#downloads th {
- background-color: #ccc;
+ padding: 0em;
+ margin: 0.5em;
}
-div#cgit div#blob {
- border: solid 1px black;
-}
-div#cgit div.error {
- color: red;
+h2 {
+ font-size: normal;
font-weight: bold;
- margin: 1em 2em;
-}
-
-div#cgit a.ls-blob, div#cgit a.ls-dir, div#cgit .ls-mod {
- font-family: monospace;
-}
-
-div#cgit td.ls-size {
- text-align: right;
- font-family: monospace;
- width: 10em;
-}
-
-div#cgit td.ls-mode {
- font-family: monospace;
- width: 10em;
-}
-
-div#cgit table.blob {
- margin-top: 0.5em;
- border-top: solid 1px black;
-}
-
-div#cgit table.blob td.hashes,
-div#cgit table.blob td.lines {
- margin: 0; padding: 0 0 0 0.5em;
- vertical-align: top;
- color: black;
-}
-
-div#cgit table.blob td.linenumbers {
- margin: 0; padding: 0 0.5em 0 0.5em;
- vertical-align: top;
- text-align: right;
- border-right: 1px solid gray;
-}
-
-div#cgit table.blob pre {
- padding: 0; margin: 0;
-}
-
-div#cgit table.blob td.linenumbers a,
-div#cgit table.ssdiff td.lineno a {
- color: gray;
- text-align: right;
- text-decoration: none;
-}
-
-div#cgit table.blob td.linenumbers a:hover,
-div#cgit table.ssdiff td.lineno a:hover {
- color: black;
-}
-
-div#cgit table.blob td.linenumbers a:target:before {
- color: red;
- content: "\2BA9";
-}
-
-div#cgit table.blame td.hashes,
-div#cgit table.blame td.lines,
-div#cgit table.blame td.linenumbers {
- padding: 0;
+ margin-bottom: 0.1em;
}
-div#cgit table.blame td.hashes div.alt,
-div#cgit table.blame td.lines div.alt {
- padding: 0 0.5em 0 0.5em;
-}
-
-div#cgit table.blame td.linenumbers div.alt {
- padding: 0 0.5em 0 0;
-}
-div#cgit table.blame div.alt:nth-child(even) {
- background: #eee;
-}
-
-div#cgit table.blame div.alt:nth-child(odd) {
- background: white;
-}
-
-div#cgit table.blame td.lines > div {
- position: relative;
-}
-
-div#cgit table.blame td.lines > div > pre {
- padding: 0 0 0 0.5em;
- position: absolute;
- top: 0;
-}
-
-div#cgit table.blame .oid {
- font-size: 100%;
-}
-
-div#cgit table.bin-blob {
- margin-top: 0.5em;
+table.list {
border: solid 1px black;
-}
-
-div#cgit table.bin-blob th {
- font-family: monospace;
- white-space: pre;
- border: solid 1px #777;
- padding: 0.5em 1em;
-}
-
-div#cgit table.bin-blob td {
- font-family: monospace;
- white-space: pre;
- border-left: solid 1px #777;
- padding: 0em 1em;
-}
-
-div#cgit table.nowrap td {
- white-space: nowrap;
-}
-
-div#cgit table.commit-info {
- border-collapse: collapse;
- margin-top: 1.5em;
-}
-
-div#cgit div.cgit-panel {
- float: right;
- margin-top: 1.5em;
-}
-
-div#cgit div.cgit-panel table {
border-collapse: collapse;
border: solid 1px #aaa;
- background-color: #eee;
-}
-
-div#cgit div.cgit-panel th {
- text-align: center;
-}
-
-div#cgit div.cgit-panel td {
- padding: 0.25em 0.5em;
-}
-
-div#cgit div.cgit-panel td.label {
- padding-right: 0.5em;
-}
-
-div#cgit div.cgit-panel td.ctrl {
- padding-left: 0.5em;
}
-div#cgit table.commit-info th {
+table.list th {
text-align: left;
- font-weight: normal;
- padding: 0.1em 1em 0.1em 0.1em;
- vertical-align: top;
-}
-
-div#cgit table.commit-info td {
- font-weight: normal;
- padding: 0.1em 1em 0.1em 0.1em;
-}
-
-div#cgit div.commit-subject {
font-weight: bold;
- font-size: 125%;
- margin: 1.5em 0em 0.5em 0em;
- padding: 0em;
-}
-
-div#cgit div.commit-msg {
- white-space: pre;
- font-family: monospace;
-}
-
-div#cgit div.notes-header {
- font-weight: bold;
- padding-top: 1.5em;
-}
-
-div#cgit div.notes {
- white-space: pre;
- font-family: monospace;
- border: solid 1px #ee9;
- background-color: #ffd;
- padding: 0.3em 2em 0.3em 1em;
- float: left;
-}
-
-div#cgit div.notes-footer {
- clear: left;
-}
-
-div#cgit div.diffstat-header {
- font-weight: bold;
- padding-top: 1.5em;
-}
-
-div#cgit table.diffstat {
- border-collapse: collapse;
- border: solid 1px #aaa;
- background-color: #eee;
-}
-
-div#cgit table.diffstat th {
- font-weight: normal;
- text-align: left;
- text-decoration: underline;
- padding: 0.1em 1em 0.1em 0.1em;
- font-size: 100%;
+ background: #ddd;
+ border-bottom: solid 1px #aaa;
+ padding: 0.1em 0.5em 0.1em;
+ vertical-align: baseline;
}
-
-div#cgit table.diffstat td {
- padding: 0.2em 0.2em 0.1em 0.1em;
- font-size: 100%;
+table.list td {
border: none;
+ padding: 0.1em 0.5em;
+ background: white;
}
-div#cgit table.diffstat td.mode {
- white-space: nowrap;
-}
-
-div#cgit table.diffstat td span.modechange {
- padding-left: 1em;
- color: red;
-}
-
-div#cgit table.diffstat td.add a {
- color: green;
-}
-
-div#cgit table.diffstat td.del a {
- color: red;
-}
-
-div#cgit table.diffstat td.upd a {
- color: blue;
-}
-
-div#cgit table.diffstat td.graph {
- width: 500px;
- vertical-align: middle;
-}
-
-div#cgit table.diffstat td.graph table {
+img {
border: none;
}
-div#cgit table.diffstat td.graph td {
- padding: 0px;
- border: 0px;
- height: 7pt;
-}
-
-div#cgit table.diffstat td.graph td.add {
- background-color: #5c5;
-}
-
-div#cgit table.diffstat td.graph td.rem {
- background-color: #c55;
-}
-
-div#cgit div.diffstat-summary {
- color: #888;
- padding-top: 0.5em;
-}
-
-div#cgit table.diff {
- width: 100%;
-}
-
-div#cgit table.diff td {
- font-family: monospace;
- white-space: pre;
-}
-
-div#cgit table.diff td div.head {
- font-weight: bold;
- margin-top: 1em;
- color: black;
-}
-
-div#cgit table.diff td div.hunk {
- color: #009;
-}
-
-div#cgit table.diff td div.add {
- color: green;
-}
-
-div#cgit table.diff td div.del {
- color: red;
-}
-
-div#cgit .oid {
- font-family: monospace;
- font-size: 90%;
-}
-
-div#cgit .left {
- text-align: left;
-}
-
-div#cgit .right {
- text-align: right;
-}
-
-div#cgit table.list td.reposection {
- font-style: italic;
- color: #888;
-}
-
-div#cgit a.button {
- font-size: 80%;
- padding: 0em 0.5em;
-}
-
-div#cgit a.primary {
- font-size: 100%;
-}
-
-div#cgit a.secondary {
- font-size: 90%;
-}
-
-div#cgit td.toplevel-repo {
-
-}
-
-div#cgit table.list td.sublevel-repo {
- padding-left: 1.5em;
-}
-
-div#cgit ul.pager {
- list-style-type: none;
- text-align: center;
- margin: 1em 0em 0em 0em;
- padding: 0;
-}
-
-div#cgit ul.pager li {
- display: inline-block;
- margin: 0.25em 0.5em;
-}
-
-div#cgit ul.pager a {
- color: #777;
-}
-
-div#cgit ul.pager .current {
- font-weight: bold;
-}
-
-div#cgit span.age-mins {
- font-weight: bold;
- color: #080;
-}
-
-div#cgit span.age-hours {
- color: #080;
-}
-
-div#cgit span.age-days {
- color: #040;
-}
-
-div#cgit span.age-weeks {
- color: #444;
-}
-
-div#cgit span.age-months {
- color: #888;
-}
-
-div#cgit span.age-years {
- color: #bbb;
-}
-
-div#cgit span.insertions {
- color: #080;
-}
-
-div#cgit span.deletions {
- color: #800;
-}
-
-div#cgit div.footer {
- margin-top: 0.5em;
- text-align: center;
- font-size: 80%;
- color: #ccc;
-}
-
-div#cgit div.footer a {
- color: #ccc;
- text-decoration: none;
-}
-
-div#cgit div.footer a:hover {
- text-decoration: underline;
-}
-
-div#cgit a.branch-deco {
- color: #000;
- margin: 0px 0.5em;
- padding: 0px 0.25em;
- background-color: #88ff88;
- border: solid 1px #007700;
- border-radius: 2px;
-}
-
-div#cgit a.tag-deco {
- color: #000;
- margin: 0px 0.5em;
- padding: 0px 0.25em;
- background-color: #ffff88;
- border: solid 1px #777700;
- border-radius: 2px;
-}
-
-div#cgit a.tag-annotated-deco {
- color: #000;
- margin: 0px 0.5em;
- padding: 0px 0.25em;
- background-color: #ffcc88;
- border: solid 1px #777700;
- border-radius: 2px;
-}
-
-div#cgit a.remote-deco {
- color: #000;
- margin: 0px 0.5em;
- padding: 0px 0.25em;
- background-color: #ccccff;
- border: solid 1px #000077;
- border-radius: 2px;
-}
-
-div#cgit a.deco {
- color: #000;
- margin: 0px 0.5em;
- padding: 0px 0.25em;
- background-color: #ff8888;
- border: solid 1px #770000;
- border-radius: 2px;
-}
-
-div#cgit div.commit-subject a.branch-deco,
-div#cgit div.commit-subject a.tag-deco,
-div#cgit div.commit-subject a.tag-annotated-deco,
-div#cgit div.commit-subject a.remote-deco,
-div#cgit div.commit-subject a.deco {
- margin-left: 1em;
- font-size: 75%;
-}
-
-div#cgit table.stats {
- border: solid 1px black;
- border-collapse: collapse;
-}
-
-div#cgit table.stats th {
- text-align: left;
- padding: 1px 0.5em;
- background-color: #eee;
- border: solid 1px black;
-}
-
-div#cgit table.stats td {
- text-align: right;
- padding: 1px 0.5em;
- border: solid 1px black;
-}
-
-div#cgit table.stats td.total {
- font-weight: bold;
- text-align: left;
-}
-
-div#cgit table.stats td.sum {
- color: #c00;
- font-weight: bold;
-/* background-color: #eee; */
-}
-
-div#cgit table.stats td.left {
- text-align: left;
-}
-
-div#cgit table.vgraph {
- border-collapse: separate;
- border: solid 1px black;
- height: 200px;
-}
-
-div#cgit table.vgraph th {
- background-color: #eee;
- font-weight: bold;
- border: solid 1px white;
- padding: 1px 0.5em;
-}
-
-div#cgit table.vgraph td {
- vertical-align: bottom;
- padding: 0px 10px;
-}
-
-div#cgit table.vgraph div.bar {
- background-color: #eee;
-}
-div#cgit table.hgraph {
- border: solid 1px black;
- width: 800px;
-}
-
-div#cgit table.hgraph th {
- background-color: #eee;
+div#header {
+ background-color: #ddd;
+ padding: 0.25em 0.25em 0.25em 0.5em;
+ font-size: 150%;
font-weight: bold;
- border: solid 1px black;
- padding: 1px 0.5em;
-}
-
-div#cgit table.hgraph td {
+ border: solid 1px #aaa;
vertical-align: middle;
- padding: 2px 2px;
-}
-
-div#cgit table.hgraph div.bar {
- background-color: #eee;
- height: 1em;
-}
-
-div#cgit table.ssdiff {
- width: 100%;
-}
-
-div#cgit table.ssdiff td {
- font-size: 75%;
- font-family: monospace;
- white-space: pre;
- padding: 1px 4px 1px 4px;
- border-left: solid 1px #aaa;
- border-right: solid 1px #aaa;
-}
-
-div#cgit table.ssdiff td.add {
- color: black;
- background: #cfc;
- min-width: 50%;
-}
-
-div#cgit table.ssdiff td.add_dark {
- color: black;
- background: #aca;
- min-width: 50%;
-}
-
-div#cgit table.ssdiff span.add {
- background: #cfc;
- font-weight: bold;
-}
-
-div#cgit table.ssdiff td.del {
- color: black;
- background: #fcc;
- min-width: 50%;
}
-div#cgit table.ssdiff td.del_dark {
- color: black;
- background: #caa;
- min-width: 50%;
-}
-
-div#cgit table.ssdiff span.del {
- background: #fcc;
- font-weight: bold;
-}
-
-div#cgit table.ssdiff td.changed {
- color: black;
- background: #ffc;
- min-width: 50%;
-}
-
-div#cgit table.ssdiff td.changed_dark {
- color: black;
- background: #cca;
- min-width: 50%;
-}
-
-div#cgit table.ssdiff td.lineno {
- color: black;
- background: #eee;
- text-align: right;
- width: 3em;
- min-width: 3em;
-}
-
-div#cgit table.ssdiff td.hunk {
- color: black;
- background: #ccf;
- border-top: solid 1px #aaa;
- border-bottom: solid 1px #aaa;
+div#header img#logo {
+ float: right;
}
-div#cgit table.ssdiff td.head {
- border-top: solid 1px #aaa;
- border-bottom: solid 1px #aaa;
+div#content {
+ margin: 0.5em 0.5em;
}
-div#cgit table.ssdiff td.head div.head {
+div.error {
+ color: red;
font-weight: bold;
- color: black;
-}
-
-div#cgit table.ssdiff td.foot {
- border-top: solid 1px #aaa;
- border-left: none;
- border-right: none;
- border-bottom: none;
-}
-
-div#cgit table.ssdiff td.space {
- border: none;
-}
-
-div#cgit table.ssdiff td.space div {
- min-height: 3em;
-}
+ margin: 1em 2em;
+} \ No newline at end of file
diff --git a/cgit.h b/cgit.h
index 7d7ece7..19f7ba7 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,404 +1,21 @@
#ifndef CGIT_H
#define CGIT_H
-#include <stdbool.h>
+#include "git.h"
+#include <openssl/sha.h>
-#include <git-compat-util.h>
-
-#include <archive.h>
-#include <commit.h>
-#include <diffcore.h>
-#include <diff.h>
-#include <environment.h>
-#include <graph.h>
-#include <grep.h>
-#include <hex.h>
-#include <log-tree.h>
-#include <notes.h>
-#include <object.h>
-#include <object-name.h>
-#include <odb.h>
-#include <path.h>
-#include <refs.h>
-#include <revision.h>
-#include <setup.h>
-#include <string-list.h>
-#include <strvec.h>
-#include <tag.h>
-#include <tree.h>
-#include <utf8.h>
-#include <wrapper.h>
-#include <xdiff-interface.h>
-#include <xdiff/xdiff.h>
-
-/* Add isgraph(x) to Git's sane ctype support (see git-compat-util.h) */
-#undef isgraph
-#define isgraph(x) (isprint((x)) && !isspace((x)))
-
-
-/*
- * Limits used for relative dates
- */
-#define TM_MIN 60
-#define TM_HOUR (TM_MIN * 60)
-#define TM_DAY (TM_HOUR * 24)
-#define TM_WEEK (TM_DAY * 7)
-#define TM_YEAR (TM_DAY * 365)
-#define TM_MONTH (TM_YEAR / 12.0)
-
-
-/*
- * Default encoding
- */
-#define PAGE_ENCODING "UTF-8"
-
-#define BIT(x) (1U << (x))
-
-typedef void (*configfn)(const char *name, const char *value);
-typedef void (*filepair_fn)(struct diff_filepair *pair);
-typedef void (*linediff_fn)(char *line, int len);
-
-typedef enum {
- DIFF_UNIFIED, DIFF_SSDIFF, DIFF_STATONLY
-} diff_type;
-
-typedef enum {
- ABOUT, COMMIT, SOURCE, EMAIL, AUTH, OWNER
-} filter_type;
-
-struct cgit_filter {
- int (*open)(struct cgit_filter *, va_list ap);
- int (*close)(struct cgit_filter *);
- void (*fprintfp)(struct cgit_filter *, FILE *, const char *prefix);
- void (*cleanup)(struct cgit_filter *);
- int argument_count;
-};
-
-struct cgit_exec_filter {
- struct cgit_filter base;
- char *cmd;
- char **argv;
- int old_stdout;
- int pid;
-};
-
-struct cgit_repo {
- char *url;
- char *name;
- char *path;
- char *desc;
- char *extra_head_content;
- char *owner;
- char *homepage;
- char *defbranch;
- char *module_link;
- struct string_list readme;
- char *section;
- char *clone_url;
- char *logo;
- char *logo_link;
- char *snapshot_prefix;
- int snapshots;
- int enable_blame;
- int enable_commit_graph;
- int enable_follow_links;
- int enable_log_filecount;
- int enable_log_linecount;
- int enable_remote_branches;
- int enable_subject_links;
- int enable_html_serving;
- int max_stats;
- int branch_sort;
- int commit_sort;
- time_t mtime;
- struct cgit_filter *about_filter;
- struct cgit_filter *commit_filter;
- struct cgit_filter *source_filter;
- struct cgit_filter *email_filter;
- struct cgit_filter *owner_filter;
- struct string_list submodules;
- int hide;
- int ignore;
-};
-
-struct cgit_repolist {
- int length;
- int count;
- struct cgit_repo *repos;
-};
-
-struct commitinfo {
- struct commit *commit;
- char *author;
- char *author_email;
- unsigned long author_date;
- int author_tz;
- char *committer;
- char *committer_email;
- unsigned long committer_date;
- int committer_tz;
- char *subject;
- char *msg;
- char *msg_encoding;
-};
-
-struct taginfo {
- char *tagger;
- char *tagger_email;
- unsigned long tagger_date;
- int tagger_tz;
- char *msg;
-};
-
-struct refinfo {
- const char *refname;
- struct object *object;
- union {
- struct taginfo *tag;
- struct commitinfo *commit;
- };
-};
-
-struct reflist {
- struct refinfo **refs;
- int alloc;
- int count;
-};
-
-struct cgit_query {
- int has_symref;
- int has_oid;
- int has_difftype;
- char *raw;
- char *repo;
- char *page;
- char *search;
- char *grep;
- char *head;
- char *oid;
- char *oid2;
- char *path;
- char *name;
- char *url;
- char *period;
- int ofs;
- int nohead;
- char *sort;
- int showmsg;
- diff_type difftype;
- int show_all;
- int context;
- int ignorews;
- int follow;
- char *vpath;
-};
-
-struct cgit_config {
- char *agefile;
- char *cache_root;
- char *clone_prefix;
- char *clone_url;
- char *favicon;
- char *footer;
- char *head_include;
- char *header;
- char *logo;
- char *logo_link;
- char *mimetype_file;
- char *module_link;
- char *project_list;
- struct string_list readme;
- struct string_list css;
- char *robots;
- char *root_title;
- char *root_desc;
- char *root_readme;
- char *script_name;
- char *section;
- char *repository_sort;
- char *virtual_root; /* Always ends with '/'. */
- char *strict_export;
- int cache_size;
- int cache_dynamic_ttl;
- int cache_max_create_time;
- int cache_repo_ttl;
- int cache_root_ttl;
- int cache_scanrc_ttl;
- int cache_static_ttl;
- int cache_about_ttl;
- int cache_snapshot_ttl;
- int case_sensitive_sort;
- int embedded;
- int enable_filter_overrides;
- int enable_follow_links;
- int enable_http_clone;
- int enable_index_links;
- int enable_index_owner;
- int enable_blame;
- int enable_commit_graph;
- int enable_log_filecount;
- int enable_log_linecount;
- int enable_remote_branches;
- int enable_subject_links;
- int enable_html_serving;
- int enable_tree_linenumbers;
- int enable_git_config;
- int local_time;
- int max_atom_items;
- int max_repo_count;
- int max_commit_count;
- int max_lock_attempts;
- int max_msg_len;
- int max_repodesc_len;
- int max_blob_size;
- int max_stats;
- int noplainemail;
- int noheader;
- int renamelimit;
- int remove_suffix;
- int scan_hidden_path;
- int section_from_path;
- int snapshots;
- int section_sort;
- int summary_branches;
- int summary_log;
- int summary_tags;
- diff_type difftype;
- int branch_sort;
- int commit_sort;
- struct string_list mimetypes;
- struct string_list js;
- struct cgit_filter *about_filter;
- struct cgit_filter *commit_filter;
- struct cgit_filter *source_filter;
- struct cgit_filter *email_filter;
- struct cgit_filter *owner_filter;
- struct cgit_filter *auth_filter;
-};
-
-struct cgit_page {
- time_t modified;
- time_t expires;
- size_t size;
- const char *mimetype;
- const char *charset;
- const char *filename;
- const char *etag;
- const char *title;
- int status;
- const char *statusmsg;
-};
-
-struct cgit_environment {
- const char *cgit_config;
- const char *http_host;
- const char *https;
- const char *no_http;
- const char *path_info;
- const char *query_string;
- const char *request_method;
- const char *script_name;
- const char *server_name;
- const char *server_port;
- const char *http_cookie;
- const char *http_referer;
- unsigned int content_length;
- int authenticated;
-};
-
-struct cgit_context {
- struct cgit_environment env;
- struct cgit_query qry;
- struct cgit_config cfg;
- struct cgit_repo *repo;
- struct cgit_page page;
-};
-
-typedef int (*write_archive_fn_t)(const char *, const char *);
-
-struct cgit_snapshot_format {
- const char *suffix;
- const char *mimetype;
- write_archive_fn_t write_func;
-};
-
-extern const char *cgit_version;
-
-extern struct cgit_repolist cgit_repolist;
-extern struct cgit_context ctx;
-extern const struct cgit_snapshot_format cgit_snapshot_formats[];
-
-extern char *cgit_default_repo_desc;
-extern struct cgit_repo *cgit_add_repo(const char *url);
-extern struct cgit_repo *cgit_get_repoinfo(const char *url);
-extern void cgit_repo_config(struct cgit_repo *repo, const char *name,
- const char *value);
-
-extern int chk_zero(int result, char *msg);
-extern int chk_positive(int result, char *msg);
-extern int chk_non_negative(int result, char *msg);
-
-extern char *trim_end(const char *str, char c);
-extern char *ensure_end(const char *str, char c);
-
-extern void strbuf_ensure_end(struct strbuf *sb, char c);
-
-extern void cgit_add_ref(struct reflist *list, struct refinfo *ref);
-extern void cgit_free_reflist_inner(struct reflist *list);
-extern int cgit_refs_cb(const struct reference *ref, void *cb_data);
-
-extern void cgit_free_commitinfo(struct commitinfo *info);
-extern void cgit_free_taginfo(struct taginfo *info);
-
-void cgit_diff_tree_cb(struct diff_queue_struct *q,
- struct diff_options *options, void *data);
-
-extern int cgit_diff_files(const struct object_id *old_oid,
- const struct object_id *new_oid,
- unsigned long *old_size, unsigned long *new_size,
- int *binary, int context, int ignorews,
- linediff_fn fn);
-
-extern void cgit_diff_tree(const struct object_id *old_oid,
- const struct object_id *new_oid,
- filepair_fn fn, const char *prefix, int ignorews);
-
-extern void cgit_diff_commit(struct commit *commit, filepair_fn fn,
- const char *prefix);
-
-__attribute__((format (printf,1,2)))
extern char *fmt(const char *format,...);
-__attribute__((format (printf,1,2)))
-extern char *fmtalloc(const char *format,...);
-
-extern struct commitinfo *cgit_parse_commit(struct commit *commit);
-extern struct taginfo *cgit_parse_tag(struct tag *tag);
-extern void cgit_parse_url(const char *url);
-
-extern const char *cgit_repobasename(const char *reponame);
+extern void html(const char *txt);
+extern void htmlf(const char *format,...);
+extern void html_txt(char *txt);
+extern void html_attr(char *txt);
-extern int cgit_parse_snapshots_mask(const char *str);
-extern const struct object_id *cgit_snapshot_get_sig(const char *ref,
- const struct cgit_snapshot_format *f);
-extern const unsigned cgit_snapshot_format_bit(const struct cgit_snapshot_format *f);
+extern void html_link_open(char *url, char *title, char *class);
+extern void html_link_close(void);
-extern int cgit_open_filter(struct cgit_filter *filter, ...);
-extern int cgit_close_filter(struct cgit_filter *filter);
-extern void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char *prefix);
-extern void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv);
-extern struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype);
-extern void cgit_cleanup_filters(void);
-extern void cgit_init_filters(void);
-
-extern void cgit_prepare_repo_env(struct cgit_repo * repo);
-
-extern int read_first_line(const char *path, char **buf, size_t *size);
-
-extern char *strdup_first_line(const char *txt);
-
-extern char *expand_macros(const char *txt);
+typedef void (*configfn)(const char *name, const char *value);
-extern char *get_mimetype_for_filename(const char *filename);
+extern int cgit_read_config(const char *filename, configfn fn);
#endif /* CGIT_H */
diff --git a/cgit.js b/cgit.js
deleted file mode 100644
index df3ad4e..0000000
--- a/cgit.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/* cgit.js: javacript functions for cgit
- *
- * Copyright (C) 2006-2018 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-(function () {
-
-/* This follows the logic and suffixes used in ui-shared.c */
-
-var age_classes = [ "age-mins", "age-hours", "age-days", "age-weeks", "age-months", "age-years" ];
-var age_suffix = [ "min.", "hours", "days", "weeks", "months", "years", "years" ];
-var age_next = [ 60, 3600, 24 * 3600, 7 * 24 * 3600, 30 * 24 * 3600, 365 * 24 * 3600, 365 * 24 * 3600 ];
-var age_limit = [ 7200, 24 * 7200, 7 * 24 * 7200, 30 * 24 * 7200, 365 * 25 * 7200, 365 * 25 * 7200 ];
-var update_next = [ 10, 5 * 60, 1800, 24 * 3600, 24 * 3600, 24 * 3600, 24 * 3600 ];
-
-function render_age(e, age) {
- var t, n;
-
- for (n = 0; n < age_classes.length; n++)
- if (age < age_limit[n])
- break;
-
- t = Math.round(age / age_next[n]) + " " + age_suffix[n];
-
- if (e.textContent != t) {
- e.textContent = t;
- if (n == age_classes.length)
- n--;
- if (e.className != age_classes[n])
- e.className = age_classes[n];
- }
-}
-
-function aging() {
- var n, next = 24 * 3600,
- now_ut = Math.round((new Date().getTime() / 1000));
-
- for (n = 0; n < age_classes.length; n++) {
- var m, elems = document.getElementsByClassName(age_classes[n]);
-
- if (elems.length && update_next[n] < next)
- next = update_next[n];
-
- for (m = 0; m < elems.length; m++) {
- var age = now_ut - elems[m].getAttribute("data-ut");
-
- render_age(elems[m], age);
- }
- }
-
- /*
- * We only need to come back when the age might have changed.
- * Eg, if everything is counted in hours already, once per
- * 5 minutes is accurate enough.
- */
-
- window.setTimeout(aging, next * 1000);
-}
-
-document.addEventListener("DOMContentLoaded", function() {
- /* we can do the aging on DOM content load since no layout dependency */
- aging();
-}, false);
-
-})();
diff --git a/cgit.mk b/cgit.mk
deleted file mode 100644
index 3fcc1ca..0000000
--- a/cgit.mk
+++ /dev/null
@@ -1,141 +0,0 @@
-# This Makefile is run in the "git" directory in order to re-use Git's
-# build variables and operating system detection. Hence all files in
-# CGit's directory must be prefixed with "../".
-include Makefile
-
-CGIT_PREFIX = ../
-
--include $(CGIT_PREFIX)cgit.conf
-
-# The CGIT_* variables are inherited when this file is called from the
-# main Makefile - they are defined there.
-
-$(CGIT_PREFIX)VERSION: force-version
- @cd $(CGIT_PREFIX) && '$(SHELL_PATH_SQ)' ./gen-version.sh "$(CGIT_VERSION)"
--include $(CGIT_PREFIX)VERSION
-.PHONY: force-version
-
-# CGIT_CFLAGS is a separate variable so that we can track it separately
-# and avoid rebuilding all of Git when these variables change.
-CGIT_CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"'
-CGIT_CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"'
-CGIT_CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"'
-
-PKG_CONFIG ?= pkg-config
-
-ifdef NO_C99_FORMAT
- CFLAGS += -DNO_C99_FORMAT
-endif
-
-ifdef NO_LUA
- LUA_MESSAGE := linking without specified Lua support
- CGIT_CFLAGS += -DNO_LUA
-else
-ifeq ($(LUA_PKGCONFIG),)
- LUA_PKGCONFIG := $(shell for pc in luajit lua lua5.2 lua5.1; do \
- $(PKG_CONFIG) --exists $$pc 2>/dev/null && echo $$pc && break; \
- done)
- LUA_MODE := autodetected
-else
- LUA_MODE := specified
-endif
-ifneq ($(LUA_PKGCONFIG),)
- LUA_MESSAGE := linking with $(LUA_MODE) $(LUA_PKGCONFIG)
- LUA_LIBS := $(shell $(PKG_CONFIG) --libs $(LUA_PKGCONFIG) 2>/dev/null)
- LUA_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(LUA_PKGCONFIG) 2>/dev/null)
- CGIT_LIBS += $(LUA_LIBS)
- CGIT_CFLAGS += $(LUA_CFLAGS)
-else
- LUA_MESSAGE := linking without autodetected Lua support
- NO_LUA := YesPlease
- CGIT_CFLAGS += -DNO_LUA
-endif
-
-endif
-
-# Add -ldl to linker flags on systems that commonly use GNU libc.
-ifneq (,$(filter $(uname_S),Linux GNU GNU/kFreeBSD))
- CGIT_LIBS += -ldl
-endif
-
-# glibc 2.1+ offers sendfile which the most common C library on Linux
-ifeq ($(uname_S),Linux)
- HAVE_LINUX_SENDFILE = YesPlease
-endif
-
-ifdef HAVE_LINUX_SENDFILE
- CGIT_CFLAGS += -DHAVE_LINUX_SENDFILE
-endif
-
-CGIT_OBJ_NAMES += cgit.o
-CGIT_OBJ_NAMES += cache.o
-CGIT_OBJ_NAMES += cmd.o
-CGIT_OBJ_NAMES += configfile.o
-CGIT_OBJ_NAMES += filter.o
-CGIT_OBJ_NAMES += html.o
-CGIT_OBJ_NAMES += parsing.o
-CGIT_OBJ_NAMES += scan-tree.o
-CGIT_OBJ_NAMES += shared.o
-CGIT_OBJ_NAMES += ui-atom.o
-CGIT_OBJ_NAMES += ui-blame.o
-CGIT_OBJ_NAMES += ui-blob.o
-CGIT_OBJ_NAMES += ui-clone.o
-CGIT_OBJ_NAMES += ui-commit.o
-CGIT_OBJ_NAMES += ui-diff.o
-CGIT_OBJ_NAMES += ui-log.o
-CGIT_OBJ_NAMES += ui-patch.o
-CGIT_OBJ_NAMES += ui-plain.o
-CGIT_OBJ_NAMES += ui-refs.o
-CGIT_OBJ_NAMES += ui-repolist.o
-CGIT_OBJ_NAMES += ui-shared.o
-CGIT_OBJ_NAMES += ui-snapshot.o
-CGIT_OBJ_NAMES += ui-ssdiff.o
-CGIT_OBJ_NAMES += ui-stats.o
-CGIT_OBJ_NAMES += ui-summary.o
-CGIT_OBJ_NAMES += ui-tag.o
-CGIT_OBJ_NAMES += ui-tree.o
-
-CGIT_OBJS := $(addprefix $(CGIT_PREFIX),$(CGIT_OBJ_NAMES))
-
-# Only cgit.c reference CGIT_VERSION so we only rebuild its objects when the
-# version changes.
-CGIT_VERSION_OBJS := $(addprefix $(CGIT_PREFIX),cgit.o cgit.sp)
-$(CGIT_VERSION_OBJS): $(CGIT_PREFIX)VERSION
-$(CGIT_VERSION_OBJS): EXTRA_CPPFLAGS = \
- -DCGIT_VERSION='"$(CGIT_VERSION)"'
-
-# Git handles dependencies using ":=" so dependencies in CGIT_OBJ are not
-# handled by that and we must handle them ourselves.
-cgit_dep_files := $(foreach f,$(CGIT_OBJS),$(dir $f).depend/$(notdir $f).d)
-cgit_dep_files_present := $(wildcard $(cgit_dep_files))
-ifneq ($(cgit_dep_files_present),)
-include $(cgit_dep_files_present)
-endif
-
-ifeq ($(wildcard $(CGIT_PREFIX).depend),)
-missing_dep_dirs += $(CGIT_PREFIX).depend
-endif
-
-$(CGIT_PREFIX).depend:
- @mkdir -p $@
-
-$(CGIT_PREFIX)CGIT-CFLAGS: FORCE
- @FLAGS='$(subst ','\'',$(CGIT_CFLAGS))'; \
- if test x"$$FLAGS" != x"`cat ../CGIT-CFLAGS 2>/dev/null`" ; then \
- echo 1>&2 " * new CGit build flags"; \
- echo "$$FLAGS" >$(CGIT_PREFIX)CGIT-CFLAGS; \
- fi
-
-$(CGIT_OBJS): %.o: %.c GIT-CFLAGS $(CGIT_PREFIX)CGIT-CFLAGS $(missing_dep_dirs)
- $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $(CGIT_CFLAGS) $<
-
-$(CGIT_PREFIX)cgit: $(CGIT_OBJS) GIT-LDFLAGS $(GITLIBS)
- @echo 1>&1 " * $(LUA_MESSAGE)"
- $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(CGIT_LIBS)
-
-CGIT_SP_OBJS := $(patsubst %.o,%.sp,$(CGIT_OBJS))
-
-$(CGIT_SP_OBJS): %.sp: %.c GIT-CFLAGS $(CGIT_PREFIX)CGIT-CFLAGS FORCE
- $(QUIET_SP)cgcc -no-compile $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $(CGIT_CFLAGS) $(SPARSE_FLAGS) $<
-
-cgit-sparse: $(CGIT_SP_OBJS)
diff --git a/cgit.png b/cgit.png
deleted file mode 100644
index 425528e..0000000
--- a/cgit.png
+++ /dev/null
Binary files differ
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
deleted file mode 100644
index 7c39bf9..0000000
--- a/cgitrc.5.txt
+++ /dev/null
@@ -1,1022 +0,0 @@
-:man source: cgit
-:man manual: cgit
-
-CGITRC(5)
-========
-
-
-NAME
-----
-cgitrc - runtime configuration for cgit
-
-
-SYNOPSIS
---------
-Cgitrc contains all runtime settings for cgit, including the list of git
-repositories, formatted as a line-separated list of NAME=VALUE pairs. Blank
-lines, and lines starting with '#', are ignored.
-
-
-LOCATION
---------
-The default location of cgitrc, defined at compile time, is /etc/cgitrc. At
-runtime, cgit will consult the environment variable CGIT_CONFIG and, if
-defined, use its value instead.
-
-
-GLOBAL SETTINGS
----------------
-about-filter::
- Specifies a command which will be invoked to format the content of
- about pages (both top-level and for each repository). The command will
- get the content of the about-file on its STDIN, the name of the file
- as the first argument, and the STDOUT from the command will be
- included verbatim on the about page. Default value: none. See
- also: "FILTER API".
-
-agefile::
- Specifies a path, relative to each repository path, which can be used
- to specify the date and time of the youngest commit in the repository.
- The first line in the file is used as input to the "parse_date"
- function in libgit. Recommended timestamp-format is "yyyy-mm-dd
- hh:mm:ss". You may want to generate this file from a post-receive
- hook. Default value: "info/web/last-modified".
-
-auth-filter::
- Specifies a command that will be invoked for authenticating repository
- access. Receives quite a few arguments, and data on both stdin and
- stdout for authentication processing. Details follow later in this
- document. If no auth-filter is specified, no authentication is
- performed. Default value: none. See also: "FILTER API".
-
-branch-sort::
- Flag which, when set to "age", enables date ordering in the branch ref
- list, and when set to "name" enables ordering by branch name. Default
- value: "name".
-
-cache-about-ttl::
- Number which specifies the time-to-live, in minutes, for the cached
- version of the repository about page. See also: "CACHE". Default
- value: "15".
-
-cache-dynamic-ttl::
- Number which specifies the time-to-live, in minutes, for the cached
- version of repository pages accessed without a fixed SHA1. See also:
- "CACHE". Default value: "5".
-
-cache-repo-ttl::
- Number which specifies the time-to-live, in minutes, for the cached
- version of the repository summary page. See also: "CACHE". Default
- value: "5".
-
-cache-root::
- Path used to store the cgit cache entries. Default value:
- "/var/cache/cgit". See also: "MACRO EXPANSION".
-
-cache-root-ttl::
- Number which specifies the time-to-live, in minutes, for the cached
- version of the repository index page. See also: "CACHE". Default
- value: "5".
-
-cache-scanrc-ttl::
- Number which specifies the time-to-live, in minutes, for the result
- of scanning a path for git repositories. See also: "CACHE". Default
- value: "15".
-
-case-sensitive-sort::
- Sort items in the repo list case sensitively. Default value: "1".
- See also: repository-sort, section-sort.
-
-cache-size::
- The maximum number of entries in the cgit cache. When set to "0",
- caching is disabled. See also: "CACHE". Default value: "0"
-
-cache-snapshot-ttl::
- Number which specifies the time-to-live, in minutes, for the cached
- version of snapshots. See also: "CACHE". Default value: "5".
-
-cache-static-ttl::
- Number which specifies the time-to-live, in minutes, for the cached
- version of repository pages accessed with a fixed SHA1. See also:
- "CACHE". Default value: -1".
-
-clone-prefix::
- Space-separated list of common prefixes which, when combined with a
- repository url, generates valid clone urls for the repository. This
- setting is only used if `repo.clone-url` is unspecified. Default value:
- none.
-
-clone-url::
- Space-separated list of clone-url templates. This setting is only
- used if `repo.clone-url` is unspecified. Default value: none. See
- also: "MACRO EXPANSION", "FILTER API".
-
-commit-filter::
- Specifies a command which will be invoked to format commit messages.
- The command will get the message on its STDIN, and the STDOUT from the
- command will be included verbatim as the commit message, i.e. this can
- be used to implement bugtracker integration. Default value: none.
- See also: "FILTER API".
-
-commit-sort::
- Flag which, when set to "date", enables strict date ordering in the
- commit log, and when set to "topo" enables strict topological
- ordering. If unset, the default ordering of "git log" is used. Default
- value: unset.
-
-css::
- Url which specifies the css document to include in all cgit pages.
- Default value: "/cgit.css". May be given multiple times, each
- css URL path is added in the head section of the document in turn.
-
-email-filter::
- Specifies a command which will be invoked to format names and email
- address of committers, authors, and taggers, as represented in various
- places throughout the cgit interface. This command will receive an
- email address and an origin page string as its command line arguments,
- and the text to format on STDIN. It is to write the formatted text back
- out onto STDOUT. Default value: none. See also: "FILTER API".
-
-embedded::
- Flag which, when set to "1", will make cgit generate a html fragment
- suitable for embedding in other html pages. Default value: none. See
- also: "noheader".
-
-enable-blame::
- Flag which, when set to "1", will allow cgit to provide a "blame" page
- for files, and will make it generate links to that page in appropriate
- places. Default value: "0".
-
-enable-commit-graph::
- Flag which, when set to "1", will make cgit print an ASCII-art commit
- history graph to the left of the commit messages in the repository
- log page. Default value: "0".
-
-enable-filter-overrides::
- Flag which, when set to "1", allows all filter settings to be
- overridden in repository-specific cgitrc files. Default value: none.
-
-enable-follow-links::
- Flag which, when set to "1", allows users to follow a file in the log
- view. Default value: "0".
-
-enable-git-config::
- Flag which, when set to "1", will allow cgit to use git config to set
- any repo specific settings. This option is used in conjunction with
- "scan-path", and must be defined prior, to augment repo-specific
- settings. The keys gitweb.owner, gitweb.category, gitweb.description,
- and gitweb.homepage will map to the cgit keys repo.owner, repo.section,
- repo.desc, and repo.homepage respectively. All git config keys that begin
- with "cgit." will be mapped to the corresponding "repo." key in cgit.
- Default value: "0". See also: scan-path, section-from-path.
-
-enable-http-clone::
- If set to "1", cgit will act as a dumb HTTP endpoint for git clones.
- You can add "http://$HTTP_HOST$SCRIPT_NAME/$CGIT_REPO_URL" to clone-url
- to expose this feature. If you use an alternate way of serving git
- repositories, you may wish to disable this. Default value: "1".
-
-enable-html-serving::
- Flag which, when set to "1", will allow the /plain handler to serve
- mimetype headers that result in the file being treated as HTML by the
- browser. When set to "0", such file types are returned instead as
- text/plain or application/octet-stream. Default value: "0". See also:
- "repo.enable-html-serving".
-
-enable-index-links::
- Flag which, when set to "1", will make cgit generate extra links for
- each repo in the repository index (specifically, to the "summary",
- "commit" and "tree" pages). Default value: "0".
-
-enable-index-owner::
- Flag which, when set to "1", will make cgit display the owner of
- each repo in the repository index. Default value: "1".
-
-enable-log-filecount::
- Flag which, when set to "1", will make cgit print the number of
- modified files for each commit on the repository log page. Default
- value: "0".
-
-enable-log-linecount::
- Flag which, when set to "1", will make cgit print the number of added
- and removed lines for each commit on the repository log page. Default
- value: "0".
-
-enable-remote-branches::
- Flag which, when set to "1", will make cgit display remote branches
- in the summary and refs views. Default value: "0". See also:
- "repo.enable-remote-branches".
-
-enable-subject-links::
- Flag which, when set to "1", will make cgit use the subject of the
- parent commit as link text when generating links to parent commits
- in commit view. Default value: "0". See also:
- "repo.enable-subject-links".
-
-enable-tree-linenumbers::
- Flag which, when set to "1", will make cgit generate linenumber links
- for plaintext blobs printed in the tree view. Default value: "1".
-
-favicon::
- Url used as link to a shortcut icon for cgit. It is suggested to use
- the value "/favicon.ico" since certain browsers will ignore other
- values. Default value: "/favicon.ico".
-
-footer::
- The content of the file specified with this option will be included
- verbatim at the bottom of all pages (i.e. it replaces the standard
- "generated by..." message. Default value: none.
-
-head-include::
- The content of the file specified with this option will be included
- verbatim in the html HEAD section on all pages. Default value: none.
-
-header::
- The content of the file specified with this option will be included
- verbatim at the top of all pages. Default value: none.
-
-include::
- Name of a configfile to include before the rest of the current config-
- file is parsed. Default value: none. See also: "MACRO EXPANSION".
-
-js::
- Url which specifies the javascript script document to include in all cgit
- pages. Default value: "/cgit.js". Setting this to an empty string will
- disable generation of the link to this file in the head section.
-
-local-time::
- Flag which, if set to "1", makes cgit print commit and tag times in the
- servers timezone. Default value: "0".
-
-logo::
- Url which specifies the source of an image which will be used as a logo
- on all cgit pages. Default value: "/cgit.png".
-
-logo-link::
- Url loaded when clicking on the cgit logo image. If unspecified the
- calculated url of the repository index page will be used. Default
- value: none.
-
-max-atom-items::
- Specifies the number of items to display in atom feeds view. Default
- value: "10".
-
-max-blob-size::
- Specifies the maximum size of a blob to display HTML for in KBytes.
- Default value: "0" (limit disabled).
-
-max-commit-count::
- Specifies the number of entries to list per page in "log" view. Default
- value: "50".
-
-max-message-length::
- Specifies the maximum number of commit message characters to display in
- "log" view. Default value: "80".
-
-max-repo-count::
- Specifies the number of entries to list per page on the repository
- index page. The value "0" shows all repositories without limitation.
- Default value: "50".
-
-max-repodesc-length::
- Specifies the maximum number of repo description characters to display
- on the repository index page. Default value: "80".
-
-max-stats::
- Set the default maximum statistics period. Valid values are "week",
- "month", "quarter" and "year". If unspecified, statistics are
- disabled. Default value: none. See also: "repo.max-stats".
-
-mimetype.<ext>::
- Set the mimetype for the specified filename extension. This is used
- by the `plain` command when returning blob content.
-
-mimetype-file::
- Specifies the file to use for automatic mimetype lookup. If specified
- then this field is used as a fallback when no "mimetype.<ext>" match is
- found. If unspecified then no such lookup is performed. The typical file
- to use on a Linux system is /etc/mime.types. The format of the file must
- comply to:
- - a comment line is an empty line or a line starting with a hash (#),
- optionally preceded by whitespace
- - a non-comment line starts with the mimetype (like image/png), followed
- by one or more file extensions (like jpg), all separated by whitespace
- Default value: none. See also: "mimetype.<ext>".
-
-module-link::
- Text which will be used as the formatstring for a hyperlink when a
- submodule is printed in a directory listing. The arguments for the
- formatstring are the path and SHA1 of the submodule commit. Default
- value: none.
-
-noplainemail::
- If set to "1" showing full author email addresses will be disabled.
- Default value: "0".
-
-noheader::
- Flag which, when set to "1", will make cgit omit the standard header
- on all pages. Default value: none. See also: "embedded".
-
-owner-filter::
- Specifies a command which will be invoked to format the Owner
- column of the main page. The command will get the owner on STDIN,
- and the STDOUT from the command will be included verbatim in the
- table. This can be used to link to additional context such as an
- owners home page. When active this filter is used instead of the
- default owner query url. Default value: none.
- See also: "FILTER API".
-
-project-list::
- A list of subdirectories inside of scan-path, relative to it, that
- should loaded as git repositories. This must be defined prior to
- scan-path. Default value: none. See also: scan-path, "MACRO
- EXPANSION".
-
-readme::
- Text which will be used as default value for "repo.readme". Multiple
- config keys may be specified, and cgit will use the first found file
- in this list. This is useful in conjunction with scan-path. Default
- value: none. See also: scan-path, repo.readme.
-
-remove-suffix::
- If set to "1" and scan-path is enabled, if any repositories are found
- with a suffix of ".git", this suffix will be removed for the url and
- name. This must be defined prior to scan-path. Default value: "0".
- See also: scan-path.
-
-renamelimit::
- Maximum number of files to consider when detecting renames. The value
- "-1" uses the compiletime value in git (for further info, look at
- `man git-diff`). Default value: "-1".
-
-repository-sort::
- The way in which repositories in each section are sorted. Valid values
- are "name" for sorting by the repo name or "age" for sorting by the
- most recently updated repository. Default value: "name". See also:
- section, case-sensitive-sort, section-sort.
-
-robots::
- Text used as content for the "robots" meta-tag. Default value:
- "index, nofollow".
-
-root-desc::
- Text printed below the heading on the repository index page. Default
- value: "a fast webinterface for the git dscm".
-
-root-readme::
- The content of the file specified with this option will be included
- verbatim below the "about" link on the repository index page. Default
- value: none.
-
-root-title::
- Text printed as heading on the repository index page. Default value:
- "Git Repository Browser".
-
-scan-hidden-path::
- If set to "1" and scan-path is enabled, scan-path will recurse into
- directories whose name starts with a period ('.'). Otherwise,
- scan-path will stay away from such directories (considered as
- "hidden"). Note that this does not apply to the ".git" directory in
- non-bare repos. This must be defined prior to scan-path.
- Default value: 0. See also: scan-path.
-
-scan-path::
- A path which will be scanned for repositories. If caching is enabled,
- the result will be cached as a cgitrc include-file in the cache
- directory. If project-list has been defined prior to scan-path,
- scan-path loads only the directories listed in the file pointed to by
- project-list. Be advised that only the global settings taken
- before the scan-path directive will be applied to each repository.
- Default value: none. See also: cache-scanrc-ttl, project-list,
- "MACRO EXPANSION".
-
-section::
- The name of the current repository section - all repositories defined
- after this option will inherit the current section name. Default value:
- none.
-
-section-sort::
- Flag which, when set to "1", will sort the sections on the repository
- listing by name. Set this flag to "0" if the order in the cgitrc file should
- be preserved. Default value: "1". See also: section,
- case-sensitive-sort, repository-sort.
-
-section-from-path::
- A number which, if defined prior to scan-path, specifies how many
- path elements from each repo path to use as a default section name.
- If negative, cgit will discard the specified number of path elements
- above the repo directory. Default value: "0".
-
-side-by-side-diffs::
- If set to "1" shows side-by-side diffs instead of unidiffs per
- default. Default value: "0".
-
-snapshots::
- Text which specifies the default set of snapshot formats that cgit
- generates links for. The value is a space-separated list of zero or
- more of the values "tar", "tar.gz", "tar.bz2", "tar.lz", "tar.xz",
- "tar.zst" and "zip". The special value "all" enables all snapshot
- formats. Default value: none.
- All compressors use default settings. Some settings can be influenced
- with environment variables, for example set ZSTD_CLEVEL=10 in web
- server environment for higher (but slower) zstd compression.
-
-source-filter::
- Specifies a command which will be invoked to format plaintext blobs
- in the tree view. The command will get the blob content on its STDIN
- and the name of the blob as its only command line argument. The STDOUT
- from the command will be included verbatim as the blob contents, i.e.
- this can be used to implement e.g. syntax highlighting. Default value:
- none. See also: "FILTER API".
-
-summary-branches::
- Specifies the number of branches to display in the repository "summary"
- view. Default value: "10".
-
-summary-log::
- Specifies the number of log entries to display in the repository
- "summary" view. Default value: "10".
-
-summary-tags::
- Specifies the number of tags to display in the repository "summary"
- view. Default value: "10".
-
-strict-export::
- Filename which, if specified, needs to be present within the repository
- for cgit to allow access to that repository. This can be used to emulate
- gitweb's EXPORT_OK and STRICT_EXPORT functionality and limit cgit's
- repositories to match those exported by git-daemon. This option must
- be defined prior to scan-path.
-
-virtual-root::
- Url which, if specified, will be used as root for all cgit links. It
- will also cause cgit to generate 'virtual urls', i.e. urls like
- '/cgit/tree/README' as opposed to '?r=cgit&p=tree&path=README'. Default
- value: none.
- NOTE: cgit has recently learned how to use PATH_INFO to achieve the
- same kind of virtual urls, so this option will probably be deprecated.
-
-
-REPOSITORY SETTINGS
--------------------
-repo.about-filter::
- Override the default about-filter. Default value: none. See also:
- "enable-filter-overrides". See also: "FILTER API".
-
-repo.branch-sort::
- Flag which, when set to "age", enables date ordering in the branch ref
- list, and when set to "name" enables ordering by branch name. Default
- value: "name".
-
-repo.clone-url::
- A list of space-separated urls which can be used to clone this repo.
- Default value: none. See also: "MACRO EXPANSION".
-
-repo.commit-filter::
- Override the default commit-filter. Default value: none. See also:
- "enable-filter-overrides". See also: "FILTER API".
-
-repo.commit-sort::
- Flag which, when set to "date", enables strict date ordering in the
- commit log, and when set to "topo" enables strict topological
- ordering. If unset, the default ordering of "git log" is used. Default
- value: unset.
-
-repo.defbranch::
- The name of the default branch for this repository. If no such branch
- exists in the repository, the first branch name (when sorted) is used
- as default instead. Default value: branch pointed to by HEAD, or
- "master" if there is no suitable HEAD.
-
-repo.desc::
- The value to show as repository description. Default value: none.
-
-repo.email-filter::
- Override the default email-filter. Default value: none. See also:
- "enable-filter-overrides". See also: "FILTER API".
-
-repo.enable-blame::
- A flag which can be used to disable the global setting
- `enable-blame'. Default value: none.
-
-repo.enable-commit-graph::
- A flag which can be used to disable the global setting
- `enable-commit-graph'. Default value: none.
-
-repo.enable-follow-links::
- A flag which can be used to disable the global setting
- `enable-follow-links'. Default value: none.
-
-repo.enable-html-serving::
- A flag which can be used to override the global setting
- `enable-html-serving`. Default value: none.
-
-repo.enable-log-filecount::
- A flag which can be used to disable the global setting
- `enable-log-filecount'. Default value: none.
-
-repo.enable-log-linecount::
- A flag which can be used to disable the global setting
- `enable-log-linecount'. Default value: none.
-
-repo.enable-remote-branches::
- Flag which, when set to "1", will make cgit display remote branches
- in the summary and refs views. Default value: <enable-remote-branches>.
-
-repo.enable-subject-links::
- A flag which can be used to override the global setting
- `enable-subject-links'. Default value: none.
-
-repo.extra-head-content::
- This value will be added verbatim to the head section of each page
- displayed for this repo. Default value: none.
-
-repo.hide::
- Flag which, when set to "1", hides the repository from the repository
- index. The repository can still be accessed by providing a direct path.
- Default value: "0". See also: "repo.ignore".
-
-repo.homepage::
- The value to show as repository homepage. Default value: none.
-
-repo.ignore::
- Flag which, when set to "1", ignores the repository. The repository
- is not shown in the index and cannot be accessed by providing a direct
- path. Default value: "0". See also: "repo.hide".
-
-repo.logo::
- Url which specifies the source of an image which will be used as a logo
- on this repo's pages. Default value: global logo.
-
-repo.logo-link::
- Url loaded when clicking on the cgit logo image. If unspecified the
- calculated url of the repository index page will be used. Default
- value: global logo-link.
-
-repo.module-link::
- Text which will be used as the formatstring for a hyperlink when a
- submodule is printed in a directory listing. The arguments for the
- formatstring are the path and SHA1 of the submodule commit. Default
- value: <module-link>
-
-repo.module-link.<path>::
- Text which will be used as the formatstring for a hyperlink when a
- submodule with the specified subdirectory path is printed in a
- directory listing. The only argument for the formatstring is the SHA1
- of the submodule commit. Default value: none.
-
-repo.max-stats::
- Override the default maximum statistics period. Valid values are equal
- to the values specified for the global "max-stats" setting. Default
- value: none.
-
-repo.name::
- The value to show as repository name. Default value: <repo.url>.
-
-repo.owner::
- A value used to identify the owner of the repository. Default value:
- none.
-
-repo.owner-filter::
- Override the default owner-filter. Default value: none. See also:
- "enable-filter-overrides". See also: "FILTER API".
-
-repo.path::
- An absolute path to the repository directory. For non-bare repositories
- this is the .git-directory. Default value: none.
-
-repo.readme::
- A path (relative to <repo.path>) which specifies a file to include
- verbatim as the "About" page for this repo. You may also specify a
- git refspec by head or by hash by prepending the refspec followed by
- a colon. For example, "master:docs/readme.mkd". If the value begins
- with a colon, i.e. ":docs/readme.rst", the head giving in query or
- the default branch of the repository will be used. Sharing any file
- will expose that entire directory tree to the "/about/PATH" endpoints,
- so be sure that there are no non-public files located in the same
- directory as the readme file. Default value: <readme>.
-
-repo.section::
- Override the current section name for this repository. Default value:
- none.
-
-repo.snapshots::
- A mask of snapshot formats for this repo that cgit generates links for,
- restricted by the global "snapshots" setting. Default value:
- <snapshots>.
-
-repo.snapshot-prefix::
- Prefix to use for snapshot links instead of the repository basename.
- For example, the "linux-stable" repository may wish to set this to
- "linux" so that snapshots are in the format "linux-3.15.4" instead
- of "linux-stable-3.15.4". Default value: <empty> meaning to use
- the repository basename.
-
-repo.source-filter::
- Override the default source-filter. Default value: none. See also:
- "enable-filter-overrides". See also: "FILTER API".
-
-repo.url::
- The relative url used to access the repository. This must be the first
- setting specified for each repo. Default value: none.
-
-
-REPOSITORY-SPECIFIC CGITRC FILE
--------------------------------
-When the option "scan-path" is used to auto-discover git repositories, cgit
-will try to parse the file "cgitrc" within any found repository. Such a
-repo-specific config file may contain any of the repo-specific options
-described above, except "repo.url" and "repo.path". Additionally, the "filter"
-options are only acknowledged in repo-specific config files when
-"enable-filter-overrides" is set to "1".
-
-Note: the "repo." prefix is dropped from the option names in repo-specific
-config files, e.g. "repo.desc" becomes "desc".
-
-
-FILTER API
-----------
-By default, filters are separate processes that are executed each time they
-are needed. Alternative technologies may be used by prefixing the filter
-specification with the relevant string; available values are:
-
-'exec:'::
- The default "one process per filter" mode.
-
-'lua:'::
- Executes the script using a built-in Lua interpreter. The script is
- loaded once per execution of cgit, and may be called multiple times
- during cgit's lifetime, making it a good choice for repeated filters
- such as the 'email filter'. It responds to three functions:
-
- 'filter_open(argument1, argument2, argument3, ...)'::
- This is called upon activation of the filter for a particular
- set of data.
- 'filter_write(buffer)'::
- This is called whenever cgit writes data to the webpage.
- 'filter_close()'::
- This is called when the current filtering operation is
- completed. It must return an integer value. Usually 0
- indicates success.
-
- Additionally, cgit exposes to the Lua the following built-in functions:
-
- 'html(str)'::
- Writes 'str' to the webpage.
- 'html_txt(str)'::
- HTML escapes and writes 'str' to the webpage.
- 'html_attr(str)'::
- HTML escapes for an attribute and writes "str' to the webpage.
- 'html_url_path(str)'::
- URL escapes for a path and writes 'str' to the webpage.
- 'html_url_arg(str)'::
- URL escapes for an argument and writes 'str' to the webpage.
- 'html_include(file)'::
- Includes 'file' in webpage.
-
-
-Parameters are provided to filters as follows.
-
-about filter::
- This filter is given a single parameter: the filename of the source
- file to filter. The filter can use the filename to determine (for
- example) the type of syntax to follow when formatting the readme file.
- The about text that is to be filtered is available on standard input
- and the filtered text is expected on standard output.
-
-auth filter::
- The authentication filter receives 12 parameters:
- - filter action, explained below, which specifies which action the
- filter is called for
- - http cookie
- - http method
- - http referer
- - http path
- - http https flag
- - cgit repo
- - cgit page
- - cgit url
- - cgit login url
- When the filter action is "body", this filter must write to output the
- HTML for displaying the login form, which POSTs to the login url. When
- the filter action is "authenticate-cookie", this filter must validate
- the http cookie and return a 0 if it is invalid or 1 if it is invalid,
- in the exit code / close function. If the filter action is
- "authenticate-post", this filter receives POST'd parameters on
- standard input, and should write a complete CGI response, preferably
- with a 302 redirect, and write to output one or more "Set-Cookie"
- HTTP headers, each followed by a newline.
-
- Please see `filters/simple-authentication.lua` for a clear example
- script that may be modified.
-
-commit filter::
- This filter is given no arguments. The commit message text that is to
- be filtered is available on standard input and the filtered text is
- expected on standard output.
-
-email filter::
- This filter is given two parameters: the email address of the relevant
- author and a string indicating the originating page. The filter will
- then receive the text string to format on standard input and is
- expected to write to standard output the formatted text to be included
- in the page.
-
-owner filter::
- This filter is given no arguments. The owner text is available on
- standard input and the filter is expected to write to standard
- output. The output is included in the Owner column.
-
-source filter::
- This filter is given a single parameter: the filename of the source
- file to filter. The filter can use the filename to determine (for
- example) the syntax highlighting mode. The contents of the source
- file that is to be filtered is available on standard input and the
- filtered contents is expected on standard output.
-
-
-All filters are handed the following environment variables:
-
-- CGIT_REPO_URL (from repo.url)
-- CGIT_REPO_NAME (from repo.name)
-- CGIT_REPO_PATH (from repo.path)
-- CGIT_REPO_OWNER (from repo.owner)
-- CGIT_REPO_DEFBRANCH (from repo.defbranch)
-- CGIT_REPO_SECTION (from repo.section)
-- CGIT_REPO_CLONE_URL (from repo.clone-url)
-
-If a setting is not defined for a repository and the corresponding global
-setting is also not defined (if applicable), then the corresponding
-environment variable will be unset.
-
-
-MACRO EXPANSION
----------------
-The following cgitrc options support a simple macro expansion feature,
-where tokens prefixed with "$" are replaced with the value of a similarly
-named environment variable:
-
-- cache-root
-- include
-- project-list
-- scan-path
-
-Macro expansion will also happen on the content of $CGIT_CONFIG, if
-defined.
-
-One usage of this feature is virtual hosting, which in its simplest form
-can be accomplished by adding the following line to /etc/cgitrc:
-
- include=/etc/cgitrc.d/$HTTP_HOST
-
-The following options are expanded during request processing, and support
-the environment variables defined in "FILTER API":
-
-- clone-url
-- repo.clone-url
-
-
-CACHE
------
-
-All cache ttl values are in minutes. Negative ttl values indicate that a page
-type will never expire, and thus the first time a URL is accessed, the result
-will be cached indefinitely, even if the underlying git repository changes.
-Conversely, when a ttl value is zero, the cache is disabled for that
-particular page type, and the page type is never cached.
-
-SIGNATURES
-----------
-
-Cgit can host .asc signatures corresponding to various snapshot formats,
-through use of git notes. For example, the following command may be used to
-add a signature to a .tar.xz archive:
-
- git notes --ref=refs/notes/signatures/tar.xz add -C "$(
- gpg --output - --armor --detach-sign cgit-1.1.tar.xz |
- git hash-object -w --stdin
- )" v1.1
-
-If it is instead desirable to attach a signature of the underlying .tar, this
-will be linked, as a special case, beside a .tar.* link that does not have its
-own signature. For example, a signature of a tarball of the latest tag might
-be added with a similar command:
-
- tag="$(git describe --abbrev=0)"
- git notes --ref=refs/notes/signatures/tar add -C "$(
- git archive --format tar --prefix "cgit-${tag#v}/" "$tag" |
- gpg --output - --armor --detach-sign |
- git hash-object -w --stdin
- )" "$tag"
-
-Since git-archive(1) is expected to produce stable output between versions,
-this allows one to generate a long-term signature of the contents of a given
-tag.
-
-EXAMPLE CGITRC FILE
--------------------
-
-....
-# Enable caching of up to 1000 output entries
-cache-size=1000
-
-
-# Specify some default clone urls using macro expansion
-clone-url=git://foo.org/$CGIT_REPO_URL git@foo.org:$CGIT_REPO_URL
-
-# Specify the css url
-css=/css/cgit.css
-
-
-# Show owner on index page
-enable-index-owner=1
-
-
-# Allow http transport git clone
-enable-http-clone=1
-
-
-# Show extra links for each repository on the index page
-enable-index-links=1
-
-
-# Enable blame page and create links to it from tree page
-enable-blame=1
-
-
-# Enable ASCII art commit history graph on the log pages
-enable-commit-graph=1
-
-
-# Show number of affected files per commit on the log pages
-enable-log-filecount=1
-
-
-# Show number of added/removed lines per commit on the log pages
-enable-log-linecount=1
-
-
-# Sort branches by date
-branch-sort=age
-
-
-# Add a cgit favicon
-favicon=/favicon.ico
-
-
-# Use a custom logo
-logo=/img/mylogo.png
-
-
-# Enable statistics per week, month and quarter
-max-stats=quarter
-
-
-# Set the title and heading of the repository index page
-root-title=example.com git repositories
-
-
-# Set a subheading for the repository index page
-root-desc=tracking the foobar development
-
-
-# Include some more info about example.com on the index page
-root-readme=/var/www/htdocs/about.html
-
-
-# Allow download of tar.gz, tar.bz2 and zip-files
-snapshots=tar.gz tar.bz2 zip
-
-
-##
-## List of common mimetypes
-##
-
-mimetype.gif=image/gif
-mimetype.html=text/html
-mimetype.jpg=image/jpeg
-mimetype.jpeg=image/jpeg
-mimetype.pdf=application/pdf
-mimetype.png=image/png
-mimetype.svg=image/svg+xml
-
-
-# Highlight source code with python pygments-based highlighter
-source-filter=/var/www/cgit/filters/syntax-highlighting.py
-
-# Format markdown, restructuredtext, manpages, text files, and html files
-# through the right converters
-about-filter=/var/www/cgit/filters/about-formatting.sh
-
-##
-## Search for these files in the root of the default branch of repositories
-## for coming up with the about page:
-##
-readme=:README.md
-readme=:readme.md
-readme=:README.mkd
-readme=:readme.mkd
-readme=:README.rst
-readme=:readme.rst
-readme=:README.html
-readme=:readme.html
-readme=:README.htm
-readme=:readme.htm
-readme=:README.txt
-readme=:readme.txt
-readme=:README
-readme=:readme
-readme=:INSTALL.md
-readme=:install.md
-readme=:INSTALL.mkd
-readme=:install.mkd
-readme=:INSTALL.rst
-readme=:install.rst
-readme=:INSTALL.html
-readme=:install.html
-readme=:INSTALL.htm
-readme=:install.htm
-readme=:INSTALL.txt
-readme=:install.txt
-readme=:INSTALL
-readme=:install
-
-
-##
-## List of repositories.
-## PS: Any repositories listed when section is unset will not be
-## displayed under a section heading
-## PPS: This list could be kept in a different file (e.g. '/etc/cgitrepos')
-## and included like this:
-## include=/etc/cgitrepos
-##
-
-
-repo.url=foo
-repo.path=/pub/git/foo.git
-repo.desc=the master foo repository
-repo.owner=fooman@example.com
-repo.readme=info/web/about.html
-
-
-repo.url=bar
-repo.path=/pub/git/bar.git
-repo.desc=the bars for your foo
-repo.owner=barman@example.com
-repo.readme=info/web/about.html
-
-
-# The next repositories will be displayed under the 'extras' heading
-section=extras
-
-
-repo.url=baz
-repo.path=/pub/git/baz.git
-repo.desc=a set of extensions for bar users
-
-repo.url=wiz
-repo.path=/pub/git/wiz.git
-repo.desc=the wizard of foo
-
-
-# Add some mirrored repositories
-section=mirrors
-
-
-repo.url=git
-repo.path=/pub/git/git.git
-repo.desc=the dscm
-
-
-repo.url=linux
-repo.path=/pub/git/linux.git
-repo.desc=the kernel
-
-# Disable adhoc downloads of this repo
-repo.snapshots=0
-
-# Disable line-counts for this repo
-repo.enable-log-linecount=0
-
-# Restrict the max statistics period for this repo
-repo.max-stats=month
-....
-
-
-BUGS
-----
-Comments currently cannot appear on the same line as a setting; the comment
-will be included as part of the value. E.g. this line:
-
- robots=index # allow indexing
-
-will generate the following html element:
-
- <meta name='robots' content='index # allow indexing'/>
-
-
-
-AUTHOR
-------
-Lars Hjemli <hjemli@gmail.com>
-Jason A. Donenfeld <Jason@zx2c4.com>
diff --git a/cmd.c b/cmd.c
deleted file mode 100644
index 0eb75b1..0000000
--- a/cmd.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/* cmd.c: the cgit command dispatcher
- *
- * Copyright (C) 2006-2017 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#include "cgit.h"
-#include "cmd.h"
-#include "cache.h"
-#include "ui-shared.h"
-#include "ui-atom.h"
-#include "ui-blame.h"
-#include "ui-blob.h"
-#include "ui-clone.h"
-#include "ui-commit.h"
-#include "ui-diff.h"
-#include "ui-log.h"
-#include "ui-patch.h"
-#include "ui-plain.h"
-#include "ui-refs.h"
-#include "ui-repolist.h"
-#include "ui-snapshot.h"
-#include "ui-stats.h"
-#include "ui-summary.h"
-#include "ui-tag.h"
-#include "ui-tree.h"
-
-static void HEAD_fn(void)
-{
- cgit_clone_head();
-}
-
-static void atom_fn(void)
-{
- cgit_print_atom(ctx.qry.head, ctx.qry.path, ctx.cfg.max_atom_items);
-}
-
-static void about_fn(void)
-{
- if (ctx.repo) {
- size_t path_info_len = ctx.env.path_info ? strlen(ctx.env.path_info) : 0;
- if (!ctx.qry.path &&
- ctx.qry.url[strlen(ctx.qry.url) - 1] != '/' &&
- (!path_info_len || ctx.env.path_info[path_info_len - 1] != '/')) {
- char *currenturl = cgit_currenturl();
- char *redirect = fmtalloc("%s/", currenturl);
- cgit_redirect(redirect, true);
- free(currenturl);
- free(redirect);
- } else if (ctx.repo->readme.nr)
- cgit_print_repo_readme(ctx.qry.path);
- else if (ctx.repo->homepage)
- cgit_redirect(ctx.repo->homepage, false);
- else {
- char *currenturl = cgit_currenturl();
- char *redirect = fmtalloc("%s../", currenturl);
- cgit_redirect(redirect, false);
- free(currenturl);
- free(redirect);
- }
- } else
- cgit_print_site_readme();
-}
-
-static void blame_fn(void)
-{
- if (ctx.repo->enable_blame)
- cgit_print_blame();
- else
- cgit_print_error_page(403, "Forbidden", "Blame is disabled");
-}
-
-static void blob_fn(void)
-{
- cgit_print_blob(ctx.qry.oid, ctx.qry.path, ctx.qry.head, 0);
-}
-
-static void commit_fn(void)
-{
- cgit_print_commit(ctx.qry.oid, ctx.qry.path);
-}
-
-static void diff_fn(void)
-{
- cgit_print_diff(ctx.qry.oid, ctx.qry.oid2, ctx.qry.path, 1, 0);
-}
-
-static void rawdiff_fn(void)
-{
- cgit_print_diff(ctx.qry.oid, ctx.qry.oid2, ctx.qry.path, 1, 1);
-}
-
-static void info_fn(void)
-{
- cgit_clone_info();
-}
-
-static void log_fn(void)
-{
- cgit_print_log(ctx.qry.oid, ctx.qry.ofs, ctx.cfg.max_commit_count,
- ctx.qry.grep, ctx.qry.search, ctx.qry.path, 1,
- ctx.repo->enable_commit_graph,
- ctx.repo->commit_sort);
-}
-
-static void ls_cache_fn(void)
-{
- ctx.page.mimetype = "text/plain";
- ctx.page.filename = "ls-cache.txt";
- cgit_print_http_headers();
- cache_ls(ctx.cfg.cache_root);
-}
-
-static void objects_fn(void)
-{
- cgit_clone_objects();
-}
-
-static void repolist_fn(void)
-{
- cgit_print_repolist();
-}
-
-static void patch_fn(void)
-{
- cgit_print_patch(ctx.qry.oid, ctx.qry.oid2, ctx.qry.path);
-}
-
-static void plain_fn(void)
-{
- cgit_print_plain();
-}
-
-static void refs_fn(void)
-{
- cgit_print_refs();
-}
-
-static void snapshot_fn(void)
-{
- cgit_print_snapshot(ctx.qry.head, ctx.qry.oid, ctx.qry.path,
- ctx.qry.nohead);
-}
-
-static void stats_fn(void)
-{
- cgit_show_stats();
-}
-
-static void summary_fn(void)
-{
- cgit_print_summary();
-}
-
-static void tag_fn(void)
-{
- cgit_print_tag(ctx.qry.oid);
-}
-
-static void tree_fn(void)
-{
- cgit_print_tree(ctx.qry.oid, ctx.qry.path);
-}
-
-#define def_cmd(name, want_repo, want_vpath, is_clone) \
- {#name, name##_fn, want_repo, want_vpath, is_clone}
-
-struct cgit_cmd *cgit_get_cmd(void)
-{
- static struct cgit_cmd cmds[] = {
- def_cmd(HEAD, 1, 0, 1),
- def_cmd(atom, 1, 0, 0),
- def_cmd(about, 0, 0, 0),
- def_cmd(blame, 1, 1, 0),
- def_cmd(blob, 1, 0, 0),
- def_cmd(commit, 1, 1, 0),
- def_cmd(diff, 1, 1, 0),
- def_cmd(info, 1, 0, 1),
- def_cmd(log, 1, 1, 0),
- def_cmd(ls_cache, 0, 0, 0),
- def_cmd(objects, 1, 0, 1),
- def_cmd(patch, 1, 1, 0),
- def_cmd(plain, 1, 0, 0),
- def_cmd(rawdiff, 1, 1, 0),
- def_cmd(refs, 1, 0, 0),
- def_cmd(repolist, 0, 0, 0),
- def_cmd(snapshot, 1, 0, 0),
- def_cmd(stats, 1, 1, 0),
- def_cmd(summary, 1, 0, 0),
- def_cmd(tag, 1, 0, 0),
- def_cmd(tree, 1, 1, 0),
- };
- int i;
-
- if (ctx.qry.page == NULL) {
- if (ctx.repo)
- ctx.qry.page = "summary";
- else
- ctx.qry.page = "repolist";
- }
-
- for (i = 0; i < sizeof(cmds)/sizeof(*cmds); i++)
- if (!strcmp(ctx.qry.page, cmds[i].name))
- return &cmds[i];
- return NULL;
-}
diff --git a/cmd.h b/cmd.h
deleted file mode 100644
index 6249b1d..0000000
--- a/cmd.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef CMD_H
-#define CMD_H
-
-typedef void (*cgit_cmd_fn)(void);
-
-struct cgit_cmd {
- const char *name;
- cgit_cmd_fn fn;
- unsigned int want_repo:1,
- want_vpath:1,
- is_clone:1;
-};
-
-extern struct cgit_cmd *cgit_get_cmd(void);
-
-#endif /* CMD_H */
diff --git a/config.c b/config.c
new file mode 100644
index 0000000..858ab69
--- /dev/null
+++ b/config.c
@@ -0,0 +1,73 @@
+#include "cgit.h"
+
+int next_char(FILE *f)
+{
+ int c = fgetc(f);
+ if (c=='\r') {
+ c = fgetc(f);
+ if (c!='\n') {
+ ungetc(c, f);
+ c = '\r';
+ }
+ }
+ return c;
+}
+
+void skip_line(FILE *f)
+{
+ int c;
+
+ while((c=next_char(f)) && c!='\n' && c!=EOF)
+ ;
+}
+
+int read_config_line(FILE *f, char *line, const char **value, int bufsize)
+{
+ int i = 0, isname = 0;
+
+ *value = NULL;
+ while(i<bufsize-1) {
+ int c = next_char(f);
+ if (!isname && (c=='#' || c==';')) {
+ skip_line(f);
+ continue;
+ }
+ if (!isname && isblank(c))
+ continue;
+
+ if (c=='=' && !*value) {
+ line[i] = 0;
+ *value = &line[i+1];
+ } else if (c=='\n' && !isname) {
+ i = 0;
+ continue;
+ } else if (c=='\n' || c==EOF) {
+ line[i] = 0;
+ break;
+ } else {
+ line[i]=c;
+ }
+ isname = 1;
+ i++;
+ }
+ line[i+1] = 0;
+ return i;
+}
+
+int cgit_read_config(const char *filename, configfn fn)
+{
+ int ret = 0, len;
+ char line[256];
+ const char *value;
+ FILE *f = fopen(filename, "r");
+
+ if (!f)
+ return -1;
+
+ while(len = read_config_line(f, line, &value, sizeof(line)))
+ (*fn)(line, value);
+
+ fclose(f);
+ return ret;
+}
+
diff --git a/configfile.c b/configfile.c
deleted file mode 100644
index e039109..0000000
--- a/configfile.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* configfile.c: parsing of config files
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#include <git-compat-util.h>
-#include "configfile.h"
-
-static int next_char(FILE *f)
-{
- int c = fgetc(f);
- if (c == '\r') {
- c = fgetc(f);
- if (c != '\n') {
- ungetc(c, f);
- c = '\r';
- }
- }
- return c;
-}
-
-static void skip_line(FILE *f)
-{
- int c;
-
- while ((c = next_char(f)) && c != '\n' && c != EOF)
- ;
-}
-
-static int read_config_line(FILE *f, struct strbuf *name, struct strbuf *value)
-{
- int c = next_char(f);
-
- strbuf_reset(name);
- strbuf_reset(value);
-
- /* Skip comments and preceding spaces. */
- for(;;) {
- if (c == EOF)
- return 0;
- else if (c == '#' || c == ';')
- skip_line(f);
- else if (!isspace(c))
- break;
- c = next_char(f);
- }
-
- /* Read variable name. */
- while (c != '=') {
- if (c == '\n' || c == EOF)
- return 0;
- strbuf_addch(name, c);
- c = next_char(f);
- }
-
- /* Read variable value. */
- c = next_char(f);
- while (c != '\n' && c != EOF) {
- strbuf_addch(value, c);
- c = next_char(f);
- }
-
- return 1;
-}
-
-int parse_configfile(const char *filename, configfile_value_fn fn)
-{
- static int nesting;
- struct strbuf name = STRBUF_INIT;
- struct strbuf value = STRBUF_INIT;
- FILE *f;
-
- /* cancel deeply nested include-commands */
- if (nesting > 8)
- return -1;
- if (!(f = fopen(filename, "r")))
- return -1;
- nesting++;
- while (read_config_line(f, &name, &value))
- fn(name.buf, value.buf);
- nesting--;
- fclose(f);
- strbuf_release(&name);
- strbuf_release(&value);
- return 0;
-}
-
diff --git a/configfile.h b/configfile.h
deleted file mode 100644
index af7ca19..0000000
--- a/configfile.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef CONFIGFILE_H
-#define CONFIGFILE_H
-
-#include "cgit.h"
-
-typedef void (*configfile_value_fn)(const char *name, const char *value);
-
-extern int parse_configfile(const char *filename, configfile_value_fn fn);
-
-#endif /* CONFIGFILE_H */
diff --git a/contrib/hooks/post-receive.agefile b/contrib/hooks/post-receive.agefile
deleted file mode 100755
index 2f72ae9..0000000
--- a/contrib/hooks/post-receive.agefile
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-#
-# An example hook to update the "agefile" for CGit's idle time calculation.
-#
-# This hook assumes that you are using the default agefile location of
-# "info/web/last-modified". If you change the value in your cgitrc then you
-# must also change it here.
-#
-# To install the hook, copy (or link) it to the file "hooks/post-receive" in
-# each of your repositories.
-#
-
-agefile="$(git rev-parse --git-dir)"/info/web/last-modified
-
-mkdir -p "$(dirname "$agefile")" &&
-git for-each-ref \
- --sort=-authordate --count=1 \
- --format='%(authordate:iso8601)' \
- >"$agefile"
diff --git a/favicon.ico b/favicon.ico
deleted file mode 100644
index 56ff593..0000000
--- a/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/filter.c b/filter.c
deleted file mode 100644
index c778d05..0000000
--- a/filter.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/* filter.c: filter framework functions
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#include "cgit.h"
-#include "html.h"
-#ifndef NO_LUA
-#include <dlfcn.h>
-#include <lua.h>
-#include <lualib.h>
-#include <lauxlib.h>
-#endif
-
-static inline void reap_filter(struct cgit_filter *filter)
-{
- if (filter && filter->cleanup)
- filter->cleanup(filter);
-}
-
-void cgit_cleanup_filters(void)
-{
- int i;
- reap_filter(ctx.cfg.about_filter);
- reap_filter(ctx.cfg.commit_filter);
- reap_filter(ctx.cfg.source_filter);
- reap_filter(ctx.cfg.email_filter);
- reap_filter(ctx.cfg.owner_filter);
- reap_filter(ctx.cfg.auth_filter);
- for (i = 0; i < cgit_repolist.count; ++i) {
- reap_filter(cgit_repolist.repos[i].about_filter);
- reap_filter(cgit_repolist.repos[i].commit_filter);
- reap_filter(cgit_repolist.repos[i].source_filter);
- reap_filter(cgit_repolist.repos[i].email_filter);
- reap_filter(cgit_repolist.repos[i].owner_filter);
- }
-}
-
-static int open_exec_filter(struct cgit_filter *base, va_list ap)
-{
- struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base;
- int pipe_fh[2];
- int i;
-
- for (i = 0; i < filter->base.argument_count; i++)
- filter->argv[i + 1] = va_arg(ap, char *);
-
- filter->old_stdout = chk_positive(dup(STDOUT_FILENO),
- "Unable to duplicate STDOUT");
- chk_zero(pipe(pipe_fh), "Unable to create pipe to subprocess");
- filter->pid = chk_non_negative(fork(), "Unable to create subprocess");
- if (filter->pid == 0) {
- close(pipe_fh[1]);
- chk_non_negative(dup2(pipe_fh[0], STDIN_FILENO),
- "Unable to use pipe as STDIN");
- execvp(filter->cmd, filter->argv);
- die_errno("Unable to exec subprocess %s", filter->cmd);
- }
- close(pipe_fh[0]);
- chk_non_negative(dup2(pipe_fh[1], STDOUT_FILENO),
- "Unable to use pipe as STDOUT");
- close(pipe_fh[1]);
- return 0;
-}
-
-static int close_exec_filter(struct cgit_filter *base)
-{
- struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base;
- int i, exit_status = 0;
-
- chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO),
- "Unable to restore STDOUT");
- close(filter->old_stdout);
- if (filter->pid < 0)
- goto done;
- waitpid(filter->pid, &exit_status, 0);
- if (WIFEXITED(exit_status))
- goto done;
- die("Subprocess %s exited abnormally", filter->cmd);
-
-done:
- for (i = 0; i < filter->base.argument_count; i++)
- filter->argv[i + 1] = NULL;
- return WEXITSTATUS(exit_status);
-
-}
-
-static void fprintf_exec_filter(struct cgit_filter *base, FILE *f, const char *prefix)
-{
- struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base;
- fprintf(f, "%sexec:%s\n", prefix, filter->cmd);
-}
-
-static void cleanup_exec_filter(struct cgit_filter *base)
-{
- struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base;
- if (filter->argv) {
- free(filter->argv);
- filter->argv = NULL;
- }
- if (filter->cmd) {
- free(filter->cmd);
- filter->cmd = NULL;
- }
-}
-
-static struct cgit_filter *new_exec_filter(const char *cmd, int argument_count)
-{
- struct cgit_exec_filter *f;
- int args_size = 0;
-
- f = xmalloc(sizeof(*f));
- /* We leave argv for now and assign it below. */
- cgit_exec_filter_init(f, strdup_first_line(cmd), NULL);
- f->base.argument_count = argument_count;
- args_size = (2 + argument_count) * sizeof(char *);
- f->argv = xmalloc(args_size);
- memset(f->argv, 0, args_size);
- f->argv[0] = f->cmd;
- return &f->base;
-}
-
-void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv)
-{
- memset(filter, 0, sizeof(*filter));
- filter->base.open = open_exec_filter;
- filter->base.close = close_exec_filter;
- filter->base.fprintfp = fprintf_exec_filter;
- filter->base.cleanup = cleanup_exec_filter;
- filter->cmd = cmd;
- filter->argv = argv;
- /* The argument count for open_filter is zero by default, unless called from new_filter, above. */
- filter->base.argument_count = 0;
-}
-
-#ifdef NO_LUA
-void cgit_init_filters(void)
-{
-}
-#endif
-
-#ifndef NO_LUA
-static ssize_t (*libc_write)(int fd, const void *buf, size_t count);
-static ssize_t (*filter_write)(struct cgit_filter *base, const void *buf, size_t count) = NULL;
-static struct cgit_filter *current_write_filter = NULL;
-
-void cgit_init_filters(void)
-{
- libc_write = dlsym(RTLD_NEXT, "write");
- if (!libc_write)
- die("Could not locate libc's write function");
-}
-
-ssize_t write(int fd, const void *buf, size_t count)
-{
- if (fd != STDOUT_FILENO || !filter_write)
- return libc_write(fd, buf, count);
- return filter_write(current_write_filter, buf, count);
-}
-
-static inline void hook_write(struct cgit_filter *filter, ssize_t (*new_write)(struct cgit_filter *base, const void *buf, size_t count))
-{
- /* We want to avoid buggy nested patterns. */
- assert(filter_write == NULL);
- assert(current_write_filter == NULL);
- current_write_filter = filter;
- filter_write = new_write;
-}
-
-static inline void unhook_write(void)
-{
- assert(filter_write != NULL);
- assert(current_write_filter != NULL);
- filter_write = NULL;
- current_write_filter = NULL;
-}
-
-struct lua_filter {
- struct cgit_filter base;
- char *script_file;
- lua_State *lua_state;
-};
-
-static void error_lua_filter(struct lua_filter *filter)
-{
- die("Lua error in %s: %s", filter->script_file, lua_tostring(filter->lua_state, -1));
- lua_pop(filter->lua_state, 1);
-}
-
-static ssize_t write_lua_filter(struct cgit_filter *base, const void *buf, size_t count)
-{
- struct lua_filter *filter = (struct lua_filter *)base;
-
- lua_getglobal(filter->lua_state, "filter_write");
- lua_pushlstring(filter->lua_state, buf, count);
- if (lua_pcall(filter->lua_state, 1, 0, 0)) {
- error_lua_filter(filter);
- errno = EIO;
- return -1;
- }
- return count;
-}
-
-static inline int hook_lua_filter(lua_State *lua_state, void (*fn)(const char *txt))
-{
- const char *str;
- ssize_t (*save_filter_write)(struct cgit_filter *base, const void *buf, size_t count);
- struct cgit_filter *save_filter;
-
- str = lua_tostring(lua_state, 1);
- if (!str)
- return 0;
-
- save_filter_write = filter_write;
- save_filter = current_write_filter;
- unhook_write();
- fn(str);
- hook_write(save_filter, save_filter_write);
-
- return 0;
-}
-
-static int html_lua_filter(lua_State *lua_state)
-{
- return hook_lua_filter(lua_state, html);
-}
-
-static int html_txt_lua_filter(lua_State *lua_state)
-{
- return hook_lua_filter(lua_state, html_txt);
-}
-
-static int html_attr_lua_filter(lua_State *lua_state)
-{
- return hook_lua_filter(lua_state, html_attr);
-}
-
-static int html_url_path_lua_filter(lua_State *lua_state)
-{
- return hook_lua_filter(lua_state, html_url_path);
-}
-
-static int html_url_arg_lua_filter(lua_State *lua_state)
-{
- return hook_lua_filter(lua_state, html_url_arg);
-}
-
-static int html_include_lua_filter(lua_State *lua_state)
-{
- return hook_lua_filter(lua_state, (void (*)(const char *))html_include);
-}
-
-static void cleanup_lua_filter(struct cgit_filter *base)
-{
- struct lua_filter *filter = (struct lua_filter *)base;
-
- if (!filter->lua_state)
- return;
-
- lua_close(filter->lua_state);
- filter->lua_state = NULL;
- if (filter->script_file) {
- free(filter->script_file);
- filter->script_file = NULL;
- }
-}
-
-static int init_lua_filter(struct lua_filter *filter)
-{
- if (filter->lua_state)
- return 0;
-
- if (!(filter->lua_state = luaL_newstate()))
- return 1;
-
- luaL_openlibs(filter->lua_state);
-
- lua_pushcfunction(filter->lua_state, html_lua_filter);
- lua_setglobal(filter->lua_state, "html");
- lua_pushcfunction(filter->lua_state, html_txt_lua_filter);
- lua_setglobal(filter->lua_state, "html_txt");
- lua_pushcfunction(filter->lua_state, html_attr_lua_filter);
- lua_setglobal(filter->lua_state, "html_attr");
- lua_pushcfunction(filter->lua_state, html_url_path_lua_filter);
- lua_setglobal(filter->lua_state, "html_url_path");
- lua_pushcfunction(filter->lua_state, html_url_arg_lua_filter);
- lua_setglobal(filter->lua_state, "html_url_arg");
- lua_pushcfunction(filter->lua_state, html_include_lua_filter);
- lua_setglobal(filter->lua_state, "html_include");
-
- if (luaL_dofile(filter->lua_state, filter->script_file)) {
- error_lua_filter(filter);
- lua_close(filter->lua_state);
- filter->lua_state = NULL;
- return 1;
- }
- return 0;
-}
-
-static int open_lua_filter(struct cgit_filter *base, va_list ap)
-{
- struct lua_filter *filter = (struct lua_filter *)base;
- int i;
-
- if (init_lua_filter(filter))
- return 1;
-
- hook_write(base, write_lua_filter);
-
- lua_getglobal(filter->lua_state, "filter_open");
- for (i = 0; i < filter->base.argument_count; ++i)
- lua_pushstring(filter->lua_state, va_arg(ap, char *));
- if (lua_pcall(filter->lua_state, filter->base.argument_count, 0, 0)) {
- error_lua_filter(filter);
- return 1;
- }
- return 0;
-}
-
-static int close_lua_filter(struct cgit_filter *base)
-{
- struct lua_filter *filter = (struct lua_filter *)base;
- int ret = 0;
-
- lua_getglobal(filter->lua_state, "filter_close");
- if (lua_pcall(filter->lua_state, 0, 1, 0)) {
- error_lua_filter(filter);
- ret = -1;
- } else {
- ret = lua_tonumber(filter->lua_state, -1);
- lua_pop(filter->lua_state, 1);
- }
-
- unhook_write();
- return ret;
-}
-
-static void fprintf_lua_filter(struct cgit_filter *base, FILE *f, const char *prefix)
-{
- struct lua_filter *filter = (struct lua_filter *)base;
- fprintf(f, "%slua:%s\n", prefix, filter->script_file);
-}
-
-
-static struct cgit_filter *new_lua_filter(const char *cmd, int argument_count)
-{
- struct lua_filter *filter;
-
- filter = xmalloc(sizeof(*filter));
- memset(filter, 0, sizeof(*filter));
- filter->base.open = open_lua_filter;
- filter->base.close = close_lua_filter;
- filter->base.fprintfp = fprintf_lua_filter;
- filter->base.cleanup = cleanup_lua_filter;
- filter->base.argument_count = argument_count;
- filter->script_file = strdup_first_line(cmd);
-
- return &filter->base;
-}
-
-#endif
-
-
-int cgit_open_filter(struct cgit_filter *filter, ...)
-{
- int result;
- va_list ap;
- if (!filter)
- return 0;
- va_start(ap, filter);
- result = filter->open(filter, ap);
- va_end(ap);
- return result;
-}
-
-int cgit_close_filter(struct cgit_filter *filter)
-{
- if (!filter)
- return 0;
- return filter->close(filter);
-}
-
-void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char *prefix)
-{
- filter->fprintfp(filter, f, prefix);
-}
-
-
-
-static const struct {
- const char *prefix;
- struct cgit_filter *(*ctor)(const char *cmd, int argument_count);
-} filter_specs[] = {
- { "exec", new_exec_filter },
-#ifndef NO_LUA
- { "lua", new_lua_filter },
-#endif
-};
-
-struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype)
-{
- const char *colon;
- int i;
- size_t len;
- int argument_count;
-
- if (!cmd || !cmd[0])
- return NULL;
-
- colon = strchr(cmd, ':');
- len = colon - cmd;
- /*
- * In case we're running on Windows, don't allow a single letter before
- * the colon.
- */
- if (len == 1)
- colon = NULL;
-
- switch (filtertype) {
- case AUTH:
- argument_count = 12;
- break;
-
- case EMAIL:
- argument_count = 2;
- break;
-
- case OWNER:
- argument_count = 0;
- break;
-
- case SOURCE:
- case ABOUT:
- argument_count = 1;
- break;
-
- case COMMIT:
- default:
- argument_count = 0;
- break;
- }
-
- /* If no prefix is given, exec filter is the default. */
- if (!colon)
- return new_exec_filter(cmd, argument_count);
-
- for (i = 0; i < ARRAY_SIZE(filter_specs); i++) {
- if (len == strlen(filter_specs[i].prefix) &&
- !strncmp(filter_specs[i].prefix, cmd, len))
- return filter_specs[i].ctor(colon + 1, argument_count);
- }
-
- die("Invalid filter type: %.*s", (int) len, cmd);
-}
diff --git a/filters/about-formatting.sh b/filters/about-formatting.sh
deleted file mode 100755
index 85daf9c..0000000
--- a/filters/about-formatting.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-
-# This may be used with the about-filter or repo.about-filter setting in cgitrc.
-# It passes formatting of about pages to differing programs, depending on the usage.
-
-# Markdown support requires python and markdown-python.
-# RestructuredText support requires python and docutils.
-# Man page support requires groff.
-
-# The following environment variables can be used to retrieve the configuration
-# of the repository for which this script is called:
-# CGIT_REPO_URL ( = repo.url setting )
-# CGIT_REPO_NAME ( = repo.name setting )
-# CGIT_REPO_PATH ( = repo.path setting )
-# CGIT_REPO_OWNER ( = repo.owner setting )
-# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
-# CGIT_REPO_SECTION ( = section setting )
-# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
-
-cd "$(dirname $0)/html-converters/"
-case "$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')" in
- *.markdown|*.mdown|*.md|*.mkd) exec ./md2html; ;;
- *.rst) exec ./rst2html; ;;
- *.[1-9]) exec ./man2html; ;;
- *.htm|*.html) exec cat; ;;
- *.txt|*) exec ./txt2html; ;;
-esac
diff --git a/filters/commit-links.sh b/filters/commit-links.sh
deleted file mode 100755
index 796ac30..0000000
--- a/filters/commit-links.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-# This script can be used to generate links in commit messages.
-#
-# To use this script, refer to this file with either the commit-filter or the
-# repo.commit-filter options in cgitrc.
-#
-# The following environment variables can be used to retrieve the configuration
-# of the repository for which this script is called:
-# CGIT_REPO_URL ( = repo.url setting )
-# CGIT_REPO_NAME ( = repo.name setting )
-# CGIT_REPO_PATH ( = repo.path setting )
-# CGIT_REPO_OWNER ( = repo.owner setting )
-# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
-# CGIT_REPO_SECTION ( = section setting )
-# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
-#
-
-regex=''
-
-# This expression generates links to commits referenced by their SHA1.
-regex=$regex'
-s|\b([0-9a-fA-F]{7,64})\b|<a href="./?id=\1">\1</a>|g'
-
-# This expression generates links to a fictional bugtracker.
-regex=$regex'
-s|#([0-9]+)\b|<a href="http://bugs.example.com/?bug=\1">#\1</a>|g'
-
-sed -re "$regex"
diff --git a/filters/email-gravatar.lua b/filters/email-gravatar.lua
deleted file mode 100644
index c39b490..0000000
--- a/filters/email-gravatar.lua
+++ /dev/null
@@ -1,35 +0,0 @@
--- This script may be used with the email-filter or repo.email-filter settings in cgitrc.
--- It adds gravatar icons to author names. It is designed to be used with the lua:
--- prefix in filters. It is much faster than the corresponding python script.
---
--- Requirements:
--- luaossl
--- <http://25thandclement.com/~william/projects/luaossl.html>
---
-
-local digest = require("openssl.digest")
-
-function md5_hex(input)
- local b = digest.new("md5"):final(input)
- local x = ""
- for i = 1, #b do
- x = x .. string.format("%.2x", string.byte(b, i))
- end
- return x
-end
-
-function filter_open(email, page)
- buffer = ""
- md5 = md5_hex(email:sub(2, -2):lower())
-end
-
-function filter_close()
- html("<img src='//www.gravatar.com/avatar/" .. md5 .. "?s=13&amp;d=retro' width='13' height='13' alt='Gravatar' /> " .. buffer)
- return 0
-end
-
-function filter_write(str)
- buffer = buffer .. str
-end
-
-
diff --git a/filters/email-gravatar.py b/filters/email-gravatar.py
deleted file mode 100755
index d70440e..0000000
--- a/filters/email-gravatar.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env python3
-
-# Please prefer the email-gravatar.lua using lua: as a prefix over this script. This
-# script is very slow, in comparison.
-#
-# This script may be used with the email-filter or repo.email-filter settings in cgitrc.
-#
-# The following environment variables can be used to retrieve the configuration
-# of the repository for which this script is called:
-# CGIT_REPO_URL ( = repo.url setting )
-# CGIT_REPO_NAME ( = repo.name setting )
-# CGIT_REPO_PATH ( = repo.path setting )
-# CGIT_REPO_OWNER ( = repo.owner setting )
-# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
-# CGIT_REPO_SECTION ( = section setting )
-# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
-#
-# It receives an email address on argv[1] and text on stdin. It prints
-# to stdout that text prepended by a gravatar at 10pt.
-
-import sys
-import hashlib
-import codecs
-
-email = sys.argv[1].lower().strip()
-if email[0] == '<':
- email = email[1:]
-if email[-1] == '>':
- email = email[0:-1]
-
-page = sys.argv[2]
-
-sys.stdin = codecs.getreader("utf-8")(sys.stdin.detach())
-sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
-
-md5 = hashlib.md5(email.encode()).hexdigest()
-text = sys.stdin.read().strip()
-
-print("<img src='//www.gravatar.com/avatar/" + md5 + "?s=13&amp;d=retro' width='13' height='13' alt='Gravatar' /> " + text)
diff --git a/filters/email-libravatar.lua b/filters/email-libravatar.lua
deleted file mode 100644
index 7336baf..0000000
--- a/filters/email-libravatar.lua
+++ /dev/null
@@ -1,36 +0,0 @@
--- This script may be used with the email-filter or repo.email-filter settings in cgitrc.
--- It adds libravatar icons to author names. It is designed to be used with the lua:
--- prefix in filters.
---
--- Requirements:
--- luaossl
--- <http://25thandclement.com/~william/projects/luaossl.html>
---
-
-local digest = require("openssl.digest")
-
-function md5_hex(input)
- local b = digest.new("md5"):final(input)
- local x = ""
- for i = 1, #b do
- x = x .. string.format("%.2x", string.byte(b, i))
- end
- return x
-end
-
-function filter_open(email, page)
- buffer = ""
- md5 = md5_hex(email:sub(2, -2):lower())
-end
-
-function filter_close()
- baseurl = os.getenv("HTTPS") and "https://seccdn.libravatar.org/" or "http://cdn.libravatar.org/"
- html("<img src='" .. baseurl .. "avatar/" .. md5 .. "?s=13&amp;d=retro' width='13' height='13' alt='Libravatar' /> " .. buffer)
- return 0
-end
-
-function filter_write(str)
- buffer = buffer .. str
-end
-
-
diff --git a/filters/file-authentication.lua b/filters/file-authentication.lua
deleted file mode 100644
index 0248804..0000000
--- a/filters/file-authentication.lua
+++ /dev/null
@@ -1,359 +0,0 @@
--- This script may be used with the auth-filter.
---
--- Requirements:
--- luaossl
--- <http://25thandclement.com/~william/projects/luaossl.html>
--- luaposix
--- <https://github.com/luaposix/luaposix>
---
-local sysstat = require("posix.sys.stat")
-local unistd = require("posix.unistd")
-local rand = require("openssl.rand")
-local hmac = require("openssl.hmac")
-
--- This file should contain a series of lines in the form of:
--- username1:hash1
--- username2:hash2
--- username3:hash3
--- ...
--- Hashes can be generated using something like `mkpasswd -m sha-512 -R 300000`.
--- This file should not be world-readable.
-local users_filename = "/etc/cgit-auth/users"
-
--- This file should contain a series of lines in the form of:
--- groupname1:username1,username2,username3,...
--- ...
-local groups_filename = "/etc/cgit-auth/groups"
-
--- This file should contain a series of lines in the form of:
--- reponame1:groupname1,groupname2,groupname3,...
--- ...
-local repos_filename = "/etc/cgit-auth/repos"
-
--- Set this to a path this script can write to for storing a persistent
--- cookie secret, which should not be world-readable.
-local secret_filename = "/var/cache/cgit/auth-secret"
-
---
---
--- Authentication functions follow below. Swap these out if you want different authentication semantics.
---
---
-
--- Looks up a hash for a given user.
-function lookup_hash(user)
- local line
- for line in io.lines(users_filename) do
- local u, h = string.match(line, "(.-):(.+)")
- if u:lower() == user:lower() then
- return h
- end
- end
- return nil
-end
-
--- Looks up users for a given repo.
-function lookup_users(repo)
- local users = nil
- local groups = nil
- local line, group, user
- for line in io.lines(repos_filename) do
- local r, g = string.match(line, "(.-):(.+)")
- if r == repo then
- groups = { }
- for group in string.gmatch(g, "([^,]+)") do
- groups[group:lower()] = true
- end
- break
- end
- end
- if groups == nil then
- return nil
- end
- for line in io.lines(groups_filename) do
- local g, u = string.match(line, "(.-):(.+)")
- if groups[g:lower()] then
- if users == nil then
- users = { }
- end
- for user in string.gmatch(u, "([^,]+)") do
- users[user:lower()] = true
- end
- end
- end
- return users
-end
-
-
--- Sets HTTP cookie headers based on post and sets up redirection.
-function authenticate_post()
- local hash = lookup_hash(post["username"])
- local redirect = validate_value("redirect", post["redirect"])
-
- if redirect == nil then
- not_found()
- return 0
- end
-
- redirect_to(redirect)
-
- if hash == nil or hash ~= unistd.crypt(post["password"], hash) then
- set_cookie("cgitauth", "")
- else
- -- One week expiration time
- local username = secure_value("username", post["username"], os.time() + 604800)
- set_cookie("cgitauth", username)
- end
-
- html("\n")
- return 0
-end
-
-
--- Returns 1 if the cookie is valid and 0 if it is not.
-function authenticate_cookie()
- accepted_users = lookup_users(cgit["repo"])
- if accepted_users == nil then
- -- We return as valid if the repo is not protected.
- return 1
- end
-
- local username = validate_value("username", get_cookie(http["cookie"], "cgitauth"))
- if username == nil or not accepted_users[username:lower()] then
- return 0
- else
- return 1
- end
-end
-
--- Prints the html for the login form.
-function body()
- html("<h2>Authentication Required</h2>")
- html("<form method='post' action='")
- html_attr(cgit["login"])
- html("'>")
- html("<input type='hidden' name='redirect' value='")
- html_attr(secure_value("redirect", cgit["url"], 0))
- html("' />")
- html("<table>")
- html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autofocus /></td></tr>")
- html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' /></td></tr>")
- html("<tr><td colspan='2'><input value='Login' type='submit' /></td></tr>")
- html("</table></form>")
-
- return 0
-end
-
-
-
---
---
--- Wrapper around filter API, exposing the http table, the cgit table, and the post table to the above functions.
---
---
-
-local actions = {}
-actions["authenticate-post"] = authenticate_post
-actions["authenticate-cookie"] = authenticate_cookie
-actions["body"] = body
-
-function filter_open(...)
- action = actions[select(1, ...)]
-
- http = {}
- http["cookie"] = select(2, ...)
- http["method"] = select(3, ...)
- http["query"] = select(4, ...)
- http["referer"] = select(5, ...)
- http["path"] = select(6, ...)
- http["host"] = select(7, ...)
- http["https"] = select(8, ...)
-
- cgit = {}
- cgit["repo"] = select(9, ...)
- cgit["page"] = select(10, ...)
- cgit["url"] = select(11, ...)
- cgit["login"] = select(12, ...)
-
-end
-
-function filter_close()
- return action()
-end
-
-function filter_write(str)
- post = parse_qs(str)
-end
-
-
---
---
--- Utility functions based on keplerproject/wsapi.
---
---
-
-function url_decode(str)
- if not str then
- return ""
- end
- str = string.gsub(str, "+", " ")
- str = string.gsub(str, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end)
- str = string.gsub(str, "\r\n", "\n")
- return str
-end
-
-function url_encode(str)
- if not str then
- return ""
- end
- str = string.gsub(str, "\n", "\r\n")
- str = string.gsub(str, "([^%w ])", function(c) return string.format("%%%02X", string.byte(c)) end)
- str = string.gsub(str, " ", "+")
- return str
-end
-
-function parse_qs(qs)
- local tab = {}
- for key, val in string.gmatch(qs, "([^&=]+)=([^&=]*)&?") do
- tab[url_decode(key)] = url_decode(val)
- end
- return tab
-end
-
-function get_cookie(cookies, name)
- cookies = string.gsub(";" .. cookies .. ";", "%s*;%s*", ";")
- return url_decode(string.match(cookies, ";" .. name .. "=(.-);"))
-end
-
-function tohex(b)
- local x = ""
- for i = 1, #b do
- x = x .. string.format("%.2x", string.byte(b, i))
- end
- return x
-end
-
---
---
--- Cookie construction and validation helpers.
---
---
-
-local secret = nil
-
--- Loads a secret from a file, creates a secret, or returns one from memory.
-function get_secret()
- if secret ~= nil then
- return secret
- end
- local secret_file = io.open(secret_filename, "r")
- if secret_file == nil then
- local old_umask = sysstat.umask(63)
- local temporary_filename = secret_filename .. ".tmp." .. tohex(rand.bytes(16))
- local temporary_file = io.open(temporary_filename, "w")
- if temporary_file == nil then
- os.exit(177)
- end
- temporary_file:write(tohex(rand.bytes(32)))
- temporary_file:close()
- unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same.
- unistd.unlink(temporary_filename)
- sysstat.umask(old_umask)
- secret_file = io.open(secret_filename, "r")
- end
- if secret_file == nil then
- os.exit(177)
- end
- secret = secret_file:read()
- secret_file:close()
- if secret:len() ~= 64 then
- os.exit(177)
- end
- return secret
-end
-
--- Returns value of cookie if cookie is valid. Otherwise returns nil.
-function validate_value(expected_field, cookie)
- local i = 0
- local value = ""
- local field = ""
- local expiration = 0
- local salt = ""
- local chmac = ""
-
- if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then
- return nil
- end
-
- for component in string.gmatch(cookie, "[^|]+") do
- if i == 0 then
- field = component
- elseif i == 1 then
- value = component
- elseif i == 2 then
- expiration = tonumber(component)
- if expiration == nil then
- expiration = -1
- end
- elseif i == 3 then
- salt = component
- elseif i == 4 then
- chmac = component
- else
- break
- end
- i = i + 1
- end
-
- if chmac == nil or chmac:len() == 0 then
- return nil
- end
-
- -- Lua hashes strings, so these comparisons are time invariant.
- if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then
- return nil
- end
-
- if expiration == -1 or (expiration ~= 0 and expiration <= os.time()) then
- return nil
- end
-
- if url_decode(field) ~= expected_field then
- return nil
- end
-
- return url_decode(value)
-end
-
-function secure_value(field, value, expiration)
- if value == nil or value:len() <= 0 then
- return ""
- end
-
- local authstr = ""
- local salt = tohex(rand.bytes(16))
- value = url_encode(value)
- field = url_encode(field)
- authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt
- authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr))
- return authstr
-end
-
-function set_cookie(cookie, value)
- html("Set-Cookie: " .. cookie .. "=" .. value .. "; HttpOnly")
- if http["https"] == "yes" or http["https"] == "on" or http["https"] == "1" then
- html("; secure")
- end
- html("\n")
-end
-
-function redirect_to(url)
- html("Status: 302 Redirect\n")
- html("Cache-Control: no-cache, no-store\n")
- html("Location: " .. url .. "\n")
-end
-
-function not_found()
- html("Status: 404 Not Found\n")
- html("Cache-Control: no-cache, no-store\n\n")
-end
diff --git a/filters/gentoo-ldap-authentication.lua b/filters/gentoo-ldap-authentication.lua
deleted file mode 100644
index 673c88d..0000000
--- a/filters/gentoo-ldap-authentication.lua
+++ /dev/null
@@ -1,360 +0,0 @@
--- This script may be used with the auth-filter. Be sure to configure it as you wish.
---
--- Requirements:
--- luaossl
--- <http://25thandclement.com/~william/projects/luaossl.html>
--- lualdap >= 1.2
--- <https://git.zx2c4.com/lualdap/about/>
--- luaposix
--- <https://github.com/luaposix/luaposix>
---
-local sysstat = require("posix.sys.stat")
-local unistd = require("posix.unistd")
-local lualdap = require("lualdap")
-local rand = require("openssl.rand")
-local hmac = require("openssl.hmac")
-
---
---
--- Configure these variables for your settings.
---
---
-
--- A list of password protected repositories, with which gentooAccess
--- group is allowed to access each one.
-local protected_repos = {
- glouglou = "infra",
- portage = "dev"
-}
-
--- Set this to a path this script can write to for storing a persistent
--- cookie secret, which should be guarded.
-local secret_filename = "/var/cache/cgit/auth-secret"
-
-
---
---
--- Authentication functions follow below. Swap these out if you want different authentication semantics.
---
---
-
--- Sets HTTP cookie headers based on post and sets up redirection.
-function authenticate_post()
- local redirect = validate_value("redirect", post["redirect"])
-
- if redirect == nil then
- not_found()
- return 0
- end
-
- redirect_to(redirect)
-
- local groups = gentoo_ldap_user_groups(post["username"], post["password"])
- if groups == nil then
- set_cookie("cgitauth", "")
- else
- -- One week expiration time
- set_cookie("cgitauth", secure_value("gentoogroups", table.concat(groups, ","), os.time() + 604800))
- end
-
- html("\n")
- return 0
-end
-
-
--- Returns 1 if the cookie is valid and 0 if it is not.
-function authenticate_cookie()
- local required_group = protected_repos[cgit["repo"]]
- if required_group == nil then
- -- We return as valid if the repo is not protected.
- return 1
- end
-
- local user_groups = validate_value("gentoogroups", get_cookie(http["cookie"], "cgitauth"))
- if user_groups == nil or user_groups == "" then
- return 0
- end
- for group in string.gmatch(user_groups, "[^,]+") do
- if group == required_group then
- return 1
- end
- end
- return 0
-end
-
--- Prints the html for the login form.
-function body()
- html("<h2>Gentoo LDAP Authentication Required</h2>")
- html("<form method='post' action='")
- html_attr(cgit["login"])
- html("'>")
- html("<input type='hidden' name='redirect' value='")
- html_attr(secure_value("redirect", cgit["url"], 0))
- html("' />")
- html("<table>")
- html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autofocus /></td></tr>")
- html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' /></td></tr>")
- html("<tr><td colspan='2'><input value='Login' type='submit' /></td></tr>")
- html("</table></form>")
-
- return 0
-end
-
---
---
--- Gentoo LDAP support.
---
---
-
-function gentoo_ldap_user_groups(username, password)
- -- Ensure the user is alphanumeric
- if username == nil or username:match("%W") then
- return nil
- end
-
- local who = "uid=" .. username .. ",ou=devs,dc=gentoo,dc=org"
-
- local ldap, err = lualdap.open_simple {
- uri = "ldap://ldap1.gentoo.org",
- who = who,
- password = password,
- starttls = true,
- certfile = "/var/www/uwsgi/cgit/gentoo-ldap/star.gentoo.org.crt",
- keyfile = "/var/www/uwsgi/cgit/gentoo-ldap/star.gentoo.org.key",
- cacertfile = "/var/www/uwsgi/cgit/gentoo-ldap/ca.pem"
- }
- if ldap == nil then
- return nil
- end
-
- local group_suffix = ".group"
- local group_suffix_len = group_suffix:len()
- local groups = {}
- for dn, attribs in ldap:search { base = who, scope = "subtree" } do
- local access = attribs["gentooAccess"]
- if dn == who and access ~= nil then
- for i, v in ipairs(access) do
- local vlen = v:len()
- if vlen > group_suffix_len and v:sub(-group_suffix_len) == group_suffix then
- table.insert(groups, v:sub(1, vlen - group_suffix_len))
- end
- end
- end
- end
-
- ldap:close()
-
- return groups
-end
-
---
---
--- Wrapper around filter API, exposing the http table, the cgit table, and the post table to the above functions.
---
---
-
-local actions = {}
-actions["authenticate-post"] = authenticate_post
-actions["authenticate-cookie"] = authenticate_cookie
-actions["body"] = body
-
-function filter_open(...)
- action = actions[select(1, ...)]
-
- http = {}
- http["cookie"] = select(2, ...)
- http["method"] = select(3, ...)
- http["query"] = select(4, ...)
- http["referer"] = select(5, ...)
- http["path"] = select(6, ...)
- http["host"] = select(7, ...)
- http["https"] = select(8, ...)
-
- cgit = {}
- cgit["repo"] = select(9, ...)
- cgit["page"] = select(10, ...)
- cgit["url"] = select(11, ...)
- cgit["login"] = select(12, ...)
-
-end
-
-function filter_close()
- return action()
-end
-
-function filter_write(str)
- post = parse_qs(str)
-end
-
-
---
---
--- Utility functions based on keplerproject/wsapi.
---
---
-
-function url_decode(str)
- if not str then
- return ""
- end
- str = string.gsub(str, "+", " ")
- str = string.gsub(str, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end)
- str = string.gsub(str, "\r\n", "\n")
- return str
-end
-
-function url_encode(str)
- if not str then
- return ""
- end
- str = string.gsub(str, "\n", "\r\n")
- str = string.gsub(str, "([^%w ])", function(c) return string.format("%%%02X", string.byte(c)) end)
- str = string.gsub(str, " ", "+")
- return str
-end
-
-function parse_qs(qs)
- local tab = {}
- for key, val in string.gmatch(qs, "([^&=]+)=([^&=]*)&?") do
- tab[url_decode(key)] = url_decode(val)
- end
- return tab
-end
-
-function get_cookie(cookies, name)
- cookies = string.gsub(";" .. cookies .. ";", "%s*;%s*", ";")
- return string.match(cookies, ";" .. name .. "=(.-);")
-end
-
-function tohex(b)
- local x = ""
- for i = 1, #b do
- x = x .. string.format("%.2x", string.byte(b, i))
- end
- return x
-end
-
---
---
--- Cookie construction and validation helpers.
---
---
-
-local secret = nil
-
--- Loads a secret from a file, creates a secret, or returns one from memory.
-function get_secret()
- if secret ~= nil then
- return secret
- end
- local secret_file = io.open(secret_filename, "r")
- if secret_file == nil then
- local old_umask = sysstat.umask(63)
- local temporary_filename = secret_filename .. ".tmp." .. tohex(rand.bytes(16))
- local temporary_file = io.open(temporary_filename, "w")
- if temporary_file == nil then
- os.exit(177)
- end
- temporary_file:write(tohex(rand.bytes(32)))
- temporary_file:close()
- unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same.
- unistd.unlink(temporary_filename)
- sysstat.umask(old_umask)
- secret_file = io.open(secret_filename, "r")
- end
- if secret_file == nil then
- os.exit(177)
- end
- secret = secret_file:read()
- secret_file:close()
- if secret:len() ~= 64 then
- os.exit(177)
- end
- return secret
-end
-
--- Returns value of cookie if cookie is valid. Otherwise returns nil.
-function validate_value(expected_field, cookie)
- local i = 0
- local value = ""
- local field = ""
- local expiration = 0
- local salt = ""
- local chmac = ""
-
- if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then
- return nil
- end
-
- for component in string.gmatch(cookie, "[^|]+") do
- if i == 0 then
- field = component
- elseif i == 1 then
- value = component
- elseif i == 2 then
- expiration = tonumber(component)
- if expiration == nil then
- expiration = -1
- end
- elseif i == 3 then
- salt = component
- elseif i == 4 then
- chmac = component
- else
- break
- end
- i = i + 1
- end
-
- if chmac == nil or chmac:len() == 0 then
- return nil
- end
-
- -- Lua hashes strings, so these comparisons are time invariant.
- if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then
- return nil
- end
-
- if expiration == -1 or (expiration ~= 0 and expiration <= os.time()) then
- return nil
- end
-
- if url_decode(field) ~= expected_field then
- return nil
- end
-
- return url_decode(value)
-end
-
-function secure_value(field, value, expiration)
- if value == nil or value:len() <= 0 then
- return ""
- end
-
- local authstr = ""
- local salt = tohex(rand.bytes(16))
- value = url_encode(value)
- field = url_encode(field)
- authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt
- authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr))
- return authstr
-end
-
-function set_cookie(cookie, value)
- html("Set-Cookie: " .. cookie .. "=" .. value .. "; HttpOnly")
- if http["https"] == "yes" or http["https"] == "on" or http["https"] == "1" then
- html("; secure")
- end
- html("\n")
-end
-
-function redirect_to(url)
- html("Status: 302 Redirect\n")
- html("Cache-Control: no-cache, no-store\n")
- html("Location: " .. url .. "\n")
-end
-
-function not_found()
- html("Status: 404 Not Found\n")
- html("Cache-Control: no-cache, no-store\n\n")
-end
diff --git a/filters/html-converters/man2html b/filters/html-converters/man2html
deleted file mode 100755
index 0ef7884..0000000
--- a/filters/html-converters/man2html
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-echo "<div style=\"font-family: monospace\">"
-groff -mandoc -T html -P -r -P -l | egrep -v '(<html>|<head>|<meta|<title>|</title>|</head>|<body>|</body>|</html>|<!DOCTYPE|"http://www.w3.org)'
-echo "</div>"
diff --git a/filters/html-converters/md2html b/filters/html-converters/md2html
deleted file mode 100755
index 59f43a8..0000000
--- a/filters/html-converters/md2html
+++ /dev/null
@@ -1,304 +0,0 @@
-#!/usr/bin/env python3
-import markdown
-import sys
-import io
-from pygments.formatters import HtmlFormatter
-from markdown.extensions.toc import TocExtension
-sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
-sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
-sys.stdout.write('''
-<style>
-.markdown-body {
- font-size: 14px;
- line-height: 1.6;
- overflow: hidden;
-}
-.markdown-body>*:first-child {
- margin-top: 0 !important;
-}
-.markdown-body>*:last-child {
- margin-bottom: 0 !important;
-}
-.markdown-body a.absent {
- color: #c00;
-}
-.markdown-body a.anchor {
- display: block;
- padding-left: 30px;
- margin-left: -30px;
- cursor: pointer;
- position: absolute;
- top: 0;
- left: 0;
- bottom: 0;
-}
-.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6 {
- margin: 20px 0 10px;
- padding: 0;
- font-weight: bold;
- -webkit-font-smoothing: antialiased;
- cursor: text;
- position: relative;
-}
-.markdown-body h1 .mini-icon-link, .markdown-body h2 .mini-icon-link, .markdown-body h3 .mini-icon-link, .markdown-body h4 .mini-icon-link, .markdown-body h5 .mini-icon-link, .markdown-body h6 .mini-icon-link {
- display: none;
- color: #000;
-}
-.markdown-body h1:hover a.anchor, .markdown-body h2:hover a.anchor, .markdown-body h3:hover a.anchor, .markdown-body h4:hover a.anchor, .markdown-body h5:hover a.anchor, .markdown-body h6:hover a.anchor {
- text-decoration: none;
- line-height: 1;
- padding-left: 0;
- margin-left: -22px;
- top: 15%;
-}
-.markdown-body h1:hover a.anchor .mini-icon-link, .markdown-body h2:hover a.anchor .mini-icon-link, .markdown-body h3:hover a.anchor .mini-icon-link, .markdown-body h4:hover a.anchor .mini-icon-link, .markdown-body h5:hover a.anchor .mini-icon-link, .markdown-body h6:hover a.anchor .mini-icon-link {
- display: inline-block;
-}
-div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div#cgit .markdown-body h3 a.toclink, div#cgit .markdown-body h4 a.toclink, div#cgit .markdown-body h5 a.toclink, div#cgit .markdown-body h6 a.toclink {
- color: black;
-}
-.markdown-body h1 tt, .markdown-body h1 code, .markdown-body h2 tt, .markdown-body h2 code, .markdown-body h3 tt, .markdown-body h3 code, .markdown-body h4 tt, .markdown-body h4 code, .markdown-body h5 tt, .markdown-body h5 code, .markdown-body h6 tt, .markdown-body h6 code {
- font-size: inherit;
-}
-.markdown-body h1 {
- font-size: 28px;
- color: #000;
-}
-.markdown-body h2 {
- font-size: 24px;
- border-bottom: 1px solid #ccc;
- color: #000;
-}
-.markdown-body h3 {
- font-size: 18px;
-}
-.markdown-body h4 {
- font-size: 16px;
-}
-.markdown-body h5 {
- font-size: 14px;
-}
-.markdown-body h6 {
- color: #777;
- font-size: 14px;
-}
-.markdown-body p, .markdown-body blockquote, .markdown-body ul, .markdown-body ol, .markdown-body dl, .markdown-body table, .markdown-body pre {
- margin: 15px 0;
-}
-.markdown-body hr {
- border: 2px solid #ccc;
-}
-.markdown-body>h2:first-child, .markdown-body>h1:first-child, .markdown-body>h1:first-child+h2, .markdown-body>h3:first-child, .markdown-body>h4:first-child, .markdown-body>h5:first-child, .markdown-body>h6:first-child {
- margin-top: 0;
- padding-top: 0;
-}
-.markdown-body a:first-child h1, .markdown-body a:first-child h2, .markdown-body a:first-child h3, .markdown-body a:first-child h4, .markdown-body a:first-child h5, .markdown-body a:first-child h6 {
- margin-top: 0;
- padding-top: 0;
-}
-.markdown-body h1+p, .markdown-body h2+p, .markdown-body h3+p, .markdown-body h4+p, .markdown-body h5+p, .markdown-body h6+p {
- margin-top: 0;
-}
-.markdown-body li p.first {
- display: inline-block;
-}
-.markdown-body ul, .markdown-body ol {
- padding-left: 30px;
-}
-.markdown-body ul.no-list, .markdown-body ol.no-list {
- list-style-type: none;
- padding: 0;
-}
-.markdown-body ul li>:first-child, .markdown-body ul li ul:first-of-type, .markdown-body ul li ol:first-of-type, .markdown-body ol li>:first-child, .markdown-body ol li ul:first-of-type, .markdown-body ol li ol:first-of-type {
- margin-top: 0px;
-}
-.markdown-body ul li p:last-of-type, .markdown-body ol li p:last-of-type {
- margin-bottom: 0;
-}
-.markdown-body ul ul, .markdown-body ul ol, .markdown-body ol ol, .markdown-body ol ul {
- margin-bottom: 0;
-}
-.markdown-body dl {
- padding: 0;
-}
-.markdown-body dl dt {
- font-size: 14px;
- font-weight: bold;
- font-style: italic;
- padding: 0;
- margin: 15px 0 5px;
-}
-.markdown-body dl dt:first-child {
- padding: 0;
-}
-.markdown-body dl dt>:first-child {
- margin-top: 0px;
-}
-.markdown-body dl dt>:last-child {
- margin-bottom: 0px;
-}
-.markdown-body dl dd {
- margin: 0 0 15px;
- padding: 0 15px;
-}
-.markdown-body dl dd>:first-child {
- margin-top: 0px;
-}
-.markdown-body dl dd>:last-child {
- margin-bottom: 0px;
-}
-.markdown-body blockquote {
- border-left: 4px solid #DDD;
- padding: 0 15px;
- color: #777;
-}
-.markdown-body blockquote>:first-child {
- margin-top: 0px;
-}
-.markdown-body blockquote>:last-child {
- margin-bottom: 0px;
-}
-.markdown-body table th {
- font-weight: bold;
-}
-.markdown-body table th, .markdown-body table td {
- border: 1px solid #ccc;
- padding: 6px 13px;
-}
-.markdown-body table tr {
- border-top: 1px solid #ccc;
- background-color: #fff;
-}
-.markdown-body table tr:nth-child(2n) {
- background-color: #f8f8f8;
-}
-.markdown-body img {
- max-width: 100%;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.markdown-body span.frame {
- display: block;
- overflow: hidden;
-}
-.markdown-body span.frame>span {
- border: 1px solid #ddd;
- display: block;
- float: left;
- overflow: hidden;
- margin: 13px 0 0;
- padding: 7px;
- width: auto;
-}
-.markdown-body span.frame span img {
- display: block;
- float: left;
-}
-.markdown-body span.frame span span {
- clear: both;
- color: #333;
- display: block;
- padding: 5px 0 0;
-}
-.markdown-body span.align-center {
- display: block;
- overflow: hidden;
- clear: both;
-}
-.markdown-body span.align-center>span {
- display: block;
- overflow: hidden;
- margin: 13px auto 0;
- text-align: center;
-}
-.markdown-body span.align-center span img {
- margin: 0 auto;
- text-align: center;
-}
-.markdown-body span.align-right {
- display: block;
- overflow: hidden;
- clear: both;
-}
-.markdown-body span.align-right>span {
- display: block;
- overflow: hidden;
- margin: 13px 0 0;
- text-align: right;
-}
-.markdown-body span.align-right span img {
- margin: 0;
- text-align: right;
-}
-.markdown-body span.float-left {
- display: block;
- margin-right: 13px;
- overflow: hidden;
- float: left;
-}
-.markdown-body span.float-left span {
- margin: 13px 0 0;
-}
-.markdown-body span.float-right {
- display: block;
- margin-left: 13px;
- overflow: hidden;
- float: right;
-}
-.markdown-body span.float-right>span {
- display: block;
- overflow: hidden;
- margin: 13px auto 0;
- text-align: right;
-}
-.markdown-body code, .markdown-body tt {
- margin: 0 2px;
- padding: 0px 5px;
- border: 1px solid #eaeaea;
- background-color: #f8f8f8;
- border-radius: 3px;
-}
-.markdown-body code {
- white-space: nowrap;
-}
-.markdown-body pre>code {
- margin: 0;
- padding: 0;
- white-space: pre;
- border: none;
- background: transparent;
-}
-.markdown-body .highlight pre, .markdown-body pre {
- background-color: #f8f8f8;
- border: 1px solid #ccc;
- font-size: 13px;
- line-height: 19px;
- overflow: auto;
- padding: 6px 10px;
- border-radius: 3px;
-}
-.markdown-body pre code, .markdown-body pre tt {
- margin: 0;
- padding: 0;
- background-color: transparent;
- border: none;
-}
-''')
-sys.stdout.write(HtmlFormatter(style='pastie').get_style_defs('.highlight'))
-sys.stdout.write('''
-</style>
-''')
-sys.stdout.write("<div class='markdown-body'>")
-sys.stdout.flush()
-# Note: you may want to run this through bleach for sanitization
-markdown.markdownFromFile(
- output_format="html5",
- extensions=[
- "markdown.extensions.fenced_code",
- "markdown.extensions.codehilite",
- "markdown.extensions.tables",
- "markdown.extensions.sane_lists",
- TocExtension(anchorlink=True)],
- extension_configs={
- "markdown.extensions.codehilite":{"css_class":"highlight"}})
-sys.stdout.write("</div>")
diff --git a/filters/html-converters/rst2html b/filters/html-converters/rst2html
deleted file mode 100755
index 02d90f8..0000000
--- a/filters/html-converters/rst2html
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-exec rst2html.py --template <(echo -e "%(stylesheet)s\n%(body_pre_docinfo)s\n%(docinfo)s\n%(body)s")
diff --git a/filters/html-converters/txt2html b/filters/html-converters/txt2html
deleted file mode 100755
index 495eece..0000000
--- a/filters/html-converters/txt2html
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-echo "<pre>"
-sed "s|&|\\&amp;|g;s|'|\\&apos;|g;s|\"|\\&quot;|g;s|<|\\&lt;|g;s|>|\\&gt;|g"
-echo "</pre>"
diff --git a/filters/owner-example.lua b/filters/owner-example.lua
deleted file mode 100644
index 50fc25a..0000000
--- a/filters/owner-example.lua
+++ /dev/null
@@ -1,17 +0,0 @@
--- This script is an example of an owner-filter. It replaces the
--- usual query link with one to a fictional homepage. This script may
--- be used with the owner-filter or repo.owner-filter settings in
--- cgitrc with the `lua:` prefix.
-
-function filter_open()
- buffer = ""
-end
-
-function filter_close()
- html(string.format("<a href=\"%s\">%s</a>", "http://wiki.example.com/about/" .. buffer, buffer))
- return 0
-end
-
-function filter_write(str)
- buffer = buffer .. str
-end
diff --git a/filters/simple-authentication.lua b/filters/simple-authentication.lua
deleted file mode 100644
index 23d3457..0000000
--- a/filters/simple-authentication.lua
+++ /dev/null
@@ -1,314 +0,0 @@
--- This script may be used with the auth-filter. Be sure to configure it as you wish.
---
--- Requirements:
--- luaossl
--- <http://25thandclement.com/~william/projects/luaossl.html>
--- luaposix
--- <https://github.com/luaposix/luaposix>
---
-local sysstat = require("posix.sys.stat")
-local unistd = require("posix.unistd")
-local rand = require("openssl.rand")
-local hmac = require("openssl.hmac")
-
---
---
--- Configure these variables for your settings.
---
---
-
--- A list of password protected repositories along with the users who can access them.
-local protected_repos = {
- glouglou = { laurent = true, jason = true },
- qt = { jason = true, bob = true }
-}
-
--- A list of users and hashes, generated with `mkpasswd -m sha-512 -R 300000`.
-local users = {
- jason = "$6$rounds=300000$YYJct3n/o.ruYK$HhpSeuCuW1fJkpvMZOZzVizeLsBKcGA/aF2UPuV5v60JyH2MVSG6P511UMTj2F3H75.IT2HIlnvXzNb60FcZH1",
- laurent = "$6$rounds=300000$dP0KNHwYb3JKigT$pN/LG7rWxQ4HniFtx5wKyJXBJUKP7R01zTNZ0qSK/aivw8ywGAOdfYiIQFqFhZFtVGvr11/7an.nesvm8iJUi.",
- bob = "$6$rounds=300000$jCLCCt6LUpTz$PI1vvd1yaVYcCzqH8QAJFcJ60b6W/6sjcOsU7mAkNo7IE8FRGW1vkjF8I/T5jt/auv5ODLb1L4S2s.CAyZyUC"
-}
-
--- Set this to a path this script can write to for storing a persistent
--- cookie secret, which should be guarded.
-local secret_filename = "/var/cache/cgit/auth-secret"
-
---
---
--- Authentication functions follow below. Swap these out if you want different authentication semantics.
---
---
-
--- Sets HTTP cookie headers based on post and sets up redirection.
-function authenticate_post()
- local hash = users[post["username"]]
- local redirect = validate_value("redirect", post["redirect"])
-
- if redirect == nil then
- not_found()
- return 0
- end
-
- redirect_to(redirect)
-
- if hash == nil or hash ~= unistd.crypt(post["password"], hash) then
- set_cookie("cgitauth", "")
- else
- -- One week expiration time
- local username = secure_value("username", post["username"], os.time() + 604800)
- set_cookie("cgitauth", username)
- end
-
- html("\n")
- return 0
-end
-
-
--- Returns 1 if the cookie is valid and 0 if it is not.
-function authenticate_cookie()
- accepted_users = protected_repos[cgit["repo"]]
- if accepted_users == nil then
- -- We return as valid if the repo is not protected.
- return 1
- end
-
- local username = validate_value("username", get_cookie(http["cookie"], "cgitauth"))
- if username == nil or not accepted_users[username:lower()] then
- return 0
- else
- return 1
- end
-end
-
--- Prints the html for the login form.
-function body()
- html("<h2>Authentication Required</h2>")
- html("<form method='post' action='")
- html_attr(cgit["login"])
- html("'>")
- html("<input type='hidden' name='redirect' value='")
- html_attr(secure_value("redirect", cgit["url"], 0))
- html("' />")
- html("<table>")
- html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autofocus /></td></tr>")
- html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' /></td></tr>")
- html("<tr><td colspan='2'><input value='Login' type='submit' /></td></tr>")
- html("</table></form>")
-
- return 0
-end
-
-
-
---
---
--- Wrapper around filter API, exposing the http table, the cgit table, and the post table to the above functions.
---
---
-
-local actions = {}
-actions["authenticate-post"] = authenticate_post
-actions["authenticate-cookie"] = authenticate_cookie
-actions["body"] = body
-
-function filter_open(...)
- action = actions[select(1, ...)]
-
- http = {}
- http["cookie"] = select(2, ...)
- http["method"] = select(3, ...)
- http["query"] = select(4, ...)
- http["referer"] = select(5, ...)
- http["path"] = select(6, ...)
- http["host"] = select(7, ...)
- http["https"] = select(8, ...)
-
- cgit = {}
- cgit["repo"] = select(9, ...)
- cgit["page"] = select(10, ...)
- cgit["url"] = select(11, ...)
- cgit["login"] = select(12, ...)
-
-end
-
-function filter_close()
- return action()
-end
-
-function filter_write(str)
- post = parse_qs(str)
-end
-
-
---
---
--- Utility functions based on keplerproject/wsapi.
---
---
-
-function url_decode(str)
- if not str then
- return ""
- end
- str = string.gsub(str, "+", " ")
- str = string.gsub(str, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end)
- str = string.gsub(str, "\r\n", "\n")
- return str
-end
-
-function url_encode(str)
- if not str then
- return ""
- end
- str = string.gsub(str, "\n", "\r\n")
- str = string.gsub(str, "([^%w ])", function(c) return string.format("%%%02X", string.byte(c)) end)
- str = string.gsub(str, " ", "+")
- return str
-end
-
-function parse_qs(qs)
- local tab = {}
- for key, val in string.gmatch(qs, "([^&=]+)=([^&=]*)&?") do
- tab[url_decode(key)] = url_decode(val)
- end
- return tab
-end
-
-function get_cookie(cookies, name)
- cookies = string.gsub(";" .. cookies .. ";", "%s*;%s*", ";")
- return url_decode(string.match(cookies, ";" .. name .. "=(.-);"))
-end
-
-function tohex(b)
- local x = ""
- for i = 1, #b do
- x = x .. string.format("%.2x", string.byte(b, i))
- end
- return x
-end
-
---
---
--- Cookie construction and validation helpers.
---
---
-
-local secret = nil
-
--- Loads a secret from a file, creates a secret, or returns one from memory.
-function get_secret()
- if secret ~= nil then
- return secret
- end
- local secret_file = io.open(secret_filename, "r")
- if secret_file == nil then
- local old_umask = sysstat.umask(63)
- local temporary_filename = secret_filename .. ".tmp." .. tohex(rand.bytes(16))
- local temporary_file = io.open(temporary_filename, "w")
- if temporary_file == nil then
- os.exit(177)
- end
- temporary_file:write(tohex(rand.bytes(32)))
- temporary_file:close()
- unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same.
- unistd.unlink(temporary_filename)
- sysstat.umask(old_umask)
- secret_file = io.open(secret_filename, "r")
- end
- if secret_file == nil then
- os.exit(177)
- end
- secret = secret_file:read()
- secret_file:close()
- if secret:len() ~= 64 then
- os.exit(177)
- end
- return secret
-end
-
--- Returns value of cookie if cookie is valid. Otherwise returns nil.
-function validate_value(expected_field, cookie)
- local i = 0
- local value = ""
- local field = ""
- local expiration = 0
- local salt = ""
- local chmac = ""
-
- if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then
- return nil
- end
-
- for component in string.gmatch(cookie, "[^|]+") do
- if i == 0 then
- field = component
- elseif i == 1 then
- value = component
- elseif i == 2 then
- expiration = tonumber(component)
- if expiration == nil then
- expiration = -1
- end
- elseif i == 3 then
- salt = component
- elseif i == 4 then
- chmac = component
- else
- break
- end
- i = i + 1
- end
-
- if chmac == nil or chmac:len() == 0 then
- return nil
- end
-
- -- Lua hashes strings, so these comparisons are time invariant.
- if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then
- return nil
- end
-
- if expiration == -1 or (expiration ~= 0 and expiration <= os.time()) then
- return nil
- end
-
- if url_decode(field) ~= expected_field then
- return nil
- end
-
- return url_decode(value)
-end
-
-function secure_value(field, value, expiration)
- if value == nil or value:len() <= 0 then
- return ""
- end
-
- local authstr = ""
- local salt = tohex(rand.bytes(16))
- value = url_encode(value)
- field = url_encode(field)
- authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt
- authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr))
- return authstr
-end
-
-function set_cookie(cookie, value)
- html("Set-Cookie: " .. cookie .. "=" .. value .. "; HttpOnly")
- if http["https"] == "yes" or http["https"] == "on" or http["https"] == "1" then
- html("; secure")
- end
- html("\n")
-end
-
-function redirect_to(url)
- html("Status: 302 Redirect\n")
- html("Cache-Control: no-cache, no-store\n")
- html("Location: " .. url .. "\n")
-end
-
-function not_found()
- html("Status: 404 Not Found\n")
- html("Cache-Control: no-cache, no-store\n\n")
-end
diff --git a/filters/syntax-highlighting.py b/filters/syntax-highlighting.py
deleted file mode 100755
index e912594..0000000
--- a/filters/syntax-highlighting.py
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/env python3
-
-# This script uses Pygments and Python3. You must have both installed
-# for this to work.
-#
-# http://pygments.org/
-# http://python.org/
-#
-# It may be used with the source-filter or repo.source-filter settings
-# in cgitrc.
-#
-# The following environment variables can be used to retrieve the
-# configuration of the repository for which this script is called:
-# CGIT_REPO_URL ( = repo.url setting )
-# CGIT_REPO_NAME ( = repo.name setting )
-# CGIT_REPO_PATH ( = repo.path setting )
-# CGIT_REPO_OWNER ( = repo.owner setting )
-# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
-# CGIT_REPO_SECTION ( = section setting )
-# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
-
-
-import sys
-import io
-from pygments import highlight
-from pygments.util import ClassNotFound
-from pygments.lexers import TextLexer
-from pygments.lexers import guess_lexer
-from pygments.lexers import guess_lexer_for_filename
-from pygments.formatters import HtmlFormatter
-
-
-sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8', errors='replace')
-sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
-data = sys.stdin.read()
-filename = sys.argv[1]
-formatter = HtmlFormatter(style='pastie', nobackground=True)
-
-try:
- lexer = guess_lexer_for_filename(filename, data)
-except ClassNotFound:
- # check if there is any shebang
- if data[0:2] == '#!':
- lexer = guess_lexer(data)
- else:
- lexer = TextLexer()
-except TypeError:
- lexer = TextLexer()
-
-# highlight! :-)
-# printout pygments' css definitions as well
-sys.stdout.write('<style>')
-sys.stdout.write(formatter.get_style_defs('.highlight'))
-sys.stdout.write('</style>')
-sys.stdout.write(highlight(data, lexer, formatter, outfile=None))
diff --git a/filters/syntax-highlighting.sh b/filters/syntax-highlighting.sh
deleted file mode 100755
index 840bc34..0000000
--- a/filters/syntax-highlighting.sh
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/bin/sh
-# This script can be used to implement syntax highlighting in the cgit
-# tree-view by referring to this file with the source-filter or repo.source-
-# filter options in cgitrc.
-#
-# This script requires a shell supporting the ${var##pattern} syntax.
-# It is supported by at least dash and bash, however busybox environments
-# might have to use an external call to sed instead.
-#
-# Note: the highlight command (http://www.andre-simon.de/) uses css for syntax
-# highlighting, so you'll probably want something like the following included
-# in your css file:
-#
-# Style definition file generated by highlight 2.4.8, http://www.andre-simon.de/
-#
-# table.blob .num { color:#2928ff; }
-# table.blob .esc { color:#ff00ff; }
-# table.blob .str { color:#ff0000; }
-# table.blob .dstr { color:#818100; }
-# table.blob .slc { color:#838183; font-style:italic; }
-# table.blob .com { color:#838183; font-style:italic; }
-# table.blob .dir { color:#008200; }
-# table.blob .sym { color:#000000; }
-# table.blob .kwa { color:#000000; font-weight:bold; }
-# table.blob .kwb { color:#830000; }
-# table.blob .kwc { color:#000000; font-weight:bold; }
-# table.blob .kwd { color:#010181; }
-#
-#
-# Style definition file generated by highlight 2.6.14, http://www.andre-simon.de/
-#
-# body.hl { background-color:#ffffff; }
-# pre.hl { color:#000000; background-color:#ffffff; font-size:10pt; font-family:'Courier New';}
-# .hl.num { color:#2928ff; }
-# .hl.esc { color:#ff00ff; }
-# .hl.str { color:#ff0000; }
-# .hl.dstr { color:#818100; }
-# .hl.slc { color:#838183; font-style:italic; }
-# .hl.com { color:#838183; font-style:italic; }
-# .hl.dir { color:#008200; }
-# .hl.sym { color:#000000; }
-# .hl.line { color:#555555; }
-# .hl.mark { background-color:#ffffbb;}
-# .hl.kwa { color:#000000; font-weight:bold; }
-# .hl.kwb { color:#830000; }
-# .hl.kwc { color:#000000; font-weight:bold; }
-# .hl.kwd { color:#010181; }
-#
-#
-# Style definition file generated by highlight 3.8, http://www.andre-simon.de/
-#
-# body.hl { background-color:#e0eaee; }
-# pre.hl { color:#000000; background-color:#e0eaee; font-size:10pt; font-family:'Courier New';}
-# .hl.num { color:#b07e00; }
-# .hl.esc { color:#ff00ff; }
-# .hl.str { color:#bf0303; }
-# .hl.pps { color:#818100; }
-# .hl.slc { color:#838183; font-style:italic; }
-# .hl.com { color:#838183; font-style:italic; }
-# .hl.ppc { color:#008200; }
-# .hl.opt { color:#000000; }
-# .hl.lin { color:#555555; }
-# .hl.kwa { color:#000000; font-weight:bold; }
-# .hl.kwb { color:#0057ae; }
-# .hl.kwc { color:#000000; font-weight:bold; }
-# .hl.kwd { color:#010181; }
-#
-#
-# Style definition file generated by highlight 3.13, http://www.andre-simon.de/
-#
-# body.hl { background-color:#e0eaee; }
-# pre.hl { color:#000000; background-color:#e0eaee; font-size:10pt; font-family:'Courier New',monospace;}
-# .hl.num { color:#b07e00; }
-# .hl.esc { color:#ff00ff; }
-# .hl.str { color:#bf0303; }
-# .hl.pps { color:#818100; }
-# .hl.slc { color:#838183; font-style:italic; }
-# .hl.com { color:#838183; font-style:italic; }
-# .hl.ppc { color:#008200; }
-# .hl.opt { color:#000000; }
-# .hl.ipl { color:#0057ae; }
-# .hl.lin { color:#555555; }
-# .hl.kwa { color:#000000; font-weight:bold; }
-# .hl.kwb { color:#0057ae; }
-# .hl.kwc { color:#000000; font-weight:bold; }
-# .hl.kwd { color:#010181; }
-#
-#
-# The following environment variables can be used to retrieve the configuration
-# of the repository for which this script is called:
-# CGIT_REPO_URL ( = repo.url setting )
-# CGIT_REPO_NAME ( = repo.name setting )
-# CGIT_REPO_PATH ( = repo.path setting )
-# CGIT_REPO_OWNER ( = repo.owner setting )
-# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
-# CGIT_REPO_SECTION ( = section setting )
-# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
-#
-
-# store filename and extension in local vars
-BASENAME="$1"
-EXTENSION="${BASENAME##*.}"
-
-[ "${BASENAME}" = "${EXTENSION}" ] && EXTENSION=txt
-[ -z "${EXTENSION}" ] && EXTENSION=txt
-
-# map Makefile and Makefile.* to .mk
-[ "${BASENAME%%.*}" = "Makefile" ] && EXTENSION=mk
-
-# highlight versions 2 and 3 have different commandline options. Specifically,
-# the -X option that is used for version 2 is replaced by the -O xhtml option
-# for version 3.
-#
-# Version 2 can be found (for example) on EPEL 5, while version 3 can be
-# found (for example) on EPEL 6.
-#
-# This is for version 2
-exec highlight --force -f -I -X -S "$EXTENSION" 2>/dev/null
-
-# This is for version 3
-#exec highlight --force -f -I -O xhtml -S "$EXTENSION" 2>/dev/null
diff --git a/gen-version.sh b/gen-version.sh
deleted file mode 100755
index 80cf49a..0000000
--- a/gen-version.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/sh
-
-# Get version-info specified in Makefile
-V=$1
-
-# Use `git describe` to get current version if we're inside a git repo
-if test "$(git rev-parse --git-dir 2>/dev/null)" = '.git'
-then
- V=$(git describe --abbrev=4 HEAD 2>/dev/null)
-fi
-
-new="CGIT_VERSION = $V"
-old=$(cat VERSION 2>/dev/null)
-
-# Exit if VERSION is uptodate
-test "$old" = "$new" && exit 0
-
-# Update VERSION with new version-info
-echo "$new" > VERSION
-cat VERSION
diff --git a/git b/git
deleted file mode 160000
-Subproject 94f057755b7941b321fd11fec1b2e3ca5313a4e
diff --git a/git.h b/git.h
new file mode 100644
index 0000000..443f216
--- /dev/null
+++ b/git.h
@@ -0,0 +1,399 @@
+#ifndef GIT_H
+#define GIT_H
+
+
+/*
+ * from git:git-compat-util.h
+ */
+
+
+#ifndef FLEX_ARRAY
+#if defined(__GNUC__) && (__GNUC__ < 3)
+#define FLEX_ARRAY 0
+#else
+#define FLEX_ARRAY /* empty */
+#endif
+#endif
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>
+
+
+static inline char* xstrdup(const char *str)
+{
+ char *ret = strdup(str);
+ if (!ret)
+ die("Out of memory, strdup failed");
+ return ret;
+}
+
+static inline void *xmalloc(size_t size)
+{
+ void *ret = malloc(size);
+ if (!ret && !size)
+ ret = malloc(1);
+ if (!ret)
+ die("Out of memory, malloc failed");
+#ifdef XMALLOC_POISON
+ memset(ret, 0xA5, size);
+#endif
+ return ret;
+}
+
+static inline void *xrealloc(void *ptr, size_t size)
+{
+ void *ret = realloc(ptr, size);
+ if (!ret && !size)
+ ret = realloc(ptr, 1);
+ if (!ret)
+ die("Out of memory, realloc failed");
+ return ret;
+}
+
+static inline void *xcalloc(size_t nmemb, size_t size)
+{
+ void *ret = calloc(nmemb, size);
+ if (!ret && (!nmemb || !size))
+ ret = calloc(1, 1);
+ if (!ret)
+ die("Out of memory, calloc failed");
+ return ret;
+}
+
+static inline ssize_t xread(int fd, void *buf, size_t len)
+{
+ ssize_t nr;
+ while (1) {
+ nr = read(fd, buf, len);
+ if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
+ continue;
+ return nr;
+ }
+}
+
+static inline ssize_t xwrite(int fd, const void *buf, size_t len)
+{
+ ssize_t nr;
+ while (1) {
+ nr = write(fd, buf, len);
+ if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
+ continue;
+ return nr;
+ }
+}
+
+
+
+
+/*
+ * from git:cache.h
+ */
+
+
+/* Convert to/from hex/sha1 representation */
+#define MINIMUM_ABBREV 4
+#define DEFAULT_ABBREV 7
+
+
+extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
+
+
+
+
+/*
+ * from git:object.h
+ */
+
+struct object_list {
+ struct object *item;
+ struct object_list *next;
+};
+
+struct object_refs {
+ unsigned count;
+ struct object *base;
+ struct object *ref[FLEX_ARRAY]; /* more */
+};
+
+struct object_array {
+ unsigned int nr;
+ unsigned int alloc;
+ struct object_array_entry {
+ struct object *item;
+ const char *name;
+ } *objects;
+};
+
+#define TYPE_BITS 3
+#define FLAG_BITS 27
+
+/*
+ * The object type is stored in 3 bits.
+ */
+struct object {
+ unsigned parsed : 1;
+ unsigned used : 1;
+ unsigned type : TYPE_BITS;
+ unsigned flags : FLAG_BITS;
+ unsigned char sha1[20];
+};
+
+
+/*
+ * from git:tree.h
+ */
+
+struct tree {
+ struct object object;
+ void *buffer;
+ unsigned long size;
+};
+
+
+
+
+/* from git:commit.h */
+
+struct commit_list {
+ struct commit *item;
+ struct commit_list *next;
+};
+
+struct commit {
+ struct object object;
+ void *util;
+ unsigned long date;
+ struct commit_list *parents;
+ struct tree *tree;
+ char *buffer;
+};
+
+
+/* Commit formats */
+enum cmit_fmt {
+ CMIT_FMT_RAW,
+ CMIT_FMT_MEDIUM,
+ CMIT_FMT_DEFAULT = CMIT_FMT_MEDIUM,
+ CMIT_FMT_SHORT,
+ CMIT_FMT_FULL,
+ CMIT_FMT_FULLER,
+ CMIT_FMT_ONELINE,
+ CMIT_FMT_EMAIL,
+
+ CMIT_FMT_UNSPECIFIED,
+};
+
+
+
+struct commit *lookup_commit(const unsigned char *sha1);
+struct commit *lookup_commit_reference(const unsigned char *sha1);
+struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
+ int quiet);
+
+typedef void (*topo_sort_set_fn_t)(struct commit*, void *data);
+typedef void* (*topo_sort_get_fn_t)(struct commit*);
+
+
+
+
+/*
+ * from git:diff.h
+ */
+
+
+struct rev_info;
+struct diff_options;
+struct diff_queue_struct;
+
+typedef void (*change_fn_t)(struct diff_options *options,
+ unsigned old_mode, unsigned new_mode,
+ const unsigned char *old_sha1,
+ const unsigned char *new_sha1,
+ const char *base, const char *path);
+
+typedef void (*add_remove_fn_t)(struct diff_options *options,
+ int addremove, unsigned mode,
+ const unsigned char *sha1,
+ const char *base, const char *path);
+
+typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
+ struct diff_options *options, void *data);
+
+#define DIFF_FORMAT_RAW 0x0001
+#define DIFF_FORMAT_DIFFSTAT 0x0002
+#define DIFF_FORMAT_NUMSTAT 0x0004
+#define DIFF_FORMAT_SUMMARY 0x0008
+#define DIFF_FORMAT_PATCH 0x0010
+
+/* These override all above */
+#define DIFF_FORMAT_NAME 0x0100
+#define DIFF_FORMAT_NAME_STATUS 0x0200
+#define DIFF_FORMAT_CHECKDIFF 0x0400
+
+/* Same as output_format = 0 but we know that -s flag was given
+ * and we should not give default value to output_format.
+ */
+#define DIFF_FORMAT_NO_OUTPUT 0x0800
+
+#define DIFF_FORMAT_CALLBACK 0x1000
+
+struct diff_options {
+ const char *filter;
+ const char *orderfile;
+ const char *pickaxe;
+ const char *single_follow;
+ unsigned recursive:1,
+ tree_in_recursive:1,
+ binary:1,
+ text:1,
+ full_index:1,
+ silent_on_remove:1,
+ find_copies_harder:1,
+ color_diff:1,
+ color_diff_words:1;
+ int context;
+ int break_opt;
+ int detect_rename;
+ int line_termination;
+ int output_format;
+ int pickaxe_opts;
+ int rename_score;
+ int reverse_diff;
+ int rename_limit;
+ int setup;
+ int abbrev;
+ const char *msg_sep;
+ const char *stat_sep;
+ long xdl_opts;
+
+ int stat_width;
+ int stat_name_width;
+
+ int nr_paths;
+ const char **paths;
+ int *pathlens;
+ change_fn_t change;
+ add_remove_fn_t add_remove;
+ diff_format_fn_t format_callback;
+ void *format_callback_data;
+};
+
+enum color_diff {
+ DIFF_RESET = 0,
+ DIFF_PLAIN = 1,
+ DIFF_METAINFO = 2,
+ DIFF_FRAGINFO = 3,
+ DIFF_FILE_OLD = 4,
+ DIFF_FILE_NEW = 5,
+ DIFF_COMMIT = 6,
+ DIFF_WHITESPACE = 7,
+};
+
+
+
+
+
+
+
+/*
+ * from git:revision.h
+ */
+
+struct rev_info;
+struct log_info;
+
+typedef void (prune_fn_t)(struct rev_info *revs, struct commit *commit);
+
+struct rev_info {
+ /* Starting list */
+ struct commit_list *commits;
+ struct object_array pending;
+
+ /* Basic information */
+ const char *prefix;
+ void *prune_data;
+ prune_fn_t *prune_fn;
+
+ /* Traversal flags */
+ unsigned int dense:1,
+ no_merges:1,
+ no_walk:1,
+ remove_empty_trees:1,
+ simplify_history:1,
+ lifo:1,
+ topo_order:1,
+ tag_objects:1,
+ tree_objects:1,
+ blob_objects:1,
+ edge_hint:1,
+ limited:1,
+ unpacked:1, /* see also ignore_packed below */
+ boundary:1,
+ parents:1;
+
+ /* Diff flags */
+ unsigned int diff:1,
+ full_diff:1,
+ show_root_diff:1,
+ no_commit_id:1,
+ verbose_header:1,
+ ignore_merges:1,
+ combine_merges:1,
+ dense_combined_merges:1,
+ always_show_header:1;
+
+ /* Format info */
+ unsigned int shown_one:1,
+ abbrev_commit:1,
+ relative_date:1;
+
+ const char **ignore_packed; /* pretend objects in these are unpacked */
+ int num_ignore_packed;
+
+ unsigned int abbrev;
+ enum cmit_fmt commit_format;
+ struct log_info *loginfo;
+ int nr, total;
+ const char *mime_boundary;
+ const char *message_id;
+ const char *ref_message_id;
+ const char *add_signoff;
+ const char *extra_headers;
+
+ /* Filter by commit log message */
+ struct grep_opt *grep_filter;
+
+ /* special limits */
+ int max_count;
+ unsigned long max_age;
+ unsigned long min_age;
+
+ /* diff info for patches and for paths limiting */
+ struct diff_options diffopt;
+ struct diff_options pruning;
+
+ topo_sort_set_fn_t topo_setter;
+ topo_sort_get_fn_t topo_getter;
+};
+
+
+extern struct commit *get_revision(struct rev_info *revs);
+
+
+
+
+#endif /* GIT_H */
diff --git a/html.c b/html.c
index 0bac34b..5780dc1 100644
--- a/html.c
+++ b/html.c
@@ -1,50 +1,4 @@
-/* html.c: helper functions for html output
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
#include "cgit.h"
-#include "html.h"
-#include "url.h"
-
-/* Percent-encoding of each character, except: a-zA-Z0-9!$()*,./:;@- */
-static const char* url_escape_table[256] = {
- "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
- "%08", "%09", "%0a", "%0b", "%0c", "%0d", "%0e", "%0f",
- "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
- "%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f",
- "%20", NULL, "%22", "%23", NULL, "%25", "%26", "%27",
- NULL, NULL, NULL, "%2b", NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, "%3c", "%3d", "%3e", "%3f",
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, "%5c", NULL, "%5e", NULL,
- "%60", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, "%7b", "%7c", "%7d", NULL, "%7f",
- "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
- "%88", "%89", "%8a", "%8b", "%8c", "%8d", "%8e", "%8f",
- "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
- "%98", "%99", "%9a", "%9b", "%9c", "%9d", "%9e", "%9f",
- "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
- "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af",
- "%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7",
- "%b8", "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf",
- "%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7",
- "%c8", "%c9", "%ca", "%cb", "%cc", "%cd", "%ce", "%cf",
- "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
- "%d8", "%d9", "%da", "%db", "%dc", "%dd", "%de", "%df",
- "%e0", "%e1", "%e2", "%e3", "%e4", "%e5", "%e6", "%e7",
- "%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee", "%ef",
- "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
- "%f8", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff"
-};
char *fmt(const char *format, ...)
{
@@ -59,233 +13,73 @@ char *fmt(const char *format, ...)
va_start(args, format);
len = vsnprintf(buf[bufidx], sizeof(buf[bufidx]), format, args);
va_end(args);
- if (len >= sizeof(buf[bufidx])) {
- fprintf(stderr, "[html.c] string truncated: %s\n", format);
- exit(1);
- }
+ if (len>sizeof(buf[bufidx]))
+ die("[html.c] string truncated: %s", format);
return buf[bufidx];
}
-char *fmtalloc(const char *format, ...)
-{
- struct strbuf sb = STRBUF_INIT;
- va_list args;
-
- va_start(args, format);
- strbuf_vaddf(&sb, format, args);
- va_end(args);
-
- return strbuf_detach(&sb, NULL);
-}
-
-void html_raw(const char *data, size_t size)
-{
- if (write(STDOUT_FILENO, data, size) != size)
- die_errno("write error on html output");
-}
-
void html(const char *txt)
{
- html_raw(txt, strlen(txt));
+ fputs(txt, stdout);
}
void htmlf(const char *format, ...)
{
va_list args;
- struct strbuf buf = STRBUF_INIT;
-
- va_start(args, format);
- strbuf_vaddf(&buf, format, args);
- va_end(args);
- html(buf.buf);
- strbuf_release(&buf);
-}
-
-void html_txtf(const char *format, ...)
-{
- va_list args;
va_start(args, format);
- html_vtxtf(format, args);
+ vprintf(format, args);
va_end(args);
}
-void html_vtxtf(const char *format, va_list ap)
+void html_txt(char *txt)
{
- va_list cp;
- struct strbuf buf = STRBUF_INIT;
-
- va_copy(cp, ap);
- strbuf_vaddf(&buf, format, cp);
- va_end(cp);
- html_txt(buf.buf);
- strbuf_release(&buf);
-}
-
-void html_txt(const char *txt)
-{
- if (txt)
- html_ntxt(txt, strlen(txt));
-}
-
-ssize_t html_ntxt(const char *txt, size_t len)
-{
- const char *t = txt;
- ssize_t slen;
-
- if (len > SSIZE_MAX)
- return -1;
-
- slen = (ssize_t) len;
- while (t && *t && slen--) {
+ char *t = txt;
+ while(*t){
int c = *t;
- if (c == '<' || c == '>' || c == '&') {
- html_raw(txt, t - txt);
- if (c == '>')
+ if (c=='<' || c=='>' || c=='&') {
+ *t = '\0';
+ html(txt);
+ *t = c;
+ if (c=='>')
html("&gt;");
- else if (c == '<')
+ else if (c=='<')
html("&lt;");
- else if (c == '&')
+ else if (c=='&')
html("&amp;");
- txt = t + 1;
+ txt = t+1;
}
t++;
}
- if (t != txt)
- html_raw(txt, t - txt);
- return slen;
+ if (t!=txt)
+ html(txt);
}
-void html_attrf(const char *fmt, ...)
-{
- va_list ap;
- struct strbuf sb = STRBUF_INIT;
-
- va_start(ap, fmt);
- strbuf_vaddf(&sb, fmt, ap);
- va_end(ap);
- html_attr(sb.buf);
- strbuf_release(&sb);
-}
-
-void html_attr(const char *txt)
+void html_attr(char *txt)
{
- const char *t = txt;
- while (t && *t) {
+ char *t = txt;
+ while(*t){
int c = *t;
- if (c == '<' || c == '>' || c == '\'' || c == '\"' || c == '&') {
- html_raw(txt, t - txt);
- if (c == '>')
+ if (c=='<' || c=='>' || c=='\'') {
+ *t = '\0';
+ html(txt);
+ *t = c;
+ if (c=='>')
html("&gt;");
- else if (c == '<')
+ else if (c=='<')
html("&lt;");
- else if (c == '\'')
- html("&#x27;");
- else if (c == '"')
- html("&quot;");
- else if (c == '&')
- html("&amp;");
- txt = t + 1;
+ else if (c=='\'')
+ html("&quote;");
+ txt = t+1;
}
t++;
}
- if (t != txt)
+ if (t!=txt)
html(txt);
}
-void html_url_path(const char *txt)
-{
- const char *t = txt;
- while (t && *t) {
- unsigned char c = *t;
- const char *e = url_escape_table[c];
- if (e && c != '+' && c != '&') {
- html_raw(txt, t - txt);
- html(e);
- txt = t + 1;
- }
- t++;
- }
- if (t != txt)
- html(txt);
-}
-
-void html_url_arg(const char *txt)
-{
- const char *t = txt;
- while (t && *t) {
- unsigned char c = *t;
- const char *e = url_escape_table[c];
- if (c == ' ')
- e = "+";
- if (e) {
- html_raw(txt, t - txt);
- html(e);
- txt = t + 1;
- }
- t++;
- }
- if (t != txt)
- html(txt);
-}
-
-void html_header_arg_in_quotes(const char *txt)
-{
- const char *t = txt;
- while (t && *t) {
- unsigned char c = *t;
- const char *e = NULL;
- if (c == '\\')
- e = "\\\\";
- else if (c == '\r')
- e = "\\r";
- else if (c == '\n')
- e = "\\n";
- else if (c == '"')
- e = "\\\"";
- if (e) {
- html_raw(txt, t - txt);
- html(e);
- txt = t + 1;
- }
- t++;
- }
- if (t != txt)
- html(txt);
-
-}
-
-void html_hidden(const char *name, const char *value)
-{
- html("<input type='hidden' name='");
- html_attr(name);
- html("' value='");
- html_attr(value);
- html("'/>");
-}
-
-void html_option(const char *value, const char *text, const char *selected_value)
-{
- html("<option value='");
- html_attr(value);
- html("'");
- if (selected_value && !strcmp(selected_value, value))
- html(" selected='selected'");
- html(">");
- html_txt(text);
- html("</option>\n");
-}
-
-void html_intoption(int value, const char *text, int selected_value)
-{
- htmlf("<option value='%d'%s>", value,
- value == selected_value ? " selected='selected'" : "");
- html_txt(text);
- html("</option>");
-}
-
-void html_link_open(const char *url, const char *title, const char *class)
+void html_link_open(char *url, char *title, char *class)
{
html("<a href='");
html_attr(url);
@@ -304,41 +98,3 @@ void html_link_close(void)
{
html("</a>");
}
-
-void html_fileperm(unsigned short mode)
-{
- htmlf("%c%c%c", (mode & 4 ? 'r' : '-'),
- (mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-'));
-}
-
-int html_include(const char *filename)
-{
- FILE *f;
- char buf[4096];
- size_t len;
-
- if (!(f = fopen(filename, "r"))) {
- fprintf(stderr, "[cgit] Failed to include file %s: %s (%d).\n",
- filename, strerror(errno), errno);
- return -1;
- }
- while ((len = fread(buf, 1, 4096, f)) > 0)
- html_raw(buf, len);
- fclose(f);
- return 0;
-}
-
-void http_parse_querystring(const char *txt, void (*fn)(const char *name, const char *value))
-{
- const char *t = txt;
-
- while (t && *t) {
- char *name = url_decode_parameter_name(&t);
- if (*name) {
- char *value = url_decode_parameter_value(&t);
- fn(name, value);
- free(value);
- }
- free(name);
- }
-}
diff --git a/html.h b/html.h
deleted file mode 100644
index fa4de77..0000000
--- a/html.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef HTML_H
-#define HTML_H
-
-#include "cgit.h"
-
-extern void html_raw(const char *txt, size_t size);
-extern void html(const char *txt);
-
-__attribute__((format (printf,1,2)))
-extern void htmlf(const char *format,...);
-
-__attribute__((format (printf,1,2)))
-extern void html_txtf(const char *format,...);
-
-__attribute__((format (printf,1,0)))
-extern void html_vtxtf(const char *format, va_list ap);
-
-__attribute__((format (printf,1,2)))
-extern void html_attrf(const char *format,...);
-
-extern void html_txt(const char *txt);
-extern ssize_t html_ntxt(const char *txt, size_t len);
-extern void html_attr(const char *txt);
-extern void html_url_path(const char *txt);
-extern void html_url_arg(const char *txt);
-extern void html_header_arg_in_quotes(const char *txt);
-extern void html_hidden(const char *name, const char *value);
-extern void html_option(const char *value, const char *text, const char *selected_value);
-extern void html_intoption(int value, const char *text, int selected_value);
-extern void html_link_open(const char *url, const char *title, const char *class);
-extern void html_link_close(void);
-extern void html_fileperm(unsigned short mode);
-extern int html_include(const char *filename);
-
-extern void http_parse_querystring(const char *txt, void (*fn)(const char *name, const char *value));
-
-#endif /* HTML_H */
diff --git a/parsing.c b/parsing.c
deleted file mode 100644
index bdaed25..0000000
--- a/parsing.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/* parsing.c: parsing of config files
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-
-/*
- * url syntax: [repo ['/' cmd [ '/' path]]]
- * repo: any valid repo url, may contain '/'
- * cmd: log | commit | diff | tree | view | blob | snapshot
- * path: any valid path, may contain '/'
- *
- */
-void cgit_parse_url(const char *url)
-{
- char *c, *cmd, *p, *buf;
- struct cgit_repo *repo;
-
- if (!url || url[0] == '\0')
- return;
-
- ctx.qry.page = NULL;
- ctx.repo = cgit_get_repoinfo(url);
- if (ctx.repo) {
- ctx.qry.repo = ctx.repo->url;
- return;
- }
-
- buf = xstrdup(url);
- cmd = NULL;
- c = strchr(buf, '/');
- while (c) {
- c[0] = '\0';
- repo = cgit_get_repoinfo(buf);
- if (repo) {
- ctx.repo = repo;
- cmd = c;
- }
- c[0] = '/';
- c = strchr(c + 1, '/');
- }
-
- if (ctx.repo) {
- ctx.qry.repo = ctx.repo->url;
- p = strchr(cmd + 1, '/');
- if (p) {
- p[0] = '\0';
- if (p[1])
- ctx.qry.path = trim_end(p + 1, '/');
- }
- if (cmd[1])
- ctx.qry.page = xstrdup(cmd + 1);
- }
- free(buf);
-}
-
-static char *substr(const char *head, const char *tail)
-{
- char *buf;
-
- if (tail < head)
- return xstrdup("");
- buf = xmalloc(tail - head + 1);
- strlcpy(buf, head, tail - head + 1);
- return buf;
-}
-
-static void parse_user(const char *t, char **name, char **email, unsigned long *date, int *tz)
-{
- struct ident_split ident;
- unsigned email_len;
-
- if (!split_ident_line(&ident, t, strchrnul(t, '\n') - t)) {
- *name = substr(ident.name_begin, ident.name_end);
-
- email_len = ident.mail_end - ident.mail_begin;
- *email = xmalloc(strlen("<") + email_len + strlen(">") + 1);
- xsnprintf(*email, email_len + 3, "<%.*s>", email_len, ident.mail_begin);
-
- if (ident.date_begin)
- *date = strtoul(ident.date_begin, NULL, 10);
- if (ident.tz_begin)
- *tz = atoi(ident.tz_begin);
- }
-}
-
-#ifdef NO_ICONV
-#define reencode(a, b, c)
-#else
-static const char *reencode(char **txt, const char *src_enc, const char *dst_enc)
-{
- char *tmp;
-
- if (!txt)
- return NULL;
-
- if (!*txt || !src_enc || !dst_enc)
- return *txt;
-
- /* no encoding needed if src_enc equals dst_enc */
- if (!strcasecmp(src_enc, dst_enc))
- return *txt;
-
- tmp = reencode_string(*txt, dst_enc, src_enc);
- if (tmp) {
- free(*txt);
- *txt = tmp;
- }
- return *txt;
-}
-#endif
-
-static const char *next_header_line(const char *p)
-{
- p = strchr(p, '\n');
- if (!p)
- return NULL;
- return p + 1;
-}
-
-static int end_of_header(const char *p)
-{
- return !p || (*p == '\n');
-}
-
-struct commitinfo *cgit_parse_commit(struct commit *commit)
-{
- struct commitinfo *ret;
- const char *p = repo_get_commit_buffer(the_repository, commit, NULL);
- const char *t;
-
- ret = xcalloc(1, sizeof(struct commitinfo));
- ret->commit = commit;
-
- if (!p)
- return ret;
-
- if (!skip_prefix(p, "tree ", &p))
- die("Bad commit: %s", oid_to_hex(&commit->object.oid));
- p += the_hash_algo->hexsz + 1;
-
- while (skip_prefix(p, "parent ", &p))
- p += the_hash_algo->hexsz + 1;
-
- if (p && skip_prefix(p, "author ", &p)) {
- parse_user(p, &ret->author, &ret->author_email,
- &ret->author_date, &ret->author_tz);
- p = next_header_line(p);
- }
-
- if (p && skip_prefix(p, "committer ", &p)) {
- parse_user(p, &ret->committer, &ret->committer_email,
- &ret->committer_date, &ret->committer_tz);
- p = next_header_line(p);
- }
-
- if (p && skip_prefix(p, "encoding ", &p)) {
- t = strchr(p, '\n');
- if (t) {
- ret->msg_encoding = substr(p, t + 1);
- p = t + 1;
- }
- }
-
- if (!ret->msg_encoding)
- ret->msg_encoding = xstrdup("UTF-8");
-
- while (!end_of_header(p))
- p = next_header_line(p);
- while (p && *p == '\n')
- p++;
- if (!p)
- return ret;
-
- t = strchrnul(p, '\n');
- ret->subject = substr(p, t);
- while (*t == '\n')
- t++;
- ret->msg = xstrdup(t);
-
- reencode(&ret->author, ret->msg_encoding, PAGE_ENCODING);
- reencode(&ret->author_email, ret->msg_encoding, PAGE_ENCODING);
- reencode(&ret->committer, ret->msg_encoding, PAGE_ENCODING);
- reencode(&ret->committer_email, ret->msg_encoding, PAGE_ENCODING);
- reencode(&ret->subject, ret->msg_encoding, PAGE_ENCODING);
- reencode(&ret->msg, ret->msg_encoding, PAGE_ENCODING);
-
- return ret;
-}
-
-struct taginfo *cgit_parse_tag(struct tag *tag)
-{
- void *data;
- enum object_type type;
- unsigned long size;
- const char *p;
- struct taginfo *ret = NULL;
-
- data = odb_read_object(the_repository->objects, &tag->object.oid, &type, &size);
- if (!data || type != OBJ_TAG)
- goto cleanup;
-
- ret = xcalloc(1, sizeof(struct taginfo));
-
- for (p = data; !end_of_header(p); p = next_header_line(p)) {
- if (skip_prefix(p, "tagger ", &p)) {
- parse_user(p, &ret->tagger, &ret->tagger_email,
- &ret->tagger_date, &ret->tagger_tz);
- }
- }
-
- while (p && *p == '\n')
- p++;
-
- if (p && *p)
- ret->msg = xstrdup(p);
-
-cleanup:
- free(data);
- return ret;
-}
diff --git a/robots.txt b/robots.txt
deleted file mode 100644
index 1b33266..0000000
--- a/robots.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-User-agent: *
-Disallow: /*/snapshot/*
-Disallow: /*/blame/*
-Allow: /
diff --git a/scan-tree.c b/scan-tree.c
deleted file mode 100644
index c120efe..0000000
--- a/scan-tree.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/* scan-tree.c
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#include "cgit.h"
-#include "scan-tree.h"
-#include "configfile.h"
-#include "html.h"
-#include <config.h>
-
-/* return 1 if path contains a objects/ directory and a HEAD file */
-static int is_git_dir(const char *path)
-{
- struct stat st;
- struct strbuf pathbuf = STRBUF_INIT;
- int result = 0;
-
- strbuf_addf(&pathbuf, "%s/objects", path);
- if (stat(pathbuf.buf, &st)) {
- if (errno != ENOENT)
- fprintf(stderr, "Error checking path %s: %s (%d)\n",
- path, strerror(errno), errno);
- goto out;
- }
- if (!S_ISDIR(st.st_mode))
- goto out;
-
- strbuf_reset(&pathbuf);
- strbuf_addf(&pathbuf, "%s/HEAD", path);
- if (stat(pathbuf.buf, &st)) {
- if (errno != ENOENT)
- fprintf(stderr, "Error checking path %s: %s (%d)\n",
- path, strerror(errno), errno);
- goto out;
- }
- if (!S_ISREG(st.st_mode))
- goto out;
-
- result = 1;
-out:
- strbuf_release(&pathbuf);
- return result;
-}
-
-static struct cgit_repo *repo;
-
-static void scan_tree_repo_config(const char *name, const char *value)
-{
- cgit_repo_config(repo, name, value);
-}
-
-static int gitconfig_config(const char *key, const char *value,
- const __attribute__((unused)) struct config_context *ctx, void *cb)
-{
- const char *name;
-
- if (!strcmp(key, "gitweb.owner"))
- cgit_repo_config(repo, "owner", value);
- else if (!strcmp(key, "gitweb.description"))
- cgit_repo_config(repo, "desc", value);
- else if (!strcmp(key, "gitweb.category"))
- cgit_repo_config(repo, "section", value);
- else if (!strcmp(key, "gitweb.homepage"))
- cgit_repo_config(repo, "homepage", value);
- else if (skip_prefix(key, "cgit.", &name))
- cgit_repo_config(repo, name, value);
-
- return 0;
-}
-
-static char *xstrrchr(char *s, char *from, int c)
-{
- while (from >= s && *from != c)
- from--;
- return from < s ? NULL : from;
-}
-
-static void add_repo(const char *base, struct strbuf *path)
-{
- struct stat st;
- struct passwd *pwd;
- size_t pathlen;
- struct strbuf rel = STRBUF_INIT;
- char *p, *slash;
- int n;
- size_t size;
-
- if (stat(path->buf, &st)) {
- fprintf(stderr, "Error accessing %s: %s (%d)\n",
- path->buf, strerror(errno), errno);
- return;
- }
-
- strbuf_addch(path, '/');
- pathlen = path->len;
-
- if (ctx.cfg.strict_export) {
- strbuf_addstr(path, ctx.cfg.strict_export);
- if(stat(path->buf, &st))
- return;
- strbuf_setlen(path, pathlen);
- }
-
- strbuf_addstr(path, "noweb");
- if (!stat(path->buf, &st))
- return;
- strbuf_setlen(path, pathlen);
-
- if (!starts_with(path->buf, base))
- strbuf_addbuf(&rel, path);
- else
- strbuf_addstr(&rel, path->buf + strlen(base) + 1);
-
- if (!strcmp(rel.buf + rel.len - 5, "/.git"))
- strbuf_setlen(&rel, rel.len - 5);
- else if (rel.len && rel.buf[rel.len - 1] == '/')
- strbuf_setlen(&rel, rel.len - 1);
-
- repo = cgit_add_repo(rel.buf);
- if (ctx.cfg.enable_git_config) {
- strbuf_addstr(path, "config");
- git_config_from_file(gitconfig_config, path->buf, NULL);
- strbuf_setlen(path, pathlen);
- }
-
- if (ctx.cfg.remove_suffix) {
- size_t urllen;
- strip_suffix(repo->url, ".git", &urllen);
- strip_suffix_mem(repo->url, &urllen, "/");
- repo->url[urllen] = '\0';
- }
- repo->path = strdup_first_line(path->buf);
- while (!repo->owner) {
- if ((pwd = getpwuid(st.st_uid)) == NULL) {
- fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n",
- path->buf, strerror(errno), errno);
- break;
- }
- if (pwd->pw_gecos)
- if ((p = strchr(pwd->pw_gecos, ',')))
- *p = '\0';
- repo->owner = strdup_first_line(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name);
- }
-
- if (repo->desc == cgit_default_repo_desc || !repo->desc) {
- strbuf_addstr(path, "description");
- if (!stat(path->buf, &st))
- read_first_line(path->buf, &repo->desc, &size);
- strbuf_setlen(path, pathlen);
- }
-
- if (ctx.cfg.section_from_path) {
- n = ctx.cfg.section_from_path;
- if (n > 0) {
- slash = rel.buf - 1;
- while (slash && n && (slash = strchr(slash + 1, '/')))
- n--;
- } else {
- slash = rel.buf + rel.len;
- while (slash && n && (slash = xstrrchr(rel.buf, slash - 1, '/')))
- n++;
- }
- if (slash && !n) {
- *slash = '\0';
- repo->section = strdup_first_line(rel.buf);
- *slash = '/';
- if (starts_with(repo->name, repo->section)) {
- repo->name += strlen(repo->section);
- if (*repo->name == '/')
- repo->name++;
- }
- }
- }
-
- strbuf_addstr(path, "cgitrc");
- if (!stat(path->buf, &st))
- parse_configfile(path->buf, &scan_tree_repo_config);
-
- strbuf_release(&rel);
-}
-
-static void scan_path(const char *base, const char *path)
-{
- DIR *dir = opendir(path);
- struct dirent *ent;
- struct strbuf pathbuf = STRBUF_INIT;
- size_t pathlen = strlen(path);
- struct stat st;
-
- if (!dir) {
- fprintf(stderr, "Error opening directory %s: %s (%d)\n",
- path, strerror(errno), errno);
- return;
- }
-
- strbuf_add(&pathbuf, path, strlen(path));
- if (is_git_dir(pathbuf.buf)) {
- add_repo(base, &pathbuf);
- goto end;
- }
- strbuf_addstr(&pathbuf, "/.git");
- if (is_git_dir(pathbuf.buf)) {
- add_repo(base, &pathbuf);
- goto end;
- }
- /*
- * Add one because we don't want to lose the trailing '/' when we
- * reset the length of pathbuf in the loop below.
- */
- pathlen++;
- while ((ent = readdir(dir)) != NULL) {
- if (ent->d_name[0] == '.') {
- if (ent->d_name[1] == '\0')
- continue;
- if (ent->d_name[1] == '.' && ent->d_name[2] == '\0')
- continue;
- if (!ctx.cfg.scan_hidden_path)
- continue;
- }
- strbuf_setlen(&pathbuf, pathlen);
- strbuf_addstr(&pathbuf, ent->d_name);
- if (stat(pathbuf.buf, &st)) {
- fprintf(stderr, "Error checking path %s: %s (%d)\n",
- pathbuf.buf, strerror(errno), errno);
- continue;
- }
- if (S_ISDIR(st.st_mode))
- scan_path(base, pathbuf.buf);
- }
-end:
- strbuf_release(&pathbuf);
- closedir(dir);
-}
-
-void scan_projects(const char *path, const char *projectsfile)
-{
- struct strbuf line = STRBUF_INIT;
- FILE *projects;
- int err;
-
- projects = fopen(projectsfile, "r");
- if (!projects) {
- fprintf(stderr, "Error opening projectsfile %s: %s (%d)\n",
- projectsfile, strerror(errno), errno);
- return;
- }
- while (strbuf_getline(&line, projects) != EOF) {
- if (!line.len)
- continue;
- strbuf_insert(&line, 0, "/", 1);
- strbuf_insert(&line, 0, path, strlen(path));
- scan_path(path, line.buf);
- }
- if ((err = ferror(projects))) {
- fprintf(stderr, "Error reading from projectsfile %s: %s (%d)\n",
- projectsfile, strerror(err), err);
- }
- fclose(projects);
- strbuf_release(&line);
-}
-
-void scan_tree(const char *path)
-{
- scan_path(path, path);
-}
diff --git a/scan-tree.h b/scan-tree.h
deleted file mode 100644
index def0a7a..0000000
--- a/scan-tree.h
+++ /dev/null
@@ -1,2 +0,0 @@
-extern void scan_projects(const char *path, const char *projectsfile);
-extern void scan_tree(const char *path);
diff --git a/shared.c b/shared.c
deleted file mode 100644
index a39394d..0000000
--- a/shared.c
+++ /dev/null
@@ -1,595 +0,0 @@
-/* shared.c: global vars + some callback functions
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-
-struct cgit_repolist cgit_repolist;
-struct cgit_context ctx;
-
-int chk_zero(int result, char *msg)
-{
- if (result != 0)
- die_errno("%s", msg);
- return result;
-}
-
-int chk_positive(int result, char *msg)
-{
- if (result <= 0)
- die_errno("%s", msg);
- return result;
-}
-
-int chk_non_negative(int result, char *msg)
-{
- if (result < 0)
- die_errno("%s", msg);
- return result;
-}
-
-char *cgit_default_repo_desc = "[no description]";
-struct cgit_repo *cgit_add_repo(const char *url)
-{
- struct cgit_repo *ret;
-
- if (++cgit_repolist.count > cgit_repolist.length) {
- if (cgit_repolist.length == 0)
- cgit_repolist.length = 8;
- else
- cgit_repolist.length *= 2;
- cgit_repolist.repos = xrealloc(cgit_repolist.repos,
- cgit_repolist.length *
- sizeof(struct cgit_repo));
- }
-
- ret = &cgit_repolist.repos[cgit_repolist.count-1];
- memset(ret, 0, sizeof(struct cgit_repo));
- ret->url = trim_end(url, '/');
- *strchrnul(ret->url, '\n') = '\0';
- ret->name = ret->url;
- ret->path = NULL;
- ret->desc = cgit_default_repo_desc;
- ret->extra_head_content = NULL;
- ret->owner = NULL;
- ret->homepage = NULL;
- ret->section = ctx.cfg.section;
- ret->snapshots = ctx.cfg.snapshots;
- ret->enable_blame = ctx.cfg.enable_blame;
- ret->enable_commit_graph = ctx.cfg.enable_commit_graph;
- ret->enable_follow_links = ctx.cfg.enable_follow_links;
- ret->enable_log_filecount = ctx.cfg.enable_log_filecount;
- ret->enable_log_linecount = ctx.cfg.enable_log_linecount;
- ret->enable_remote_branches = ctx.cfg.enable_remote_branches;
- ret->enable_subject_links = ctx.cfg.enable_subject_links;
- ret->enable_html_serving = ctx.cfg.enable_html_serving;
- ret->max_stats = ctx.cfg.max_stats;
- ret->branch_sort = ctx.cfg.branch_sort;
- ret->commit_sort = ctx.cfg.commit_sort;
- ret->module_link = ctx.cfg.module_link;
- ret->readme = ctx.cfg.readme;
- ret->mtime = -1;
- ret->about_filter = ctx.cfg.about_filter;
- ret->commit_filter = ctx.cfg.commit_filter;
- ret->source_filter = ctx.cfg.source_filter;
- ret->email_filter = ctx.cfg.email_filter;
- ret->owner_filter = ctx.cfg.owner_filter;
- ret->clone_url = ctx.cfg.clone_url;
- ret->submodules.strdup_strings = 1;
- ret->hide = ret->ignore = 0;
- return ret;
-}
-
-struct cgit_repo *cgit_get_repoinfo(const char *url)
-{
- int i;
- struct cgit_repo *repo;
-
- for (i = 0; i < cgit_repolist.count; i++) {
- repo = &cgit_repolist.repos[i];
- if (repo->ignore)
- continue;
- if (!strcmp(repo->url, url))
- return repo;
- }
- return NULL;
-}
-
-void cgit_free_commitinfo(struct commitinfo *info)
-{
- free(info->author);
- free(info->author_email);
- free(info->committer);
- free(info->committer_email);
- free(info->subject);
- free(info->msg);
- free(info->msg_encoding);
- free(info);
-}
-
-char *trim_end(const char *str, char c)
-{
- int len;
-
- if (str == NULL)
- return NULL;
- len = strlen(str);
- while (len > 0 && str[len - 1] == c)
- len--;
- if (len == 0)
- return NULL;
- return xstrndup(str, len);
-}
-
-char *ensure_end(const char *str, char c)
-{
- size_t len = strlen(str);
- char *result;
-
- if (len && str[len - 1] == c)
- return xstrndup(str, len);
-
- result = xmalloc(len + 2);
- memcpy(result, str, len);
- result[len] = '/';
- result[len + 1] = '\0';
- return result;
-}
-
-void strbuf_ensure_end(struct strbuf *sb, char c)
-{
- if (!sb->len || sb->buf[sb->len - 1] != c)
- strbuf_addch(sb, c);
-}
-
-void cgit_add_ref(struct reflist *list, struct refinfo *ref)
-{
- size_t size;
-
- if (list->count >= list->alloc) {
- list->alloc += (list->alloc ? list->alloc : 4);
- size = list->alloc * sizeof(struct refinfo *);
- list->refs = xrealloc(list->refs, size);
- }
- list->refs[list->count++] = ref;
-}
-
-static struct refinfo *cgit_mk_refinfo(const char *refname, const struct object_id *oid)
-{
- struct refinfo *ref;
-
- ref = xmalloc(sizeof (struct refinfo));
- ref->refname = xstrdup(refname);
- ref->object = parse_object(the_repository, oid);
- switch (ref->object->type) {
- case OBJ_TAG:
- ref->tag = cgit_parse_tag((struct tag *)ref->object);
- break;
- case OBJ_COMMIT:
- ref->commit = cgit_parse_commit((struct commit *)ref->object);
- break;
- }
- return ref;
-}
-
-void cgit_free_taginfo(struct taginfo *tag)
-{
- if (tag->tagger)
- free(tag->tagger);
- if (tag->tagger_email)
- free(tag->tagger_email);
- if (tag->msg)
- free(tag->msg);
- free(tag);
-}
-
-static void cgit_free_refinfo(struct refinfo *ref)
-{
- if (ref->refname)
- free((char *)ref->refname);
- switch (ref->object->type) {
- case OBJ_TAG:
- cgit_free_taginfo(ref->tag);
- break;
- case OBJ_COMMIT:
- cgit_free_commitinfo(ref->commit);
- break;
- }
- free(ref);
-}
-
-void cgit_free_reflist_inner(struct reflist *list)
-{
- int i;
-
- for (i = 0; i < list->count; i++) {
- cgit_free_refinfo(list->refs[i]);
- }
- free(list->refs);
-}
-
-int cgit_refs_cb(const struct reference *ref, void *cb_data)
-{
- struct reflist *list = (struct reflist *)cb_data;
- struct refinfo *info = cgit_mk_refinfo(ref->name, ref->oid);
-
- if (info)
- cgit_add_ref(list, info);
- return 0;
-}
-
-void cgit_diff_tree_cb(struct diff_queue_struct *q,
- struct diff_options *options, void *data)
-{
- int i;
-
- for (i = 0; i < q->nr; i++) {
- if (q->queue[i]->status == 'U')
- continue;
- ((filepair_fn)data)(q->queue[i]);
- }
-}
-
-static int load_mmfile(mmfile_t *file, const struct object_id *oid)
-{
- enum object_type type;
-
- if (is_null_oid(oid)) {
- file->ptr = (char *)"";
- file->size = 0;
- } else {
- file->ptr = odb_read_object(the_repository->objects, oid, &type,
- (unsigned long *)&file->size);
- }
- return 1;
-}
-
-/*
- * Receive diff-buffers from xdiff and concatenate them as
- * needed across multiple callbacks.
- *
- * This is basically a copy of xdiff-interface.c/xdiff_outf(),
- * ripped from git and modified to use globals instead of
- * a special callback-struct.
- */
-static char *diffbuf = NULL;
-static int buflen = 0;
-
-static int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf)
-{
- int i;
-
- for (i = 0; i < nbuf; i++) {
- if (mb[i].ptr[mb[i].size-1] != '\n') {
- /* Incomplete line */
- diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
- memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
- buflen += mb[i].size;
- continue;
- }
-
- /* we have a complete line */
- if (!diffbuf) {
- ((linediff_fn)priv)(mb[i].ptr, mb[i].size);
- continue;
- }
- diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
- memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
- ((linediff_fn)priv)(diffbuf, buflen + mb[i].size);
- free(diffbuf);
- diffbuf = NULL;
- buflen = 0;
- }
- if (diffbuf) {
- ((linediff_fn)priv)(diffbuf, buflen);
- free(diffbuf);
- diffbuf = NULL;
- buflen = 0;
- }
- return 0;
-}
-
-int cgit_diff_files(const struct object_id *old_oid,
- const struct object_id *new_oid, unsigned long *old_size,
- unsigned long *new_size, int *binary, int context,
- int ignorews, linediff_fn fn)
-{
- mmfile_t file1, file2;
- xpparam_t diff_params;
- xdemitconf_t emit_params;
- xdemitcb_t emit_cb;
-
- if (!load_mmfile(&file1, old_oid) || !load_mmfile(&file2, new_oid))
- return 1;
-
- *old_size = file1.size;
- *new_size = file2.size;
-
- if ((file1.ptr && buffer_is_binary(file1.ptr, file1.size)) ||
- (file2.ptr && buffer_is_binary(file2.ptr, file2.size))) {
- *binary = 1;
- if (file1.size)
- free(file1.ptr);
- if (file2.size)
- free(file2.ptr);
- return 0;
- }
-
- memset(&diff_params, 0, sizeof(diff_params));
- memset(&emit_params, 0, sizeof(emit_params));
- memset(&emit_cb, 0, sizeof(emit_cb));
- diff_params.flags = XDF_NEED_MINIMAL;
- if (ignorews)
- diff_params.flags |= XDF_IGNORE_WHITESPACE;
- emit_params.ctxlen = context > 0 ? context : 3;
- emit_params.flags = XDL_EMIT_FUNCNAMES;
- emit_cb.out_line = filediff_cb;
- emit_cb.priv = fn;
- xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb);
- if (file1.size)
- free(file1.ptr);
- if (file2.size)
- free(file2.ptr);
- return 0;
-}
-
-void cgit_diff_tree(const struct object_id *old_oid,
- const struct object_id *new_oid,
- filepair_fn fn, const char *prefix, int ignorews)
-{
- struct diff_options opt;
- struct pathspec_item *item;
-
- repo_diff_setup(the_repository, &opt);
- opt.output_format = DIFF_FORMAT_CALLBACK;
- opt.detect_rename = 1;
- opt.rename_limit = ctx.cfg.renamelimit;
- opt.flags.recursive = 1;
- if (ignorews)
- DIFF_XDL_SET(&opt, IGNORE_WHITESPACE);
- opt.format_callback = cgit_diff_tree_cb;
- opt.format_callback_data = fn;
- if (prefix) {
- item = xcalloc(1, sizeof(*item));
- item->match = xstrdup(prefix);
- item->len = strlen(prefix);
- opt.pathspec.nr = 1;
- opt.pathspec.items = item;
- }
- diff_setup_done(&opt);
-
- if (old_oid && !is_null_oid(old_oid))
- diff_tree_oid(old_oid, new_oid, "", &opt);
- else
- diff_root_tree_oid(new_oid, "", &opt);
- diffcore_std(&opt);
- diff_flush(&opt);
-}
-
-void cgit_diff_commit(struct commit *commit, filepair_fn fn, const char *prefix)
-{
- const struct object_id *old_oid = NULL;
-
- if (commit->parents)
- old_oid = &commit->parents->item->object.oid;
- cgit_diff_tree(old_oid, &commit->object.oid, fn, prefix,
- ctx.qry.ignorews);
-}
-
-int cgit_parse_snapshots_mask(const char *str)
-{
- struct string_list tokens = STRING_LIST_INIT_DUP;
- struct string_list_item *item;
- const struct cgit_snapshot_format *f;
- int rv = 0;
-
- /* favor legacy setting */
- if (atoi(str))
- return 1;
-
- if (strcmp(str, "all") == 0)
- return INT_MAX;
-
- string_list_split(&tokens, str, " ", -1);
- string_list_remove_empty_items(&tokens, 0);
-
- for_each_string_list_item(item, &tokens) {
- for (f = cgit_snapshot_formats; f->suffix; f++) {
- if (!strcmp(item->string, f->suffix) ||
- !strcmp(item->string, f->suffix + 1)) {
- rv |= cgit_snapshot_format_bit(f);
- break;
- }
- }
- }
-
- string_list_clear(&tokens, 0);
- return rv;
-}
-
-typedef struct {
- char * name;
- char * value;
-} cgit_env_var;
-
-void cgit_prepare_repo_env(struct cgit_repo * repo)
-{
- cgit_env_var env_vars[] = {
- { .name = "CGIT_REPO_URL", .value = repo->url },
- { .name = "CGIT_REPO_NAME", .value = repo->name },
- { .name = "CGIT_REPO_PATH", .value = repo->path },
- { .name = "CGIT_REPO_OWNER", .value = repo->owner },
- { .name = "CGIT_REPO_DEFBRANCH", .value = repo->defbranch },
- { .name = "CGIT_REPO_SECTION", .value = repo->section },
- { .name = "CGIT_REPO_CLONE_URL", .value = repo->clone_url }
- };
- int env_var_count = ARRAY_SIZE(env_vars);
- cgit_env_var *p, *q;
- static char *warn = "cgit warning: failed to set env: %s=%s\n";
-
- p = env_vars;
- q = p + env_var_count;
- for (; p < q; p++)
- if (p->value && setenv(p->name, p->value, 1))
- fprintf(stderr, warn, p->name, p->value);
-}
-
-/* Read the content of the specified file into a newly allocated buffer,
- * zeroterminate the buffer, truncate at a new line, and return 0 on success,
- * errno otherwise.
- */
-int read_first_line(const char *path, char **buf, size_t *size)
-{
- int fd, e;
- struct stat st;
-
- fd = open(path, O_RDONLY);
- if (fd == -1)
- return errno;
- if (fstat(fd, &st)) {
- e = errno;
- close(fd);
- return e;
- }
- if (!S_ISREG(st.st_mode)) {
- close(fd);
- return EISDIR;
- }
- *buf = xmalloc(st.st_size + 1);
- *size = read_in_full(fd, *buf, st.st_size);
- e = errno;
- (*buf)[*size] = '\0';
- *strchrnul(*buf, '\n') = '\0';
- close(fd);
- return (*size == st.st_size ? 0 : e);
-}
-
-char *strdup_first_line(const char *txt)
-{
- char *t = xstrdup(txt);
- *strchrnul(t, '\n') = '\0';
- return t;
-}
-
-static int is_token_char(char c)
-{
- return isalnum(c) || c == '_';
-}
-
-/* Replace name with getenv(name), return pointer to zero-terminating char
- */
-static char *expand_macro(char *name, int maxlength)
-{
- char *value;
- size_t len;
-
- len = 0;
- value = getenv(name);
- if (value) {
- len = strlen(value) + 1;
- if (len > maxlength)
- len = maxlength;
- strlcpy(name, value, len);
- --len;
- }
- return name + len;
-}
-
-#define EXPBUFSIZE (1024 * 8)
-
-/* Replace all tokens prefixed by '$' in the specified text with the
- * value of the named environment variable.
- * NB: the return value is a static buffer, i.e. it must be strdup'd
- * by the caller.
- */
-char *expand_macros(const char *txt)
-{
- static char result[EXPBUFSIZE];
- char *p, *start;
- int len;
-
- p = result;
- start = NULL;
- while (p < result + EXPBUFSIZE - 1 && txt && *txt) {
- *p = *txt;
- if (start) {
- if (!is_token_char(*txt)) {
- if (p - start > 0) {
- *p = '\0';
- len = result + EXPBUFSIZE - start - 1;
- p = expand_macro(start, len) - 1;
- }
- start = NULL;
- txt--;
- }
- p++;
- txt++;
- continue;
- }
- if (*txt == '$') {
- start = p;
- txt++;
- continue;
- }
- p++;
- txt++;
- }
- *p = '\0';
- if (start && p - start > 0) {
- len = result + EXPBUFSIZE - start - 1;
- p = expand_macro(start, len);
- *p = '\0';
- }
- return result;
-}
-
-char *get_mimetype_for_filename(const char *filename)
-{
- const char *ext;
- char *mimetype, line[1024];
- struct string_list list = STRING_LIST_INIT_NODUP;
- int i;
- FILE *file;
- struct string_list_item *mime;
-
- if (!filename)
- return NULL;
-
- ext = strrchr(filename, '.');
- if (!ext)
- return NULL;
- ++ext;
- if (!ext[0])
- return NULL;
- mime = string_list_lookup(&ctx.cfg.mimetypes, ext);
- if (mime)
- return xstrdup(mime->util);
-
- if (!ctx.cfg.mimetype_file)
- return NULL;
- file = fopen(ctx.cfg.mimetype_file, "r");
- if (!file)
- return NULL;
- while (fgets(line, sizeof(line), file)) {
- if (!line[0] || line[0] == '#')
- continue;
- string_list_split_in_place(&list, line, " \t\r\n", -1);
- string_list_remove_empty_items(&list, 0);
- mimetype = list.items[0].string;
- for (i = 1; i < list.nr; i++) {
- if (!strcasecmp(ext, list.items[i].string)) {
- fclose(file);
- return xstrdup(mimetype);
- }
- }
- string_list_clear(&list, 0);
- }
- fclose(file);
- return NULL;
-}
diff --git a/tests/.gitignore b/tests/.gitignore
deleted file mode 100644
index 3fd2e96..0000000
--- a/tests/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-trash\ directory.t*
-test-results
diff --git a/tests/Makefile b/tests/Makefile
deleted file mode 100644
index 65e1117..0000000
--- a/tests/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-include ../git/config.mak.uname
--include ../cgit.conf
-
-SHELL_PATH ?= $(SHELL)
-SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
-
-T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
-
-all: $(T)
-
-$(T):
- @'$(SHELL_PATH_SQ)' $@ $(CGIT_TEST_OPTS)
-
-clean:
- $(RM) -rf trash
-
-.PHONY: $(T) clean
diff --git a/tests/filters/dump.lua b/tests/filters/dump.lua
deleted file mode 100644
index 1f15c93..0000000
--- a/tests/filters/dump.lua
+++ /dev/null
@@ -1,17 +0,0 @@
-function filter_open(...)
- buffer = ""
- for i = 1, select("#", ...) do
- buffer = buffer .. select(i, ...) .. " "
- end
-end
-
-function filter_close()
- html(buffer)
- return 0
-end
-
-function filter_write(str)
- buffer = buffer .. string.upper(str)
-end
-
-
diff --git a/tests/filters/dump.sh b/tests/filters/dump.sh
deleted file mode 100755
index da6f7a1..0000000
--- a/tests/filters/dump.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-[ "$#" -gt 0 ] && printf "%s " "$*"
-tr '[:lower:]' '[:upper:]'
diff --git a/tests/setup.sh b/tests/setup.sh
deleted file mode 100755
index 8db810f..0000000
--- a/tests/setup.sh
+++ /dev/null
@@ -1,180 +0,0 @@
-# This file should be sourced by all test-scripts
-#
-# Main functions:
-# prepare_tests(description) - setup for testing, i.e. create repos+config
-# run_test(description, script) - run one test, i.e. eval script
-#
-# Helper functions
-# cgit_query(querystring) - call cgit with the specified querystring
-# cgit_url(url) - call cgit with the specified virtual url
-#
-# Example script:
-#
-# . setup.sh
-# prepare_tests "html validation"
-# run_test 'repo index' 'cgit_url "/" | tidy -e'
-# run_test 'repo summary' 'cgit_url "/foo" | tidy -e'
-
-# We don't want to run Git commands through Valgrind, so we filter out the
-# --valgrind option here and handle it ourselves. We copy the arguments
-# assuming that none contain a newline, although other whitespace is
-# preserved.
-LF='
-'
-test_argv=
-
-while test $# != 0
-do
- case "$1" in
- --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind)
- cgit_valgrind=t
- test_argv="$test_argv${LF}--verbose"
- ;;
- *)
- test_argv="$test_argv$LF$1"
- ;;
- esac
- shift
-done
-
-OLDIFS=$IFS
-IFS=$LF
-set -- $test_argv
-IFS=$OLDIFS
-
-: ${TEST_DIRECTORY=$(pwd)/../git/t}
-: ${TEST_OUTPUT_DIRECTORY=$(pwd)}
-TEST_NO_CREATE_REPO=YesPlease
-. "$TEST_DIRECTORY"/test-lib.sh
-
-# Prepend the directory containing cgit to PATH.
-if test -n "$cgit_valgrind"
-then
- GIT_VALGRIND="$TEST_DIRECTORY/valgrind"
- CGIT_VALGRIND=$(cd ../valgrind && pwd)
- PATH="$CGIT_VALGRIND/bin:$PATH"
- export GIT_VALGRIND CGIT_VALGRIND
-else
- PATH="$(pwd)/../..:$PATH"
-fi
-
-FILTER_DIRECTORY=$(cd ../filters && pwd)
-
-if cgit --version | grep -F -q "[+] Lua scripting"; then
- export CGIT_HAS_LUA=1
-else
- export CGIT_HAS_LUA=0
-fi
-
-mkrepo() {
- name=$1
- count=$2
- test_create_repo "$name"
- (
- cd "$name"
- n=1
- while test $n -le $count
- do
- echo $n >file-$n
- git add file-$n
- git commit -m "commit $n"
- n=$(expr $n + 1)
- done
- case "$3" in
- testplus)
- echo "hello" >a+b
- git add a+b
- git commit -m "add a+b"
- git branch "1+2"
- ;;
- commit-graph)
- git commit-graph write
- ;;
- esac
- )
-}
-
-setup_repos()
-{
- rm -rf cache
- mkdir -p cache
- mkrepo repos/foo 5 >/dev/null
- mkrepo repos/bar 50 commit-graph >/dev/null
- mkrepo repos/foo+bar 10 testplus >/dev/null
- mkrepo "repos/with space" 2 >/dev/null
- mkrepo repos/filter 5 testplus >/dev/null
- cat >cgitrc <<EOF
-virtual-root=/
-cache-root=$PWD/cache
-
-cache-size=1021
-snapshots=tar.gz tar.bz tar.lz tar.xz tar.zst zip
-enable-log-filecount=1
-enable-log-linecount=1
-summary-log=5
-summary-branches=5
-summary-tags=5
-clone-url=git://example.org/\$CGIT_REPO_URL.git
-enable-filter-overrides=1
-
-repo.url=foo
-repo.path=$PWD/repos/foo/.git
-# Do not specify a description for this repo, as it then will be assigned
-# the constant value "[no description]" (which actually used to cause a
-# segfault).
-
-repo.url=bar
-repo.path=$PWD/repos/bar/.git
-repo.desc=the bar repo
-
-repo.url=foo+bar
-repo.path=$PWD/repos/foo+bar/.git
-repo.desc=the foo+bar repo
-
-repo.url=with space
-repo.path=$PWD/repos/with space/.git
-repo.desc=spaced repo
-
-repo.url=filter-exec
-repo.path=$PWD/repos/filter/.git
-repo.desc=filtered repo
-repo.about-filter=exec:$FILTER_DIRECTORY/dump.sh
-repo.commit-filter=exec:$FILTER_DIRECTORY/dump.sh
-repo.email-filter=exec:$FILTER_DIRECTORY/dump.sh
-repo.source-filter=exec:$FILTER_DIRECTORY/dump.sh
-repo.readme=master:a+b
-EOF
-
- if [ $CGIT_HAS_LUA -eq 1 ]; then
- cat >>cgitrc <<EOF
-repo.url=filter-lua
-repo.path=$PWD/repos/filter/.git
-repo.desc=filtered repo
-repo.about-filter=lua:$FILTER_DIRECTORY/dump.lua
-repo.commit-filter=lua:$FILTER_DIRECTORY/dump.lua
-repo.email-filter=lua:$FILTER_DIRECTORY/dump.lua
-repo.source-filter=lua:$FILTER_DIRECTORY/dump.lua
-repo.readme=master:a+b
-EOF
- fi
-}
-
-cgit_query()
-{
- CGIT_CONFIG="$PWD/cgitrc" QUERY_STRING="$1" cgit
-}
-
-cgit_url()
-{
- CGIT_CONFIG="$PWD/cgitrc" QUERY_STRING="url=$1" cgit
-}
-
-strip_headers() {
- while read -r line
- do
- test -z "$line" && break
- done
- cat
-}
-
-test -z "$CGIT_TEST_NO_CREATE_REPOS" && setup_repos
diff --git a/tests/t0001-validate-git-versions.sh b/tests/t0001-validate-git-versions.sh
deleted file mode 100755
index dd84fe3..0000000
--- a/tests/t0001-validate-git-versions.sh
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/bin/sh
-
-if [ "${CGIT_TEST_NO_GIT_VERSION}" = "YesPlease" ]; then
- exit 0
-fi
-
-test_description='Check Git version is correct'
-CGIT_TEST_NO_CREATE_REPOS=YesPlease
-. ./setup.sh
-
-test_expect_success 'extract Git version from Makefile' '
- sed -n -e "/^GIT_VER[ ]*=/ {
- s/^GIT_VER[ ]*=[ ]*//
- p
- }" ../../Makefile >makefile_version
-'
-
-# Note that Git's GIT-VERSION-GEN script applies "s/-/./g" to the version
-# string to produce the internal version in the GIT-VERSION-FILE, so we
-# must apply the same transformation to the version in the Makefile before
-# comparing them.
-test_expect_success 'test Git version matches Makefile' '
- ( cat ../../git/GIT-VERSION-FILE || echo "No GIT-VERSION-FILE" ) |
- sed -e "s/GIT_VERSION[ ]*=[ ]*//" -e "s/\\.dirty$//" >git_version &&
- sed -e "s/-/./g" makefile_version >makefile_git_version &&
- test_cmp git_version makefile_git_version
-'
-
-test_expect_success 'test submodule version matches Makefile' '
- if ! test -e ../../git/.git
- then
- echo "git/ is not a Git repository" >&2
- else
- (
- cd ../.. &&
- sm_oid=$(git ls-files --stage -- git |
- sed -e "s/^[0-9]* \\([0-9a-f]*\\) [0-9] .*$/\\1/") &&
- cd git &&
- git describe --match "v[0-9]*" $sm_oid
- ) | sed -e "s/^v//" -e "s/-/./" >sm_version &&
- test_cmp sm_version makefile_version
- fi
-'
-
-test_done
diff --git a/tests/t0010-validate-html.sh b/tests/t0010-validate-html.sh
deleted file mode 100755
index ca08d69..0000000
--- a/tests/t0010-validate-html.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/sh
-
-test_description='Validate html with tidy'
-. ./setup.sh
-
-
-test_url()
-{
- tidy_opt="-eq"
- test -z "$NO_TIDY_WARNINGS" || tidy_opt+=" --show-warnings no"
- cgit_url "$1" >tidy-$test_count.tmp || return
- sed -e "1,4d" tidy-$test_count.tmp >tidy-$test_count || return
- "$tidy" $tidy_opt tidy-$test_count
- rc=$?
-
- # tidy returns with exitcode 1 on warnings, 2 on error
- if test $rc = 2
- then
- false
- else
- :
- fi
-}
-
-tidy=`which tidy 2>/dev/null`
-test -n "$tidy" || {
- skip_all='Skipping html validation tests: tidy not found'
- test_done
- exit
-}
-
-test_expect_success 'index page' 'test_url ""'
-test_expect_success 'foo' 'test_url "foo"'
-test_expect_success 'foo/log' 'test_url "foo/log"'
-test_expect_success 'foo/tree' 'test_url "foo/tree"'
-test_expect_success 'foo/tree/file-1' 'test_url "foo/tree/file-1"'
-test_expect_success 'foo/commit' 'test_url "foo/commit"'
-test_expect_success 'foo/diff' 'test_url "foo/diff"'
-
-test_done
diff --git a/tests/t0020-validate-cache.sh b/tests/t0020-validate-cache.sh
deleted file mode 100755
index 657765d..0000000
--- a/tests/t0020-validate-cache.sh
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/bin/sh
-
-test_description='Validate cache'
-. ./setup.sh
-
-test_expect_success 'verify cache-size=0' '
-
- rm -f cache/* &&
- sed -e "s/cache-size=1021$/cache-size=0/" cgitrc >cgitrc.tmp &&
- mv -f cgitrc.tmp cgitrc &&
- cgit_url "" &&
- cgit_url "foo" &&
- cgit_url "foo/refs" &&
- cgit_url "foo/tree" &&
- cgit_url "foo/log" &&
- cgit_url "foo/diff" &&
- cgit_url "foo/patch" &&
- cgit_url "bar" &&
- cgit_url "bar/refs" &&
- cgit_url "bar/tree" &&
- cgit_url "bar/log" &&
- cgit_url "bar/diff" &&
- cgit_url "bar/patch" &&
- ls cache >output &&
- test_line_count = 0 output
-'
-
-test_expect_success 'verify cache-size=1' '
-
- rm -f cache/* &&
- sed -e "s/cache-size=0$/cache-size=1/" cgitrc >cgitrc.tmp &&
- mv -f cgitrc.tmp cgitrc &&
- cgit_url "" &&
- cgit_url "foo" &&
- cgit_url "foo/refs" &&
- cgit_url "foo/tree" &&
- cgit_url "foo/log" &&
- cgit_url "foo/diff" &&
- cgit_url "foo/patch" &&
- cgit_url "bar" &&
- cgit_url "bar/refs" &&
- cgit_url "bar/tree" &&
- cgit_url "bar/log" &&
- cgit_url "bar/diff" &&
- cgit_url "bar/patch" &&
- ls cache >output &&
- test_line_count = 1 output
-'
-
-test_expect_success 'verify cache-size=1021' '
-
- rm -f cache/* &&
- sed -e "s/cache-size=1$/cache-size=1021/" cgitrc >cgitrc.tmp &&
- mv -f cgitrc.tmp cgitrc &&
- cgit_url "" &&
- cgit_url "foo" &&
- cgit_url "foo/refs" &&
- cgit_url "foo/tree" &&
- cgit_url "foo/log" &&
- cgit_url "foo/diff" &&
- cgit_url "foo/patch" &&
- cgit_url "bar" &&
- cgit_url "bar/refs" &&
- cgit_url "bar/tree" &&
- cgit_url "bar/log" &&
- cgit_url "bar/diff" &&
- cgit_url "bar/patch" &&
- ls cache >output &&
- test_line_count = 13 output &&
- cgit_url "foo/ls_cache" >output.full &&
- strip_headers <output.full >output &&
- test_line_count = 13 output &&
- # Check that ls_cache output is cached correctly
- cgit_url "foo/ls_cache" >output.second &&
- test_cmp output.full output.second
-'
-
-test_done
diff --git a/tests/t0101-index.sh b/tests/t0101-index.sh
deleted file mode 100755
index 82ef9b0..0000000
--- a/tests/t0101-index.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-
-test_description='Check content on index page'
-. ./setup.sh
-
-test_expect_success 'generate index page' 'cgit_url "" >tmp'
-test_expect_success 'find foo repo' 'grep "foo" tmp'
-test_expect_success 'find foo description' 'grep "\[no description\]" tmp'
-test_expect_success 'find bar repo' 'grep "bar" tmp'
-test_expect_success 'find bar description' 'grep "the bar repo" tmp'
-test_expect_success 'find foo+bar repo' 'grep ">foo+bar<" tmp'
-test_expect_success 'verify foo+bar link' 'grep "/foo+bar/" tmp'
-test_expect_success 'verify "with%20space" link' 'grep "/with%20space/" tmp'
-test_expect_success 'no tree-link' '! grep "foo/tree" tmp'
-test_expect_success 'no log-link' '! grep "foo/log" tmp'
-
-test_done
diff --git a/tests/t0102-summary.sh b/tests/t0102-summary.sh
deleted file mode 100755
index b8864cb..0000000
--- a/tests/t0102-summary.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/sh
-
-test_description='Check content on summary page'
-. ./setup.sh
-
-test_expect_success 'generate foo summary' 'cgit_url "foo" >tmp'
-test_expect_success 'find commit 1' 'grep "commit 1" tmp'
-test_expect_success 'find commit 5' 'grep "commit 5" tmp'
-test_expect_success 'find branch master' 'grep "master" tmp'
-test_expect_success 'no tags' '! grep "tags" tmp'
-test_expect_success 'clone-url expanded correctly' '
- grep "git://example.org/foo.git" tmp
-'
-
-test_expect_success 'generate bar summary' 'cgit_url "bar" >tmp'
-test_expect_success 'no commit 45' '! grep "commit 45" tmp'
-test_expect_success 'find commit 46' 'grep "commit 46" tmp'
-test_expect_success 'find commit 50' 'grep "commit 50" tmp'
-test_expect_success 'find branch master' 'grep "master" tmp'
-test_expect_success 'no tags' '! grep "tags" tmp'
-test_expect_success 'clone-url expanded correctly' '
- grep "git://example.org/bar.git" tmp
-'
-
-test_done
diff --git a/tests/t0103-log.sh b/tests/t0103-log.sh
deleted file mode 100755
index bdf1435..0000000
--- a/tests/t0103-log.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-
-test_description='Check content on log page'
-. ./setup.sh
-
-test_expect_success 'generate foo/log' 'cgit_url "foo/log" >tmp'
-test_expect_success 'find commit 1' 'grep "commit 1" tmp'
-test_expect_success 'find commit 5' 'grep "commit 5" tmp'
-
-test_expect_success 'generate bar/log' 'cgit_url "bar/log" >tmp'
-test_expect_success 'find commit 1' 'grep "commit 1" tmp'
-test_expect_success 'find commit 50' 'grep "commit 50" tmp'
-
-test_expect_success 'generate "with%20space/log?qt=grep&q=commit+1"' '
- cgit_url "with+space/log&qt=grep&q=commit+1" >tmp
-'
-test_expect_success 'find commit 1' 'grep "commit 1" tmp'
-test_expect_success 'find link with %20 in path' 'grep "/with%20space/log/?qt=grep" tmp'
-test_expect_success 'find link with + in arg' 'grep "/log/?qt=grep&amp;q=commit+1" tmp'
-test_expect_success 'no links with space in path' '! grep "href=./with space/" tmp'
-test_expect_success 'no links with space in arg' '! grep "q=commit 1" tmp'
-test_expect_success 'commit 2 is not visible' '! grep "commit 2" tmp'
-
-test_done
diff --git a/tests/t0104-tree.sh b/tests/t0104-tree.sh
deleted file mode 100755
index 2e140f5..0000000
--- a/tests/t0104-tree.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-
-test_description='Check content on tree page'
-. ./setup.sh
-
-test_expect_success 'generate bar/tree' 'cgit_url "bar/tree" >tmp'
-test_expect_success 'find file-1' 'grep "file-1" tmp'
-test_expect_success 'find file-50' 'grep "file-50" tmp'
-
-test_expect_success 'generate bar/tree/file-50' 'cgit_url "bar/tree/file-50" >tmp'
-
-test_expect_success 'find line 1' '
- grep "<a id=.n1. href=.#n1.>1</a>" tmp
-'
-
-test_expect_success 'no line 2' '
- ! grep "<a id=.n2. href=.#n2.>2</a>" tmp
-'
-
-test_expect_success 'generate foo+bar/tree' 'cgit_url "foo%2bbar/tree" >tmp'
-
-test_expect_success 'verify a+b link' '
- grep "/foo+bar/tree/a+b" tmp
-'
-
-test_expect_success 'generate foo+bar/tree?h=1+2' 'cgit_url "foo%2bbar/tree&h=1%2b2" >tmp'
-
-test_expect_success 'verify a+b?h=1+2 link' '
- grep "/foo+bar/tree/a+b?h=1%2b2" tmp
-'
-
-test_done
diff --git a/tests/t0105-commit.sh b/tests/t0105-commit.sh
deleted file mode 100755
index 1a12ee3..0000000
--- a/tests/t0105-commit.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/sh
-
-test_description='Check content on commit page'
-. ./setup.sh
-
-test_expect_success 'generate foo/commit' 'cgit_url "foo/commit" >tmp'
-test_expect_success 'find tree link' 'grep "<a href=./foo/tree/.>" tmp'
-test_expect_success 'find parent link' 'grep -E "<a href=./foo/commit/\?id=.+>" tmp'
-
-test_expect_success 'find commit subject' '
- grep "<div class=.commit-subject.>commit 5<" tmp
-'
-
-test_expect_success 'find commit msg' 'grep "<div class=.commit-msg.></div>" tmp'
-test_expect_success 'find diffstat' 'grep "<table summary=.diffstat. class=.diffstat.>" tmp'
-
-test_expect_success 'find diff summary' '
- grep "1 files changed, 1 insertions, 0 deletions" tmp
-'
-
-test_expect_success 'get root commit' '
- root=$(cd repos/foo && git rev-list --reverse HEAD | head -1) &&
- cgit_url "foo/commit&id=$root" >tmp &&
- grep "</html>" tmp
-'
-
-test_expect_success 'root commit contains diffstat' '
- grep "<a href=./foo/diff/file-1.id=[0-9a-f]\{40,64\}.>file-1</a>" tmp
-'
-
-test_expect_success 'root commit contains diff' '
- grep ">diff --git a/file-1 b/file-1<" tmp &&
- grep "<div class=.add.>+1</div>" tmp
-'
-
-test_done
diff --git a/tests/t0106-diff.sh b/tests/t0106-diff.sh
deleted file mode 100755
index 82b645e..0000000
--- a/tests/t0106-diff.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-
-test_description='Check content on diff page'
-. ./setup.sh
-
-test_expect_success 'generate foo/diff' 'cgit_url "foo/diff" >tmp'
-test_expect_success 'find diff header' 'grep "a/file-5 b/file-5" tmp'
-test_expect_success 'find blob link' 'grep "<a href=./foo/tree/file-5?id=" tmp'
-test_expect_success 'find added file' 'grep "new file mode 100644" tmp'
-
-test_expect_success 'find hunk header' '
- grep "<div class=.hunk.>@@ -0,0 +1 @@</div>" tmp
-'
-
-test_expect_success 'find added line' '
- grep "<div class=.add.>+5</div>" tmp
-'
-
-test_done
diff --git a/tests/t0107-snapshot.sh b/tests/t0107-snapshot.sh
deleted file mode 100755
index 0811ec4..0000000
--- a/tests/t0107-snapshot.sh
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/bin/sh
-
-test_description='Verify snapshot'
-. ./setup.sh
-
-test_expect_success 'get foo/snapshot/master.tar.gz' '
- cgit_url "foo/snapshot/master.tar.gz" >tmp
-'
-
-test_expect_success 'check html headers' '
- head -n 1 tmp |
- grep "Content-Type: application/x-gzip" &&
-
- head -n 2 tmp |
- grep "Content-Disposition: inline; filename=.master.tar.gz."
-'
-
-test_expect_success 'strip off the header lines' '
- strip_headers <tmp >master.tar.gz
-'
-
-test_expect_success 'verify gzip format' '
- gunzip --test master.tar.gz
-'
-
-test_expect_success 'untar' '
- rm -rf master &&
- gzip -dc master.tar.gz | tar -xf -
-'
-
-test_expect_success 'count files' '
- ls master/ >output &&
- test_line_count = 5 output
-'
-
-test_expect_success 'verify untarred file-5' '
- grep "^5$" master/file-5 &&
- test_line_count = 1 master/file-5
-'
-
-if test -n "$(which lzip 2>/dev/null)"; then
- test_set_prereq LZIP
-else
- say 'Skipping LZIP validation tests: lzip not found'
-fi
-
-test_expect_success LZIP 'get foo/snapshot/master.tar.lz' '
- cgit_url "foo/snapshot/master.tar.lz" >tmp
-'
-
-test_expect_success LZIP 'check html headers' '
- head -n 1 tmp |
- grep "Content-Type: application/x-lzip" &&
-
- head -n 2 tmp |
- grep "Content-Disposition: inline; filename=.master.tar.lz."
-'
-
-test_expect_success LZIP 'strip off the header lines' '
- strip_headers <tmp >master.tar.lz
-'
-
-test_expect_success LZIP 'verify lzip format' '
- lzip --test master.tar.lz
-'
-
-test_expect_success LZIP 'untar' '
- rm -rf master &&
- lzip -dc master.tar.lz | tar -xf -
-'
-
-test_expect_success LZIP 'count files' '
- ls master/ >output &&
- test_line_count = 5 output
-'
-
-test_expect_success LZIP 'verify untarred file-5' '
- grep "^5$" master/file-5 &&
- test_line_count = 1 master/file-5
-'
-
-if test -n "$(which xz 2>/dev/null)"; then
- test_set_prereq XZ
-else
- say 'Skipping XZ validation tests: xz not found'
-fi
-
-test_expect_success XZ 'get foo/snapshot/master.tar.xz' '
- cgit_url "foo/snapshot/master.tar.xz" >tmp
-'
-
-test_expect_success XZ 'check html headers' '
- head -n 1 tmp |
- grep "Content-Type: application/x-xz" &&
-
- head -n 2 tmp |
- grep "Content-Disposition: inline; filename=.master.tar.xz."
-'
-
-test_expect_success XZ 'strip off the header lines' '
- strip_headers <tmp >master.tar.xz
-'
-
-test_expect_success XZ 'verify xz format' '
- xz --test master.tar.xz
-'
-
-test_expect_success XZ 'untar' '
- rm -rf master &&
- xz -dc master.tar.xz | tar -xf -
-'
-
-test_expect_success XZ 'count files' '
- ls master/ >output &&
- test_line_count = 5 output
-'
-
-test_expect_success XZ 'verify untarred file-5' '
- grep "^5$" master/file-5 &&
- test_line_count = 1 master/file-5
-'
-
-if test -n "$(which zstd 2>/dev/null)"; then
- test_set_prereq ZSTD
-else
- say 'Skipping ZSTD validation tests: zstd not found'
-fi
-
-test_expect_success ZSTD 'get foo/snapshot/master.tar.zst' '
- cgit_url "foo/snapshot/master.tar.zst" >tmp
-'
-
-test_expect_success ZSTD 'check html headers' '
- head -n 1 tmp |
- grep "Content-Type: application/x-zstd" &&
-
- head -n 2 tmp |
- grep "Content-Disposition: inline; filename=.master.tar.zst."
-'
-
-test_expect_success ZSTD 'strip off the header lines' '
- strip_headers <tmp >master.tar.zst
-'
-
-test_expect_success ZSTD 'verify zstd format' '
- zstd --test master.tar.zst
-'
-
-test_expect_success ZSTD 'untar' '
- rm -rf master &&
- zstd -dc master.tar.zst | tar -xf -
-'
-
-test_expect_success ZSTD 'count files' '
- ls master/ >output &&
- test_line_count = 5 output
-'
-
-test_expect_success ZSTD 'verify untarred file-5' '
- grep "^5$" master/file-5 &&
- test_line_count = 1 master/file-5
-'
-
-test_expect_success 'get foo/snapshot/master.zip' '
- cgit_url "foo/snapshot/master.zip" >tmp
-'
-
-test_expect_success 'check HTML headers (zip)' '
- head -n 1 tmp |
- grep "Content-Type: application/x-zip" &&
-
- head -n 2 tmp |
- grep "Content-Disposition: inline; filename=.master.zip."
-'
-
-test_expect_success 'strip off the header lines (zip)' '
- strip_headers <tmp >master.zip
-'
-
-if test -n "$(which unzip 2>/dev/null)"; then
- test_set_prereq UNZIP
-else
- say 'Skipping ZIP validation tests: unzip not found'
-fi
-
-test_expect_success UNZIP 'verify zip format' '
- unzip -t master.zip
-'
-
-test_expect_success UNZIP 'unzip' '
- rm -rf master &&
- unzip master.zip
-'
-
-test_expect_success UNZIP 'count files (zip)' '
- ls master/ >output &&
- test_line_count = 5 output
-'
-
-test_expect_success UNZIP 'verify unzipped file-5' '
- grep "^5$" master/file-5 &&
- test_line_count = 1 master/file-5
-'
-
-test_done
diff --git a/tests/t0108-patch.sh b/tests/t0108-patch.sh
deleted file mode 100755
index 013d680..0000000
--- a/tests/t0108-patch.sh
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/sh
-
-test_description='Check content on patch page'
-. ./setup.sh
-
-test_expect_success 'generate foo/patch' '
- cgit_query "url=foo/patch" >tmp
-'
-
-test_expect_success 'find `From:` line' '
- grep "^From: " tmp
-'
-
-test_expect_success 'find `Date:` line' '
- grep "^Date: " tmp
-'
-
-test_expect_success 'find `Subject:` line' '
- grep "^Subject: commit 5" tmp
-'
-
-test_expect_success 'find `cgit` signature' '
- tail -2 tmp | head -1 | grep "^cgit"
-'
-
-test_expect_success 'compare with output of git-format-patch(1)' '
- CGIT_VERSION=$(sed -n "s/CGIT_VERSION = //p" ../../VERSION) &&
- git --git-dir="$PWD/repos/foo/.git" format-patch --subject-prefix="" --signature="cgit $CGIT_VERSION" --stdout HEAD^ >tmp2 &&
- strip_headers <tmp >tmp_ &&
- test_cmp tmp_ tmp2
-'
-
-test_expect_success 'find initial commit' '
- root=$(git --git-dir="$PWD/repos/foo/.git" rev-list --max-parents=0 HEAD)
-'
-
-test_expect_success 'generate patch for initial commit' '
- cgit_query "url=foo/patch&id=$root" >tmp
-'
-
-test_expect_success 'find `cgit` signature' '
- tail -2 tmp | head -1 | grep "^cgit"
-'
-
-test_expect_success 'generate patches for multiple commits' '
- id=$(git --git-dir="$PWD/repos/foo/.git" rev-parse HEAD) &&
- id2=$(git --git-dir="$PWD/repos/foo/.git" rev-parse HEAD~3) &&
- cgit_query "url=foo/patch&id=$id&id2=$id2" >tmp
-'
-
-test_expect_success 'find `cgit` signature' '
- tail -2 tmp | head -1 | grep "^cgit"
-'
-
-test_expect_success 'compare with output of git-format-patch(1)' '
- CGIT_VERSION=$(sed -n "s/CGIT_VERSION = //p" ../../VERSION) &&
- git --git-dir="$PWD/repos/foo/.git" format-patch -N --subject-prefix="" --signature="cgit $CGIT_VERSION" --stdout HEAD~3..HEAD >tmp2 &&
- strip_headers <tmp >tmp_ &&
- test_cmp tmp_ tmp2
-'
-
-test_done
diff --git a/tests/t0109-gitconfig.sh b/tests/t0109-gitconfig.sh
deleted file mode 100755
index 189ef28..0000000
--- a/tests/t0109-gitconfig.sh
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/sh
-
-test_description='Ensure that git does not access $HOME'
-. ./setup.sh
-
-test -n "$(which strace 2>/dev/null)" || {
- skip_all='Skipping access validation tests: strace not found'
- test_done
- exit
-}
-
-strace true 2>/dev/null || {
- skip_all='Skipping access validation tests: strace not functional'
- test_done
- exit
-}
-
-test_no_home_access () {
- non_existent_path="/path/to/some/place/that/does/not/possibly/exist"
- while test -d "$non_existent_path"; do
- non_existent_path="$non_existent_path/$(date +%N)"
- done &&
- strace \
- -E HOME="$non_existent_path" \
- -E CGIT_CONFIG="$PWD/cgitrc" \
- -E QUERY_STRING="url=$1" \
- -e access -f -o strace.out cgit &&
- ! grep "$non_existent_path" strace.out
-}
-
-test_no_home_access_success() {
- test_expect_success "do not access \$HOME: $1" "
- test_no_home_access '$1'
- "
-}
-
-test_no_home_access_success
-test_no_home_access_success foo
-test_no_home_access_success foo/refs
-test_no_home_access_success foo/log
-test_no_home_access_success foo/tree
-test_no_home_access_success foo/tree/file-1
-test_no_home_access_success foo/commit
-test_no_home_access_success foo/diff
-test_no_home_access_success foo/patch
-test_no_home_access_success foo/snapshot/master.tar.gz
-
-test_done
diff --git a/tests/t0110-rawdiff.sh b/tests/t0110-rawdiff.sh
deleted file mode 100755
index 66fa7d5..0000000
--- a/tests/t0110-rawdiff.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/sh
-
-test_description='Check content on rawdiff page'
-. ./setup.sh
-
-test_expect_success 'generate foo/rawdiff' '
- cgit_query "url=foo/rawdiff" >tmp
-'
-
-test_expect_success 'compare with output of git-diff(1)' '
- git --git-dir="$PWD/repos/foo/.git" diff HEAD^.. >tmp2 &&
- sed "1,4d" tmp >tmp_ &&
- cmp tmp_ tmp2
-'
-
-test_expect_success 'find initial commit' '
- root=$(git --git-dir="$PWD/repos/foo/.git" rev-list --max-parents=0 HEAD)
-'
-
-test_expect_success 'generate diff for initial commit' '
- cgit_query "url=foo/rawdiff&id=$root" >tmp
-'
-
-test_expect_success 'compare with output of git-diff-tree(1)' '
- git --git-dir="$PWD/repos/foo/.git" diff-tree -p --no-commit-id --root "$root" >tmp2 &&
- sed "1,4d" tmp >tmp_ &&
- cmp tmp_ tmp2
-'
-
-test_expect_success 'generate diff for multiple commits' '
- id=$(git --git-dir="$PWD/repos/foo/.git" rev-parse HEAD) &&
- id2=$(git --git-dir="$PWD/repos/foo/.git" rev-parse HEAD~3) &&
- cgit_query "url=foo/rawdiff&id=$id&id2=$id2" >tmp
-'
-
-test_expect_success 'compare with output of git-diff(1)' '
- git --git-dir="$PWD/repos/foo/.git" diff HEAD~3..HEAD >tmp2 &&
- sed "1,4d" tmp >tmp_ &&
- cmp tmp_ tmp2
-'
-
-test_done
diff --git a/tests/t0111-filter.sh b/tests/t0111-filter.sh
deleted file mode 100755
index 2fdc366..0000000
--- a/tests/t0111-filter.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/sh
-
-test_description='Check filtered content'
-. ./setup.sh
-
-prefixes="exec"
-if [ $CGIT_HAS_LUA -eq 1 ]; then
- prefixes="$prefixes lua"
-fi
-
-for prefix in $prefixes
-do
- test_expect_success "generate filter-$prefix/tree/a%2bb" "
- cgit_url 'filter-$prefix/tree/a%2bb' >tmp
- "
-
- test_expect_success "check whether the $prefix source filter works" '
- grep "<code>a+b HELLO$" tmp
- '
-
- test_expect_success "generate filter-$prefix/about/" "
- cgit_url 'filter-$prefix/about/' >tmp
- "
-
- test_expect_success "check whether the $prefix about filter works" '
- grep "<div id='"'"'summary'"'"'>a+b HELLO$" tmp
- '
-
- test_expect_success "generate filter-$prefix/commit/" "
- cgit_url 'filter-$prefix/commit/' >tmp
- "
-
- test_expect_success "check whether the $prefix commit filter works" '
- grep "<div class='"'"'commit-subject'"'"'>ADD A+B" tmp
- '
-
- test_expect_success "check whether the $prefix email filter works for authors" '
- grep "<author@example.com> commit A U THOR &LT;AUTHOR@EXAMPLE.COM&GT;" tmp
- '
-
- test_expect_success "check whether the $prefix email filter works for committers" '
- grep "<committer@example.com> commit C O MITTER &LT;COMMITTER@EXAMPLE.COM&GT;" tmp
- '
-done
-
-test_done
diff --git a/tests/valgrind/bin/cgit b/tests/valgrind/bin/cgit
deleted file mode 100755
index dcdfbe5..0000000
--- a/tests/valgrind/bin/cgit
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-
-# Note that we currently use Git's suppression file and there are variables
-# $GIT_VALGRIND and $CGIT_VALGRIND which point to different places.
-exec valgrind -q --error-exitcode=126 \
- --suppressions="$GIT_VALGRIND/default.supp" \
- --gen-suppressions=all \
- --leak-check=no \
- --track-origins=yes \
- --log-fd=4 \
- --input-fd=4 \
- "$CGIT_VALGRIND/../../cgit" "$@"
diff --git a/ui-atom.c b/ui-atom.c
deleted file mode 100644
index 0659e96..0000000
--- a/ui-atom.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/* ui-atom.c: functions for atom feeds
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-atom.h"
-#include "html.h"
-#include "ui-shared.h"
-
-static void add_entry(struct commit *commit, const char *host)
-{
- char delim = '&';
- char *hex;
- char *mail, *t, *t2;
- struct commitinfo *info;
-
- info = cgit_parse_commit(commit);
- hex = oid_to_hex(&commit->object.oid);
- html("<entry>\n");
- html("<title>");
- html_txt(info->subject);
- html("</title>\n");
- html("<updated>");
- html_txt(show_date(info->committer_date, 0,
- date_mode_from_type(DATE_ISO8601_STRICT)));
- html("</updated>\n");
- html("<author>\n");
- if (info->author) {
- html("<name>");
- html_txt(info->author);
- html("</name>\n");
- }
- if (info->author_email && !ctx.cfg.noplainemail) {
- mail = xstrdup(info->author_email);
- t = strchr(mail, '<');
- if (t)
- t++;
- else
- t = mail;
- t2 = strchr(t, '>');
- if (t2)
- *t2 = '\0';
- html("<email>");
- html_txt(t);
- html("</email>\n");
- free(mail);
- }
- html("</author>\n");
- html("<published>");
- html_txt(show_date(info->author_date, 0,
- date_mode_from_type(DATE_ISO8601_STRICT)));
- html("</published>\n");
- if (host) {
- char *pageurl;
- html("<link rel='alternate' type='text/html' href='");
- html(cgit_httpscheme());
- html_attr(host);
- pageurl = cgit_pageurl(ctx.repo->url, "commit", NULL);
- html_attr(pageurl);
- if (ctx.cfg.virtual_root)
- delim = '?';
- html_attrf("%cid=%s", delim, hex);
- html("'/>\n");
- free(pageurl);
- }
- html("<id>");
- html_txtf("urn:%s:%s", the_hash_algo->name, hex);
- html("</id>\n");
- html("<content type='text'>\n");
- html_txt(info->msg);
- html("</content>\n");
- html("</entry>\n");
- cgit_free_commitinfo(info);
-}
-
-
-void cgit_print_atom(char *tip, const char *path, int max_count)
-{
- char *host;
- const char *argv[] = {NULL, tip, NULL, NULL, NULL};
- struct commit *commit;
- struct rev_info rev;
- int argc = 2;
- bool first = true;
-
- if (ctx.qry.show_all)
- argv[1] = "--all";
- else if (!tip)
- argv[1] = ctx.qry.head;
-
- if (path) {
- argv[argc++] = "--";
- argv[argc++] = path;
- }
-
- repo_init_revisions(the_repository, &rev, NULL);
- rev.abbrev = DEFAULT_ABBREV;
- rev.commit_format = CMIT_FMT_DEFAULT;
- rev.verbose_header = 1;
- rev.show_root_diff = 0;
- rev.max_count = max_count;
- setup_revisions(argc, argv, &rev, NULL);
- prepare_revision_walk(&rev);
-
- host = cgit_hosturl();
- ctx.page.mimetype = "text/xml";
- ctx.page.charset = "utf-8";
- cgit_print_http_headers();
- html("<feed xmlns='http://www.w3.org/2005/Atom'>\n");
- html("<title>");
- html_txt(ctx.repo->name);
- if (path) {
- html("/");
- html_txt(path);
- }
- if (tip && !ctx.qry.show_all) {
- html(", branch ");
- html_txt(tip);
- }
- html("</title>\n");
- html("<subtitle>");
- html_txt(ctx.repo->desc);
- html("</subtitle>\n");
- if (host) {
- char *fullurl = cgit_currentfullurl();
- char *repourl = cgit_repourl(ctx.repo->url);
- html("<id>");
- html_txtf("%s%s%s", cgit_httpscheme(), host, fullurl);
- html("</id>\n");
- html("<link rel='self' href='");
- html_attrf("%s%s%s", cgit_httpscheme(), host, fullurl);
- html("'/>\n");
- html("<link rel='alternate' type='text/html' href='");
- html_attrf("%s%s%s", cgit_httpscheme(), host, repourl);
- html("'/>\n");
- free(fullurl);
- free(repourl);
- }
- while ((commit = get_revision(&rev)) != NULL) {
- if (first) {
- html("<updated>");
- html_txt(show_date(commit->date, 0,
- date_mode_from_type(DATE_ISO8601_STRICT)));
- html("</updated>\n");
- first = false;
- }
- add_entry(commit, host);
- release_commit_memory(the_repository->parsed_objects, commit);
- commit->parents = NULL;
- }
- html("</feed>\n");
- free(host);
-}
diff --git a/ui-atom.h b/ui-atom.h
deleted file mode 100644
index dda953b..0000000
--- a/ui-atom.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef UI_ATOM_H
-#define UI_ATOM_H
-
-extern void cgit_print_atom(char *tip, const char *path, int max_count);
-
-#endif
diff --git a/ui-blame.c b/ui-blame.c
deleted file mode 100644
index 5c6f36e..0000000
--- a/ui-blame.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/* ui-blame.c: functions for blame output
- *
- * Copyright (C) 2006-2017 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-blame.h"
-#include "html.h"
-#include "ui-shared.h"
-#include "strvec.h"
-#include "blame.h"
-
-
-static char *emit_suspect_detail(struct blame_origin *suspect)
-{
- struct commitinfo *info;
- struct strbuf detail = STRBUF_INIT;
-
- info = cgit_parse_commit(suspect->commit);
-
- strbuf_addf(&detail, "author %s", info->author);
- if (!ctx.cfg.noplainemail)
- strbuf_addf(&detail, " %s", info->author_email);
- strbuf_addf(&detail, " %s\n",
- show_date(info->author_date, info->author_tz,
- cgit_date_mode(DATE_ISO8601)));
-
- strbuf_addf(&detail, "committer %s", info->committer);
- if (!ctx.cfg.noplainemail)
- strbuf_addf(&detail, " %s", info->committer_email);
- strbuf_addf(&detail, " %s\n\n",
- show_date(info->committer_date, info->committer_tz,
- cgit_date_mode(DATE_ISO8601)));
-
- strbuf_addstr(&detail, info->subject);
-
- cgit_free_commitinfo(info);
- return strbuf_detach(&detail, NULL);
-}
-
-static void emit_blame_entry_hash(struct blame_entry *ent)
-{
- struct blame_origin *suspect = ent->suspect;
- struct object_id *oid = &suspect->commit->object.oid;
- unsigned long line = 0;
-
- char *detail = emit_suspect_detail(suspect);
- html("<span class='oid'>");
- cgit_commit_link(repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV), detail,
- NULL, ctx.qry.head, oid_to_hex(oid), suspect->path);
- html("</span>");
- free(detail);
-
- if (!repo_parse_commit(the_repository, suspect->commit) && suspect->commit->parents) {
- struct commit *parent = suspect->commit->parents->item;
-
- html(" ");
- cgit_blame_link("^", "Blame the previous revision", NULL,
- ctx.qry.head, oid_to_hex(&parent->object.oid),
- suspect->path);
- }
-
- while (line++ < ent->num_lines)
- html("\n");
-}
-
-static void emit_blame_entry_linenumber(struct blame_entry *ent)
-{
- const char *numberfmt = "<a id='n%1$d' href='#n%1$d'>%1$d</a>\n";
-
- unsigned long lineno = ent->lno;
- while (lineno < ent->lno + ent->num_lines)
- htmlf(numberfmt, ++lineno);
-}
-
-static void emit_blame_entry_line_background(struct blame_scoreboard *sb,
- struct blame_entry *ent)
-{
- unsigned long line;
- size_t len, maxlen = 2;
- const char* pos, *endpos;
-
- for (line = ent->lno; line < ent->lno + ent->num_lines; line++) {
- html("\n");
- pos = blame_nth_line(sb, line);
- endpos = blame_nth_line(sb, line + 1);
- len = 0;
- while (pos < endpos) {
- len++;
- if (*pos++ == '\t')
- len = (len + 7) & ~7;
- }
- if (len > maxlen)
- maxlen = len;
- }
-
- for (len = 0; len < maxlen - 1; len++)
- html(" ");
-}
-
-struct walk_tree_context {
- char *curr_rev;
- int match_baselen;
- int state;
-};
-
-static void print_object(const struct object_id *oid, const char *path,
- const char *basename, const char *rev)
-{
- enum object_type type;
- char *buf;
- unsigned long size;
- struct strvec rev_argv = STRVEC_INIT;
- struct rev_info revs;
- struct blame_scoreboard sb;
- struct blame_origin *o;
- struct blame_entry *ent = NULL;
-
- type = odb_read_object_info(the_repository->objects, oid, &size);
- if (type == OBJ_BAD) {
- cgit_print_error_page(404, "Not found", "Bad object name: %s",
- oid_to_hex(oid));
- return;
- }
-
- buf = odb_read_object(the_repository->objects, oid, &type, &size);
- if (!buf) {
- cgit_print_error_page(500, "Internal server error",
- "Error reading object %s", oid_to_hex(oid));
- return;
- }
-
- strvec_push(&rev_argv, "blame");
- strvec_push(&rev_argv, rev);
- repo_init_revisions(the_repository, &revs, NULL);
- revs.diffopt.flags.allow_textconv = 1;
- setup_revisions(rev_argv.nr, rev_argv.v, &revs, NULL);
- init_scoreboard(&sb);
- sb.revs = &revs;
- sb.repo = the_repository;
- sb.path = path;
- setup_scoreboard(&sb, &o);
- o->suspects = blame_entry_prepend(NULL, 0, sb.num_lines, o);
- prio_queue_put(&sb.commits, o->commit);
- blame_origin_decref(o);
- sb.ent = NULL;
- sb.path = path;
- assign_blame(&sb, 0);
- blame_sort_final(&sb);
- blame_coalesce(&sb);
-
- cgit_set_title_from_path(path);
-
- cgit_print_layout_start();
- htmlf("blob: %s (", oid_to_hex(oid));
- cgit_plain_link("plain", NULL, NULL, ctx.qry.head, rev, path);
- html(") (");
- cgit_tree_link("tree", NULL, NULL, ctx.qry.head, rev, path);
- html(")\n");
-
- if (buffer_is_binary(buf, size)) {
- html("<div class='error'>blob is binary.</div>");
- goto cleanup;
- }
- if (ctx.cfg.max_blob_size && size / 1024 > ctx.cfg.max_blob_size) {
- htmlf("<div class='error'>blob size (%ldKB)"
- " exceeds display size limit (%dKB).</div>",
- size / 1024, ctx.cfg.max_blob_size);
- goto cleanup;
- }
-
- html("<table class='blame blob'>\n<tr>\n");
-
- /* Commit hashes */
- html("<td class='hashes'>");
- for (ent = sb.ent; ent; ent = ent->next) {
- html("<div class='alt'><pre>");
- emit_blame_entry_hash(ent);
- html("</pre></div>");
- }
- html("</td>\n");
-
- /* Line numbers */
- if (ctx.cfg.enable_tree_linenumbers) {
- html("<td class='linenumbers'>");
- for (ent = sb.ent; ent; ent = ent->next) {
- html("<div class='alt'><pre>");
- emit_blame_entry_linenumber(ent);
- html("</pre></div>");
- }
- html("</td>\n");
- }
-
- html("<td class='lines'><div>");
-
- /* Colored bars behind lines */
- html("<div>");
- for (ent = sb.ent; ent; ) {
- struct blame_entry *e = ent->next;
- html("<div class='alt'><pre>");
- emit_blame_entry_line_background(&sb, ent);
- html("</pre></div>");
- free(ent);
- ent = e;
- }
- html("</div>");
-
- free((void *)sb.final_buf);
-
- /* Lines */
- html("<pre><code>");
- if (ctx.repo->source_filter) {
- char *filter_arg = xstrdup(basename);
- cgit_open_filter(ctx.repo->source_filter, filter_arg);
- html_raw(buf, size);
- cgit_close_filter(ctx.repo->source_filter);
- free(filter_arg);
- } else {
- html_txt(buf);
- }
- html("</code></pre>");
-
- html("</div></td>\n");
-
- html("</tr>\n</table>\n");
-
- cgit_print_layout_end();
-
-cleanup:
- free(buf);
-}
-
-static int walk_tree(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode, void *cbdata)
-{
- struct walk_tree_context *walk_tree_ctx = cbdata;
-
- if (base->len == walk_tree_ctx->match_baselen) {
- if (S_ISREG(mode)) {
- struct strbuf buffer = STRBUF_INIT;
- strbuf_addbuf(&buffer, base);
- strbuf_addstr(&buffer, pathname);
- print_object(oid, buffer.buf, pathname,
- walk_tree_ctx->curr_rev);
- strbuf_release(&buffer);
- walk_tree_ctx->state = 1;
- } else if (S_ISDIR(mode)) {
- walk_tree_ctx->state = 2;
- }
- } else if (base->len < INT_MAX
- && (int)base->len > walk_tree_ctx->match_baselen) {
- walk_tree_ctx->state = 2;
- } else if (S_ISDIR(mode)) {
- return READ_TREE_RECURSIVE;
- }
- return 0;
-}
-
-static int basedir_len(const char *path)
-{
- const char *p = strrchr(path, '/');
- if (p)
- return p - path + 1;
- return 0;
-}
-
-void cgit_print_blame(void)
-{
- const char *rev = ctx.qry.oid;
- struct object_id oid;
- struct commit *commit;
- struct pathspec_item path_items = {
- .match = ctx.qry.path,
- .len = ctx.qry.path ? strlen(ctx.qry.path) : 0
- };
- struct pathspec paths = {
- .nr = 1,
- .items = &path_items
- };
- struct walk_tree_context walk_tree_ctx = {
- .state = 0
- };
-
- if (!rev)
- rev = ctx.qry.head;
-
- if (repo_get_oid(the_repository, rev, &oid)) {
- cgit_print_error_page(404, "Not found",
- "Invalid revision name: %s", rev);
- return;
- }
- commit = lookup_commit_reference(the_repository, &oid);
- if (!commit || repo_parse_commit(the_repository, commit)) {
- cgit_print_error_page(404, "Not found",
- "Invalid commit reference: %s", rev);
- return;
- }
-
- walk_tree_ctx.curr_rev = xstrdup(rev);
- walk_tree_ctx.match_baselen = (path_items.match) ?
- basedir_len(path_items.match) : -1;
-
- read_tree(the_repository, repo_get_commit_tree(the_repository, commit),
- &paths, walk_tree, &walk_tree_ctx);
- if (!walk_tree_ctx.state)
- cgit_print_error_page(404, "Not found", "Not found");
- else if (walk_tree_ctx.state == 2)
- cgit_print_error_page(404, "No blame for folders",
- "Blame is not available for folders.");
-
- free(walk_tree_ctx.curr_rev);
-}
diff --git a/ui-blame.h b/ui-blame.h
deleted file mode 100644
index 5b97e03..0000000
--- a/ui-blame.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef UI_BLAME_H
-#define UI_BLAME_H
-
-extern void cgit_print_blame(void);
-
-#endif /* UI_BLAME_H */
diff --git a/ui-blob.c b/ui-blob.c
deleted file mode 100644
index bc91656..0000000
--- a/ui-blob.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* ui-blob.c: show blob content
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-blob.h"
-#include "html.h"
-#include "ui-shared.h"
-
-struct walk_tree_context {
- const char *match_path;
- struct object_id *matched_oid;
- unsigned int found_path:1;
- unsigned int file_only:1;
-};
-
-static int walk_tree(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode, void *cbdata)
-{
- struct walk_tree_context *walk_tree_ctx = cbdata;
-
- if (walk_tree_ctx->file_only && !S_ISREG(mode))
- return READ_TREE_RECURSIVE;
- if (strncmp(base->buf, walk_tree_ctx->match_path, base->len)
- || strcmp(walk_tree_ctx->match_path + base->len, pathname))
- return READ_TREE_RECURSIVE;
- oidcpy(walk_tree_ctx->matched_oid, oid);
- walk_tree_ctx->found_path = 1;
- return 0;
-}
-
-int cgit_ref_path_exists(const char *path, const char *ref, int file_only)
-{
- struct object_id oid;
- unsigned long size;
- struct pathspec_item path_items = {
- .match = xstrdup(path),
- .len = strlen(path)
- };
- struct pathspec paths = {
- .nr = 1,
- .items = &path_items
- };
- struct walk_tree_context walk_tree_ctx = {
- .match_path = path,
- .matched_oid = &oid,
- .found_path = 0,
- .file_only = file_only
- };
-
- if (repo_get_oid(the_repository, ref, &oid))
- goto done;
- if (odb_read_object_info(the_repository->objects, &oid, &size) != OBJ_COMMIT)
- goto done;
- read_tree(the_repository,
- repo_get_commit_tree(the_repository, lookup_commit_reference(the_repository, &oid)),
- &paths, walk_tree, &walk_tree_ctx);
-
-done:
- free(path_items.match);
- return walk_tree_ctx.found_path;
-}
-
-int cgit_print_file(char *path, const char *head, int file_only)
-{
- struct object_id oid;
- enum object_type type;
- char *buf;
- unsigned long size;
- struct commit *commit;
- struct pathspec_item path_items = {
- .match = path,
- .len = strlen(path)
- };
- struct pathspec paths = {
- .nr = 1,
- .items = &path_items
- };
- struct walk_tree_context walk_tree_ctx = {
- .match_path = path,
- .matched_oid = &oid,
- .found_path = 0,
- .file_only = file_only
- };
-
- if (repo_get_oid(the_repository, head, &oid))
- return -1;
- type = odb_read_object_info(the_repository->objects, &oid, &size);
- if (type == OBJ_COMMIT) {
- commit = lookup_commit_reference(the_repository, &oid);
- read_tree(the_repository, repo_get_commit_tree(the_repository, commit),
- &paths, walk_tree, &walk_tree_ctx);
- if (!walk_tree_ctx.found_path)
- return -1;
- type = odb_read_object_info(the_repository->objects, &oid, &size);
- }
- if (type == OBJ_BAD)
- return -1;
- buf = odb_read_object(the_repository->objects, &oid, &type, &size);
- if (!buf)
- return -1;
- buf[size] = '\0';
- html_raw(buf, size);
- free(buf);
- return 0;
-}
-
-void cgit_print_blob(const char *hex, char *path, const char *head, int file_only)
-{
- struct object_id oid;
- enum object_type type;
- char *buf;
- unsigned long size;
- struct commit *commit;
- struct pathspec_item path_items = {
- .match = path,
- .len = path ? strlen(path) : 0
- };
- struct pathspec paths = {
- .nr = 1,
- .items = &path_items
- };
- struct walk_tree_context walk_tree_ctx = {
- .match_path = path,
- .matched_oid = &oid,
- .found_path = 0,
- .file_only = file_only
- };
-
- if (hex) {
- if (get_oid_hex(hex, &oid)) {
- cgit_print_error_page(400, "Bad request",
- "Bad hex value: %s", hex);
- return;
- }
- } else {
- if (repo_get_oid(the_repository, head, &oid)) {
- cgit_print_error_page(404, "Not found",
- "Bad ref: %s", head);
- return;
- }
- }
-
- type = odb_read_object_info(the_repository->objects, &oid, &size);
-
- if ((!hex) && type == OBJ_COMMIT && path) {
- commit = lookup_commit_reference(the_repository, &oid);
- read_tree(the_repository, repo_get_commit_tree(the_repository, commit),
- &paths, walk_tree, &walk_tree_ctx);
- type = odb_read_object_info(the_repository->objects, &oid, &size);
- }
-
- if (type == OBJ_BAD) {
- cgit_print_error_page(404, "Not found",
- "Bad object name: %s", hex);
- return;
- }
-
- buf = odb_read_object(the_repository->objects, &oid, &type, &size);
- if (!buf) {
- cgit_print_error_page(500, "Internal server error",
- "Error reading object %s", hex);
- return;
- }
-
- buf[size] = '\0';
- if (buffer_is_binary(buf, size))
- ctx.page.mimetype = "application/octet-stream";
- else
- ctx.page.mimetype = "text/plain";
- ctx.page.filename = path;
-
- html("X-Content-Type-Options: nosniff\n");
- html("Content-Security-Policy: default-src 'none'\n");
- cgit_print_http_headers();
- html_raw(buf, size);
- free(buf);
-}
diff --git a/ui-blob.h b/ui-blob.h
deleted file mode 100644
index 16847b2..0000000
--- a/ui-blob.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef UI_BLOB_H
-#define UI_BLOB_H
-
-extern int cgit_ref_path_exists(const char *path, const char *ref, int file_only);
-extern int cgit_print_file(char *path, const char *head, int file_only);
-extern void cgit_print_blob(const char *hex, char *path, const char *head, int file_only);
-
-#endif /* UI_BLOB_H */
diff --git a/ui-clone.c b/ui-clone.c
deleted file mode 100644
index e11f496..0000000
--- a/ui-clone.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/* ui-clone.c: functions for http cloning, based on
- * git's http-backend.c by Shawn O. Pearce
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-clone.h"
-#include "html.h"
-#include "ui-shared.h"
-#include "packfile.h"
-
-static int print_ref_info(const struct reference *ref, void *cb_data)
-{
- struct object *obj;
-
- if (!(obj = parse_object(the_repository, ref->oid)))
- return 0;
-
- htmlf("%s\t%s\n", oid_to_hex(ref->oid), ref->name);
- if (obj->type == OBJ_TAG) {
- if (!(obj = deref_tag(the_repository, obj, ref->name, 0)))
- return 0;
- htmlf("%s\t%s^{}\n", oid_to_hex(&obj->oid), ref->name);
- }
- return 0;
-}
-
-static void print_pack_info(void)
-{
- struct odb_source *source;
- char *offset;
-
- ctx.page.mimetype = "text/plain";
- ctx.page.filename = "objects/info/packs";
- cgit_print_http_headers();
- odb_reprepare(the_repository->objects);
- for (source = the_repository->objects->sources; source; source = source->next) {
- struct odb_source_files *files = odb_source_files_downcast(source);
- struct packfile_list_entry *e;
- for (e = files->packed->packs.head; e; e = e->next) {
- struct packed_git *p = e->pack;
- if (p->pack_local) {
- offset = strrchr(p->pack_name, '/');
- if (offset && offset[1] != '\0')
- ++offset;
- else
- offset = p->pack_name;
- htmlf("P %s\n", offset);
- }
- }
- }
-}
-
-static void send_file(const char *path)
-{
- struct stat st;
-
- if (stat(path, &st)) {
- switch (errno) {
- case ENOENT:
- cgit_print_error_page(404, "Not found", "Not found");
- break;
- case EACCES:
- cgit_print_error_page(403, "Forbidden", "Forbidden");
- break;
- default:
- cgit_print_error_page(400, "Bad request", "Bad request");
- }
- return;
- }
- ctx.page.mimetype = "application/octet-stream";
- ctx.page.filename = path;
- skip_prefix(path, ctx.repo->path, &ctx.page.filename);
- skip_prefix(ctx.page.filename, "/", &ctx.page.filename);
- cgit_print_http_headers();
- html_include(path);
-}
-
-void cgit_clone_info(void)
-{
- if (!ctx.qry.path || strcmp(ctx.qry.path, "refs")) {
- cgit_print_error_page(400, "Bad request", "Bad request");
- return;
- }
-
- ctx.page.mimetype = "text/plain";
- ctx.page.filename = "info/refs";
- cgit_print_http_headers();
- refs_for_each_ref(get_main_ref_store(the_repository),
- print_ref_info, NULL);
-}
-
-void cgit_clone_objects(void)
-{
- char *p, *path;
-
- if (!ctx.qry.path)
- goto err;
-
- if (!strcmp(ctx.qry.path, "info/packs")) {
- print_pack_info();
- return;
- }
-
- /* Avoid directory traversal by forbidding "..", but also work around
- * other funny business by just specifying a fairly strict format. For
- * example, now we don't have to stress out about the Cygwin port.
- */
- for (p = ctx.qry.path; *p; ++p) {
- if (*p == '.' && *(p + 1) == '.')
- goto err;
- if (!isalnum(*p) && *p != '/' && *p != '.' && *p != '-')
- goto err;
- }
-
- path = repo_git_path(the_repository, "objects/%s", ctx.qry.path);
- send_file(path);
- free(path);
- return;
-
-err:
- cgit_print_error_page(400, "Bad request", "Bad request");
-}
-
-void cgit_clone_head(void)
-{
- char *path;
-
- path = repo_git_path(the_repository, "HEAD");
- send_file(path);
- free(path);
-}
diff --git a/ui-clone.h b/ui-clone.h
deleted file mode 100644
index 3e460a3..0000000
--- a/ui-clone.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef UI_CLONE_H
-#define UI_CLONE_H
-
-void cgit_clone_info(void);
-void cgit_clone_objects(void);
-void cgit_clone_head(void);
-
-#endif /* UI_CLONE_H */
diff --git a/ui-commit.c b/ui-commit.c
deleted file mode 100644
index 972e9bc..0000000
--- a/ui-commit.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/* ui-commit.c: generate commit view
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-commit.h"
-#include "html.h"
-#include "ui-shared.h"
-#include "ui-diff.h"
-#include "ui-log.h"
-
-void cgit_print_commit(char *hex, const char *prefix)
-{
- struct commit *commit, *parent;
- struct commitinfo *info, *parent_info;
- struct commit_list *p;
- struct strbuf notes = STRBUF_INIT;
- struct object_id oid;
- char *tmp, *tmp2;
- int parents = 0;
-
- if (!hex)
- hex = ctx.qry.head;
-
- if (repo_get_oid(the_repository, hex, &oid)) {
- cgit_print_error_page(400, "Bad request",
- "Bad object id: %s", hex);
- return;
- }
- commit = lookup_commit_reference(the_repository, &oid);
- if (!commit) {
- cgit_print_error_page(404, "Not found",
- "Bad commit reference: %s", hex);
- return;
- }
- info = cgit_parse_commit(commit);
-
- format_display_notes(&oid, &notes, PAGE_ENCODING, 1);
-
- load_ref_decorations(NULL, DECORATE_FULL_REFS);
-
- ctx.page.title = fmtalloc("%s - %s", info->subject, ctx.page.title);
- cgit_print_layout_start();
- cgit_print_diff_ctrls();
- html("<table summary='commit info' class='commit-info'>\n");
- html("<tr><th>author</th><td>");
- cgit_open_filter(ctx.repo->email_filter, info->author_email, "commit");
- html_txt(info->author);
- if (!ctx.cfg.noplainemail) {
- html(" ");
- html_txt(info->author_email);
- }
- cgit_close_filter(ctx.repo->email_filter);
- html("</td><td class='right'>");
- html_txt(show_date(info->author_date, info->author_tz,
- cgit_date_mode(DATE_ISO8601)));
- html("</td></tr>\n");
- html("<tr><th>committer</th><td>");
- cgit_open_filter(ctx.repo->email_filter, info->committer_email, "commit");
- html_txt(info->committer);
- if (!ctx.cfg.noplainemail) {
- html(" ");
- html_txt(info->committer_email);
- }
- cgit_close_filter(ctx.repo->email_filter);
- html("</td><td class='right'>");
- html_txt(show_date(info->committer_date, info->committer_tz,
- cgit_date_mode(DATE_ISO8601)));
- html("</td></tr>\n");
- html("<tr><th>commit</th><td colspan='2' class='oid'>");
- tmp = oid_to_hex(&commit->object.oid);
- cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp, prefix);
- html(" (");
- cgit_patch_link("patch", NULL, NULL, NULL, tmp, prefix);
- html(")</td></tr>\n");
- html("<tr><th>tree</th><td colspan='2' class='oid'>");
- tmp = xstrdup(hex);
- cgit_tree_link(oid_to_hex(get_commit_tree_oid(commit)), NULL, NULL,
- ctx.qry.head, tmp, NULL);
- if (prefix) {
- html(" /");
- cgit_tree_link(prefix, NULL, NULL, ctx.qry.head, tmp, prefix);
- }
- free(tmp);
- html("</td></tr>\n");
- for (p = commit->parents; p; p = p->next) {
- parent = lookup_commit_reference(the_repository, &p->item->object.oid);
- if (!parent) {
- html("<tr><td colspan='3'>");
- cgit_print_error("Error reading parent commit");
- html("</td></tr>");
- continue;
- }
- html("<tr><th>parent</th>"
- "<td colspan='2' class='oid'>");
- tmp = tmp2 = oid_to_hex(&p->item->object.oid);
- if (ctx.repo->enable_subject_links) {
- parent_info = cgit_parse_commit(parent);
- tmp2 = parent_info->subject;
- }
- cgit_commit_link(tmp2, NULL, NULL, ctx.qry.head, tmp, prefix);
- html(" (");
- cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex,
- oid_to_hex(&p->item->object.oid), prefix);
- html(")</td></tr>");
- parents++;
- }
- if (ctx.repo->snapshots) {
- html("<tr><th>download</th><td colspan='2' class='oid'>");
- cgit_print_snapshot_links(ctx.repo, hex, "<br/>");
- html("</td></tr>");
- }
- html("</table>\n");
- html("<div class='commit-subject'>");
- cgit_open_filter(ctx.repo->commit_filter);
- html_txt(info->subject);
- cgit_close_filter(ctx.repo->commit_filter);
- show_commit_decorations(commit);
- html("</div>");
- html("<div class='commit-msg'>");
- cgit_open_filter(ctx.repo->commit_filter);
- html_txt(info->msg);
- cgit_close_filter(ctx.repo->commit_filter);
- html("</div>");
- if (notes.len != 0) {
- html("<div class='notes-header'>Notes</div>");
- html("<div class='notes'>");
- cgit_open_filter(ctx.repo->commit_filter);
- html_txt(notes.buf);
- cgit_close_filter(ctx.repo->commit_filter);
- html("</div>");
- html("<div class='notes-footer'></div>");
- }
- if (parents < 3) {
- if (parents)
- tmp = oid_to_hex(&commit->parents->item->object.oid);
- else
- tmp = NULL;
- cgit_print_diff(ctx.qry.oid, tmp, prefix, 0, 0);
- }
- strbuf_release(&notes);
- cgit_free_commitinfo(info);
- cgit_print_layout_end();
-}
diff --git a/ui-commit.h b/ui-commit.h
deleted file mode 100644
index 8198b4b..0000000
--- a/ui-commit.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef UI_COMMIT_H
-#define UI_COMMIT_H
-
-extern void cgit_print_commit(char *hex, const char *prefix);
-
-#endif /* UI_COMMIT_H */
diff --git a/ui-diff.c b/ui-diff.c
deleted file mode 100644
index 6cfa697..0000000
--- a/ui-diff.c
+++ /dev/null
@@ -1,503 +0,0 @@
-/* ui-diff.c: show diff between two blobs
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-diff.h"
-#include "html.h"
-#include "ui-shared.h"
-#include "ui-ssdiff.h"
-
-struct object_id old_rev_oid[1];
-struct object_id new_rev_oid[1];
-
-static int files, slots;
-static int total_adds, total_rems, max_changes;
-static int lines_added, lines_removed;
-
-static struct fileinfo {
- char status;
- struct object_id old_oid[1];
- struct object_id new_oid[1];
- unsigned short old_mode;
- unsigned short new_mode;
- char *old_path;
- char *new_path;
- unsigned int added;
- unsigned int removed;
- unsigned long old_size;
- unsigned long new_size;
- unsigned int binary:1;
-} *items;
-
-static int use_ssdiff = 0;
-static struct diff_filepair *current_filepair;
-static const char *current_prefix;
-
-struct diff_filespec *cgit_get_current_old_file(void)
-{
- return current_filepair->one;
-}
-
-struct diff_filespec *cgit_get_current_new_file(void)
-{
- return current_filepair->two;
-}
-
-static void print_fileinfo(struct fileinfo *info)
-{
- char *class;
-
- switch (info->status) {
- case DIFF_STATUS_ADDED:
- class = "add";
- break;
- case DIFF_STATUS_COPIED:
- class = "cpy";
- break;
- case DIFF_STATUS_DELETED:
- class = "del";
- break;
- case DIFF_STATUS_MODIFIED:
- class = "upd";
- break;
- case DIFF_STATUS_RENAMED:
- class = "mov";
- break;
- case DIFF_STATUS_TYPE_CHANGED:
- class = "typ";
- break;
- case DIFF_STATUS_UNKNOWN:
- class = "unk";
- break;
- case DIFF_STATUS_UNMERGED:
- class = "stg";
- break;
- default:
- die("bug: unhandled diff status %c", info->status);
- }
-
- html("<tr>");
- html("<td class='mode'>");
- if (is_null_oid(info->new_oid)) {
- cgit_print_filemode(info->old_mode);
- } else {
- cgit_print_filemode(info->new_mode);
- }
-
- if (info->old_mode != info->new_mode &&
- !is_null_oid(info->old_oid) &&
- !is_null_oid(info->new_oid)) {
- html("<span class='modechange'>[");
- cgit_print_filemode(info->old_mode);
- html("]</span>");
- }
- htmlf("</td><td class='%s'>", class);
- cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.oid,
- ctx.qry.oid2, info->new_path);
- if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED) {
- htmlf(" (%s from ",
- info->status == DIFF_STATUS_COPIED ? "copied" : "renamed");
- html_txt(info->old_path);
- html(")");
- }
- html("</td><td class='right'>");
- if (info->binary) {
- htmlf("bin</td><td class='graph'>%ld -> %ld bytes",
- info->old_size, info->new_size);
- return;
- }
- htmlf("%d", info->added + info->removed);
- html("</td><td class='graph'>");
- htmlf("<table summary='file diffstat' width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes));
- htmlf("<td class='add' style='width: %.1f%%;'/>",
- info->added * 100.0 / max_changes);
- htmlf("<td class='rem' style='width: %.1f%%;'/>",
- info->removed * 100.0 / max_changes);
- htmlf("<td class='none' style='width: %.1f%%;'/>",
- (max_changes - info->removed - info->added) * 100.0 / max_changes);
- html("</tr></table></td></tr>\n");
-}
-
-static void count_diff_lines(char *line, int len)
-{
- if (line && (len > 0)) {
- if (line[0] == '+')
- lines_added++;
- else if (line[0] == '-')
- lines_removed++;
- }
-}
-
-static int show_filepair(struct diff_filepair *pair)
-{
- /* Always show if we have no limiting prefix. */
- if (!current_prefix)
- return 1;
-
- /* Show if either path in the pair begins with the prefix. */
- if (starts_with(pair->one->path, current_prefix) ||
- starts_with(pair->two->path, current_prefix))
- return 1;
-
- /* Otherwise we don't want to show this filepair. */
- return 0;
-}
-
-static void inspect_filepair(struct diff_filepair *pair)
-{
- int binary = 0;
- unsigned long old_size = 0;
- unsigned long new_size = 0;
-
- if (!show_filepair(pair))
- return;
-
- files++;
- lines_added = 0;
- lines_removed = 0;
- cgit_diff_files(&pair->one->oid, &pair->two->oid, &old_size, &new_size,
- &binary, 0, ctx.qry.ignorews, count_diff_lines);
- if (files >= slots) {
- if (slots == 0)
- slots = 4;
- else
- slots = slots * 2;
- items = xrealloc(items, slots * sizeof(struct fileinfo));
- }
- items[files-1].status = pair->status;
- oidcpy(items[files-1].old_oid, &pair->one->oid);
- oidcpy(items[files-1].new_oid, &pair->two->oid);
- items[files-1].old_mode = pair->one->mode;
- items[files-1].new_mode = pair->two->mode;
- items[files-1].old_path = xstrdup(pair->one->path);
- items[files-1].new_path = xstrdup(pair->two->path);
- items[files-1].added = lines_added;
- items[files-1].removed = lines_removed;
- items[files-1].old_size = old_size;
- items[files-1].new_size = new_size;
- items[files-1].binary = binary;
- if (lines_added + lines_removed > max_changes)
- max_changes = lines_added + lines_removed;
- total_adds += lines_added;
- total_rems += lines_removed;
-}
-
-static void cgit_print_diffstat(const struct object_id *old_oid,
- const struct object_id *new_oid,
- const char *prefix)
-{
- int i;
-
- html("<div class='diffstat-header'>");
- cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.oid,
- ctx.qry.oid2, NULL);
- if (prefix) {
- html(" (limited to '");
- html_txt(prefix);
- html("')");
- }
- html("</div>");
- html("<table summary='diffstat' class='diffstat'>");
- max_changes = 0;
- cgit_diff_tree(old_oid, new_oid, inspect_filepair, prefix,
- ctx.qry.ignorews);
- for (i = 0; i<files; i++)
- print_fileinfo(&items[i]);
- html("</table>");
- html("<div class='diffstat-summary'>");
- htmlf("%d files changed, %d insertions, %d deletions",
- files, total_adds, total_rems);
- html("</div>");
-}
-
-
-/*
- * print a single line returned from xdiff
- */
-static void print_line(char *line, int len)
-{
- char *class = "ctx";
- char c = line[len-1];
-
- if (line[0] == '+')
- class = "add";
- else if (line[0] == '-')
- class = "del";
- else if (line[0] == '@')
- class = "hunk";
-
- htmlf("<div class='%s'>", class);
- line[len-1] = '\0';
- html_txt(line);
- html("</div>");
- line[len-1] = c;
-}
-
-static void header(const struct object_id *oid1, char *path1, int mode1,
- const struct object_id *oid2, char *path2, int mode2)
-{
- char *abbrev1, *abbrev2;
- int subproject;
-
- subproject = (S_ISGITLINK(mode1) || S_ISGITLINK(mode2));
- html("<div class='head'>");
- html("diff --git a/");
- html_txt(path1);
- html(" b/");
- html_txt(path2);
-
- if (mode1 == 0)
- htmlf("<br/>new file mode %.6o", mode2);
-
- if (mode2 == 0)
- htmlf("<br/>deleted file mode %.6o", mode1);
-
- if (!subproject) {
- abbrev1 = xstrdup(repo_find_unique_abbrev(the_repository, oid1, DEFAULT_ABBREV));
- abbrev2 = xstrdup(repo_find_unique_abbrev(the_repository, oid2, DEFAULT_ABBREV));
- htmlf("<br/>index %s..%s", abbrev1, abbrev2);
- free(abbrev1);
- free(abbrev2);
- if (mode1 != 0 && mode2 != 0) {
- htmlf(" %.6o", mode1);
- if (mode2 != mode1)
- htmlf("..%.6o", mode2);
- }
- if (is_null_oid(oid1)) {
- path1 = "dev/null";
- html("<br/>--- /");
- } else
- html("<br/>--- a/");
- if (mode1 != 0)
- cgit_tree_link(path1, NULL, NULL, ctx.qry.head,
- oid_to_hex(old_rev_oid), path1);
- else
- html_txt(path1);
- if (is_null_oid(oid2)) {
- path2 = "dev/null";
- html("<br/>+++ /");
- } else
- html("<br/>+++ b/");
- if (mode2 != 0)
- cgit_tree_link(path2, NULL, NULL, ctx.qry.head,
- oid_to_hex(new_rev_oid), path2);
- else
- html_txt(path2);
- }
- html("</div>");
-}
-
-static void filepair_cb(struct diff_filepair *pair)
-{
- unsigned long old_size = 0;
- unsigned long new_size = 0;
- int binary = 0;
- linediff_fn print_line_fn = print_line;
-
- if (!show_filepair(pair))
- return;
-
- current_filepair = pair;
- if (use_ssdiff) {
- cgit_ssdiff_header_begin();
- print_line_fn = cgit_ssdiff_line_cb;
- }
- header(&pair->one->oid, pair->one->path, pair->one->mode,
- &pair->two->oid, pair->two->path, pair->two->mode);
- if (use_ssdiff)
- cgit_ssdiff_header_end();
- if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) {
- if (S_ISGITLINK(pair->one->mode))
- print_line_fn(fmt("-Subproject %s", oid_to_hex(&pair->one->oid)), 52);
- if (S_ISGITLINK(pair->two->mode))
- print_line_fn(fmt("+Subproject %s", oid_to_hex(&pair->two->oid)), 52);
- if (use_ssdiff)
- cgit_ssdiff_footer();
- return;
- }
- if (cgit_diff_files(&pair->one->oid, &pair->two->oid, &old_size,
- &new_size, &binary, ctx.qry.context,
- ctx.qry.ignorews, print_line_fn))
- cgit_print_error("Error running diff");
- if (binary) {
- if (use_ssdiff)
- html("<tr><td colspan='4'>Binary files differ</td></tr>");
- else
- html("Binary files differ");
- }
- if (use_ssdiff)
- cgit_ssdiff_footer();
-}
-
-void cgit_print_diff_ctrls(void)
-{
- int i, curr;
-
- html("<div class='cgit-panel'>");
- html("<b>diff options</b>");
- html("<form method='get'>");
- cgit_add_hidden_formfields(1, 0, ctx.qry.page);
- html("<table>");
- html("<tr><td colspan='2'/></tr>");
- html("<tr>");
- html("<td class='label'>context:</td>");
- html("<td class='ctrl'>");
- html("<select name='context' onchange='this.form.submit();'>");
- curr = ctx.qry.context;
- if (!curr)
- curr = 3;
- for (i = 1; i <= 10; i++)
- html_intoption(i, fmt("%d", i), curr);
- for (i = 15; i <= 40; i += 5)
- html_intoption(i, fmt("%d", i), curr);
- html("</select>");
- html("</td>");
- html("</tr><tr>");
- html("<td class='label'>space:</td>");
- html("<td class='ctrl'>");
- html("<select name='ignorews' onchange='this.form.submit();'>");
- html_intoption(0, "include", ctx.qry.ignorews);
- html_intoption(1, "ignore", ctx.qry.ignorews);
- html("</select>");
- html("</td>");
- html("</tr><tr>");
- html("<td class='label'>mode:</td>");
- html("<td class='ctrl'>");
- html("<select name='dt' onchange='this.form.submit();'>");
- curr = ctx.qry.has_difftype ? ctx.qry.difftype : ctx.cfg.difftype;
- html_intoption(0, "unified", curr);
- html_intoption(1, "ssdiff", curr);
- html_intoption(2, "stat only", curr);
- html("</select></td></tr>");
- html("<tr><td/><td class='ctrl'>");
- html("<noscript><input type='submit' value='reload'/></noscript>");
- html("</td></tr></table>");
- html("</form>");
- html("</div>");
-}
-
-void cgit_print_diff(const char *new_rev, const char *old_rev,
- const char *prefix, int show_ctrls, int raw)
-{
- struct commit *commit, *commit2;
- const struct object_id *old_tree_oid, *new_tree_oid;
- diff_type difftype;
-
- /*
- * If "follow" is set then the diff machinery needs to examine the
- * entire commit to detect renames so we must limit the paths in our
- * own callbacks and not pass the prefix to the diff machinery.
- */
- if (ctx.qry.follow && ctx.repo->enable_follow_links) {
- current_prefix = prefix;
- prefix = "";
- } else {
- current_prefix = NULL;
- }
-
- if (!new_rev)
- new_rev = ctx.qry.head;
- if (repo_get_oid(the_repository, new_rev, new_rev_oid)) {
- cgit_print_error_page(404, "Not found",
- "Bad object name: %s", new_rev);
- return;
- }
- commit = lookup_commit_reference(the_repository, new_rev_oid);
- if (!commit || repo_parse_commit(the_repository, commit)) {
- cgit_print_error_page(404, "Not found",
- "Bad commit: %s", oid_to_hex(new_rev_oid));
- return;
- }
- new_tree_oid = get_commit_tree_oid(commit);
-
- if (old_rev) {
- if (repo_get_oid(the_repository, old_rev, old_rev_oid)) {
- cgit_print_error_page(404, "Not found",
- "Bad object name: %s", old_rev);
- return;
- }
- } else if (commit->parents && commit->parents->item) {
- oidcpy(old_rev_oid, &commit->parents->item->object.oid);
- } else {
- oidclr(old_rev_oid, the_repository->hash_algo);
- }
-
- if (!is_null_oid(old_rev_oid)) {
- commit2 = lookup_commit_reference(the_repository, old_rev_oid);
- if (!commit2 || repo_parse_commit(the_repository, commit2)) {
- cgit_print_error_page(404, "Not found",
- "Bad commit: %s", oid_to_hex(old_rev_oid));
- return;
- }
- old_tree_oid = get_commit_tree_oid(commit2);
- } else {
- old_tree_oid = NULL;
- }
-
- if (raw) {
- struct diff_options diffopt;
-
- repo_diff_setup(the_repository, &diffopt);
- diffopt.output_format = DIFF_FORMAT_PATCH;
- diffopt.flags.recursive = 1;
- diff_setup_done(&diffopt);
-
- ctx.page.mimetype = "text/plain";
- cgit_print_http_headers();
- if (old_tree_oid) {
- diff_tree_oid(old_tree_oid, new_tree_oid, "",
- &diffopt);
- } else {
- diff_root_tree_oid(new_tree_oid, "", &diffopt);
- }
- diffcore_std(&diffopt);
- diff_flush(&diffopt);
-
- return;
- }
-
- difftype = ctx.qry.has_difftype ? ctx.qry.difftype : ctx.cfg.difftype;
- use_ssdiff = difftype == DIFF_SSDIFF;
-
- if (show_ctrls) {
- cgit_print_layout_start();
- cgit_print_diff_ctrls();
- }
-
- /*
- * Clicking on a link to a file in the diff stat should show a diff
- * of the file, showing the diff stat limited to a single file is
- * pretty useless. All links from this point on will be to
- * individual files, so we simply reset the difftype in the query
- * here to avoid propagating DIFF_STATONLY to the individual files.
- */
- if (difftype == DIFF_STATONLY)
- ctx.qry.difftype = ctx.cfg.difftype;
-
- cgit_print_diffstat(old_rev_oid, new_rev_oid, prefix);
-
- if (difftype == DIFF_STATONLY)
- return;
-
- if (use_ssdiff) {
- html("<table summary='ssdiff' class='ssdiff'>");
- } else {
- html("<table summary='diff' class='diff'>");
- html("<tr><td>");
- }
- cgit_diff_tree(old_rev_oid, new_rev_oid, filepair_cb, prefix,
- ctx.qry.ignorews);
- if (!use_ssdiff)
- html("</td></tr>");
- html("</table>");
-
- if (show_ctrls)
- cgit_print_layout_end();
-}
diff --git a/ui-diff.h b/ui-diff.h
deleted file mode 100644
index 39264a1..0000000
--- a/ui-diff.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef UI_DIFF_H
-#define UI_DIFF_H
-
-extern void cgit_print_diff_ctrls(void);
-
-extern void cgit_print_diff(const char *new_hex, const char *old_hex,
- const char *prefix, int show_ctrls, int raw);
-
-extern struct diff_filespec *cgit_get_current_old_file(void);
-extern struct diff_filespec *cgit_get_current_new_file(void);
-
-extern struct object_id old_rev_oid[1];
-extern struct object_id new_rev_oid[1];
-
-#endif /* UI_DIFF_H */
diff --git a/ui-log.c b/ui-log.c
deleted file mode 100644
index 9906bbc..0000000
--- a/ui-log.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/* ui-log.c: functions for log output
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-log.h"
-#include "html.h"
-#include "ui-shared.h"
-#include "strvec.h"
-
-static int files, add_lines, rem_lines, lines_counted;
-
-/*
- * The list of available column colors in the commit graph.
- */
-static const char *column_colors_html[] = {
- "<span class='column1'>",
- "<span class='column2'>",
- "<span class='column3'>",
- "<span class='column4'>",
- "<span class='column5'>",
- "<span class='column6'>",
- "</span>",
-};
-
-#define COLUMN_COLORS_HTML_MAX (ARRAY_SIZE(column_colors_html) - 1)
-
-static void count_lines(char *line, int size)
-{
- if (size <= 0)
- return;
-
- if (line[0] == '+')
- add_lines++;
-
- else if (line[0] == '-')
- rem_lines++;
-}
-
-static void inspect_files(struct diff_filepair *pair)
-{
- unsigned long old_size = 0;
- unsigned long new_size = 0;
- int binary = 0;
-
- files++;
- if (ctx.repo->enable_log_linecount)
- cgit_diff_files(&pair->one->oid, &pair->two->oid, &old_size,
- &new_size, &binary, 0, ctx.qry.ignorews,
- count_lines);
-}
-
-void show_commit_decorations(struct commit *commit)
-{
- const struct name_decoration *deco;
- static char buf[1024];
-
- buf[sizeof(buf) - 1] = 0;
- deco = get_name_decoration(&commit->object);
- if (!deco)
- return;
- html("<span class='decoration'>");
- while (deco) {
- struct object_id oid_tag, peeled;
- int is_annotated = 0;
-
- strlcpy(buf, prettify_refname(deco->name), sizeof(buf));
- switch(deco->type) {
- case DECORATION_NONE:
- /* If the git-core doesn't recognize it,
- * don't display anything. */
- break;
- case DECORATION_REF_LOCAL:
- cgit_log_link(buf, NULL, "branch-deco", buf, NULL,
- ctx.qry.vpath, 0, NULL, NULL,
- ctx.qry.showmsg, 0);
- break;
- case DECORATION_REF_TAG:
- if (!refs_read_ref(get_main_ref_store(the_repository), deco->name, &oid_tag) &&
- !peel_object(the_repository, &oid_tag, &peeled, PEEL_OBJECT_VERIFY_TAGGED_OBJECT_TYPE))
- is_annotated = !oideq(&oid_tag, &peeled);
- cgit_tag_link(buf, NULL, is_annotated ? "tag-annotated-deco" : "tag-deco", buf);
- break;
- case DECORATION_REF_REMOTE:
- if (!ctx.repo->enable_remote_branches)
- break;
- cgit_log_link(buf, NULL, "remote-deco", NULL,
- oid_to_hex(&commit->object.oid),
- ctx.qry.vpath, 0, NULL, NULL,
- ctx.qry.showmsg, 0);
- break;
- default:
- cgit_commit_link(buf, NULL, "deco", ctx.qry.head,
- oid_to_hex(&commit->object.oid),
- ctx.qry.vpath);
- break;
- }
- deco = deco->next;
- }
- html("</span>");
-}
-
-static void handle_rename(struct diff_filepair *pair)
-{
- /*
- * After we have seen a rename, we generate links to the previous
- * name of the file so that commit & diff views get fed the path
- * that is correct for the commit they are showing, avoiding the
- * need to walk the entire history leading back to every commit we
- * show in order detect renames.
- */
- if (0 != strcmp(ctx.qry.vpath, pair->two->path)) {
- free(ctx.qry.vpath);
- ctx.qry.vpath = xstrdup(pair->two->path);
- }
- inspect_files(pair);
-}
-
-static int show_commit(struct commit *commit, struct rev_info *revs)
-{
- struct commit_list *parents = commit->parents;
- struct commit *parent;
- int found = 0, saved_fmt;
- struct diff_flags saved_flags = revs->diffopt.flags;
-
- /* Always show if we're not in "follow" mode with a single file. */
- if (!ctx.qry.follow)
- return 1;
-
- /*
- * In "follow" mode, we don't show merges. This is consistent with
- * "git log --follow -- <file>".
- */
- if (parents && parents->next)
- return 0;
-
- /*
- * If this is the root commit, do what rev_info tells us.
- */
- if (!parents)
- return revs->show_root_diff;
-
- /* When we get here we have precisely one parent. */
- parent = parents->item;
- /* If we can't parse the commit, let print_commit() report an error. */
- if (repo_parse_commit(the_repository, parent))
- return 1;
-
- files = 0;
- add_lines = 0;
- rem_lines = 0;
-
- revs->diffopt.flags.recursive = 1;
- diff_tree_oid(get_commit_tree_oid(parent),
- get_commit_tree_oid(commit),
- "", &revs->diffopt);
- diffcore_std(&revs->diffopt);
-
- found = !diff_queue_is_empty(&revs->diffopt);
- saved_fmt = revs->diffopt.output_format;
- revs->diffopt.output_format = DIFF_FORMAT_CALLBACK;
- revs->diffopt.format_callback = cgit_diff_tree_cb;
- revs->diffopt.format_callback_data = handle_rename;
- revs->diffopt.no_free = 1;
- diff_flush(&revs->diffopt);
- revs->diffopt.output_format = saved_fmt;
- revs->diffopt.flags = saved_flags;
-
- lines_counted = 1;
- return found;
-}
-
-static void print_commit(struct commit *commit, struct rev_info *revs)
-{
- struct commitinfo *info;
- int columns = revs->graph ? 4 : 3;
- struct strbuf graphbuf = STRBUF_INIT;
- struct strbuf msgbuf = STRBUF_INIT;
-
- if (ctx.repo->enable_log_filecount)
- columns++;
- if (ctx.repo->enable_log_linecount)
- columns++;
-
- if (revs->graph) {
- /* Advance graph until current commit */
- while (!graph_next_line(revs->graph, &graphbuf)) {
- /* Print graph segment in otherwise empty table row */
- html("<tr class='nohover'><td class='commitgraph'>");
- html(graphbuf.buf);
- htmlf("</td><td colspan='%d' /></tr>\n", columns);
- strbuf_setlen(&graphbuf, 0);
- }
- /* Current commit's graph segment is now ready in graphbuf */
- }
-
- info = cgit_parse_commit(commit);
- htmlf("<tr%s>", ctx.qry.showmsg ? " class='logheader'" : "");
-
- if (revs->graph) {
- /* Print graph segment for current commit */
- html("<td class='commitgraph'>");
- html(graphbuf.buf);
- html("</td>");
- strbuf_setlen(&graphbuf, 0);
- }
- else {
- html("<td>");
- cgit_print_age(info->committer_date, info->committer_tz, TM_WEEK * 2);
- html("</td>");
- }
-
- htmlf("<td%s>", ctx.qry.showmsg ? " class='logsubject'" : "");
- if (ctx.qry.showmsg) {
- /* line-wrap long commit subjects instead of truncating them */
- size_t subject_len = strlen(info->subject);
-
- if (subject_len > ctx.cfg.max_msg_len &&
- ctx.cfg.max_msg_len >= 15) {
- /* symbol for signaling line-wrap (in PAGE_ENCODING) */
- const char wrap_symbol[] = { ' ', 0xE2, 0x86, 0xB5, 0 };
- int i = ctx.cfg.max_msg_len - strlen(wrap_symbol);
-
- /* Rewind i to preceding space character */
- while (i > 0 && !isspace(info->subject[i]))
- --i;
- if (!i) /* Oops, zero spaces. Reset i */
- i = ctx.cfg.max_msg_len - strlen(wrap_symbol);
-
- /* add remainder starting at i to msgbuf */
- strbuf_add(&msgbuf, info->subject + i, subject_len - i);
- strbuf_trim(&msgbuf);
- strbuf_add(&msgbuf, "\n\n", 2);
-
- /* Place wrap_symbol at position i in info->subject */
- strlcpy(info->subject + i, wrap_symbol, subject_len - i + 1);
- }
- }
- cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head,
- oid_to_hex(&commit->object.oid), ctx.qry.vpath);
- show_commit_decorations(commit);
- html("</td><td>");
- cgit_open_filter(ctx.repo->email_filter, info->author_email, "log");
- html_txt(info->author);
- cgit_close_filter(ctx.repo->email_filter);
-
- if (revs->graph) {
- html("</td><td>");
- cgit_print_age(info->committer_date, info->committer_tz, TM_WEEK * 2);
- }
-
- if (!lines_counted && (ctx.repo->enable_log_filecount ||
- ctx.repo->enable_log_linecount)) {
- files = 0;
- add_lines = 0;
- rem_lines = 0;
- cgit_diff_commit(commit, inspect_files, ctx.qry.vpath);
- }
-
- if (ctx.repo->enable_log_filecount)
- htmlf("</td><td>%d", files);
- if (ctx.repo->enable_log_linecount)
- htmlf("</td><td><span class='deletions'>-%d</span>/"
- "<span class='insertions'>+%d</span>", rem_lines, add_lines);
-
- html("</td></tr>\n");
-
- if ((revs->graph && !graph_is_commit_finished(revs->graph))
- || ctx.qry.showmsg) { /* Print a second table row */
- html("<tr class='nohover-highlight'>");
-
- if (ctx.qry.showmsg) {
- /* Concatenate commit message + notes in msgbuf */
- if (info->msg && *(info->msg)) {
- strbuf_addstr(&msgbuf, info->msg);
- strbuf_addch(&msgbuf, '\n');
- }
- format_display_notes(&commit->object.oid,
- &msgbuf, PAGE_ENCODING, 0);
- strbuf_addch(&msgbuf, '\n');
- strbuf_ltrim(&msgbuf);
- }
-
- if (revs->graph) {
- int lines = 0;
-
- /* Calculate graph padding */
- if (ctx.qry.showmsg) {
- /* Count #lines in commit message + notes */
- const char *p = msgbuf.buf;
- lines = 1;
- while ((p = strchr(p, '\n'))) {
- p++;
- lines++;
- }
- }
-
- /* Print graph padding */
- html("<td class='commitgraph'>");
- while (lines > 0 || !graph_is_commit_finished(revs->graph)) {
- if (graphbuf.len)
- html("\n");
- strbuf_setlen(&graphbuf, 0);
- graph_next_line(revs->graph, &graphbuf);
- html(graphbuf.buf);
- lines--;
- }
- html("</td>\n");
- }
- else
- html("<td/>"); /* Empty 'Age' column */
-
- /* Print msgbuf into remainder of table row */
- htmlf("<td colspan='%d'%s>\n", columns - (revs->graph ? 1 : 0),
- ctx.qry.showmsg ? " class='logmsg'" : "");
- html_txt(msgbuf.buf);
- html("</td></tr>\n");
- }
-
- strbuf_release(&msgbuf);
- strbuf_release(&graphbuf);
- cgit_free_commitinfo(info);
-}
-
-static const char *disambiguate_ref(const char *ref, int *must_free_result)
-{
- struct object_id oid;
- struct strbuf longref = STRBUF_INIT;
-
- strbuf_addf(&longref, "refs/heads/%s", ref);
- if (repo_get_oid(the_repository, longref.buf, &oid) == 0) {
- *must_free_result = 1;
- return strbuf_detach(&longref, NULL);
- }
-
- *must_free_result = 0;
- strbuf_release(&longref);
- return ref;
-}
-
-static char *next_token(char **src)
-{
- char *result;
-
- if (!src || !*src)
- return NULL;
- while (isspace(**src))
- (*src)++;
- if (!**src)
- return NULL;
- result = *src;
- while (**src) {
- if (isspace(**src)) {
- **src = '\0';
- (*src)++;
- break;
- }
- (*src)++;
- }
- return result;
-}
-
-void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern,
- const char *path, int pager, int commit_graph, int commit_sort)
-{
- struct rev_info rev;
- struct commit *commit;
- struct strvec rev_argv = STRVEC_INIT;
- int i, columns = commit_graph ? 4 : 3;
- int must_free_tip = 0;
-
- /* rev_argv.argv[0] will be ignored by setup_revisions */
- strvec_push(&rev_argv, "log_rev_setup");
-
- if (!tip)
- tip = ctx.qry.head;
- tip = disambiguate_ref(tip, &must_free_tip);
- strvec_push(&rev_argv, tip);
-
- if (grep && pattern && *pattern) {
- pattern = xstrdup(pattern);
- if (!strcmp(grep, "grep") || !strcmp(grep, "author") ||
- !strcmp(grep, "committer")) {
- strvec_pushf(&rev_argv, "--%s=%s", grep, pattern);
- } else if (!strcmp(grep, "range")) {
- char *arg;
- /* Split the pattern at whitespace and add each token
- * as a revision expression. Do not accept other
- * rev-list options. Also, replace the previously
- * pushed tip (it's no longer relevant).
- */
- strvec_pop(&rev_argv);
- while ((arg = next_token(&pattern))) {
- if (*arg == '-') {
- fprintf(stderr, "Bad range expr: %s\n",
- arg);
- break;
- }
- strvec_push(&rev_argv, arg);
- }
- }
- }
-
- if (!path || !ctx.repo->enable_follow_links) {
- /*
- * If we don't have a path, "follow" is a no-op so make sure
- * the variable is set to false to avoid needing to check
- * both this and whether we have a path everywhere.
- */
- ctx.qry.follow = 0;
- }
-
- if (commit_graph && !ctx.qry.follow) {
- strvec_push(&rev_argv, "--graph");
- strvec_push(&rev_argv, "--color");
- graph_set_column_colors(column_colors_html,
- COLUMN_COLORS_HTML_MAX);
- }
-
- if (commit_sort == 1)
- strvec_push(&rev_argv, "--date-order");
- else if (commit_sort == 2)
- strvec_push(&rev_argv, "--topo-order");
-
- if (path && ctx.qry.follow)
- strvec_push(&rev_argv, "--follow");
- strvec_push(&rev_argv, "--");
- if (path)
- strvec_push(&rev_argv, path);
-
- repo_init_revisions(the_repository, &rev, NULL);
- rev.abbrev = DEFAULT_ABBREV;
- rev.commit_format = CMIT_FMT_DEFAULT;
- rev.verbose_header = 1;
- rev.show_root_diff = 0;
- rev.ignore_missing = 1;
- rev.simplify_history = 1;
- setup_revisions(rev_argv.nr, rev_argv.v, &rev, NULL);
- load_ref_decorations(NULL, DECORATE_FULL_REFS);
- rev.show_decorations = 1;
- rev.grep_filter.ignore_case = 1;
-
- rev.diffopt.detect_rename = 1;
- rev.diffopt.rename_limit = ctx.cfg.renamelimit;
- if (ctx.qry.ignorews)
- DIFF_XDL_SET(&rev.diffopt, IGNORE_WHITESPACE);
-
- compile_grep_patterns(&rev.grep_filter);
- prepare_revision_walk(&rev);
-
- if (pager) {
- cgit_print_layout_start();
- html("<table class='list nowrap'>");
- }
-
- html("<tr class='nohover'>");
- if (commit_graph)
- html("<th></th>");
- else
- html("<th class='left'>Age</th>");
- html("<th class='left'>Commit message");
- if (pager) {
- html(" (");
- cgit_log_link(ctx.qry.showmsg ? "Collapse" : "Expand", NULL,
- NULL, ctx.qry.head, ctx.qry.oid,
- ctx.qry.vpath, ctx.qry.ofs, ctx.qry.grep,
- ctx.qry.search, ctx.qry.showmsg ? 0 : 1,
- ctx.qry.follow);
- html(")");
- }
- html("</th><th class='left'>Author</th>");
- if (rev.graph)
- html("<th class='left'>Age</th>");
- if (ctx.repo->enable_log_filecount) {
- html("<th class='left'>Files</th>");
- columns++;
- }
- if (ctx.repo->enable_log_linecount) {
- html("<th class='left'>Lines</th>");
- columns++;
- }
- html("</tr>\n");
-
- if (ofs<0)
- ofs = 0;
-
- for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; /* nop */) {
- if (show_commit(commit, &rev))
- i++;
- release_commit_memory(the_repository->parsed_objects, commit);
- commit->parents = NULL;
- }
-
- for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; /* nop */) {
- /*
- * In "follow" mode, we must count the files and lines the
- * first time we invoke diff on a given commit, and we need
- * to do that to see if the commit touches the path we care
- * about, so we do it in show_commit. Hence we must clear
- * lines_counted here.
- *
- * This has the side effect of avoiding running diff twice
- * when we are both following renames and showing file
- * and/or line counts.
- */
- lines_counted = 0;
- if (show_commit(commit, &rev)) {
- i++;
- print_commit(commit, &rev);
- }
- release_commit_memory(the_repository->parsed_objects, commit);
- commit->parents = NULL;
- }
- if (pager) {
- html("</table><ul class='pager'>");
- if (ofs > 0) {
- html("<li>");
- cgit_log_link("[prev]", NULL, NULL, ctx.qry.head,
- ctx.qry.oid, ctx.qry.vpath,
- ofs - cnt, ctx.qry.grep,
- ctx.qry.search, ctx.qry.showmsg,
- ctx.qry.follow);
- html("</li>");
- }
- if ((commit = get_revision(&rev)) != NULL) {
- html("<li>");
- cgit_log_link("[next]", NULL, NULL, ctx.qry.head,
- ctx.qry.oid, ctx.qry.vpath,
- ofs + cnt, ctx.qry.grep,
- ctx.qry.search, ctx.qry.showmsg,
- ctx.qry.follow);
- html("</li>");
- }
- html("</ul>");
- cgit_print_layout_end();
- } else if ((commit = get_revision(&rev)) != NULL) {
- htmlf("<tr class='nohover'><td colspan='%d'>", columns);
- cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL,
- ctx.qry.vpath, 0, NULL, NULL, ctx.qry.showmsg,
- ctx.qry.follow);
- html("</td></tr>\n");
- }
-
- /* If we allocated tip then it is safe to cast away const. */
- if (must_free_tip)
- free((char*) tip);
-}
diff --git a/ui-log.h b/ui-log.h
deleted file mode 100644
index 325607c..0000000
--- a/ui-log.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef UI_LOG_H
-#define UI_LOG_H
-
-extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep,
- char *pattern, const char *path, int pager,
- int commit_graph, int commit_sort);
-extern void show_commit_decorations(struct commit *commit);
-
-#endif /* UI_LOG_H */
diff --git a/ui-patch.c b/ui-patch.c
deleted file mode 100644
index f9d2eeb..0000000
--- a/ui-patch.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/* ui-patch.c: generate patch view
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-patch.h"
-#include "html.h"
-#include "ui-shared.h"
-
-/* two commit hashes with two dots in between and termination */
-#define REV_RANGE_LEN 2 * GIT_MAX_HEXSZ + 3
-
-void cgit_print_patch(const char *new_rev, const char *old_rev,
- const char *prefix)
-{
- struct rev_info rev;
- struct commit *commit;
- struct object_id new_rev_oid, old_rev_oid;
- char rev_range[REV_RANGE_LEN];
- const char *rev_argv[] = { NULL, "--reverse", "--format=email", rev_range, "--", prefix, NULL };
- int rev_argc = ARRAY_SIZE(rev_argv) - 1;
- char *patchname;
-
- if (!prefix)
- rev_argc--;
-
- if (!new_rev)
- new_rev = ctx.qry.head;
-
- if (repo_get_oid(the_repository, new_rev, &new_rev_oid)) {
- cgit_print_error_page(404, "Not found",
- "Bad object id: %s", new_rev);
- return;
- }
- commit = lookup_commit_reference(the_repository, &new_rev_oid);
- if (!commit) {
- cgit_print_error_page(404, "Not found",
- "Bad commit reference: %s", new_rev);
- return;
- }
-
- if (old_rev) {
- if (repo_get_oid(the_repository, old_rev, &old_rev_oid)) {
- cgit_print_error_page(404, "Not found",
- "Bad object id: %s", old_rev);
- return;
- }
- if (!lookup_commit_reference(the_repository, &old_rev_oid)) {
- cgit_print_error_page(404, "Not found",
- "Bad commit reference: %s", old_rev);
- return;
- }
- } else if (commit->parents && commit->parents->item) {
- oidcpy(&old_rev_oid, &commit->parents->item->object.oid);
- } else {
- oidclr(&old_rev_oid, the_repository->hash_algo);
- }
-
- if (is_null_oid(&old_rev_oid)) {
- memcpy(rev_range, oid_to_hex(&new_rev_oid), the_hash_algo->hexsz + 1);
- } else {
- xsnprintf(rev_range, REV_RANGE_LEN, "%s..%s", oid_to_hex(&old_rev_oid),
- oid_to_hex(&new_rev_oid));
- }
-
- patchname = fmt("%s.patch", rev_range);
- ctx.page.mimetype = "text/plain";
- ctx.page.filename = patchname;
- cgit_print_http_headers();
-
- if (ctx.cfg.noplainemail) {
- rev_argv[2] = "--format=format:From %H Mon Sep 17 00:00:00 "
- "2001%nFrom: %an%nDate: %aD%n%w(78,0,1)Subject: "
- "%s%n%n%w(0)%b";
- }
-
- repo_init_revisions(the_repository, &rev, NULL);
- rev.abbrev = DEFAULT_ABBREV;
- rev.verbose_header = 1;
- rev.diff = 1;
- rev.show_root_diff = 1;
- rev.max_parents = 1;
- rev.diffopt.output_format |= DIFF_FORMAT_DIFFSTAT |
- DIFF_FORMAT_PATCH | DIFF_FORMAT_SUMMARY;
- if (prefix)
- rev.diffopt.stat_sep = fmt("(limited to '%s')\n\n", prefix);
- setup_revisions(rev_argc, rev_argv, &rev, NULL);
- prepare_revision_walk(&rev);
-
- while ((commit = get_revision(&rev)) != NULL) {
- log_tree_commit(&rev, commit);
- printf("-- \ncgit %s\n\n", cgit_version);
- }
-}
diff --git a/ui-patch.h b/ui-patch.h
deleted file mode 100644
index 7a6cacd..0000000
--- a/ui-patch.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef UI_PATCH_H
-#define UI_PATCH_H
-
-extern void cgit_print_patch(const char *new_rev, const char *old_rev,
- const char *prefix);
-
-#endif /* UI_PATCH_H */
diff --git a/ui-plain.c b/ui-plain.c
deleted file mode 100644
index a2a4087..0000000
--- a/ui-plain.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/* ui-plain.c: functions for output of plain blobs by path
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-plain.h"
-#include "html.h"
-#include "ui-shared.h"
-
-struct walk_tree_context {
- int match_baselen;
- int match;
-};
-
-static int print_object(const struct object_id *oid, const char *path)
-{
- enum object_type type;
- char *buf, *mimetype;
- unsigned long size;
-
- type = odb_read_object_info(the_repository->objects, oid, &size);
- if (type == OBJ_BAD) {
- cgit_print_error_page(404, "Not found", "Not found");
- return 0;
- }
-
- buf = odb_read_object(the_repository->objects, oid, &type, &size);
- if (!buf) {
- cgit_print_error_page(404, "Not found", "Not found");
- return 0;
- }
-
- mimetype = get_mimetype_for_filename(path);
- ctx.page.mimetype = mimetype;
-
- if (!ctx.repo->enable_html_serving) {
- html("X-Content-Type-Options: nosniff\n");
- html("Content-Security-Policy: default-src 'none'\n");
- if (mimetype) {
- /* Built-in white list allows PDF and everything that isn't text/ and application/ */
- if ((!strncmp(mimetype, "text/", 5) || !strncmp(mimetype, "application/", 12)) && strcmp(mimetype, "application/pdf"))
- ctx.page.mimetype = NULL;
- }
- }
-
- if (!ctx.page.mimetype) {
- if (buffer_is_binary(buf, size)) {
- ctx.page.mimetype = "application/octet-stream";
- ctx.page.charset = NULL;
- } else {
- ctx.page.mimetype = "text/plain";
- }
- }
- ctx.page.filename = path;
- ctx.page.size = size;
- ctx.page.etag = oid_to_hex(oid);
- cgit_print_http_headers();
- html_raw(buf, size);
- free(mimetype);
- free(buf);
- return 1;
-}
-
-static char *buildpath(const char *base, int baselen, const char *path)
-{
- if (path[0])
- return fmtalloc("%.*s%s/", baselen, base, path);
- else
- return fmtalloc("%.*s/", baselen, base);
-}
-
-static void print_dir(const struct object_id *oid, const char *base,
- int baselen, const char *path)
-{
- char *fullpath, *slash;
- size_t len;
-
- fullpath = buildpath(base, baselen, path);
- slash = (fullpath[0] == '/' ? "" : "/");
- ctx.page.etag = oid_to_hex(oid);
- cgit_print_http_headers();
- htmlf("<html><head><title>%s", slash);
- html_txt(fullpath);
- htmlf("</title></head>\n<body>\n<h2>%s", slash);
- html_txt(fullpath);
- html("</h2>\n<ul>\n");
- len = strlen(fullpath);
- if (len > 1) {
- fullpath[len - 1] = 0;
- slash = strrchr(fullpath, '/');
- if (slash)
- *(slash + 1) = 0;
- else {
- free(fullpath);
- fullpath = NULL;
- }
- html("<li>");
- cgit_plain_link("../", NULL, NULL, ctx.qry.head, ctx.qry.oid,
- fullpath);
- html("</li>\n");
- }
- free(fullpath);
-}
-
-static void print_dir_entry(const struct object_id *oid, const char *base,
- int baselen, const char *path, unsigned mode)
-{
- char *fullpath;
-
- fullpath = buildpath(base, baselen, path);
- if (!S_ISDIR(mode) && !S_ISGITLINK(mode))
- fullpath[strlen(fullpath) - 1] = 0;
- html(" <li>");
- if (S_ISGITLINK(mode)) {
- cgit_submodule_link(NULL, fullpath, oid_to_hex(oid));
- } else
- cgit_plain_link(path, NULL, NULL, ctx.qry.head, ctx.qry.oid,
- fullpath);
- html("</li>\n");
- free(fullpath);
-}
-
-static void print_dir_tail(void)
-{
- html(" </ul>\n</body></html>\n");
-}
-
-static int walk_tree(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode, void *cbdata)
-{
- struct walk_tree_context *walk_tree_ctx = cbdata;
-
- if (base->len == walk_tree_ctx->match_baselen) {
- if (S_ISREG(mode) || S_ISLNK(mode)) {
- if (print_object(oid, pathname))
- walk_tree_ctx->match = 1;
- } else if (S_ISDIR(mode)) {
- print_dir(oid, base->buf, base->len, pathname);
- walk_tree_ctx->match = 2;
- return READ_TREE_RECURSIVE;
- }
- } else if (base->len < INT_MAX && (int)base->len > walk_tree_ctx->match_baselen) {
- print_dir_entry(oid, base->buf, base->len, pathname, mode);
- walk_tree_ctx->match = 2;
- } else if (S_ISDIR(mode)) {
- return READ_TREE_RECURSIVE;
- }
-
- return 0;
-}
-
-static int basedir_len(const char *path)
-{
- const char *p = strrchr(path, '/');
- if (p)
- return p - path + 1;
- return 0;
-}
-
-void cgit_print_plain(void)
-{
- const char *rev = ctx.qry.oid;
- struct object_id oid;
- struct commit *commit;
- struct pathspec_item path_items = {
- .match = ctx.qry.path,
- .len = ctx.qry.path ? strlen(ctx.qry.path) : 0
- };
- struct pathspec paths = {
- .nr = 1,
- .items = &path_items
- };
- struct walk_tree_context walk_tree_ctx = {
- .match = 0
- };
-
- if (!rev)
- rev = ctx.qry.head;
-
- if (repo_get_oid(the_repository, rev, &oid)) {
- cgit_print_error_page(404, "Not found", "Not found");
- return;
- }
- commit = lookup_commit_reference(the_repository, &oid);
- if (!commit || repo_parse_commit(the_repository, commit)) {
- cgit_print_error_page(404, "Not found", "Not found");
- return;
- }
- if (!path_items.match) {
- path_items.match = "";
- walk_tree_ctx.match_baselen = -1;
- print_dir(get_commit_tree_oid(commit), "", 0, "");
- walk_tree_ctx.match = 2;
- }
- else
- walk_tree_ctx.match_baselen = basedir_len(path_items.match);
- read_tree(the_repository, repo_get_commit_tree(the_repository, commit),
- &paths, walk_tree, &walk_tree_ctx);
- if (!walk_tree_ctx.match)
- cgit_print_error_page(404, "Not found", "Not found");
- else if (walk_tree_ctx.match == 2)
- print_dir_tail();
-}
diff --git a/ui-plain.h b/ui-plain.h
deleted file mode 100644
index 5bff07b..0000000
--- a/ui-plain.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef UI_PLAIN_H
-#define UI_PLAIN_H
-
-extern void cgit_print_plain(void);
-
-#endif /* UI_PLAIN_H */
diff --git a/ui-refs.c b/ui-refs.c
deleted file mode 100644
index 11fb9fc..0000000
--- a/ui-refs.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/* ui-refs.c: browse symbolic refs
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-refs.h"
-#include "html.h"
-#include "ui-shared.h"
-
-static inline int cmp_age(int age1, int age2)
-{
- /* age1 and age2 are assumed to be non-negative */
- return age2 - age1;
-}
-
-static int cmp_ref_name(const void *a, const void *b)
-{
- struct refinfo *r1 = *(struct refinfo **)a;
- struct refinfo *r2 = *(struct refinfo **)b;
-
- return strcmp(r1->refname, r2->refname);
-}
-
-static int cmp_branch_age(const void *a, const void *b)
-{
- struct refinfo *r1 = *(struct refinfo **)a;
- struct refinfo *r2 = *(struct refinfo **)b;
-
- return cmp_age(r1->commit->committer_date, r2->commit->committer_date);
-}
-
-static int get_ref_age(struct refinfo *ref)
-{
- if (!ref->object)
- return 0;
- switch (ref->object->type) {
- case OBJ_TAG:
- return ref->tag ? ref->tag->tagger_date : 0;
- case OBJ_COMMIT:
- return ref->commit ? ref->commit->committer_date : 0;
- }
- return 0;
-}
-
-static int cmp_tag_age(const void *a, const void *b)
-{
- struct refinfo *r1 = *(struct refinfo **)a;
- struct refinfo *r2 = *(struct refinfo **)b;
-
- return cmp_age(get_ref_age(r1), get_ref_age(r2));
-}
-
-static int print_branch(struct refinfo *ref)
-{
- struct commitinfo *info = ref->commit;
- char *name = (char *)ref->refname;
-
- if (!info)
- return 1;
- html("<tr><td>");
- cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL,
- ctx.qry.showmsg, 0);
- html("</td><td>");
-
- if (ref->object->type == OBJ_COMMIT) {
- cgit_commit_link(info->subject, NULL, NULL, name, NULL, NULL);
- html("</td><td>");
- cgit_open_filter(ctx.repo->email_filter, info->author_email, "refs");
- html_txt(info->author);
- cgit_close_filter(ctx.repo->email_filter);
- html("</td><td colspan='2'>");
- cgit_print_age(info->committer_date, info->committer_tz, -1);
- } else {
- html("</td><td></td><td>");
- cgit_object_link(ref->object);
- }
- html("</td></tr>\n");
- return 0;
-}
-
-static void print_tag_header(void)
-{
- html("<tr class='nohover'><th class='left'>Tag</th>"
- "<th class='left'>Download</th>"
- "<th class='left'>Author</th>"
- "<th class='left' colspan='2'>Age</th></tr>\n");
-}
-
-static int print_tag(struct refinfo *ref)
-{
- struct tag *tag = NULL;
- struct taginfo *info = NULL;
- char *name = (char *)ref->refname;
- struct object *obj = ref->object;
-
- if (obj->type == OBJ_TAG) {
- tag = (struct tag *)obj;
- obj = tag->tagged;
- info = ref->tag;
- if (!info)
- return 1;
- }
-
- html("<tr><td>");
- cgit_tag_link(name, NULL, NULL, name);
- html("</td><td>");
- if (ctx.repo->snapshots && (obj->type == OBJ_COMMIT))
- cgit_print_snapshot_links(ctx.repo, name, "&nbsp;&nbsp;");
- else
- cgit_object_link(obj);
- html("</td><td>");
- if (info) {
- if (info->tagger) {
- cgit_open_filter(ctx.repo->email_filter, info->tagger_email, "refs");
- html_txt(info->tagger);
- cgit_close_filter(ctx.repo->email_filter);
- }
- } else if (ref->object->type == OBJ_COMMIT) {
- cgit_open_filter(ctx.repo->email_filter, ref->commit->author_email, "refs");
- html_txt(ref->commit->author);
- cgit_close_filter(ctx.repo->email_filter);
- }
- html("</td><td colspan='2'>");
- if (info) {
- if (info->tagger_date > 0)
- cgit_print_age(info->tagger_date, info->tagger_tz, -1);
- } else if (ref->object->type == OBJ_COMMIT) {
- cgit_print_age(ref->commit->commit->date, 0, -1);
- }
- html("</td></tr>\n");
-
- return 0;
-}
-
-static void print_refs_link(const char *path)
-{
- html("<tr class='nohover'><td colspan='5'>");
- cgit_refs_link("[...]", NULL, NULL, ctx.qry.head, NULL, path);
- html("</td></tr>");
-}
-
-void cgit_print_branches(int maxcount)
-{
- struct reflist list;
- int i;
-
- html("<tr class='nohover'><th class='left'>Branch</th>"
- "<th class='left'>Commit message</th>"
- "<th class='left'>Author</th>"
- "<th class='left' colspan='2'>Age</th></tr>\n");
-
- list.refs = NULL;
- list.alloc = list.count = 0;
- refs_for_each_branch_ref(get_main_ref_store(the_repository),
- cgit_refs_cb, &list);
- if (ctx.repo->enable_remote_branches)
- refs_for_each_remote_ref(get_main_ref_store(the_repository),
- cgit_refs_cb, &list);
-
- if (maxcount == 0 || maxcount > list.count)
- maxcount = list.count;
-
- qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age);
- if (ctx.repo->branch_sort == 0)
- qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name);
-
- for (i = 0; i < maxcount; i++)
- print_branch(list.refs[i]);
-
- if (maxcount < list.count)
- print_refs_link("heads");
-
- cgit_free_reflist_inner(&list);
-}
-
-void cgit_print_tags(int maxcount)
-{
- struct reflist list;
- int i;
-
- list.refs = NULL;
- list.alloc = list.count = 0;
- refs_for_each_tag_ref(get_main_ref_store(the_repository),
- cgit_refs_cb, &list);
- if (list.count == 0)
- return;
- qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age);
- if (!maxcount)
- maxcount = list.count;
- else if (maxcount > list.count)
- maxcount = list.count;
- print_tag_header();
- for (i = 0; i < maxcount; i++)
- print_tag(list.refs[i]);
-
- if (maxcount < list.count)
- print_refs_link("tags");
-
- cgit_free_reflist_inner(&list);
-}
-
-void cgit_print_refs(void)
-{
- cgit_print_layout_start();
- html("<table class='list nowrap'>");
-
- if (ctx.qry.path && starts_with(ctx.qry.path, "heads"))
- cgit_print_branches(0);
- else if (ctx.qry.path && starts_with(ctx.qry.path, "tags"))
- cgit_print_tags(0);
- else {
- cgit_print_branches(0);
- html("<tr class='nohover'><td colspan='5'>&nbsp;</td></tr>");
- cgit_print_tags(0);
- }
- html("</table>");
- cgit_print_layout_end();
-}
diff --git a/ui-refs.h b/ui-refs.h
deleted file mode 100644
index 1d4a54a..0000000
--- a/ui-refs.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef UI_REFS_H
-#define UI_REFS_H
-
-extern void cgit_print_branches(int maxcount);
-extern void cgit_print_tags(int maxcount);
-extern void cgit_print_refs(void);
-
-#endif /* UI_REFS_H */
diff --git a/ui-repolist.c b/ui-repolist.c
deleted file mode 100644
index 1b224cf..0000000
--- a/ui-repolist.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/* ui-repolist.c: functions for generating the repolist page
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#include "cgit.h"
-#include "ui-repolist.h"
-#include "html.h"
-#include "ui-shared.h"
-
-static time_t read_agefile(const char *path)
-{
- time_t result;
- size_t size;
- char *buf = NULL;
- struct strbuf date_buf = STRBUF_INIT;
-
- if (read_first_line(path, &buf, &size)) {
- free(buf);
- return 0;
- }
-
- if (parse_date(buf, &date_buf) == 0)
- result = strtoul(date_buf.buf, NULL, 10);
- else
- result = 0;
- free(buf);
- strbuf_release(&date_buf);
- return result;
-}
-
-static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime)
-{
- struct strbuf path = STRBUF_INIT;
- struct stat s;
- struct cgit_repo *r = (struct cgit_repo *)repo;
-
- if (repo->mtime != -1) {
- *mtime = repo->mtime;
- return 1;
- }
- strbuf_addf(&path, "%s/%s", repo->path, ctx.cfg.agefile);
- if (stat(path.buf, &s) == 0) {
- *mtime = read_agefile(path.buf);
- if (*mtime) {
- r->mtime = *mtime;
- goto end;
- }
- }
-
- strbuf_reset(&path);
- strbuf_addf(&path, "%s/refs/heads/%s", repo->path,
- repo->defbranch ? repo->defbranch : "master");
- if (stat(path.buf, &s) == 0) {
- *mtime = s.st_mtime;
- r->mtime = *mtime;
- goto end;
- }
-
- strbuf_reset(&path);
- strbuf_addf(&path, "%s/%s", repo->path, "packed-refs");
- if (stat(path.buf, &s) == 0) {
- *mtime = s.st_mtime;
- r->mtime = *mtime;
- goto end;
- }
-
- *mtime = 0;
- r->mtime = *mtime;
-end:
- strbuf_release(&path);
- return (r->mtime != 0);
-}
-
-static void print_modtime(struct cgit_repo *repo)
-{
- time_t t;
- if (get_repo_modtime(repo, &t))
- cgit_print_age(t, 0, -1);
-}
-
-static int is_match(struct cgit_repo *repo)
-{
- if (!ctx.qry.search)
- return 1;
- if (repo->url && strcasestr(repo->url, ctx.qry.search))
- return 1;
- if (repo->name && strcasestr(repo->name, ctx.qry.search))
- return 1;
- if (repo->desc && strcasestr(repo->desc, ctx.qry.search))
- return 1;
- if (repo->owner && strcasestr(repo->owner, ctx.qry.search))
- return 1;
- return 0;
-}
-
-static int is_in_url(struct cgit_repo *repo)
-{
- if (!ctx.qry.url)
- return 1;
- if (repo->url && starts_with(repo->url, ctx.qry.url))
- return 1;
- return 0;
-}
-
-static int is_visible(struct cgit_repo *repo)
-{
- if (repo->hide || repo->ignore)
- return 0;
- if (!(is_match(repo) && is_in_url(repo)))
- return 0;
- return 1;
-}
-
-static int any_repos_visible(void)
-{
- int i;
-
- for (i = 0; i < cgit_repolist.count; i++) {
- if (is_visible(&cgit_repolist.repos[i]))
- return 1;
- }
- return 0;
-}
-
-static void print_sort_header(const char *title, const char *sort)
-{
- char *currenturl = cgit_currenturl();
- html("<th class='left'><a href='");
- html_attr(currenturl);
- htmlf("?s=%s", sort);
- if (ctx.qry.search) {
- html("&amp;q=");
- html_url_arg(ctx.qry.search);
- }
- htmlf("'>%s</a></th>", title);
- free(currenturl);
-}
-
-static void print_header(void)
-{
- html("<tr class='nohover'>");
- print_sort_header("Name", "name");
- print_sort_header("Description", "desc");
- if (ctx.cfg.enable_index_owner)
- print_sort_header("Owner", "owner");
- print_sort_header("Idle", "idle");
- if (ctx.cfg.enable_index_links)
- html("<th class='left'>Links</th>");
- html("</tr>\n");
-}
-
-
-static void print_pager(int items, int pagelen, char *search, char *sort)
-{
- int i, ofs;
- char *class = NULL;
- html("<ul class='pager'>");
- for (i = 0, ofs = 0; ofs < items; i++, ofs = i * pagelen) {
- class = (ctx.qry.ofs == ofs) ? "current" : NULL;
- html("<li>");
- cgit_index_link(fmt("[%d]", i + 1), fmt("Page %d", i + 1),
- class, search, sort, ofs, 0);
- html("</li>");
- }
- html("</ul>");
-}
-
-static int cmp(const char *s1, const char *s2)
-{
- if (s1 && s2) {
- if (ctx.cfg.case_sensitive_sort)
- return strcmp(s1, s2);
- else
- return strcasecmp(s1, s2);
- }
- if (s1 && !s2)
- return -1;
- if (s2 && !s1)
- return 1;
- return 0;
-}
-
-static int sort_name(const void *a, const void *b)
-{
- const struct cgit_repo *r1 = a;
- const struct cgit_repo *r2 = b;
-
- return cmp(r1->name, r2->name);
-}
-
-static int sort_desc(const void *a, const void *b)
-{
- const struct cgit_repo *r1 = a;
- const struct cgit_repo *r2 = b;
-
- return cmp(r1->desc, r2->desc);
-}
-
-static int sort_owner(const void *a, const void *b)
-{
- const struct cgit_repo *r1 = a;
- const struct cgit_repo *r2 = b;
-
- return cmp(r1->owner, r2->owner);
-}
-
-static int sort_idle(const void *a, const void *b)
-{
- const struct cgit_repo *r1 = a;
- const struct cgit_repo *r2 = b;
- time_t t1, t2;
-
- t1 = t2 = 0;
- get_repo_modtime(r1, &t1);
- get_repo_modtime(r2, &t2);
- return t2 - t1;
-}
-
-static int sort_section(const void *a, const void *b)
-{
- const struct cgit_repo *r1 = a;
- const struct cgit_repo *r2 = b;
- int result;
-
- result = cmp(r1->section, r2->section);
- if (!result) {
- if (!strcmp(ctx.cfg.repository_sort, "age"))
- result = sort_idle(r1, r2);
- if (!result)
- result = cmp(r1->name, r2->name);
- }
- return result;
-}
-
-struct sortcolumn {
- const char *name;
- int (*fn)(const void *a, const void *b);
-};
-
-static const struct sortcolumn sortcolumn[] = {
- {"section", sort_section},
- {"name", sort_name},
- {"desc", sort_desc},
- {"owner", sort_owner},
- {"idle", sort_idle},
- {NULL, NULL}
-};
-
-static int sort_repolist(char *field)
-{
- const struct sortcolumn *column;
-
- for (column = &sortcolumn[0]; column->name; column++) {
- if (strcmp(field, column->name))
- continue;
- qsort(cgit_repolist.repos, cgit_repolist.count,
- sizeof(struct cgit_repo), column->fn);
- return 1;
- }
- return 0;
-}
-
-
-void cgit_print_repolist(void)
-{
- int i, columns = 3, hits = 0, header = 0;
- char *last_section = NULL;
- char *section;
- char *repourl;
- int sorted = 0;
-
- if (!any_repos_visible()) {
- cgit_print_error_page(404, "Not found", "No repositories found");
- return;
- }
-
- if (ctx.cfg.enable_index_links)
- ++columns;
- if (ctx.cfg.enable_index_owner)
- ++columns;
-
- ctx.page.title = ctx.cfg.root_title;
- cgit_print_http_headers();
- cgit_print_docstart();
- cgit_print_pageheader();
-
- if (ctx.qry.sort)
- sorted = sort_repolist(ctx.qry.sort);
- else if (ctx.cfg.section_sort)
- sort_repolist("section");
-
- html("<table summary='repository list' class='list nowrap'>");
- for (i = 0; i < cgit_repolist.count; i++) {
- ctx.repo = &cgit_repolist.repos[i];
- if (!is_visible(ctx.repo))
- continue;
- hits++;
- if (hits <= ctx.qry.ofs)
- continue;
- if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count)
- continue;
- if (!header++)
- print_header();
- section = ctx.repo->section;
- if (section && !strcmp(section, ""))
- section = NULL;
- if (!sorted &&
- ((last_section == NULL && section != NULL) ||
- (last_section != NULL && section == NULL) ||
- (last_section != NULL && section != NULL &&
- strcmp(section, last_section)))) {
- htmlf("<tr class='nohover-highlight'><td colspan='%d' class='reposection'>",
- columns);
- html_txt(section);
- html("</td></tr>");
- last_section = section;
- }
- htmlf("<tr><td class='%s'>",
- !sorted && section ? "sublevel-repo" : "toplevel-repo");
- cgit_summary_link(ctx.repo->name, NULL, NULL, NULL);
- html("</td><td>");
- repourl = cgit_repourl(ctx.repo->url);
- html_link_open(repourl, NULL, NULL);
- free(repourl);
- if (html_ntxt(ctx.repo->desc, ctx.cfg.max_repodesc_len) < 0)
- html("...");
- html_link_close();
- html("</td><td>");
- if (ctx.cfg.enable_index_owner) {
- if (ctx.repo->owner_filter) {
- cgit_open_filter(ctx.repo->owner_filter);
- html_txt(ctx.repo->owner);
- cgit_close_filter(ctx.repo->owner_filter);
- } else {
- char *currenturl = cgit_currenturl();
- html("<a href='");
- html_attr(currenturl);
- html("?q=");
- html_url_arg(ctx.repo->owner);
- html("'>");
- html_txt(ctx.repo->owner);
- html("</a>");
- free(currenturl);
- }
- html("</td><td>");
- }
- print_modtime(ctx.repo);
- html("</td>");
- if (ctx.cfg.enable_index_links) {
- html("<td>");
- cgit_summary_link("summary", NULL, "button", NULL);
- cgit_log_link("log", NULL, "button", NULL, NULL, NULL,
- 0, NULL, NULL, ctx.qry.showmsg, 0);
- cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL);
- html("</td>");
- }
- html("</tr>\n");
- }
- html("</table>");
- if (hits > ctx.cfg.max_repo_count)
- print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search, ctx.qry.sort);
- cgit_print_docend();
-}
-
-void cgit_print_site_readme(void)
-{
- cgit_print_layout_start();
- if (!ctx.cfg.root_readme)
- goto done;
- cgit_open_filter(ctx.cfg.about_filter, ctx.cfg.root_readme);
- html_include(ctx.cfg.root_readme);
- cgit_close_filter(ctx.cfg.about_filter);
-done:
- cgit_print_layout_end();
-}
diff --git a/ui-repolist.h b/ui-repolist.h
deleted file mode 100644
index 1b6b322..0000000
--- a/ui-repolist.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef UI_REPOLIST_H
-#define UI_REPOLIST_H
-
-extern void cgit_print_repolist(void);
-extern void cgit_print_site_readme(void);
-
-#endif /* UI_REPOLIST_H */
diff --git a/ui-shared.c b/ui-shared.c
deleted file mode 100644
index df52a9b..0000000
--- a/ui-shared.c
+++ /dev/null
@@ -1,1265 +0,0 @@
-/* ui-shared.c: common web output functions
- *
- * Copyright (C) 2006-2017 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-shared.h"
-#include "cmd.h"
-#include "html.h"
-#include "version.h"
-
-static const char cgit_doctype[] =
-"<!DOCTYPE html>\n";
-
-static char *http_date(time_t t)
-{
- static char day[][4] =
- {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
- static char month[][4] =
- {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
- struct tm tm;
- gmtime_r(&t, &tm);
- return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm.tm_wday],
- tm.tm_mday, month[tm.tm_mon], 1900 + tm.tm_year,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
-}
-
-void cgit_print_error(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- cgit_vprint_error(fmt, ap);
- va_end(ap);
-}
-
-void cgit_vprint_error(const char *fmt, va_list ap)
-{
- va_list cp;
- html("<div class='error'>");
- va_copy(cp, ap);
- html_vtxtf(fmt, cp);
- va_end(cp);
- html("</div>\n");
-}
-
-const char *cgit_httpscheme(void)
-{
- if (ctx.env.https && !strcmp(ctx.env.https, "on"))
- return "https://";
- else
- return "http://";
-}
-
-char *cgit_hosturl(void)
-{
- if (ctx.env.http_host)
- return xstrdup(ctx.env.http_host);
- if (!ctx.env.server_name)
- return NULL;
- if (!ctx.env.server_port || atoi(ctx.env.server_port) == 80)
- return xstrdup(ctx.env.server_name);
- return fmtalloc("%s:%s", ctx.env.server_name, ctx.env.server_port);
-}
-
-char *cgit_currenturl(void)
-{
- const char *root = cgit_rooturl();
-
- if (!ctx.qry.url)
- return xstrdup(root);
- if (root[0] && root[strlen(root) - 1] == '/')
- return fmtalloc("%s%s", root, ctx.qry.url);
- return fmtalloc("%s/%s", root, ctx.qry.url);
-}
-
-char *cgit_currentfullurl(void)
-{
- const char *root = cgit_rooturl();
- const char *orig_query = ctx.env.query_string ? ctx.env.query_string : "";
- size_t len = strlen(orig_query);
- char *query = xmalloc(len + 2), *start_url, *ret;
-
- /* Remove all url=... parts from query string */
- memcpy(query + 1, orig_query, len + 1);
- query[0] = '?';
- start_url = query;
- while ((start_url = strstr(start_url, "url=")) != NULL) {
- if (start_url[-1] == '?' || start_url[-1] == '&') {
- const char *end_url = strchr(start_url, '&');
- if (end_url)
- memmove(start_url, end_url + 1, strlen(end_url));
- else
- start_url[0] = '\0';
- } else
- ++start_url;
- }
- if (!query[1])
- query[0] = '\0';
-
- if (!ctx.qry.url)
- ret = fmtalloc("%s%s", root, query);
- else if (root[0] && root[strlen(root) - 1] == '/')
- ret = fmtalloc("%s%s%s", root, ctx.qry.url, query);
- else
- ret = fmtalloc("%s/%s%s", root, ctx.qry.url, query);
- free(query);
- return ret;
-}
-
-const char *cgit_rooturl(void)
-{
- if (ctx.cfg.virtual_root)
- return ctx.cfg.virtual_root;
- else
- return ctx.cfg.script_name;
-}
-
-const char *cgit_loginurl(void)
-{
- static const char *login_url;
- if (!login_url)
- login_url = fmtalloc("%s?p=login", cgit_rooturl());
- return login_url;
-}
-
-char *cgit_repourl(const char *reponame)
-{
- if (ctx.cfg.virtual_root)
- return fmtalloc("%s%s/", ctx.cfg.virtual_root, reponame);
- else
- return fmtalloc("?r=%s", reponame);
-}
-
-char *cgit_fileurl(const char *reponame, const char *pagename,
- const char *filename, const char *query)
-{
- struct strbuf sb = STRBUF_INIT;
- char *delim;
-
- if (ctx.cfg.virtual_root) {
- strbuf_addf(&sb, "%s%s/%s/%s", ctx.cfg.virtual_root, reponame,
- pagename, (filename ? filename:""));
- delim = "?";
- } else {
- strbuf_addf(&sb, "?url=%s/%s/%s", reponame, pagename,
- (filename ? filename : ""));
- delim = "&amp;";
- }
- if (query)
- strbuf_addf(&sb, "%s%s", delim, query);
- return strbuf_detach(&sb, NULL);
-}
-
-char *cgit_pageurl(const char *reponame, const char *pagename,
- const char *query)
-{
- return cgit_fileurl(reponame, pagename, NULL, query);
-}
-
-const char *cgit_repobasename(const char *reponame)
-{
- /* I assume we don't need to store more than one repo basename */
- static char rvbuf[1024];
- int p;
- const char *rv;
- size_t len;
-
- len = strlcpy(rvbuf, reponame, sizeof(rvbuf));
- if (len >= sizeof(rvbuf))
- die("cgit_repobasename: truncated repository name '%s'", reponame);
- p = len - 1;
- /* strip trailing slashes */
- while (p && rvbuf[p] == '/')
- rvbuf[p--] = '\0';
- /* strip trailing .git */
- if (p >= 3 && starts_with(&rvbuf[p-3], ".git")) {
- p -= 3;
- rvbuf[p--] = '\0';
- }
- /* strip more trailing slashes if any */
- while (p && rvbuf[p] == '/')
- rvbuf[p--] = '\0';
- /* find last slash in the remaining string */
- rv = strrchr(rvbuf, '/');
- if (rv)
- return ++rv;
- return rvbuf;
-}
-
-const char *cgit_snapshot_prefix(const struct cgit_repo *repo)
-{
- if (repo->snapshot_prefix)
- return repo->snapshot_prefix;
-
- return cgit_repobasename(repo->url);
-}
-
-static void site_url(const char *page, const char *search, const char *sort, int ofs, int always_root)
-{
- char *delim = "?";
-
- if (always_root || page)
- html_attr(cgit_rooturl());
- else {
- char *currenturl = cgit_currenturl();
- html_attr(currenturl);
- free(currenturl);
- }
-
- if (page) {
- htmlf("?p=%s", page);
- delim = "&amp;";
- }
- if (search) {
- html(delim);
- html("q=");
- html_attr(search);
- delim = "&amp;";
- }
- if (sort) {
- html(delim);
- html("s=");
- html_attr(sort);
- delim = "&amp;";
- }
- if (ofs) {
- html(delim);
- htmlf("ofs=%d", ofs);
- }
-}
-
-static void site_link(const char *page, const char *name, const char *title,
- const char *class, const char *search, const char *sort, int ofs, int always_root)
-{
- html("<a");
- if (title) {
- html(" title='");
- html_attr(title);
- html("'");
- }
- if (class) {
- html(" class='");
- html_attr(class);
- html("'");
- }
- html(" href='");
- site_url(page, search, sort, ofs, always_root);
- html("'>");
- html_txt(name);
- html("</a>");
-}
-
-void cgit_index_link(const char *name, const char *title, const char *class,
- const char *pattern, const char *sort, int ofs, int always_root)
-{
- site_link(NULL, name, title, class, pattern, sort, ofs, always_root);
-}
-
-static char *repolink(const char *title, const char *class, const char *page,
- const char *head, const char *path)
-{
- char *delim = "?";
-
- html("<a");
- if (title) {
- html(" title='");
- html_attr(title);
- html("'");
- }
- if (class) {
- html(" class='");
- html_attr(class);
- html("'");
- }
- html(" href='");
- if (ctx.cfg.virtual_root) {
- html_url_path(ctx.cfg.virtual_root);
- html_url_path(ctx.repo->url);
- if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')
- html("/");
- if (page) {
- html_url_path(page);
- html("/");
- if (path)
- html_url_path(path);
- }
- } else {
- html_url_path(ctx.cfg.script_name);
- html("?url=");
- html_url_arg(ctx.repo->url);
- if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')
- html("/");
- if (page) {
- html_url_arg(page);
- html("/");
- if (path)
- html_url_arg(path);
- }
- delim = "&amp;";
- }
- if (head && ctx.repo->defbranch && strcmp(head, ctx.repo->defbranch)) {
- html(delim);
- html("h=");
- html_url_arg(head);
- delim = "&amp;";
- }
- return fmt("%s", delim);
-}
-
-static void reporevlink(const char *page, const char *name, const char *title,
- const char *class, const char *head, const char *rev,
- const char *path)
-{
- char *delim;
-
- delim = repolink(title, class, page, head, path);
- if (rev && ctx.qry.head != NULL && strcmp(rev, ctx.qry.head)) {
- html(delim);
- html("id=");
- html_url_arg(rev);
- }
- html("'>");
- html_txt(name);
- html("</a>");
-}
-
-void cgit_summary_link(const char *name, const char *title, const char *class,
- const char *head)
-{
- reporevlink(NULL, name, title, class, head, NULL, NULL);
-}
-
-void cgit_tag_link(const char *name, const char *title, const char *class,
- const char *tag)
-{
- reporevlink("tag", name, title, class, tag, NULL, NULL);
-}
-
-void cgit_tree_link(const char *name, const char *title, const char *class,
- const char *head, const char *rev, const char *path)
-{
- reporevlink("tree", name, title, class, head, rev, path);
-}
-
-void cgit_plain_link(const char *name, const char *title, const char *class,
- const char *head, const char *rev, const char *path)
-{
- reporevlink("plain", name, title, class, head, rev, path);
-}
-
-void cgit_blame_link(const char *name, const char *title, const char *class,
- const char *head, const char *rev, const char *path)
-{
- reporevlink("blame", name, title, class, head, rev, path);
-}
-
-void cgit_log_link(const char *name, const char *title, const char *class,
- const char *head, const char *rev, const char *path,
- int ofs, const char *grep, const char *pattern, int showmsg,
- int follow)
-{
- char *delim;
-
- delim = repolink(title, class, "log", head, path);
- if (rev && ctx.qry.head && strcmp(rev, ctx.qry.head)) {
- html(delim);
- html("id=");
- html_url_arg(rev);
- delim = "&amp;";
- }
- if (grep && pattern) {
- html(delim);
- html("qt=");
- html_url_arg(grep);
- delim = "&amp;";
- html(delim);
- html("q=");
- html_url_arg(pattern);
- }
- if (ofs > 0) {
- html(delim);
- html("ofs=");
- htmlf("%d", ofs);
- delim = "&amp;";
- }
- if (showmsg) {
- html(delim);
- html("showmsg=1");
- delim = "&amp;";
- }
- if (follow) {
- html(delim);
- html("follow=1");
- }
- html("'>");
- html_txt(name);
- html("</a>");
-}
-
-void cgit_commit_link(const char *name, const char *title, const char *class,
- const char *head, const char *rev, const char *path)
-{
- char *delim;
-
- delim = repolink(title, class, "commit", head, path);
- if (rev && ctx.qry.head && strcmp(rev, ctx.qry.head)) {
- html(delim);
- html("id=");
- html_url_arg(rev);
- delim = "&amp;";
- }
- if (ctx.qry.difftype) {
- html(delim);
- htmlf("dt=%d", ctx.qry.difftype);
- delim = "&amp;";
- }
- if (ctx.qry.context > 0 && ctx.qry.context != 3) {
- html(delim);
- html("context=");
- htmlf("%d", ctx.qry.context);
- delim = "&amp;";
- }
- if (ctx.qry.ignorews) {
- html(delim);
- html("ignorews=1");
- delim = "&amp;";
- }
- if (ctx.qry.follow) {
- html(delim);
- html("follow=1");
- }
- html("'>");
- if (name[0] != '\0') {
- if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) {
- html_ntxt(name, ctx.cfg.max_msg_len - 3);
- html("...");
- } else
- html_txt(name);
- } else
- html_txt("(no commit message)");
- html("</a>");
-}
-
-void cgit_refs_link(const char *name, const char *title, const char *class,
- const char *head, const char *rev, const char *path)
-{
- reporevlink("refs", name, title, class, head, rev, path);
-}
-
-void cgit_snapshot_link(const char *name, const char *title, const char *class,
- const char *head, const char *rev,
- const char *archivename)
-{
- reporevlink("snapshot", name, title, class, head, rev, archivename);
-}
-
-void cgit_diff_link(const char *name, const char *title, const char *class,
- const char *head, const char *new_rev, const char *old_rev,
- const char *path)
-{
- char *delim;
-
- delim = repolink(title, class, "diff", head, path);
- if (new_rev && ctx.qry.head != NULL && strcmp(new_rev, ctx.qry.head)) {
- html(delim);
- html("id=");
- html_url_arg(new_rev);
- delim = "&amp;";
- }
- if (old_rev) {
- html(delim);
- html("id2=");
- html_url_arg(old_rev);
- delim = "&amp;";
- }
- if (ctx.qry.difftype) {
- html(delim);
- htmlf("dt=%d", ctx.qry.difftype);
- delim = "&amp;";
- }
- if (ctx.qry.context > 0 && ctx.qry.context != 3) {
- html(delim);
- html("context=");
- htmlf("%d", ctx.qry.context);
- delim = "&amp;";
- }
- if (ctx.qry.ignorews) {
- html(delim);
- html("ignorews=1");
- delim = "&amp;";
- }
- if (ctx.qry.follow) {
- html(delim);
- html("follow=1");
- }
- html("'>");
- html_txt(name);
- html("</a>");
-}
-
-void cgit_patch_link(const char *name, const char *title, const char *class,
- const char *head, const char *rev, const char *path)
-{
- reporevlink("patch", name, title, class, head, rev, path);
-}
-
-void cgit_stats_link(const char *name, const char *title, const char *class,
- const char *head, const char *path)
-{
- reporevlink("stats", name, title, class, head, NULL, path);
-}
-
-static void cgit_self_link(char *name, const char *title, const char *class)
-{
- if (!strcmp(ctx.qry.page, "repolist"))
- cgit_index_link(name, title, class, ctx.qry.search, ctx.qry.sort,
- ctx.qry.ofs, 1);
- else if (!strcmp(ctx.qry.page, "summary"))
- cgit_summary_link(name, title, class, ctx.qry.head);
- else if (!strcmp(ctx.qry.page, "tag"))
- cgit_tag_link(name, title, class, ctx.qry.has_oid ?
- ctx.qry.oid : ctx.qry.head);
- else if (!strcmp(ctx.qry.page, "tree"))
- cgit_tree_link(name, title, class, ctx.qry.head,
- ctx.qry.has_oid ? ctx.qry.oid : NULL,
- ctx.qry.path);
- else if (!strcmp(ctx.qry.page, "plain"))
- cgit_plain_link(name, title, class, ctx.qry.head,
- ctx.qry.has_oid ? ctx.qry.oid : NULL,
- ctx.qry.path);
- else if (!strcmp(ctx.qry.page, "blame"))
- cgit_blame_link(name, title, class, ctx.qry.head,
- ctx.qry.has_oid ? ctx.qry.oid : NULL,
- ctx.qry.path);
- else if (!strcmp(ctx.qry.page, "log"))
- cgit_log_link(name, title, class, ctx.qry.head,
- ctx.qry.has_oid ? ctx.qry.oid : NULL,
- ctx.qry.path, ctx.qry.ofs,
- ctx.qry.grep, ctx.qry.search,
- ctx.qry.showmsg, ctx.qry.follow);
- else if (!strcmp(ctx.qry.page, "commit"))
- cgit_commit_link(name, title, class, ctx.qry.head,
- ctx.qry.has_oid ? ctx.qry.oid : NULL,
- ctx.qry.path);
- else if (!strcmp(ctx.qry.page, "patch"))
- cgit_patch_link(name, title, class, ctx.qry.head,
- ctx.qry.has_oid ? ctx.qry.oid : NULL,
- ctx.qry.path);
- else if (!strcmp(ctx.qry.page, "refs"))
- cgit_refs_link(name, title, class, ctx.qry.head,
- ctx.qry.has_oid ? ctx.qry.oid : NULL,
- ctx.qry.path);
- else if (!strcmp(ctx.qry.page, "snapshot"))
- cgit_snapshot_link(name, title, class, ctx.qry.head,
- ctx.qry.has_oid ? ctx.qry.oid : NULL,
- ctx.qry.path);
- else if (!strcmp(ctx.qry.page, "diff"))
- cgit_diff_link(name, title, class, ctx.qry.head,
- ctx.qry.oid, ctx.qry.oid2,
- ctx.qry.path);
- else if (!strcmp(ctx.qry.page, "stats"))
- cgit_stats_link(name, title, class, ctx.qry.head,
- ctx.qry.path);
- else {
- /* Don't known how to make link for this page */
- repolink(title, class, ctx.qry.page, ctx.qry.head, ctx.qry.path);
- html("><!-- cgit_self_link() doesn't know how to make link for page '");
- html_txt(ctx.qry.page);
- html("' -->");
- html_txt(name);
- html("</a>");
- }
-}
-
-void cgit_object_link(struct object *obj)
-{
- char *page, *shortrev, *fullrev, *name;
-
- fullrev = oid_to_hex(&obj->oid);
- shortrev = xstrdup(fullrev);
- shortrev[10] = '\0';
- if (obj->type == OBJ_COMMIT) {
- cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL,
- ctx.qry.head, fullrev, NULL);
- return;
- } else if (obj->type == OBJ_TREE)
- page = "tree";
- else if (obj->type == OBJ_TAG)
- page = "tag";
- else
- page = "blob";
- name = fmt("%s %s...", type_name(obj->type), shortrev);
- reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL);
-}
-
-static struct string_list_item *lookup_path(struct string_list *list,
- const char *path)
-{
- struct string_list_item *item;
-
- while (path && path[0]) {
- if ((item = string_list_lookup(list, path)))
- return item;
- if (!(path = strchr(path, '/')))
- break;
- path++;
- }
- return NULL;
-}
-
-void cgit_submodule_link(const char *class, char *path, const char *rev)
-{
- struct string_list *list;
- struct string_list_item *item;
- char tail, *dir;
- size_t len;
-
- len = 0;
- tail = 0;
- list = &ctx.repo->submodules;
- item = lookup_path(list, path);
- if (!item) {
- len = strlen(path);
- tail = path[len - 1];
- if (tail == '/') {
- path[len - 1] = 0;
- item = lookup_path(list, path);
- }
- }
- if (item || ctx.repo->module_link) {
- html("<a ");
- if (class)
- htmlf("class='%s' ", class);
- html("href='");
- if (item) {
- html_attrf(item->util, rev);
- } else {
- dir = strrchr(path, '/');
- if (dir)
- dir++;
- else
- dir = path;
- html_attrf(ctx.repo->module_link, dir, rev);
- }
- html("'>");
- html_txt(path);
- html("</a>");
- } else {
- html("<span");
- if (class)
- htmlf(" class='%s'", class);
- html(">");
- html_txt(path);
- html("</span>");
- }
- html_txtf(" @ %.7s", rev);
- if (item && tail)
- path[len - 1] = tail;
-}
-
-const struct date_mode cgit_date_mode(enum date_mode_type type)
-{
- static struct date_mode mode;
- mode.type = type;
- mode.local = ctx.cfg.local_time;
- return mode;
-}
-
-static void print_rel_date(time_t t, int tz, double value,
- const char *class, const char *suffix)
-{
- htmlf("<span class='%s' data-ut='%" PRIu64 "' title='", class, (uint64_t)t);
- html_attr(show_date(t, tz, cgit_date_mode(DATE_ISO8601)));
- htmlf("'>%.0f %s</span>", value, suffix);
-}
-
-void cgit_print_age(time_t t, int tz, time_t max_relative)
-{
- time_t now, secs;
-
- if (!t)
- return;
- time(&now);
- secs = now - t;
- if (secs < 0)
- secs = 0;
-
- if (secs > max_relative && max_relative >= 0) {
- html("<span title='");
- html_attr(show_date(t, tz, cgit_date_mode(DATE_ISO8601)));
- html("'>");
- html_txt(show_date(t, tz, cgit_date_mode(DATE_SHORT)));
- html("</span>");
- return;
- }
-
- if (secs < TM_HOUR * 2) {
- print_rel_date(t, tz, secs * 1.0 / TM_MIN, "age-mins", "min.");
- return;
- }
- if (secs < TM_DAY * 2) {
- print_rel_date(t, tz, secs * 1.0 / TM_HOUR, "age-hours", "hours");
- return;
- }
- if (secs < TM_WEEK * 2) {
- print_rel_date(t, tz, secs * 1.0 / TM_DAY, "age-days", "days");
- return;
- }
- if (secs < TM_MONTH * 2) {
- print_rel_date(t, tz, secs * 1.0 / TM_WEEK, "age-weeks", "weeks");
- return;
- }
- if (secs < TM_YEAR * 2) {
- print_rel_date(t, tz, secs * 1.0 / TM_MONTH, "age-months", "months");
- return;
- }
- print_rel_date(t, tz, secs * 1.0 / TM_YEAR, "age-years", "years");
-}
-
-void cgit_print_http_headers(void)
-{
- if (ctx.env.no_http && !strcmp(ctx.env.no_http, "1"))
- return;
-
- if (ctx.page.status)
- htmlf("Status: %d %s\n", ctx.page.status, ctx.page.statusmsg);
- if (ctx.page.mimetype && ctx.page.charset)
- htmlf("Content-Type: %s; charset=%s\n", ctx.page.mimetype,
- ctx.page.charset);
- else if (ctx.page.mimetype)
- htmlf("Content-Type: %s\n", ctx.page.mimetype);
- if (ctx.page.size)
- htmlf("Content-Length: %zd\n", ctx.page.size);
- if (ctx.page.filename) {
- html("Content-Disposition: inline; filename=\"");
- html_header_arg_in_quotes(ctx.page.filename);
- html("\"\n");
- }
- if (!ctx.env.authenticated)
- html("Cache-Control: no-cache, no-store\n");
- htmlf("Last-Modified: %s\n", http_date(ctx.page.modified));
- htmlf("Expires: %s\n", http_date(ctx.page.expires));
- if (ctx.page.etag)
- htmlf("ETag: \"%s\"\n", ctx.page.etag);
- html("\n");
- if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD"))
- exit(0);
-}
-
-void cgit_redirect(const char *url, bool permanent)
-{
- htmlf("Status: %d %s\n", permanent ? 301 : 302, permanent ? "Moved" : "Found");
- html("Location: ");
- html_url_path(url);
- html("\n\n");
-}
-
-static void print_rel_vcs_link(const char *url)
-{
- html("<link rel='vcs-git' href='");
- html_attr(url);
- html("' title='");
- html_attr(ctx.repo->name);
- html(" Git repository'/>\n");
-}
-
-static int emit_css_link(struct string_list_item *s, void *arg)
-{
- /* Do not emit anything if css= is specified. */
- if (s && *s->string == '\0')
- return 0;
-
- html("<link rel='stylesheet' type='text/css' href='");
- if (s)
- html_attr(s->string);
- else
- html_attr((const char *)arg);
- html("'/>\n");
-
- return 0;
-}
-
-static int emit_js_link(struct string_list_item *s, void *arg)
-{
- /* Do not emit anything if js= is specified. */
- if (s && *s->string == '\0')
- return 0;
-
- html("<script type='text/javascript' src='");
- if (s)
- html_attr(s->string);
- else
- html_attr((const char *)arg);
- html("'></script>\n");
-
- return 0;
-}
-
-void cgit_print_docstart(void)
-{
- char *host = cgit_hosturl();
-
- if (ctx.cfg.embedded) {
- if (ctx.cfg.header)
- html_include(ctx.cfg.header);
- return;
- }
-
- html(cgit_doctype);
- html("<html lang='en'>\n");
- html("<head>\n");
- html("<title>");
- html_txt(ctx.page.title);
- html("</title>\n");
- htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
- if (ctx.cfg.robots && *ctx.cfg.robots)
- htmlf("<meta name='robots' content='%s'/>\n", ctx.cfg.robots);
-
- if (ctx.cfg.css.items)
- for_each_string_list(&ctx.cfg.css, emit_css_link, NULL);
- else
- emit_css_link(NULL, "/cgit.css");
-
- if (ctx.cfg.js.items)
- for_each_string_list(&ctx.cfg.js, emit_js_link, NULL);
- else
- emit_js_link(NULL, "/cgit.js");
-
- if (ctx.cfg.favicon && *ctx.cfg.favicon) {
- html("<link rel='shortcut icon' href='");
- html_attr(ctx.cfg.favicon);
- html("'/>\n");
- }
- if (host && ctx.repo && ctx.qry.head) {
- char *fileurl;
- struct strbuf sb = STRBUF_INIT;
- strbuf_addf(&sb, "h=%s", ctx.qry.head);
-
- html("<link rel='alternate' title='Atom feed' href='");
- html(cgit_httpscheme());
- html_attr(host);
- fileurl = cgit_fileurl(ctx.repo->url, "atom", ctx.qry.vpath,
- sb.buf);
- html_attr(fileurl);
- html("' type='application/atom+xml'/>\n");
- strbuf_release(&sb);
- free(fileurl);
- }
- if (ctx.repo)
- cgit_add_clone_urls(print_rel_vcs_link);
- if (ctx.cfg.head_include)
- html_include(ctx.cfg.head_include);
- if (ctx.repo && ctx.repo->extra_head_content)
- html(ctx.repo->extra_head_content);
- html("</head>\n");
- html("<body>\n");
- if (ctx.cfg.header)
- html_include(ctx.cfg.header);
- free(host);
-}
-
-void cgit_print_docend(void)
-{
- html("</div> <!-- class=content -->\n");
- if (ctx.cfg.embedded) {
- html("</div> <!-- id=cgit -->\n");
- if (ctx.cfg.footer)
- html_include(ctx.cfg.footer);
- return;
- }
- if (ctx.cfg.footer)
- html_include(ctx.cfg.footer);
- else {
- htmlf("<div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit %s</a> "
- "(<a href='https://git-scm.com/'>git %s</a>) at ", cgit_version, git_version_string);
- html_txt(show_date(time(NULL), 0, cgit_date_mode(DATE_ISO8601)));
- html("</div>\n");
- }
- html("</div> <!-- id=cgit -->\n");
- html("</body>\n</html>\n");
-}
-
-void cgit_print_error_page(int code, const char *msg, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- cgit_vprint_error_page(code, msg, fmt, ap);
- va_end(ap);
-}
-
-void cgit_vprint_error_page(int code, const char *msg, const char *fmt, va_list ap)
-{
- ctx.page.expires = ctx.cfg.cache_dynamic_ttl;
- ctx.page.status = code;
- ctx.page.statusmsg = msg;
- cgit_print_layout_start();
- cgit_vprint_error(fmt, ap);
- cgit_print_layout_end();
-}
-
-void cgit_print_layout_start(void)
-{
- cgit_print_http_headers();
- cgit_print_docstart();
- cgit_print_pageheader();
-}
-
-void cgit_print_layout_end(void)
-{
- cgit_print_docend();
-}
-
-static void add_clone_urls(void (*fn)(const char *), char *txt, char *suffix)
-{
- struct strbuf **url_list = strbuf_split_str(txt, ' ', 0);
- int i;
-
- for (i = 0; url_list[i]; i++) {
- strbuf_rtrim(url_list[i]);
- if (url_list[i]->len == 0)
- continue;
- if (suffix && *suffix)
- strbuf_addf(url_list[i], "/%s", suffix);
- fn(url_list[i]->buf);
- }
-
- strbuf_list_free(url_list);
-}
-
-void cgit_add_clone_urls(void (*fn)(const char *))
-{
- if (ctx.repo->clone_url)
- add_clone_urls(fn, expand_macros(ctx.repo->clone_url), NULL);
- else if (ctx.cfg.clone_prefix)
- add_clone_urls(fn, ctx.cfg.clone_prefix, ctx.repo->url);
-}
-
-static int print_branch_option(const struct reference *ref, void *cb_data)
-{
- char *name = (char *)ref->name;
- html_option(name, name, ctx.qry.head);
- return 0;
-}
-
-void cgit_add_hidden_formfields(int incl_head, int incl_search,
- const char *page)
-{
- if (!ctx.cfg.virtual_root) {
- struct strbuf url = STRBUF_INIT;
-
- strbuf_addf(&url, "%s/%s", ctx.qry.repo, page);
- if (ctx.qry.vpath)
- strbuf_addf(&url, "/%s", ctx.qry.vpath);
- html_hidden("url", url.buf);
- strbuf_release(&url);
- }
-
- if (incl_head && ctx.qry.head && ctx.repo->defbranch &&
- strcmp(ctx.qry.head, ctx.repo->defbranch))
- html_hidden("h", ctx.qry.head);
-
- if (ctx.qry.oid)
- html_hidden("id", ctx.qry.oid);
- if (ctx.qry.oid2)
- html_hidden("id2", ctx.qry.oid2);
- if (ctx.qry.showmsg)
- html_hidden("showmsg", "1");
-
- if (incl_search) {
- if (ctx.qry.grep)
- html_hidden("qt", ctx.qry.grep);
- if (ctx.qry.search)
- html_hidden("q", ctx.qry.search);
- }
-}
-
-static const char *hc(const char *page)
-{
- if (!ctx.qry.page)
- return NULL;
-
- return strcmp(ctx.qry.page, page) ? NULL : "active";
-}
-
-static void cgit_print_path_crumbs(char *path)
-{
- char *old_path = ctx.qry.path;
- char *p = path, *q, *end = path + strlen(path);
- int levels = 0;
-
- ctx.qry.path = NULL;
- cgit_self_link("root", NULL, NULL);
- ctx.qry.path = p = path;
- while (p < end) {
- if (!(q = strchr(p, '/')) || levels > 15)
- q = end;
- *q = '\0';
- html_txt("/");
- cgit_self_link(p, NULL, NULL);
- if (q < end)
- *q = '/';
- p = q + 1;
- ++levels;
- }
- ctx.qry.path = old_path;
-}
-
-static void print_header(void)
-{
- char *logo = NULL, *logo_link = NULL;
-
- html("<table id='header'>\n");
- html("<tr>\n");
-
- if (ctx.repo && ctx.repo->logo && *ctx.repo->logo)
- logo = ctx.repo->logo;
- else
- logo = ctx.cfg.logo;
- if (ctx.repo && ctx.repo->logo_link && *ctx.repo->logo_link)
- logo_link = ctx.repo->logo_link;
- else
- logo_link = ctx.cfg.logo_link;
- if (logo && *logo) {
- html("<td class='logo' rowspan='2'><a href='");
- if (logo_link && *logo_link)
- html_attr(logo_link);
- else
- html_attr(cgit_rooturl());
- html("'><img src='");
- html_attr(logo);
- html("' alt='cgit logo'/></a></td>\n");
- }
-
- html("<td class='main'>");
- if (ctx.repo) {
- cgit_index_link("index", NULL, NULL, NULL, NULL, 0, 1);
- html(" : ");
- cgit_summary_link(ctx.repo->name, NULL, NULL, NULL);
- if (ctx.env.authenticated) {
- html("</td><td class='form'>");
- html("<form method='get'>\n");
- cgit_add_hidden_formfields(0, 1, ctx.qry.page);
- html("<select name='h' onchange='this.form.submit();'>\n");
- refs_for_each_branch_ref(get_main_ref_store(the_repository),
- print_branch_option, ctx.qry.head);
- if (ctx.repo->enable_remote_branches)
- refs_for_each_remote_ref(get_main_ref_store(the_repository),
- print_branch_option, ctx.qry.head);
- html("</select> ");
- html("<input type='submit' value='switch'/>");
- html("</form>");
- }
- } else
- html_txt(ctx.cfg.root_title);
- html("</td></tr>\n");
-
- html("<tr><td class='sub'>");
- if (ctx.repo) {
- html_txt(ctx.repo->desc);
- html("</td><td class='sub right'>");
- if (ctx.repo->owner_filter) {
- cgit_open_filter(ctx.repo->owner_filter);
- html_txt(ctx.repo->owner);
- cgit_close_filter(ctx.repo->owner_filter);
- } else {
- html_txt(ctx.repo->owner);
- }
- } else {
- if (ctx.cfg.root_desc)
- html_txt(ctx.cfg.root_desc);
- }
- html("</td></tr></table>\n");
-}
-
-void cgit_print_pageheader(void)
-{
- html("<div id='cgit'>");
- if (!ctx.env.authenticated || !ctx.cfg.noheader)
- print_header();
-
- html("<table class='tabs'><tr><td>\n");
- if (ctx.env.authenticated && ctx.repo) {
- if (ctx.repo->readme.nr)
- reporevlink("about", "about", NULL,
- hc("about"), ctx.qry.head, NULL,
- NULL);
- cgit_summary_link("summary", NULL, hc("summary"),
- ctx.qry.head);
- cgit_refs_link("refs", NULL, hc("refs"), ctx.qry.head,
- ctx.qry.oid, NULL);
- cgit_log_link("log", NULL, hc("log"), ctx.qry.head,
- NULL, ctx.qry.vpath, 0, NULL, NULL,
- ctx.qry.showmsg, ctx.qry.follow);
- if (ctx.qry.page && !strcmp(ctx.qry.page, "blame"))
- cgit_blame_link("blame", NULL, hc("blame"), ctx.qry.head,
- ctx.qry.oid, ctx.qry.vpath);
- else
- cgit_tree_link("tree", NULL, hc("tree"), ctx.qry.head,
- ctx.qry.oid, ctx.qry.vpath);
- cgit_commit_link("commit", NULL, hc("commit"),
- ctx.qry.head, ctx.qry.oid, ctx.qry.vpath);
- cgit_diff_link("diff", NULL, hc("diff"), ctx.qry.head,
- ctx.qry.oid, ctx.qry.oid2, ctx.qry.vpath);
- if (ctx.repo->max_stats)
- cgit_stats_link("stats", NULL, hc("stats"),
- ctx.qry.head, ctx.qry.vpath);
- if (ctx.repo->homepage) {
- html("<a href='");
- html_attr(ctx.repo->homepage);
- html("'>homepage</a>");
- }
- html("</td><td class='form'>");
- html("<form class='right' method='get' action='");
- if (ctx.cfg.virtual_root) {
- char *fileurl = cgit_fileurl(ctx.qry.repo, "log",
- ctx.qry.vpath, NULL);
- html_url_path(fileurl);
- free(fileurl);
- }
- html("'>\n");
- cgit_add_hidden_formfields(1, 0, "log");
- html("<select name='qt'>\n");
- html_option("grep", "log msg", ctx.qry.grep);
- html_option("author", "author", ctx.qry.grep);
- html_option("committer", "committer", ctx.qry.grep);
- html_option("range", "range", ctx.qry.grep);
- html("</select>\n");
- html("<input class='txt' type='search' size='10' name='q' value='");
- html_attr(ctx.qry.search);
- html("'/>\n");
- html("<input type='submit' value='search'/>\n");
- html("</form>\n");
- } else if (ctx.env.authenticated) {
- char *currenturl = cgit_currenturl();
- site_link(NULL, "index", NULL, hc("repolist"), NULL, NULL, 0, 1);
- if (ctx.cfg.root_readme)
- site_link("about", "about", NULL, hc("about"),
- NULL, NULL, 0, 1);
- html("</td><td class='form'>");
- html("<form method='get' action='");
- html_attr(currenturl);
- html("'>\n");
- html("<input type='search' name='q' size='10' value='");
- html_attr(ctx.qry.search);
- html("'/>\n");
- html("<input type='submit' value='search'/>\n");
- html("</form>");
- free(currenturl);
- }
- html("</td></tr></table>\n");
- if (ctx.env.authenticated && ctx.repo && ctx.qry.vpath) {
- html("<div class='path'>");
- html("path: ");
- cgit_print_path_crumbs(ctx.qry.vpath);
- if (ctx.repo->enable_follow_links && !strcmp(ctx.qry.page, "log")) {
- html(" (");
- ctx.qry.follow = !ctx.qry.follow;
- cgit_self_link(ctx.qry.follow ? "follow" : "unfollow",
- NULL, NULL);
- ctx.qry.follow = !ctx.qry.follow;
- html(")");
- }
- html("</div>");
- }
- html("<div class='content'>");
-}
-
-void cgit_print_filemode(unsigned short mode)
-{
- if (S_ISDIR(mode))
- html("d");
- else if (S_ISLNK(mode))
- html("l");
- else if (S_ISGITLINK(mode))
- html("m");
- else
- html("-");
- html_fileperm(mode >> 6);
- html_fileperm(mode >> 3);
- html_fileperm(mode);
-}
-
-void cgit_compose_snapshot_prefix(struct strbuf *filename, const char *base,
- const char *ref)
-{
- struct object_id oid;
-
- /*
- * Prettify snapshot names by stripping leading "v" or "V" if the tag
- * name starts with {v,V}[0-9] and the prettify mapping is injective,
- * i.e. each stripped tag can be inverted without ambiguities.
- */
- if (repo_get_oid(the_repository, fmt("refs/tags/%s", ref), &oid) == 0 &&
- (ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1]) &&
- ((repo_get_oid(the_repository, fmt("refs/tags/%s", ref + 1), &oid) == 0) +
- (repo_get_oid(the_repository, fmt("refs/tags/v%s", ref + 1), &oid) == 0) +
- (repo_get_oid(the_repository, fmt("refs/tags/V%s", ref + 1), &oid) == 0) == 1))
- ref++;
-
- strbuf_addf(filename, "%s-%s", base, ref);
-}
-
-void cgit_print_snapshot_links(const struct cgit_repo *repo, const char *ref,
- const char *separator)
-{
- const struct cgit_snapshot_format *f;
- struct strbuf filename = STRBUF_INIT;
- const char *basename;
- size_t prefixlen;
-
- basename = cgit_snapshot_prefix(repo);
- if (starts_with(ref, basename))
- strbuf_addstr(&filename, ref);
- else
- cgit_compose_snapshot_prefix(&filename, basename, ref);
-
- prefixlen = filename.len;
- for (f = cgit_snapshot_formats; f->suffix; f++) {
- if (!(repo->snapshots & cgit_snapshot_format_bit(f)))
- continue;
- strbuf_setlen(&filename, prefixlen);
- strbuf_addstr(&filename, f->suffix);
- cgit_snapshot_link(filename.buf, NULL, NULL, NULL, NULL,
- filename.buf);
- if (cgit_snapshot_get_sig(ref, f)) {
- strbuf_addstr(&filename, ".asc");
- html(" (");
- cgit_snapshot_link("sig", NULL, NULL, NULL, NULL,
- filename.buf);
- html(")");
- } else if (starts_with(f->suffix, ".tar") && cgit_snapshot_get_sig(ref, &cgit_snapshot_formats[0])) {
- strbuf_setlen(&filename, strlen(filename.buf) - strlen(f->suffix));
- strbuf_addstr(&filename, ".tar.asc");
- html(" (");
- cgit_snapshot_link("sig", NULL, NULL, NULL, NULL,
- filename.buf);
- html(")");
- }
- html(separator);
- }
- strbuf_release(&filename);
-}
-
-void cgit_set_title_from_path(const char *path)
-{
- struct strbuf sb = STRBUF_INIT;
- const char *slash, *last_slash;
-
- if (!path)
- return;
-
- for (last_slash = path + strlen(path); (slash = memrchr(path, '/', last_slash - path)) != NULL; last_slash = slash) {
- strbuf_add(&sb, slash + 1, last_slash - slash - 1);
- strbuf_addstr(&sb, " \xc2\xab ");
- }
- strbuf_add(&sb, path, last_slash - path);
- strbuf_addf(&sb, " - %s", ctx.page.title);
- ctx.page.title = strbuf_detach(&sb, NULL);
-}
diff --git a/ui-shared.h b/ui-shared.h
deleted file mode 100644
index 2a3a7f5..0000000
--- a/ui-shared.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#ifndef UI_SHARED_H
-#define UI_SHARED_H
-
-extern const char *cgit_httpscheme(void);
-extern char *cgit_hosturl(void);
-extern const char *cgit_rooturl(void);
-extern char *cgit_currenturl(void);
-extern char *cgit_currentfullurl(void);
-extern const char *cgit_loginurl(void);
-extern char *cgit_repourl(const char *reponame);
-extern char *cgit_fileurl(const char *reponame, const char *pagename,
- const char *filename, const char *query);
-extern char *cgit_pageurl(const char *reponame, const char *pagename,
- const char *query);
-
-extern void cgit_add_clone_urls(void (*fn)(const char *));
-
-extern void cgit_index_link(const char *name, const char *title,
- const char *class, const char *pattern, const char *sort, int ofs, int always_root);
-extern void cgit_summary_link(const char *name, const char *title,
- const char *class, const char *head);
-extern void cgit_tag_link(const char *name, const char *title,
- const char *class, const char *tag);
-extern void cgit_tree_link(const char *name, const char *title,
- const char *class, const char *head,
- const char *rev, const char *path);
-extern void cgit_plain_link(const char *name, const char *title,
- const char *class, const char *head,
- const char *rev, const char *path);
-extern void cgit_blame_link(const char *name, const char *title,
- const char *class, const char *head,
- const char *rev, const char *path);
-extern void cgit_log_link(const char *name, const char *title,
- const char *class, const char *head, const char *rev,
- const char *path, int ofs, const char *grep,
- const char *pattern, int showmsg, int follow);
-extern void cgit_commit_link(const char *name, const char *title,
- const char *class, const char *head,
- const char *rev, const char *path);
-extern void cgit_patch_link(const char *name, const char *title,
- const char *class, const char *head,
- const char *rev, const char *path);
-extern void cgit_refs_link(const char *name, const char *title,
- const char *class, const char *head,
- const char *rev, const char *path);
-extern void cgit_snapshot_link(const char *name, const char *title,
- const char *class, const char *head,
- const char *rev, const char *archivename);
-extern void cgit_diff_link(const char *name, const char *title,
- const char *class, const char *head,
- const char *new_rev, const char *old_rev,
- const char *path);
-extern void cgit_stats_link(const char *name, const char *title,
- const char *class, const char *head,
- const char *path);
-extern void cgit_object_link(struct object *obj);
-
-extern void cgit_submodule_link(const char *class, char *path,
- const char *rev);
-
-extern void cgit_print_layout_start(void);
-extern void cgit_print_layout_end(void);
-
-__attribute__((format (printf,1,2)))
-extern void cgit_print_error(const char *fmt, ...);
-__attribute__((format (printf,1,0)))
-extern void cgit_vprint_error(const char *fmt, va_list ap);
-extern const struct date_mode cgit_date_mode(enum date_mode_type type);
-extern void cgit_print_age(time_t t, int tz, time_t max_relative);
-extern void cgit_print_http_headers(void);
-extern void cgit_redirect(const char *url, bool permanent);
-extern void cgit_print_docstart(void);
-extern void cgit_print_docend(void);
-__attribute__((format (printf,3,4)))
-extern void cgit_print_error_page(int code, const char *msg, const char *fmt, ...);
-extern void cgit_vprint_error_page(int code, const char *msg, const char *fmt, va_list ap);
-extern void cgit_print_pageheader(void);
-extern void cgit_print_filemode(unsigned short mode);
-extern void cgit_compose_snapshot_prefix(struct strbuf *filename,
- const char *base, const char *ref);
-extern void cgit_print_snapshot_links(const struct cgit_repo *repo,
- const char *ref, const char *separator);
-extern const char *cgit_snapshot_prefix(const struct cgit_repo *repo);
-extern void cgit_add_hidden_formfields(int incl_head, int incl_search,
- const char *page);
-
-extern void cgit_set_title_from_path(const char *path);
-#endif /* UI_SHARED_H */
diff --git a/ui-snapshot.c b/ui-snapshot.c
deleted file mode 100644
index d157222..0000000
--- a/ui-snapshot.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/* ui-snapshot.c: generate snapshot of a commit
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-snapshot.h"
-#include "html.h"
-#include "ui-shared.h"
-
-static int write_archive_type(const char *format, const char *hex, const char *prefix)
-{
- struct strvec argv = STRVEC_INIT;
- const char **nargv;
- int result;
- strvec_push(&argv, "snapshot");
- strvec_push(&argv, format);
- if (prefix) {
- struct strbuf buf = STRBUF_INIT;
- strbuf_addstr(&buf, prefix);
- strbuf_addch(&buf, '/');
- strvec_push(&argv, "--prefix");
- strvec_push(&argv, buf.buf);
- strbuf_release(&buf);
- }
- strvec_push(&argv, hex);
- /*
- * Now we need to copy the pointers to arguments into a new
- * structure because write_archive will rearrange its arguments
- * which may result in duplicated/missing entries causing leaks
- * or double-frees in strvec_clear.
- */
- nargv = xmalloc(sizeof(char *) * (argv.nr + 1));
- /* strvec guarantees a trailing NULL entry. */
- memcpy(nargv, argv.v, sizeof(char *) * (argv.nr + 1));
-
- result = write_archive(argv.nr, nargv, NULL, the_repository, NULL, 0);
- strvec_clear(&argv);
- free(nargv);
- return result;
-}
-
-static int write_tar_archive(const char *hex, const char *prefix)
-{
- return write_archive_type("--format=tar", hex, prefix);
-}
-
-static int write_zip_archive(const char *hex, const char *prefix)
-{
- return write_archive_type("--format=zip", hex, prefix);
-}
-
-static int write_compressed_tar_archive(const char *hex,
- const char *prefix,
- char *filter_argv[])
-{
- int rv;
- struct cgit_exec_filter f;
- cgit_exec_filter_init(&f, filter_argv[0], filter_argv);
-
- cgit_open_filter(&f.base);
- rv = write_tar_archive(hex, prefix);
- cgit_close_filter(&f.base);
- return rv;
-}
-
-static int write_tar_gzip_archive(const char *hex, const char *prefix)
-{
- char *argv[] = { "gzip", "-n", NULL };
- return write_compressed_tar_archive(hex, prefix, argv);
-}
-
-static int write_tar_bzip2_archive(const char *hex, const char *prefix)
-{
- char *argv[] = { "bzip2", NULL };
- return write_compressed_tar_archive(hex, prefix, argv);
-}
-
-static int write_tar_lzip_archive(const char *hex, const char *prefix)
-{
- char *argv[] = { "lzip", NULL };
- return write_compressed_tar_archive(hex, prefix, argv);
-}
-
-static int write_tar_xz_archive(const char *hex, const char *prefix)
-{
- char *argv[] = { "xz", NULL };
- return write_compressed_tar_archive(hex, prefix, argv);
-}
-
-static int write_tar_zstd_archive(const char *hex, const char *prefix)
-{
- char *argv[] = { "zstd", "-T0", NULL };
- return write_compressed_tar_archive(hex, prefix, argv);
-}
-
-const struct cgit_snapshot_format cgit_snapshot_formats[] = {
- /* .tar must remain the 0 index */
- { ".tar", "application/x-tar", write_tar_archive },
- { ".tar.gz", "application/x-gzip", write_tar_gzip_archive },
- { ".tar.bz2", "application/x-bzip2", write_tar_bzip2_archive },
- { ".tar.lz", "application/x-lzip", write_tar_lzip_archive },
- { ".tar.xz", "application/x-xz", write_tar_xz_archive },
- { ".tar.zst", "application/x-zstd", write_tar_zstd_archive },
- { ".zip", "application/x-zip", write_zip_archive },
- { NULL }
-};
-
-static struct notes_tree snapshot_sig_notes[ARRAY_SIZE(cgit_snapshot_formats)];
-
-const struct object_id *cgit_snapshot_get_sig(const char *ref,
- const struct cgit_snapshot_format *f)
-{
- struct notes_tree *tree;
- struct object_id oid;
-
- if (repo_get_oid(the_repository, ref, &oid))
- return NULL;
-
- tree = &snapshot_sig_notes[f - &cgit_snapshot_formats[0]];
- if (!tree->initialized) {
- struct strbuf notes_ref = STRBUF_INIT;
-
- strbuf_addf(&notes_ref, "refs/notes/signatures/%s",
- f->suffix + 1);
-
- init_notes(tree, notes_ref.buf, combine_notes_ignore, 0);
- strbuf_release(&notes_ref);
- }
-
- return get_note(tree, &oid);
-}
-
-static const struct cgit_snapshot_format *get_format(const char *filename)
-{
- const struct cgit_snapshot_format *fmt;
-
- for (fmt = cgit_snapshot_formats; fmt->suffix; fmt++) {
- if (ends_with(filename, fmt->suffix))
- return fmt;
- }
- return NULL;
-}
-
-const unsigned cgit_snapshot_format_bit(const struct cgit_snapshot_format *f)
-{
- return BIT(f - &cgit_snapshot_formats[0]);
-}
-
-static int make_snapshot(const struct cgit_snapshot_format *format,
- const char *hex, const char *prefix,
- const char *filename)
-{
- struct object_id oid;
-
- if (repo_get_oid(the_repository, hex, &oid)) {
- cgit_print_error_page(404, "Not found",
- "Bad object id: %s", hex);
- return 1;
- }
- if (!lookup_commit_reference(the_repository, &oid)) {
- cgit_print_error_page(400, "Bad request",
- "Not a commit reference: %s", hex);
- return 1;
- }
- ctx.page.etag = oid_to_hex(&oid);
- ctx.page.mimetype = xstrdup(format->mimetype);
- ctx.page.filename = xstrdup(filename);
- cgit_print_http_headers();
- init_archivers();
- format->write_func(hex, prefix);
- return 0;
-}
-
-static int write_sig(const struct cgit_snapshot_format *format,
- const char *hex, const char *archive,
- const char *filename)
-{
- const struct object_id *note = cgit_snapshot_get_sig(hex, format);
- enum object_type type;
- unsigned long size;
- char *buf;
-
- if (!note) {
- cgit_print_error_page(404, "Not found",
- "No signature for %s", archive);
- return 0;
- }
-
- buf = odb_read_object(the_repository->objects, note, &type, &size);
- if (!buf) {
- cgit_print_error_page(404, "Not found", "Not found");
- return 0;
- }
-
- html("X-Content-Type-Options: nosniff\n");
- html("Content-Security-Policy: default-src 'none'\n");
- ctx.page.etag = oid_to_hex(note);
- ctx.page.mimetype = xstrdup("application/pgp-signature");
- ctx.page.filename = xstrdup(filename);
- cgit_print_http_headers();
-
- html_raw(buf, size);
- free(buf);
- return 0;
-}
-
-/* Try to guess the requested revision from the requested snapshot name.
- * First the format extension is stripped, e.g. "cgit-0.7.2.tar.gz" become
- * "cgit-0.7.2". If this is a valid commit object name we've got a winner.
- * Otherwise, if the snapshot name has a prefix matching the result from
- * repo_basename(), we strip the basename and any following '-' and '_'
- * characters ("cgit-0.7.2" -> "0.7.2") and check the resulting name once
- * more. If this still isn't a valid commit object name, we check if pre-
- * pending a 'v' or a 'V' to the remaining snapshot name ("0.7.2" ->
- * "v0.7.2") gives us something valid.
- */
-static const char *get_ref_from_filename(const struct cgit_repo *repo,
- const char *filename,
- const struct cgit_snapshot_format *format)
-{
- const char *reponame;
- struct object_id oid;
- struct strbuf snapshot = STRBUF_INIT;
- int result = 1;
-
- strbuf_addstr(&snapshot, filename);
- strbuf_setlen(&snapshot, snapshot.len - strlen(format->suffix));
-
- if (repo_get_oid(the_repository, snapshot.buf, &oid) == 0)
- goto out;
-
- reponame = cgit_snapshot_prefix(repo);
- if (starts_with(snapshot.buf, reponame)) {
- const char *new_start = snapshot.buf;
- new_start += strlen(reponame);
- while (new_start && (*new_start == '-' || *new_start == '_'))
- new_start++;
- strbuf_splice(&snapshot, 0, new_start - snapshot.buf, "", 0);
- }
-
- if (repo_get_oid(the_repository, snapshot.buf, &oid) == 0)
- goto out;
-
- strbuf_insert(&snapshot, 0, "v", 1);
- if (repo_get_oid(the_repository, snapshot.buf, &oid) == 0)
- goto out;
-
- strbuf_splice(&snapshot, 0, 1, "V", 1);
- if (repo_get_oid(the_repository, snapshot.buf, &oid) == 0)
- goto out;
-
- result = 0;
- strbuf_release(&snapshot);
-
-out:
- return result ? strbuf_detach(&snapshot, NULL) : NULL;
-}
-
-void cgit_print_snapshot(const char *head, const char *hex,
- const char *filename, int dwim)
-{
- const struct cgit_snapshot_format* f;
- const char *sig_filename = NULL;
- char *adj_filename = NULL;
- char *prefix = NULL;
-
- if (!filename) {
- cgit_print_error_page(400, "Bad request",
- "No snapshot name specified");
- return;
- }
-
- if (ends_with(filename, ".asc")) {
- sig_filename = filename;
-
- /* Strip ".asc" from filename for common format processing */
- adj_filename = xstrdup(filename);
- adj_filename[strlen(adj_filename) - 4] = '\0';
- filename = adj_filename;
- }
-
- f = get_format(filename);
- if (!f || (!sig_filename && !(ctx.repo->snapshots & cgit_snapshot_format_bit(f)))) {
- cgit_print_error_page(400, "Bad request",
- "Unsupported snapshot format: %s", filename);
- return;
- }
-
- if (!hex && dwim) {
- hex = get_ref_from_filename(ctx.repo, filename, f);
- if (hex == NULL) {
- cgit_print_error_page(404, "Not found", "Not found");
- return;
- }
- prefix = xstrdup(filename);
- prefix[strlen(filename) - strlen(f->suffix)] = '\0';
- }
-
- if (!hex)
- hex = head;
-
- if (!prefix)
- prefix = xstrdup(cgit_snapshot_prefix(ctx.repo));
-
- if (sig_filename)
- write_sig(f, hex, filename, sig_filename);
- else
- make_snapshot(f, hex, prefix, filename);
-
- free(prefix);
- free(adj_filename);
-}
diff --git a/ui-snapshot.h b/ui-snapshot.h
deleted file mode 100644
index a8deec3..0000000
--- a/ui-snapshot.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef UI_SNAPSHOT_H
-#define UI_SNAPSHOT_H
-
-extern void cgit_print_snapshot(const char *head, const char *hex,
- const char *filename, int dwim);
-
-#endif /* UI_SNAPSHOT_H */
diff --git a/ui-ssdiff.c b/ui-ssdiff.c
deleted file mode 100644
index af8bc9e..0000000
--- a/ui-ssdiff.c
+++ /dev/null
@@ -1,420 +0,0 @@
-#include "cgit.h"
-#include "ui-ssdiff.h"
-#include "html.h"
-#include "ui-shared.h"
-#include "ui-diff.h"
-
-extern int use_ssdiff;
-
-static int current_old_line, current_new_line;
-static int **L = NULL;
-
-struct deferred_lines {
- int line_no;
- char *line;
- struct deferred_lines *next;
-};
-
-static struct deferred_lines *deferred_old, *deferred_old_last;
-static struct deferred_lines *deferred_new, *deferred_new_last;
-
-static void create_or_reset_lcs_table(void)
-{
- int i;
-
- if (L != NULL) {
- memset(*L, 0, sizeof(int) * MAX_SSDIFF_SIZE);
- return;
- }
-
- // xcalloc will die if we ran out of memory;
- // not very helpful for debugging
- L = (int**)xcalloc(MAX_SSDIFF_M, sizeof(int *));
- *L = (int*)xcalloc(MAX_SSDIFF_SIZE, sizeof(int));
-
- for (i = 1; i < MAX_SSDIFF_M; i++) {
- L[i] = *L + i * MAX_SSDIFF_N;
- }
-}
-
-static char *longest_common_subsequence(char *A, char *B)
-{
- int i, j, ri;
- int m = strlen(A);
- int n = strlen(B);
- int tmp1, tmp2;
- int lcs_length;
- char *result;
-
- // We bail if the lines are too long
- if (m >= MAX_SSDIFF_M || n >= MAX_SSDIFF_N)
- return NULL;
-
- create_or_reset_lcs_table();
-
- for (i = m; i >= 0; i--) {
- for (j = n; j >= 0; j--) {
- if (A[i] == '\0' || B[j] == '\0') {
- L[i][j] = 0;
- } else if (A[i] == B[j]) {
- L[i][j] = 1 + L[i + 1][j + 1];
- } else {
- tmp1 = L[i + 1][j];
- tmp2 = L[i][j + 1];
- L[i][j] = (tmp1 > tmp2 ? tmp1 : tmp2);
- }
- }
- }
-
- lcs_length = L[0][0];
- result = xmalloc(lcs_length + 2);
- memset(result, 0, sizeof(*result) * (lcs_length + 2));
-
- ri = 0;
- i = 0;
- j = 0;
- while (i < m && j < n) {
- if (A[i] == B[j]) {
- result[ri] = A[i];
- ri += 1;
- i += 1;
- j += 1;
- } else if (L[i + 1][j] >= L[i][j + 1]) {
- i += 1;
- } else {
- j += 1;
- }
- }
-
- return result;
-}
-
-static int line_from_hunk(char *line, char type)
-{
- char *buf1, *buf2;
- int len, res;
-
- buf1 = strchr(line, type);
- if (buf1 == NULL)
- return 0;
- buf1 += 1;
- buf2 = strchr(buf1, ',');
- if (buf2 == NULL)
- return 0;
- len = buf2 - buf1;
- buf2 = xmalloc(len + 1);
- strlcpy(buf2, buf1, len + 1);
- res = atoi(buf2);
- free(buf2);
- return res;
-}
-
-static char *replace_tabs(char *line)
-{
- char *prev_buf = line;
- char *cur_buf;
- size_t linelen = strlen(line);
- int n_tabs = 0;
- int i;
- char *result;
- size_t result_len;
-
- if (linelen == 0) {
- result = xmalloc(1);
- result[0] = '\0';
- return result;
- }
-
- for (i = 0; i < linelen; i++) {
- if (line[i] == '\t')
- n_tabs += 1;
- }
- result_len = linelen + n_tabs * 8;
- result = xmalloc(result_len + 1);
- result[0] = '\0';
-
- for (;;) {
- cur_buf = strchr(prev_buf, '\t');
- if (!cur_buf) {
- linelen = strlen(result);
- strlcpy(&result[linelen], prev_buf, result_len - linelen + 1);
- break;
- } else {
- linelen = strlen(result);
- strlcpy(&result[linelen], prev_buf, cur_buf - prev_buf + 1);
- linelen = strlen(result);
- memset(&result[linelen], ' ', 8 - (linelen % 8));
- result[linelen + 8 - (linelen % 8)] = '\0';
- }
- prev_buf = cur_buf + 1;
- }
- return result;
-}
-
-static int calc_deferred_lines(struct deferred_lines *start)
-{
- struct deferred_lines *item = start;
- int result = 0;
- while (item) {
- result += 1;
- item = item->next;
- }
- return result;
-}
-
-static void deferred_old_add(char *line, int line_no)
-{
- struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines));
- item->line = xstrdup(line);
- item->line_no = line_no;
- item->next = NULL;
- if (deferred_old) {
- deferred_old_last->next = item;
- deferred_old_last = item;
- } else {
- deferred_old = deferred_old_last = item;
- }
-}
-
-static void deferred_new_add(char *line, int line_no)
-{
- struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines));
- item->line = xstrdup(line);
- item->line_no = line_no;
- item->next = NULL;
- if (deferred_new) {
- deferred_new_last->next = item;
- deferred_new_last = item;
- } else {
- deferred_new = deferred_new_last = item;
- }
-}
-
-static void print_part_with_lcs(char *class, char *line, char *lcs)
-{
- int line_len = strlen(line);
- int i, j;
- char c[2] = " ";
- int same = 1;
-
- j = 0;
- for (i = 0; i < line_len; i++) {
- c[0] = line[i];
- if (same) {
- if (line[i] == lcs[j])
- j += 1;
- else {
- same = 0;
- htmlf("<span class='%s'>", class);
- }
- } else if (line[i] == lcs[j]) {
- same = 1;
- html("</span>");
- j += 1;
- }
- html_txt(c);
- }
- if (!same)
- html("</span>");
-}
-
-static void print_ssdiff_line(char *class,
- int old_line_no,
- char *old_line,
- int new_line_no,
- char *new_line, int individual_chars)
-{
- char *lcs = NULL;
-
- if (old_line)
- old_line = replace_tabs(old_line + 1);
- if (new_line)
- new_line = replace_tabs(new_line + 1);
- if (individual_chars && old_line && new_line)
- lcs = longest_common_subsequence(old_line, new_line);
- html("<tr>\n");
- if (old_line_no > 0) {
- struct diff_filespec *old_file = cgit_get_current_old_file();
- char *lineno_str = fmt("n%d", old_line_no);
- char *id_str = fmt("id=%s#%s", is_null_oid(&old_file->oid)?"HEAD":oid_to_hex(old_rev_oid), lineno_str);
- char *fileurl = cgit_fileurl(ctx.repo->url, "tree", old_file->path, id_str);
- html("<td class='lineno'><a href='");
- html(fileurl);
- htmlf("'>%s</a>", lineno_str + 1);
- html("</td>");
- htmlf("<td class='%s'>", class);
- free(fileurl);
- } else if (old_line)
- htmlf("<td class='lineno'></td><td class='%s'>", class);
- else
- htmlf("<td class='lineno'></td><td class='%s_dark'>", class);
- if (old_line) {
- if (lcs)
- print_part_with_lcs("del", old_line, lcs);
- else
- html_txt(old_line);
- }
-
- html("</td>\n");
- if (new_line_no > 0) {
- struct diff_filespec *new_file = cgit_get_current_new_file();
- char *lineno_str = fmt("n%d", new_line_no);
- char *id_str = fmt("id=%s#%s", is_null_oid(&new_file->oid)?"HEAD":oid_to_hex(new_rev_oid), lineno_str);
- char *fileurl = cgit_fileurl(ctx.repo->url, "tree", new_file->path, id_str);
- html("<td class='lineno'><a href='");
- html(fileurl);
- htmlf("'>%s</a>", lineno_str + 1);
- html("</td>");
- htmlf("<td class='%s'>", class);
- free(fileurl);
- } else if (new_line)
- htmlf("<td class='lineno'></td><td class='%s'>", class);
- else
- htmlf("<td class='lineno'></td><td class='%s_dark'>", class);
- if (new_line) {
- if (lcs)
- print_part_with_lcs("add", new_line, lcs);
- else
- html_txt(new_line);
- }
-
- html("</td></tr>");
- if (lcs)
- free(lcs);
- if (new_line)
- free(new_line);
- if (old_line)
- free(old_line);
-}
-
-static void print_deferred_old_lines(void)
-{
- struct deferred_lines *iter_old, *tmp;
- iter_old = deferred_old;
- while (iter_old) {
- print_ssdiff_line("del", iter_old->line_no,
- iter_old->line, -1, NULL, 0);
- tmp = iter_old->next;
- free(iter_old);
- iter_old = tmp;
- }
-}
-
-static void print_deferred_new_lines(void)
-{
- struct deferred_lines *iter_new, *tmp;
- iter_new = deferred_new;
- while (iter_new) {
- print_ssdiff_line("add", -1, NULL,
- iter_new->line_no, iter_new->line, 0);
- tmp = iter_new->next;
- free(iter_new);
- iter_new = tmp;
- }
-}
-
-static void print_deferred_changed_lines(void)
-{
- struct deferred_lines *iter_old, *iter_new, *tmp;
- int n_old_lines = calc_deferred_lines(deferred_old);
- int n_new_lines = calc_deferred_lines(deferred_new);
- int individual_chars = (n_old_lines == n_new_lines ? 1 : 0);
-
- iter_old = deferred_old;
- iter_new = deferred_new;
- while (iter_old || iter_new) {
- if (iter_old && iter_new)
- print_ssdiff_line("changed", iter_old->line_no,
- iter_old->line,
- iter_new->line_no, iter_new->line,
- individual_chars);
- else if (iter_old)
- print_ssdiff_line("changed", iter_old->line_no,
- iter_old->line, -1, NULL, 0);
- else if (iter_new)
- print_ssdiff_line("changed", -1, NULL,
- iter_new->line_no, iter_new->line, 0);
- if (iter_old) {
- tmp = iter_old->next;
- free(iter_old);
- iter_old = tmp;
- }
-
- if (iter_new) {
- tmp = iter_new->next;
- free(iter_new);
- iter_new = tmp;
- }
- }
-}
-
-void cgit_ssdiff_print_deferred_lines(void)
-{
- if (!deferred_old && !deferred_new)
- return;
- if (deferred_old && !deferred_new)
- print_deferred_old_lines();
- else if (!deferred_old && deferred_new)
- print_deferred_new_lines();
- else
- print_deferred_changed_lines();
- deferred_old = deferred_old_last = NULL;
- deferred_new = deferred_new_last = NULL;
-}
-
-/*
- * print a single line returned from xdiff
- */
-void cgit_ssdiff_line_cb(char *line, int len)
-{
- char c = line[len - 1];
- line[len - 1] = '\0';
- if (line[0] == '@') {
- current_old_line = line_from_hunk(line, '-');
- current_new_line = line_from_hunk(line, '+');
- }
-
- if (line[0] == ' ') {
- if (deferred_old || deferred_new)
- cgit_ssdiff_print_deferred_lines();
- print_ssdiff_line("ctx", current_old_line, line,
- current_new_line, line, 0);
- current_old_line += 1;
- current_new_line += 1;
- } else if (line[0] == '+') {
- deferred_new_add(line, current_new_line);
- current_new_line += 1;
- } else if (line[0] == '-') {
- deferred_old_add(line, current_old_line);
- current_old_line += 1;
- } else if (line[0] == '@') {
- html("<tr><td colspan='4' class='hunk'>");
- html_txt(line);
- html("</td></tr>");
- } else {
- html("<tr><td colspan='4' class='ctx'>");
- html_txt(line);
- html("</td></tr>");
- }
- line[len - 1] = c;
-}
-
-void cgit_ssdiff_header_begin(void)
-{
- current_old_line = -1;
- current_new_line = -1;
- html("<tr><td class='space' colspan='4'><div></div></td></tr>");
- html("<tr><td class='head' colspan='4'>");
-}
-
-void cgit_ssdiff_header_end(void)
-{
- html("</td></tr>");
-}
-
-void cgit_ssdiff_footer(void)
-{
- if (deferred_old || deferred_new)
- cgit_ssdiff_print_deferred_lines();
- html("<tr><td class='foot' colspan='4'></td></tr>");
-}
diff --git a/ui-ssdiff.h b/ui-ssdiff.h
deleted file mode 100644
index 11f2714..0000000
--- a/ui-ssdiff.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef UI_SSDIFF_H
-#define UI_SSDIFF_H
-
-/*
- * ssdiff line limits
- */
-#ifndef MAX_SSDIFF_M
-#define MAX_SSDIFF_M 128
-#endif
-
-#ifndef MAX_SSDIFF_N
-#define MAX_SSDIFF_N 128
-#endif
-#define MAX_SSDIFF_SIZE ((MAX_SSDIFF_M) * (MAX_SSDIFF_N))
-
-extern void cgit_ssdiff_print_deferred_lines(void);
-
-extern void cgit_ssdiff_line_cb(char *line, int len);
-
-extern void cgit_ssdiff_header_begin(void);
-extern void cgit_ssdiff_header_end(void);
-
-extern void cgit_ssdiff_footer(void);
-
-#endif /* UI_SSDIFF_H */
diff --git a/ui-stats.c b/ui-stats.c
deleted file mode 100644
index 02c60ef..0000000
--- a/ui-stats.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/* ui-stats.c: generate stats view
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-stats.h"
-#include "html.h"
-#include "ui-shared.h"
-
-struct authorstat {
- long total;
- struct string_list list;
-};
-
-#define DAY_SECS (60 * 60 * 24)
-#define WEEK_SECS (DAY_SECS * 7)
-
-static void trunc_week(struct tm *tm)
-{
- time_t t = timegm(tm);
- t -= ((tm->tm_wday + 6) % 7) * DAY_SECS;
- gmtime_r(&t, tm);
-}
-
-static void dec_week(struct tm *tm)
-{
- time_t t = timegm(tm);
- t -= WEEK_SECS;
- gmtime_r(&t, tm);
-}
-
-static void inc_week(struct tm *tm)
-{
- time_t t = timegm(tm);
- t += WEEK_SECS;
- gmtime_r(&t, tm);
-}
-
-static char *pretty_week(struct tm *tm)
-{
- static char buf[10];
-
- strftime(buf, sizeof(buf), "W%V %G", tm);
- return buf;
-}
-
-static void trunc_month(struct tm *tm)
-{
- tm->tm_mday = 1;
-}
-
-static void dec_month(struct tm *tm)
-{
- tm->tm_mon--;
- if (tm->tm_mon < 0) {
- tm->tm_year--;
- tm->tm_mon = 11;
- }
-}
-
-static void inc_month(struct tm *tm)
-{
- tm->tm_mon++;
- if (tm->tm_mon > 11) {
- tm->tm_year++;
- tm->tm_mon = 0;
- }
-}
-
-static char *pretty_month(struct tm *tm)
-{
- static const char *months[] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
- return fmt("%s %d", months[tm->tm_mon], tm->tm_year + 1900);
-}
-
-static void trunc_quarter(struct tm *tm)
-{
- trunc_month(tm);
- while (tm->tm_mon % 3 != 0)
- dec_month(tm);
-}
-
-static void dec_quarter(struct tm *tm)
-{
- dec_month(tm);
- dec_month(tm);
- dec_month(tm);
-}
-
-static void inc_quarter(struct tm *tm)
-{
- inc_month(tm);
- inc_month(tm);
- inc_month(tm);
-}
-
-static char *pretty_quarter(struct tm *tm)
-{
- return fmt("Q%d %d", tm->tm_mon / 3 + 1, tm->tm_year + 1900);
-}
-
-static void trunc_year(struct tm *tm)
-{
- trunc_month(tm);
- tm->tm_mon = 0;
-}
-
-static void dec_year(struct tm *tm)
-{
- tm->tm_year--;
-}
-
-static void inc_year(struct tm *tm)
-{
- tm->tm_year++;
-}
-
-static char *pretty_year(struct tm *tm)
-{
- return fmt("%d", tm->tm_year + 1900);
-}
-
-static const struct cgit_period periods[] = {
- {'w', "week", 12, 4, trunc_week, dec_week, inc_week, pretty_week},
- {'m', "month", 12, 4, trunc_month, dec_month, inc_month, pretty_month},
- {'q', "quarter", 12, 4, trunc_quarter, dec_quarter, inc_quarter, pretty_quarter},
- {'y', "year", 12, 4, trunc_year, dec_year, inc_year, pretty_year},
-};
-
-/* Given a period code or name, return a period index (1, 2, 3 or 4)
- * and update the period pointer to the correcsponding struct.
- * If no matching code is found, return 0.
- */
-int cgit_find_stats_period(const char *expr, const struct cgit_period **period)
-{
- int i;
- char code = '\0';
-
- if (!expr)
- return 0;
-
- if (strlen(expr) == 1)
- code = expr[0];
-
- for (i = 0; i < sizeof(periods) / sizeof(periods[0]); i++)
- if (periods[i].code == code || !strcmp(periods[i].name, expr)) {
- if (period)
- *period = &periods[i];
- return i + 1;
- }
- return 0;
-}
-
-const char *cgit_find_stats_periodname(int idx)
-{
- if (idx > 0 && idx < 4)
- return periods[idx - 1].name;
- else
- return "";
-}
-
-static void add_commit(struct string_list *authors, struct commit *commit,
- const struct cgit_period *period)
-{
- struct commitinfo *info;
- struct string_list_item *author, *item;
- struct authorstat *authorstat;
- struct string_list *items;
- char *tmp;
- struct tm date;
- time_t t;
- uintptr_t *counter;
-
- info = cgit_parse_commit(commit);
- tmp = xstrdup(info->author);
- author = string_list_insert(authors, tmp);
- if (!author->util)
- author->util = xcalloc(1, sizeof(struct authorstat));
- else
- free(tmp);
- authorstat = author->util;
- items = &authorstat->list;
- t = info->committer_date;
- gmtime_r(&t, &date);
- period->trunc(&date);
- tmp = xstrdup(period->pretty(&date));
- item = string_list_insert(items, tmp);
- counter = (uintptr_t *)&item->util;
- if (*counter)
- free(tmp);
- (*counter)++;
-
- authorstat->total++;
- cgit_free_commitinfo(info);
-}
-
-static int cmp_total_commits(const void *a1, const void *a2)
-{
- const struct string_list_item *i1 = a1;
- const struct string_list_item *i2 = a2;
- const struct authorstat *auth1 = i1->util;
- const struct authorstat *auth2 = i2->util;
-
- return auth2->total - auth1->total;
-}
-
-/* Walk the commit DAG and collect number of commits per author per
- * timeperiod into a nested string_list collection.
- */
-static struct string_list collect_stats(const struct cgit_period *period)
-{
- struct string_list authors;
- struct rev_info rev;
- struct commit *commit;
- const char *argv[] = {NULL, ctx.qry.head, NULL, NULL, NULL, NULL};
- int argc = 3;
- time_t now;
- long i;
- struct tm tm;
- char tmp[11];
-
- time(&now);
- gmtime_r(&now, &tm);
- period->trunc(&tm);
- for (i = 1; i < period->count; i++)
- period->dec(&tm);
- strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
- argv[2] = xstrdup(fmt("--since=%s", tmp));
- if (ctx.qry.path) {
- argv[3] = "--";
- argv[4] = ctx.qry.path;
- argc += 2;
- }
- repo_init_revisions(the_repository, &rev, NULL);
- rev.abbrev = DEFAULT_ABBREV;
- rev.commit_format = CMIT_FMT_DEFAULT;
- rev.max_parents = 1;
- rev.verbose_header = 1;
- rev.show_root_diff = 0;
- setup_revisions(argc, argv, &rev, NULL);
- prepare_revision_walk(&rev);
- memset(&authors, 0, sizeof(authors));
- while ((commit = get_revision(&rev)) != NULL) {
- add_commit(&authors, commit, period);
- release_commit_memory(the_repository->parsed_objects, commit);
- commit->parents = NULL;
- }
- return authors;
-}
-
-static void print_combined_authorrow(struct string_list *authors, int from,
- int to, const char *name,
- const char *leftclass,
- const char *centerclass,
- const char *rightclass,
- const struct cgit_period *period)
-{
- struct string_list_item *author;
- struct authorstat *authorstat;
- struct string_list *items;
- struct string_list_item *date;
- time_t now;
- long i, j, total, subtotal;
- struct tm tm;
- char *tmp;
-
- time(&now);
- gmtime_r(&now, &tm);
- period->trunc(&tm);
- for (i = 1; i < period->count; i++)
- period->dec(&tm);
-
- total = 0;
- htmlf("<tr><td class='%s'>%s</td>", leftclass,
- fmt(name, to - from + 1));
- for (j = 0; j < period->count; j++) {
- tmp = period->pretty(&tm);
- period->inc(&tm);
- subtotal = 0;
- for (i = from; i <= to; i++) {
- author = &authors->items[i];
- authorstat = author->util;
- items = &authorstat->list;
- date = string_list_lookup(items, tmp);
- if (date)
- subtotal += (uintptr_t)date->util;
- }
- htmlf("<td class='%s'>%ld</td>", centerclass, subtotal);
- total += subtotal;
- }
- htmlf("<td class='%s'>%ld</td></tr>", rightclass, total);
-}
-
-static void print_authors(struct string_list *authors, int top,
- const struct cgit_period *period)
-{
- struct string_list_item *author;
- struct authorstat *authorstat;
- struct string_list *items;
- struct string_list_item *date;
- time_t now;
- long i, j, total;
- struct tm tm;
- char *tmp;
-
- time(&now);
- gmtime_r(&now, &tm);
- period->trunc(&tm);
- for (i = 1; i < period->count; i++)
- period->dec(&tm);
-
- html("<table class='stats'><tr><th>Author</th>");
- for (j = 0; j < period->count; j++) {
- tmp = period->pretty(&tm);
- htmlf("<th>%s</th>", tmp);
- period->inc(&tm);
- }
- html("<th>Total</th></tr>\n");
-
- if (top <= 0 || top > authors->nr)
- top = authors->nr;
-
- for (i = 0; i < top; i++) {
- author = &authors->items[i];
- html("<tr><td class='left'>");
- html_txt(author->string);
- html("</td>");
- authorstat = author->util;
- items = &authorstat->list;
- total = 0;
- for (j = 0; j < period->count; j++)
- period->dec(&tm);
- for (j = 0; j < period->count; j++) {
- tmp = period->pretty(&tm);
- period->inc(&tm);
- date = string_list_lookup(items, tmp);
- if (!date)
- html("<td>0</td>");
- else {
- htmlf("<td>%lu</td>", (uintptr_t)date->util);
- total += (uintptr_t)date->util;
- }
- }
- htmlf("<td class='sum'>%ld</td></tr>", total);
- }
-
- if (top < authors->nr)
- print_combined_authorrow(authors, top, authors->nr - 1,
- "Others (%ld)", "left", "", "sum", period);
-
- print_combined_authorrow(authors, 0, authors->nr - 1, "Total",
- "total", "sum", "sum", period);
- html("</table>");
-}
-
-/* Create a sorted string_list with one entry per author. The util-field
- * for each author is another string_list which is used to calculate the
- * number of commits per time-interval.
- */
-void cgit_show_stats(void)
-{
- struct string_list authors;
- const struct cgit_period *period;
- int top, i;
- const char *code = "w";
-
- if (ctx.qry.period)
- code = ctx.qry.period;
-
- i = cgit_find_stats_period(code, &period);
- if (!i) {
- cgit_print_error_page(404, "Not found",
- "Unknown statistics type: %c", code[0]);
- return;
- }
- if (i > ctx.repo->max_stats) {
- cgit_print_error_page(400, "Bad request",
- "Statistics type disabled: %s", period->name);
- return;
- }
- authors = collect_stats(period);
- qsort(authors.items, authors.nr, sizeof(struct string_list_item),
- cmp_total_commits);
-
- top = ctx.qry.ofs;
- if (!top)
- top = 10;
-
- cgit_print_layout_start();
- html("<div class='cgit-panel'>");
- html("<b>stat options</b>");
- html("<form method='get'>");
- cgit_add_hidden_formfields(1, 0, "stats");
- html("<table><tr><td colspan='2'/></tr>");
- if (ctx.repo->max_stats > 1) {
- html("<tr><td class='label'>Period:</td>");
- html("<td class='ctrl'><select name='period' onchange='this.form.submit();'>");
- for (i = 0; i < ctx.repo->max_stats; i++)
- html_option(fmt("%c", periods[i].code),
- periods[i].name, fmt("%c", period->code));
- html("</select></td></tr>");
- }
- html("<tr><td class='label'>Authors:</td>");
- html("<td class='ctrl'><select name='ofs' onchange='this.form.submit();'>");
- html_intoption(10, "10", top);
- html_intoption(25, "25", top);
- html_intoption(50, "50", top);
- html_intoption(100, "100", top);
- html_intoption(-1, "all", top);
- html("</select></td></tr>");
- html("<tr><td/><td class='ctrl'>");
- html("<noscript><input type='submit' value='Reload'/></noscript>");
- html("</td></tr></table>");
- html("</form>");
- html("</div>");
- htmlf("<h2>Commits per author per %s", period->name);
- if (ctx.qry.path) {
- html(" (path '");
- html_txt(ctx.qry.path);
- html("')");
- }
- html("</h2>");
- print_authors(&authors, top, period);
- cgit_print_layout_end();
-}
-
diff --git a/ui-stats.h b/ui-stats.h
deleted file mode 100644
index 0e61b03..0000000
--- a/ui-stats.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef UI_STATS_H
-#define UI_STATS_H
-
-#include "cgit.h"
-
-struct cgit_period {
- const char code;
- const char *name;
- int max_periods;
- int count;
-
- /* Convert a tm value to the first day in the period */
- void (*trunc)(struct tm *tm);
-
- /* Update tm value to start of next/previous period */
- void (*dec)(struct tm *tm);
- void (*inc)(struct tm *tm);
-
- /* Pretty-print a tm value */
- char *(*pretty)(struct tm *tm);
-};
-
-extern int cgit_find_stats_period(const char *expr, const struct cgit_period **period);
-extern const char *cgit_find_stats_periodname(int idx);
-
-extern void cgit_show_stats(void);
-
-#endif /* UI_STATS_H */
diff --git a/ui-summary.c b/ui-summary.c
deleted file mode 100644
index 947812a..0000000
--- a/ui-summary.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/* ui-summary.c: functions for generating repo summary page
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#include "cgit.h"
-#include "ui-summary.h"
-#include "html.h"
-#include "ui-blob.h"
-#include "ui-log.h"
-#include "ui-plain.h"
-#include "ui-refs.h"
-#include "ui-shared.h"
-
-static int urls;
-
-static void print_url(const char *url)
-{
- int columns = 3;
-
- if (ctx.repo->enable_log_filecount)
- columns++;
- if (ctx.repo->enable_log_linecount)
- columns++;
-
- if (urls++ == 0) {
- htmlf("<tr class='nohover'><td colspan='%d'>&nbsp;</td></tr>", columns);
- htmlf("<tr class='nohover'><th class='left' colspan='%d'>Clone</th></tr>\n", columns);
- }
-
- htmlf("<tr><td colspan='%d'><a rel='vcs-git' href='", columns);
- html_url_path(url);
- html("' title='");
- html_attr(ctx.repo->name);
- html(" Git repository'>");
- html_txt(url);
- html("</a></td></tr>\n");
-}
-
-void cgit_print_summary(void)
-{
- int columns = 3;
-
- if (ctx.repo->enable_log_filecount)
- columns++;
- if (ctx.repo->enable_log_linecount)
- columns++;
-
- cgit_print_layout_start();
- html("<table summary='repository info' class='list nowrap'>");
- cgit_print_branches(ctx.cfg.summary_branches);
- htmlf("<tr class='nohover'><td colspan='%d'>&nbsp;</td></tr>", columns);
- cgit_print_tags(ctx.cfg.summary_tags);
- if (ctx.cfg.summary_log > 0) {
- htmlf("<tr class='nohover'><td colspan='%d'>&nbsp;</td></tr>", columns);
- cgit_print_log(ctx.qry.head, 0, ctx.cfg.summary_log, NULL,
- NULL, NULL, 0, 0, 0);
- }
- urls = 0;
- cgit_add_clone_urls(print_url);
- html("</table>");
- cgit_print_layout_end();
-}
-
-/* The caller must free the return value. */
-static char* append_readme_path(const char *filename, const char *ref, const char *path)
-{
- char *file, *base_dir, *full_path, *resolved_base = NULL, *resolved_full = NULL;
- /* If a subpath is specified for the about page, make it relative
- * to the directory containing the configured readme. */
-
- file = xstrdup(filename);
- base_dir = dirname(file);
- if (!strcmp(base_dir, ".") || !strcmp(base_dir, "..")) {
- if (!ref) {
- free(file);
- return NULL;
- }
- full_path = xstrdup(path);
- } else
- full_path = fmtalloc("%s/%s", base_dir, path);
-
- if (!ref) {
- resolved_base = realpath(base_dir, NULL);
- resolved_full = realpath(full_path, NULL);
- if (!resolved_base || !resolved_full || !starts_with(resolved_full, resolved_base)) {
- free(full_path);
- full_path = NULL;
- }
- }
-
- free(file);
- free(resolved_base);
- free(resolved_full);
-
- return full_path;
-}
-
-void cgit_print_repo_readme(const char *path)
-{
- char *filename, *ref, *mimetype;
- int free_filename = 0;
-
- mimetype = get_mimetype_for_filename(path);
- if (mimetype && (!strncmp(mimetype, "image/", 6) || !strncmp(mimetype, "video/", 6))) {
- ctx.page.mimetype = mimetype;
- ctx.page.charset = NULL;
- cgit_print_plain();
- free(mimetype);
- return;
- }
- free(mimetype);
-
- cgit_print_layout_start();
- if (ctx.repo->readme.nr == 0)
- goto done;
-
- filename = ctx.repo->readme.items[0].string;
- ref = ctx.repo->readme.items[0].util;
-
- if (path) {
- free_filename = 1;
- filename = append_readme_path(filename, ref, path);
- if (!filename)
- goto done;
- }
-
- /* Print the calculated readme, either from the git repo or from the
- * filesystem, while applying the about-filter.
- */
- html("<div id='summary'>");
- cgit_open_filter(ctx.repo->about_filter, filename);
- if (ref)
- cgit_print_file(filename, ref, 1);
- else
- html_include(filename);
- cgit_close_filter(ctx.repo->about_filter);
-
- html("</div>");
- if (free_filename)
- free(filename);
-
-done:
- cgit_print_layout_end();
-}
diff --git a/ui-summary.h b/ui-summary.h
deleted file mode 100644
index cba696a..0000000
--- a/ui-summary.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef UI_SUMMARY_H
-#define UI_SUMMARY_H
-
-extern void cgit_print_summary(void);
-extern void cgit_print_repo_readme(const char *path);
-
-#endif /* UI_SUMMARY_H */
diff --git a/ui-tag.c b/ui-tag.c
deleted file mode 100644
index 8f58f14..0000000
--- a/ui-tag.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* ui-tag.c: display a tag
- *
- * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-tag.h"
-#include "html.h"
-#include "ui-shared.h"
-
-static void print_tag_content(char *buf)
-{
- char *p;
-
- if (!buf)
- return;
-
- html("<div class='commit-subject'>");
- p = strchr(buf, '\n');
- if (p)
- *p = '\0';
- html_txt(buf);
- html("</div>");
- if (p) {
- html("<div class='commit-msg'>");
- html_txt(++p);
- html("</div>");
- }
-}
-
-static void print_download_links(char *revname)
-{
- html("<tr><th>download</th><td class='oid'>");
- cgit_print_snapshot_links(ctx.repo, revname, "<br/>");
- html("</td></tr>");
-}
-
-void cgit_print_tag(char *revname)
-{
- struct strbuf fullref = STRBUF_INIT;
- struct object_id oid;
- struct object *obj;
-
- if (!revname)
- revname = ctx.qry.head;
-
- strbuf_addf(&fullref, "refs/tags/%s", revname);
- if (repo_get_oid(the_repository, fullref.buf, &oid)) {
- cgit_print_error_page(404, "Not found",
- "Bad tag reference: %s", revname);
- goto cleanup;
- }
- obj = parse_object(the_repository, &oid);
- if (!obj) {
- cgit_print_error_page(500, "Internal server error",
- "Bad object id: %s", oid_to_hex(&oid));
- goto cleanup;
- }
- if (obj->type == OBJ_TAG) {
- struct tag *tag;
- struct taginfo *info;
-
- tag = lookup_tag(the_repository, &oid);
- if (!tag || parse_tag(the_repository, tag) || !(info = cgit_parse_tag(tag))) {
- cgit_print_error_page(500, "Internal server error",
- "Bad tag object: %s", revname);
- goto cleanup;
- }
- cgit_print_layout_start();
- html("<table class='commit-info'>\n");
- html("<tr><td>tag name</td><td>");
- html_txt(revname);
- htmlf(" (%s)</td></tr>\n", oid_to_hex(&oid));
- if (info->tagger_date > 0) {
- html("<tr><td>tag date</td><td>");
- html_txt(show_date(info->tagger_date, info->tagger_tz,
- cgit_date_mode(DATE_ISO8601)));
- html("</td></tr>\n");
- }
- if (info->tagger) {
- html("<tr><td>tagged by</td><td>");
- cgit_open_filter(ctx.repo->email_filter, info->tagger_email, "tag");
- html_txt(info->tagger);
- if (info->tagger_email && !ctx.cfg.noplainemail) {
- html(" ");
- html_txt(info->tagger_email);
- }
- cgit_close_filter(ctx.repo->email_filter);
- html("</td></tr>\n");
- }
- html("<tr><td>tagged object</td><td class='oid'>");
- cgit_object_link(tag->tagged);
- html("</td></tr>\n");
- if (ctx.repo->snapshots)
- print_download_links(revname);
- html("</table>\n");
- print_tag_content(info->msg);
- cgit_print_layout_end();
- cgit_free_taginfo(info);
- } else {
- cgit_print_layout_start();
- html("<table class='commit-info'>\n");
- html("<tr><td>tag name</td><td>");
- html_txt(revname);
- html("</td></tr>\n");
- html("<tr><td>tagged object</td><td class='oid'>");
- cgit_object_link(obj);
- html("</td></tr>\n");
- if (ctx.repo->snapshots)
- print_download_links(revname);
- html("</table>\n");
- cgit_print_layout_end();
- }
-
-cleanup:
- strbuf_release(&fullref);
-}
diff --git a/ui-tag.h b/ui-tag.h
deleted file mode 100644
index d295cdc..0000000
--- a/ui-tag.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef UI_TAG_H
-#define UI_TAG_H
-
-extern void cgit_print_tag(char *revname);
-
-#endif /* UI_TAG_H */
diff --git a/ui-tree.c b/ui-tree.c
deleted file mode 100644
index 5ac8c9a..0000000
--- a/ui-tree.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/* ui-tree.c: functions for tree output
- *
- * Copyright (C) 2006-2017 cgit Development Team <cgit@lists.zx2c4.com>
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
- #define USE_THE_REPOSITORY_VARIABLE
-
-#include "cgit.h"
-#include "ui-tree.h"
-#include "html.h"
-#include "ui-shared.h"
-
-struct walk_tree_context {
- char *curr_rev;
- char *match_path;
- int state;
-};
-
-static void print_text_buffer(const char *name, char *buf, unsigned long size)
-{
- unsigned long lineno, idx;
- const char *numberfmt = "<a id='n%1$d' href='#n%1$d'>%1$d</a>\n";
-
- html("<table summary='blob content' class='blob'>\n");
-
- if (ctx.cfg.enable_tree_linenumbers) {
- html("<tr><td class='linenumbers'><pre>");
- idx = 0;
- lineno = 0;
-
- if (size) {
- htmlf(numberfmt, ++lineno);
- while (idx < size - 1) { // skip absolute last newline
- if (buf[idx] == '\n')
- htmlf(numberfmt, ++lineno);
- idx++;
- }
- }
- html("</pre></td>\n");
- }
- else {
- html("<tr>\n");
- }
-
- if (ctx.repo->source_filter) {
- char *filter_arg = xstrdup(name);
- html("<td class='lines'><pre><code>");
- cgit_open_filter(ctx.repo->source_filter, filter_arg);
- html_raw(buf, size);
- cgit_close_filter(ctx.repo->source_filter);
- free(filter_arg);
- html("</code></pre></td></tr></table>\n");
- return;
- }
-
- html("<td class='lines'><pre><code>");
- html_txt(buf);
- html("</code></pre></td></tr></table>\n");
-}
-
-#define ROWLEN 32
-
-static void print_binary_buffer(char *buf, unsigned long size)
-{
- unsigned long ofs, idx;
- static char ascii[ROWLEN + 1];
-
- html("<table summary='blob content' class='bin-blob'>\n");
- html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>");
- for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) {
- htmlf("<tr><td class='right'>%04lx</td><td class='hex'>", ofs);
- for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
- htmlf("%*s%02x",
- idx == 16 ? 4 : 1, "",
- buf[idx] & 0xff);
- html(" </td><td class='hex'>");
- for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++)
- ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.';
- ascii[idx] = '\0';
- html_txt(ascii);
- html("</td></tr>\n");
- }
- html("</table>\n");
-}
-
-static void print_object(const struct object_id *oid, const char *path, const char *basename, const char *rev)
-{
- enum object_type type;
- char *buf;
- unsigned long size;
- bool is_binary;
-
- type = odb_read_object_info(the_repository->objects, oid, &size);
- if (type == OBJ_BAD) {
- cgit_print_error_page(404, "Not found",
- "Bad object name: %s", oid_to_hex(oid));
- return;
- }
-
- buf = odb_read_object(the_repository->objects, oid, &type, &size);
- if (!buf) {
- cgit_print_error_page(500, "Internal server error",
- "Error reading object %s", oid_to_hex(oid));
- return;
- }
- is_binary = buffer_is_binary(buf, size);
-
- cgit_set_title_from_path(path);
-
- cgit_print_layout_start();
- htmlf("blob: %s (", oid_to_hex(oid));
- cgit_plain_link("plain", NULL, NULL, ctx.qry.head,
- rev, path);
- if (ctx.repo->enable_blame && !is_binary) {
- html(") (");
- cgit_blame_link("blame", NULL, NULL, ctx.qry.head,
- rev, path);
- }
- html(")\n");
-
- if (ctx.cfg.max_blob_size && size / 1024 > ctx.cfg.max_blob_size) {
- htmlf("<div class='error'>blob size (%ldKB) exceeds display size limit (%dKB).</div>",
- size / 1024, ctx.cfg.max_blob_size);
- return;
- }
-
- if (is_binary)
- print_binary_buffer(buf, size);
- else
- print_text_buffer(basename, buf, size);
-
- free(buf);
-}
-
-struct single_tree_ctx {
- struct strbuf *path;
- struct object_id oid;
- char *name;
- size_t count;
-};
-
-static int single_tree_cb(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode, void *cbdata)
-{
- struct single_tree_ctx *ctx = cbdata;
-
- if (++ctx->count > 1)
- return -1;
-
- if (!S_ISDIR(mode)) {
- ctx->count = 2;
- return -1;
- }
-
- ctx->name = xstrdup(pathname);
- oidcpy(&ctx->oid, oid);
- strbuf_addf(ctx->path, "/%s", pathname);
- return 0;
-}
-
-static void write_tree_link(const struct object_id *oid, char *name,
- char *rev, struct strbuf *fullpath)
-{
- size_t initial_length = fullpath->len;
- struct tree *tree;
- struct single_tree_ctx tree_ctx = {
- .path = fullpath,
- .count = 1,
- };
- struct pathspec paths = {
- .nr = 0
- };
-
- oidcpy(&tree_ctx.oid, oid);
-
- while (tree_ctx.count == 1) {
- cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, rev,
- fullpath->buf);
-
- tree = lookup_tree(the_repository, &tree_ctx.oid);
- if (!tree)
- return;
-
- free(tree_ctx.name);
- tree_ctx.name = NULL;
- tree_ctx.count = 0;
-
- read_tree(the_repository, tree, &paths, single_tree_cb, &tree_ctx);
-
- if (tree_ctx.count != 1)
- break;
-
- html(" / ");
- name = tree_ctx.name;
- }
-
- strbuf_setlen(fullpath, initial_length);
-}
-
-static int ls_item(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode, void *cbdata)
-{
- struct walk_tree_context *walk_tree_ctx = cbdata;
- char *name;
- struct strbuf fullpath = STRBUF_INIT;
- struct strbuf linkpath = STRBUF_INIT;
- struct strbuf class = STRBUF_INIT;
- enum object_type type;
- unsigned long size = 0;
- char *buf;
-
- name = xstrdup(pathname);
- strbuf_addf(&fullpath, "%s%s%s", ctx.qry.path ? ctx.qry.path : "",
- ctx.qry.path ? "/" : "", name);
-
- if (!S_ISGITLINK(mode)) {
- type = odb_read_object_info(the_repository->objects, oid, &size);
- if (type == OBJ_BAD) {
- htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>",
- name,
- oid_to_hex(oid));
- goto cleanup;
- }
- }
-
- html("<tr><td class='ls-mode'>");
- cgit_print_filemode(mode);
- html("</td><td>");
- if (S_ISGITLINK(mode)) {
- cgit_submodule_link("ls-mod", fullpath.buf, oid_to_hex(oid));
- } else if (S_ISDIR(mode)) {
- write_tree_link(oid, name, walk_tree_ctx->curr_rev,
- &fullpath);
- } else {
- char *ext = strrchr(name, '.');
- strbuf_addstr(&class, "ls-blob");
- if (ext)
- strbuf_addf(&class, " %s", ext + 1);
- cgit_tree_link(name, NULL, class.buf, ctx.qry.head,
- walk_tree_ctx->curr_rev, fullpath.buf);
- }
- if (S_ISLNK(mode)) {
- html(" -> ");
- buf = odb_read_object(the_repository->objects, oid, &type, &size);
- if (!buf) {
- htmlf("Error reading object: %s", oid_to_hex(oid));
- goto cleanup;
- }
- strbuf_addbuf(&linkpath, &fullpath);
- strbuf_addf(&linkpath, "/../%s", buf);
- strbuf_normalize_path(&linkpath);
- cgit_tree_link(buf, NULL, class.buf, ctx.qry.head,
- walk_tree_ctx->curr_rev, linkpath.buf);
- free(buf);
- strbuf_release(&linkpath);
- }
- htmlf("</td><td class='ls-size'>%li</td>", size);
-
- html("<td>");
- cgit_log_link("log", NULL, "button", ctx.qry.head,
- walk_tree_ctx->curr_rev, fullpath.buf, 0, NULL, NULL,
- ctx.qry.showmsg, 0);
- if (ctx.repo->max_stats)
- cgit_stats_link("stats", NULL, "button", ctx.qry.head,
- fullpath.buf);
- if (!S_ISGITLINK(mode))
- cgit_plain_link("plain", NULL, "button", ctx.qry.head,
- walk_tree_ctx->curr_rev, fullpath.buf);
- if (!S_ISDIR(mode) && ctx.repo->enable_blame)
- cgit_blame_link("blame", NULL, "button", ctx.qry.head,
- walk_tree_ctx->curr_rev, fullpath.buf);
- html("</td></tr>\n");
-
-cleanup:
- free(name);
- strbuf_release(&fullpath);
- strbuf_release(&class);
- return 0;
-}
-
-static void ls_head(void)
-{
- cgit_print_layout_start();
- html("<table summary='tree listing' class='list'>\n");
- html("<tr class='nohover'>");
- html("<th class='left'>Mode</th>");
- html("<th class='left'>Name</th>");
- html("<th class='right'>Size</th>");
- html("<th/>");
- html("</tr>\n");
-}
-
-static void ls_tail(void)
-{
- html("</table>\n");
- cgit_print_layout_end();
-}
-
-static void ls_tree(const struct object_id *oid, const char *path, struct walk_tree_context *walk_tree_ctx)
-{
- struct tree *tree;
- struct pathspec paths = {
- .nr = 0
- };
-
- tree = parse_tree_indirect(oid);
- if (!tree) {
- cgit_print_error_page(404, "Not found",
- "Not a tree object: %s", oid_to_hex(oid));
- return;
- }
-
- ls_head();
- read_tree(the_repository, tree, &paths, ls_item, walk_tree_ctx);
- ls_tail();
-}
-
-
-static int walk_tree(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode, void *cbdata)
-{
- struct walk_tree_context *walk_tree_ctx = cbdata;
-
- if (walk_tree_ctx->state == 0) {
- struct strbuf buffer = STRBUF_INIT;
-
- strbuf_addbuf(&buffer, base);
- strbuf_addstr(&buffer, pathname);
- if (strcmp(walk_tree_ctx->match_path, buffer.buf))
- return READ_TREE_RECURSIVE;
-
- if (S_ISDIR(mode)) {
- walk_tree_ctx->state = 1;
- cgit_set_title_from_path(buffer.buf);
- strbuf_release(&buffer);
- ls_head();
- return READ_TREE_RECURSIVE;
- } else {
- walk_tree_ctx->state = 2;
- print_object(oid, buffer.buf, pathname, walk_tree_ctx->curr_rev);
- strbuf_release(&buffer);
- return 0;
- }
- }
- ls_item(oid, base, pathname, mode, walk_tree_ctx);
- return 0;
-}
-
-/*
- * Show a tree or a blob
- * rev: the commit pointing at the root tree object
- * path: path to tree or blob
- */
-void cgit_print_tree(const char *rev, char *path)
-{
- struct object_id oid;
- struct commit *commit;
- struct pathspec_item path_items = {
- .match = path,
- .len = path ? strlen(path) : 0
- };
- struct pathspec paths = {
- .nr = path ? 1 : 0,
- .items = &path_items
- };
- struct walk_tree_context walk_tree_ctx = {
- .match_path = path,
- .state = 0
- };
-
- if (!rev)
- rev = ctx.qry.head;
-
- if (repo_get_oid(the_repository, rev, &oid)) {
- cgit_print_error_page(404, "Not found",
- "Invalid revision name: %s", rev);
- return;
- }
- commit = lookup_commit_reference(the_repository, &oid);
- if (!commit || repo_parse_commit(the_repository, commit)) {
- cgit_print_error_page(404, "Not found",
- "Invalid commit reference: %s", rev);
- return;
- }
-
- walk_tree_ctx.curr_rev = xstrdup(rev);
-
- if (path == NULL) {
- ls_tree(get_commit_tree_oid(commit), NULL, &walk_tree_ctx);
- goto cleanup;
- }
-
- read_tree(the_repository, repo_get_commit_tree(the_repository, commit),
- &paths, walk_tree, &walk_tree_ctx);
- if (walk_tree_ctx.state == 1)
- ls_tail();
- else if (walk_tree_ctx.state == 2)
- cgit_print_layout_end();
- else
- cgit_print_error_page(404, "Not found", "Path not found");
-
-cleanup:
- free(walk_tree_ctx.curr_rev);
-}
diff --git a/ui-tree.h b/ui-tree.h
deleted file mode 100644
index bbd34e3..0000000
--- a/ui-tree.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef UI_TREE_H
-#define UI_TREE_H
-
-extern void cgit_print_tree(const char *rev, char *path);
-
-#endif /* UI_TREE_H */