ADDED .editorconfig Index: .editorconfig ================================================================== --- /dev/null +++ .editorconfig @@ -0,0 +1,14 @@ +# EditorConfig (https://editorconfig.com) Configuration for Fossil +# +# Following https://fossil-scm.org/fossil/doc/trunk/www/style.wiki +# + +# Defaults for all files +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 + +[{Makefile,Makefile.*,*.mk}] +indent_style = tab ADDED .fossil-settings/binary-glob Index: .fossil-settings/binary-glob ================================================================== --- /dev/null +++ .fossil-settings/binary-glob @@ -0,0 +1,11 @@ +*.gif +*.ico +*.jpg +*.odp +*.dia +*.pdf +*.png +compat/zlib/contrib/blast/test.pk +compat/zlib/contrib/dotzlib/DotZLib.chm +compat/zlib/contrib/puff/zeros.raw +compat/zlib/zlib.3.pdf DELETED .fossil-settings/clean-glob Index: .fossil-settings/clean-glob ================================================================== --- .fossil-settings/clean-glob +++ /dev/null @@ -1,17 +0,0 @@ -*.a -*.lib -*.manifest -*.o -*.obj -*.pdb -*.res -Makefile -bld/* -wbld/* -win/*.c -win/*.h -win/*.exe -win/headers -win/linkopts -autoconfig.h -config.log ADDED .fossil-settings/crlf-glob Index: .fossil-settings/crlf-glob ================================================================== --- /dev/null +++ .fossil-settings/crlf-glob @@ -0,0 +1,5 @@ +compat/zlib/* +setup/fossil.iss +test/th1-docs-input.txt +test/th1-hooks-input.txt +win/buildmsvc.bat Index: .fossil-settings/encoding-glob ================================================================== --- .fossil-settings/encoding-glob +++ .fossil-settings/encoding-glob @@ -1,2 +1,4 @@ compat/zlib/contrib/dotzlib/DotZLib/*.cs +test/utf16be.txt +test/utf16le.txt win/fossil.rc Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -1,5 +1,22 @@ +*.a +*.lib +*.manifest +*.o +*.obj +*.pdb +*.res +Makefile +bld/* +wbld/* +win/*.c +win/*.h +win/*.exe +win/headers +win/linkopts +autoconfig.h +config.log compat/openssl* compat/tcl* fossil fossil.exe win/fossil.exe Index: Dockerfile ================================================================== --- Dockerfile +++ Dockerfile @@ -1,25 +1,23 @@ ### # Dockerfile for Fossil ### -FROM fedora:23 +FROM fedora:29 ### Now install some additional parts we will need for the build -RUN dnf update -y && dnf install -y gcc make zlib-devel openssl-devel tar && dnf clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil +RUN dnf update -y && dnf install -y gcc make tcl tcl-devel zlib-devel openssl-devel tar && dnf clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil ### If you want to build "trunk", change the next line accordingly. ENV FOSSIL_INSTALL_VERSION release -RUN curl "http://core.tcl.tk/tcl/tarball/tcl-src.tar.gz?name=tcl-src&uuid=release" | tar zx -RUN cd tcl-src/unix && ./configure --prefix=/usr --disable-load && make && make install -RUN curl "http://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx -RUN cd fossil-src && ./configure --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl --with-tcl-stubs --with-tcl-private-stubs +RUN curl "https://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx +RUN cd fossil-src && ./configure --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl=1 --with-tcl-stubs --with-tcl-private-stubs RUN cd fossil-src/src && mv main.c main.c.orig && sed s/\"now\"/0/ main.c RUN cd fossil-src && make && strip fossil && cp fossil /usr/bin && cd .. && rm -rf fossil-src && chmod a+rx /usr/bin/fossil && mkdir -p /opt/fossil && chown fossil:fossil /opt/fossil ### Build is done, remove modules no longer needed -RUN dnf remove -y gcc make zlib-devel openssl-devel tar && dnf clean all +RUN dnf remove -y gcc make zlib-devel tcl-devel openssl-devel tar && dnf clean all USER fossil ENV HOME /opt/fossil Index: Makefile.classic ================================================================== --- Makefile.classic +++ Makefile.classic @@ -19,10 +19,11 @@ # will run on the platform that is doing the build. This is used # to compile code-generator programs as part of the build process. # See TCC below for the C compiler for building the finished binary. # BCC = gcc +BCCFLAGS = $(CFLAGS) #### The suffix to add to final executable file. When cross-compiling # to windows, make this ".exe". Otherwise leave it blank. # E = @@ -42,14 +43,26 @@ # TCC += -DFOSSIL_ENABLE_MINIZ # To add support for HTTPS TCC += -DFOSSIL_ENABLE_SSL +# To enable legacy mv/rm support +TCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 + #### We sometimes add the -static option here so that we can build a # static executable that will run in a chroot jail. #LIB = -static TCC += -DFOSSIL_DYNAMIC_BUILD=1 + +TCCFLAGS = $(CFLAGS) + +# We don't attempt to use libedit or libreadline in this simplified +# build system (contrast auto.def and Makefile.in) so use the included +# copy of linenoise. MinGW can't make use of this, but linenoise is +# ifdef'd out elsewhere for that platform. Note that this is a make +# flag handled in src/main.mk, not a C preprocessor flag. +USE_LINENOISE := 1 #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library unless the miniz # library in the source tree is being used. There are no other # required dependencies. @@ -60,10 +73,15 @@ # If using zlib: LIB += $(ZLIB_LIB.$(FOSSIL_ENABLE_MINIZ)) $(LDFLAGS) # If using HTTPS: LIB += -lcrypto -lssl + +# Many platforms put cos() needed by src/piechart.c in libm, rather than +# in libc. We cannot enable this by default because libm doesn't exist +# everywhere. +#LIB += -lm #### Tcl shell for use in running the fossil testsuite. If you do not # care about testing the end result, this can be blank. # TCLSH = tclsh @@ -81,7 +99,9 @@ TCC.DragonFly += -DUSE_PREAD TCC.FreeBSD += -DUSE_PREAD TCC.NetBSD += -DUSE_PREAD TCC.OpenBSD += -DUSE_PREAD TCC += $(TCC.$(HOST_OS)) + +APPNAME = fossil$(E) include $(SRCDIR)/main.mk Index: Makefile.in ================================================================== --- Makefile.in +++ Makefile.in @@ -34,19 +34,51 @@ TCC = @CC@ #### Tcl shell for use in running the fossil testsuite. If you do not # care about testing the end result, this can be blank. # -TCLSH = tclsh +TCLSH = @TCLSH@ +CFLAGS = @CFLAGS@ LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ -TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H -D_HAVE_SQLITE_CONFIG_H +BCCFLAGS = @CPPFLAGS@ $(CFLAGS) +TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ $(CFLAGS) -DHAVE_AUTOCONFIG_H -D_HAVE_SQLITE_CONFIG_H INSTALLDIR = $(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ USE_LINENOISE = @USE_LINENOISE@ +USE_MMAN_H = @USE_MMAN_H@ USE_SEE = @USE_SEE@ FOSSIL_ENABLE_MINIZ = @FOSSIL_ENABLE_MINIZ@ +APPNAME = fossil + +.PHONY: all tags include $(SRCDIR)/main.mk distclean: clean - rm -f autoconfig.h config.log Makefile + -rm -f autoconfig.h config.log Makefile + -rm -f cscope.out tags + +reconfig: + @AUTOREMAKE@ + +tags: + ctags -R @srcdir@/src + @COLLECT_CSCOPE_DATA@ + +# Automatically reconfigure whenever an autosetup file or one of the +# make source files change. +# +# The "touch" is necessary to avoid a make loop due to a new upstream +# feature in autosetup (GH 0a71e3c3b7) which rewrites *.in outputs only +# if doing so will write different contents; otherwise, it leaves them +# alone so the mtime doesn't change. This means that if you change one +# our depdendencies besides Makefile.in, we'll reconfigure but Makefile +# won't change, so this rule will remain out of date, so we'll reconfig +# but Makefile won't change, so we'll reconfig but... endlessly. +# +# This is also why we repeat the reconfig target's command here instead +# of delegating to it with "$(MAKE) reconfig": having children running +# around interfering makes this failure mode even worse. +Makefile: @srcdir@/Makefile.in $(SRCDIR)/main.mk @AUTODEPS@ + @AUTOREMAKE@ + touch @builddir@/Makefile ADDED Makefile.osx-jaguar Index: Makefile.osx-jaguar ================================================================== --- /dev/null +++ Makefile.osx-jaguar @@ -0,0 +1,73 @@ +#!/usr/bin/make +# +# This is a specially modified version of the Makefile that will build +# Fossil on Mac OSX Jaguar (10.2) circa 2002. This Makefile is used for +# testing on an old PPC iBook. The use of this old platform helps to verify +# Fossil and SQLite running on big-endian hardware. +# +# To build with this Makefile, run: +# +# make -f Makefile.osx-jaguar +# +# +# This is the top-level makefile for Fossil when the build is occurring +# on a unix platform. This works out-of-the-box on most unix platforms. +# But you are free to vary some of the definitions if desired. +# +#### The toplevel directory of the source tree. Fossil can be built +# in a directory that is separate from the source tree. Just change +# the following to point from the build directory to the src/ folder. +# +SRCDIR = ./src + +#### The directory into which object code files should be written. +# Having a "./" prefix in the value of this variable breaks our use of the +# "makeheaders" tool when running make on the MinGW platform, apparently +# due to some command line argument manipulation performed automatically +# by the shell. +# +# +OBJDIR = bld + +#### C Compiler and options for use in building executables that +# will run on the platform that is doing the build. This is used +# to compile code-generator programs as part of the build process. +# See TCC below for the C compiler for building the finished binary. +# +BCC = cc +BCCFLAGS = $(CFLAGS) + +#### The suffix to add to final executable file. When cross-compiling +# to windows, make this ".exe". Otherwise leave it blank. +# +E = + +TCC = cc +TCCFLAGS = $(CFLAGS) + +#### Tcl shell for use in running the fossil testsuite. If you do not +# care about testing the end result, this can be blank. +# +TCLSH = tclsh + +# LIB = -lz +LIB = compat/zlib/libz.a +TCC += -g -O0 -DHAVE_AUTOCONFIG_H +TCC += -Icompat/zlib +TCC += -DSQLITE_WITHOUT_ZONEMALLOC +TCC += -D_BSD_SOURCE=1 +TCC += -DWITHOUT_ICONV +TCC += -Dsocklen_t=int +TCC += -DSQLITE_MAX_MMAP_SIZE=0 +TCC += -DFOSSIL_ENABLE_LEGACY_MV_RM=1 +INSTALLDIR = $(DESTDIR)/usr/local/bin +USE_SYSTEM_SQLITE = +USE_LINENOISE = 1 +# FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@ +FOSSIL_ENABLE_TCL = 0 +FOSSIL_ENABLE_MINIZ = 0 + +include $(SRCDIR)/main.mk + +distclean: clean + rm -f autoconfig.h config.log Makefile ADDED README.md Index: README.md ================================================================== --- /dev/null +++ README.md @@ -0,0 +1,15 @@ +# About Fossil + +Fossil is a distributed version control system that has been widely +used since 2007. Fossil was originally designed to support the +[SQLite](https://sqlite.org) project but has been adopted by many other +projects as well. + +Fossil is self-hosting at . + +If you are reading this on GitHub, then you are looking at a Git mirror +of the self-hosting Fossil repository. The purpose of that mirror is to +test and exercise Fossil's ability to export a Git mirror. Nobody much +uses the GitHub mirror, except to verify that the mirror logic works. If +you want to know more about Fossil, visit the official self-hosting site +linked above. Index: VERSION ================================================================== --- VERSION +++ VERSION @@ -1,1 +1,1 @@ -1.36 +2.12 Index: ajax/index.html ================================================================== --- ajax/index.html +++ ajax/index.html @@ -1,12 +1,11 @@ - + - Fossil/JSON raw request sending - + Fossil/JSON raw request sending + @ @
Edit mode: - @ @ @ @
@
- @ @ @ @ @ @ @@ -66,52 +65,48 @@ @ @ @ @ @ - @ @ @ @ @ @ @ - @ @ @ @ @ @ @ @ @ @ - @ @ @ @ @ @ @ @
@
- @ - @ - @ - @ - @ - @ - @ - @ - @ @ - @ - @ - @ - @ - @ #if 0 /* Cut/Copy/Paste requires special browser permissions for security ** reasons. So omit these buttons */ - @ - @ - @ #endif @
@
%s(zContent)
- @ + + +

As a double-check, open the Developer Console in your web-browser +and verify that two CSP violations were detected and blocked.

+ Index: test/delta1.test ================================================================== --- test/delta1.test +++ test/delta1.test @@ -34,18 +34,27 @@ set f1 [read_file $f] write_file t1 $f1 for {set i 0} {$i<100} {incr i} { write_file t2 [random_changes $f1 1 1 0 0.1] fossil test-delta t1 t2 - test delta-$base-$i-1 {$RESULT=="ok"} + test delta-$base-$i-1 {[normalize_result]=="ok"} write_file t2 [random_changes $f1 1 1 0 0.2] fossil test-delta t1 t2 - test delta-$base-$i-2 {$RESULT=="ok"} + test delta-$base-$i-2 {[normalize_result]=="ok"} write_file t2 [random_changes $f1 1 1 0 0.4] fossil test-delta t1 t2 - test delta-$base-$i-3 {$RESULT=="ok"} + test delta-$base-$i-3 {[normalize_result]=="ok"} } } +set empties { "" "" "" a a "" } +set i 0 +foreach {f1 f2} $empties { + incr i + write_file t1 $f1 + write_file t2 $f2 + fossil test-delta t1 t2 + test delta-empty-$i {[normalize_result]=="ok"} +} ############################################################################### test_cleanup Index: test/diff-test-1.wiki ================================================================== --- test/diff-test-1.wiki +++ test/diff-test-1.wiki @@ -1,10 +1,13 @@ Graph Test One This page contains list of URLs of interesting diffs. -Click on all URLs, one by one, to verify +Click on all URLs, one by one, to verify the correct operation of the diff logic. +For correct testing, many of these require show-version-diffs +to be enabled in the [/setup_timeline|Timeline Display Preferences] +configuration page. * Multiple edits on a single line. This is an SQLite version update diff. It is a large diff and contains many other interesting features. Scan the whole diff. @@ -17,11 +20,11 @@ The edit of a line with multibyte characters is the first chunk. * Large diff of sqlite3.c. This diff was very slow prior to the performance enhancement change [9e15437e97]. * - A difficult indentation change. (show-version-diffs must be enabled) + A difficult indentation change. * Another tricky indentation. Notice especially lines 59398 and 59407 on the left. * Inverse of the previous. ADDED test/diff.test Index: test/diff.test ================================================================== --- /dev/null +++ test/diff.test @@ -0,0 +1,116 @@ +# +# Copyright (c) 2016 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# 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. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# Tests for the diff command. +# + +require_no_open_checkout + +test_setup; set rootDir [file normalize [pwd]] + +################################### +# Tests of binary file detection. # +################################### + +file mkdir .fossil-settings +write_file [file join .fossil-settings binary-glob] "*" + +write_file file0.dat ""; # no content. +write_file file1.dat "test file 1 (one line no term)." +write_file file2.dat "test file 2 (NUL character).\0" +write_file file3.dat "test file 3 (long line).[string repeat x 32768]" +write_file file4.dat "test file 4 (long line).[string repeat y 32768]\ntwo" +write_file file5.dat "[string repeat z 32768]\ntest file 5 (long line)." + +fossil add $rootDir +fossil commit -m "c1" + +############################################################################### + +fossil ls +test diff-ls-1 {[normalize_result] eq \ +"file0.dat\nfile1.dat\nfile2.dat\nfile3.dat\nfile4.dat\nfile5.dat"} + +############################################################################### + +write_file file0.dat "\0" +fossil diff file0.dat + +test diff-file0-1 {[normalize_result] eq {Index: file0.dat +================================================================== +--- file0.dat ++++ file0.dat +cannot compute difference between binary files}} + +############################################################################### + +write_file file1.dat [string repeat z 32768] +fossil diff file1.dat + +test diff-file1-1 {[normalize_result] eq {Index: file1.dat +================================================================== +--- file1.dat ++++ file1.dat +cannot compute difference between binary files}} + +############################################################################### + +write_file file2.dat "test file 2 (no NUL character)." +fossil diff file2.dat + +test diff-file2-1 {[normalize_result] eq {Index: file2.dat +================================================================== +--- file2.dat ++++ file2.dat +cannot compute difference between binary files}} + +############################################################################### + +write_file file3.dat "test file 3 (not a long line)." +fossil diff file3.dat + +test diff-file3-1 {[normalize_result] eq {Index: file3.dat +================================================================== +--- file3.dat ++++ file3.dat +cannot compute difference between binary files}} + +############################################################################### + +write_file file4.dat "test file 4 (not a long line).\ntwo" +fossil diff file4.dat + +test diff-file4-1 {[normalize_result] eq {Index: file4.dat +================================================================== +--- file4.dat ++++ file4.dat +cannot compute difference between binary files}} + +############################################################################### + +write_file file5.dat "[string repeat 0 16]\ntest file 5 (not a long line)." +fossil diff file5.dat + +test diff-file5-1 {[normalize_result] eq {Index: file5.dat +================================================================== +--- file5.dat ++++ file5.dat +cannot compute difference between binary files}} + +############################################################################### + +test_cleanup Index: test/fake-editor.tcl ================================================================== --- test/fake-editor.tcl +++ test/fake-editor.tcl @@ -50,11 +50,11 @@ ############################################################################### set fileName [lindex $argv 0] -if {[file exists $fileName]} then { +if {[file exists $fileName]} { set data [readFile $fileName] } else { set data "" } @@ -67,11 +67,11 @@ # modified) content back to the original file. # set script $env(FAKE_EDITOR_SCRIPT) set code [catch $script error] - if {$code != 0} then { + if {$code != 0} { if {[info exists env(FAKE_EDITOR_VERBOSE)]} { if {[info exists errorInfo]} { puts stdout "ERROR ($code): $errorInfo" } else { puts stdout "ERROR ($code): $error" Index: test/fileStat.th1 ================================================================== --- test/fileStat.th1 +++ test/fileStat.th1 @@ -60,11 +60,11 @@ tclEval { # # NOTE: Get the unique Id of the latest check-in on trunk. # return [lindex [regexp -line -inline -nocase -- \ - {^uuid:\s+([0-9A-F]{40}) } [eval [getFossilCommand \ + {^(?:uuid|hash):\s+([0-9A-F]{40}) } [eval [getFossilCommand \ $repository "" info trunk]]] end] } } proc theSumOfAllFiles { id } { Index: test/fileage-test-1.wiki ================================================================== --- test/fileage-test-1.wiki +++ test/fileage-test-1.wiki @@ -1,8 +1,8 @@ This page contains URLs for file-age computations that have given -trouble in the past. Shif-click on on the links, one-by-one, to verify +trouble in the past. Shift-click on on the links, one-by-one, to verify that the current implementation works correctly: * [/fileage?name=c9df0dcdaa402] - Verify that the many execute permission changes that occurred about 24 hours before check-in c9df0dcdaa402 do not appear as file changes. Index: test/graph-test-1.wiki ================================================================== --- test/graph-test-1.wiki +++ test/graph-test-1.wiki @@ -42,11 +42,11 @@ Check-ins tagged "release" and merge-ins * Only check-ins tagged "release" * History of source file "Makefile". - * + * 20 elements after 1970-01-01. * All check-ins - a huge graph. * This malformed commit has a @@ -66,10 +66,42 @@ * This timeline has a hidden commit. Click Unhide to reveal. * Isolated check-ins. + * Single branch raiser from bottom of page + up to checkins 057e4b and d3cc6d + * Branch riser comes from the bottom of the screen + * Branch risers comes from the bottom of the + screen, not from the andygoth-crlf branch. + * Check-in 2de15c8e has merge arrows from two + different trunk check-ins. One of the merge risers also branches + to check-in ea7f3297 + * + Cherrypick merge arrows + * Branch + 1.37 with cherry-pick merges from trunk. + * + Single check-in takes both a full merge and a cherrypick merge + * + Mixed merge arrow, partly fully and partly cherrypick + * + Mixed merge arrow to bottom of screen. + * + A fork on trunk keeps the longest chain of child nodes directly + above the fork and the shorter chain off to the side. + * + The "jan-manifest-tags" branch containing a non-trunk fork + * + The "diff-eolws" branch containing a non-trunk fork + * + All forks + * All leaves External: * Timewarp due to a mis-configured system clock. @@ -80,5 +112,8 @@ target='testwindow'>Merge arrows to the left and to the right * Previous, with a scrunched graph * Previous, with a severely scrunched graph + * The "wal" branch SQLite repository, containing + multiple non-trunk forks. ADDED test/graph-test-2.md Index: test/graph-test-2.md ================================================================== --- /dev/null +++ test/graph-test-2.md @@ -0,0 +1,72 @@ +# Graph Test Cases + +There are test cases for the merge-riser coalescing logic that +was added on 2020-06-08. + + * [e19cfba5373369b](/info/e19cfba5373369b?diff=0) + * [c779b6890464cae](/info/c779b6890464cae?diff=0) + * [eed3946bd92a499](/info/eed3946bd92a499?diff=0) + * [9e1fa626e47f147](/info/9e1fa626e47f147?diff=0) + * [68bd2e7bedb8d05](/info/68bd2e7bedb8d05?diff=0) + * [8ac66ef33b464d2](/info/8ac66ef33b464d2?diff=0) + * [ef6979eac9abded](/info/ef6979eac9abded?diff=0) + * [7766e689926c703](/info/7766e689926c703?diff=0) + * [642f4dcfa24f1f9](/info/642f4dcfa24f1f9?diff=0) + * [3ea66260b5555d2](/info/3ea66260b5555d2?diff=0) + * [66ae70a54b20656](/info/66ae70a54b20656?diff=0) + * [b0f2a0ac53926c9](/info/b0f2a0ac53926c9?diff=0) + * [303e7af7c31866c](/info/303e7af7c31866c?diff=0) + * [b31afcc2cab1dc4](/info/b31afcc2cab1dc4?diff=0) + * [1a164e5fb76a46b](/info/1a164e5fb76a46b?diff=0) + * [f325b2343e6a18f](/info/f325b2343e6a18f?diff=0) + * [2d75e87b760c0a9](/info/2d75e87b760c0a9?diff=0) + * [76442af7e13267b](/info/76442af7e13267b?diff=0) + + +The list above was generated by the following script: + +~~~~~ +.mode list +SELECT printf(' * [%s](/info/%s?diff=0)', hash, hash) FROM ( + SELECT count(*) AS cnt, sum(cherrypick=1) AS cp, sum(cherrypick=0) AS n, + (SELECT substr(uuid,1,15) FROM blob WHERE rid=cid) AS hash + FROM ( + SELECT cid, 0 AS cherrypick FROM plink WHERE NOT isprim + UNION ALL + SELECT childid, 1 FROM cherrypick + ) + GROUP BY cid + HAVING (cp>0 AND n>0) OR cp>3 OR n>2 + ORDER BY cnt +); +~~~~~ + +Similar links to the SQLite repository: + + * [7f72fc4f47445a2](https://sqlite.org/src/info/7f72fc4f47445a2?diff=0) + * [db2935473eab91c](https://sqlite.org/src/info/db2935473eab91c?diff=0) + * [a56506b9387a067](https://sqlite.org/src/info/a56506b9387a067?diff=0) + * [d59567dda231e7f](https://sqlite.org/src/info/d59567dda231e7f?diff=0) + * [2b750b0f74e5a11](https://sqlite.org/src/info/2b750b0f74e5a11?diff=0) + * [c697d2f83c2d8ea](https://sqlite.org/src/info/c697d2f83c2d8ea?diff=0) + * [b330c7ff6fd1230](https://sqlite.org/src/info/b330c7ff6fd1230?diff=0) + * [746fcd2fd412ddc](https://sqlite.org/src/info/746fcd2fd412ddc?diff=0) + * [71866b367f32b5a](https://sqlite.org/src/info/71866b367f32b5a?diff=0) + * [05418b2a4a6e6a9](https://sqlite.org/src/info/05418b2a4a6e6a9?diff=0) + +Generated by a very similar script: + +~~~~~ +SELECT printf(' * [%s](https://sqlite.org/src/info/%s?diff=0)', hash, hash) FROM ( + SELECT count(*) AS cnt, sum(cherrypick=1) AS cp, sum(cherrypick=0) AS n, + (SELECT substr(uuid,1,15) FROM blob WHERE rid=cid) AS hash + FROM ( + SELECT cid, 0 AS cherrypick FROM plink WHERE NOT isprim + UNION ALL + SELECT childid, 1 FROM cherrypick + ) + GROUP BY cid + HAVING (cp>0 AND n>0) OR cp>2 OR n>2 + ORDER BY cnt +); +~~~~~ Index: test/json.test ================================================================== --- test/json.test +++ test/json.test @@ -23,21 +23,24 @@ # practice of eliminating all trace of the fossil json command when # not configured. If that changes, these conditions might not prevent # the rest of this file from running. fossil test-th-eval "hasfeature json" -if {$::RESULT ne "1"} then { +if {[normalize_result] ne "1"} { puts "Fossil was not compiled with JSON support." test_cleanup_then_return } # We need a JSON parser to effectively test the JSON produced by # fossil. It looks like the one from tcllib is exactly what we need. # On ActiveTcl, add it with teacup. On other platforms, YMMV. # teacup install json # teacup install json::write -package require json +if {[catch {package require json}] != 0} then { + puts "The \"json\" package is not available." + test_cleanup_then_return +} proc json2dict {txt} { set rc [catch {::json::json2dict $txt} result options] if {$rc != 0} { protOut "JSON ERROR: $result" @@ -74,11 +77,12 @@ # # Returns the status code from the HTTP header. proc fossil_http_json {url {cookie "Muppet=Monster"} args} { global RESULT JR set request "GET $url HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Fossil-http-json\r\nCookie: $cookie" - set RESULT [fossil_maybe_answer $request http {*}$args] + set RESULT [fossil_maybe_answer $request http {*}$args --ipaddr 127.0.0.1] + set head ""; set body ""; set status "--NO_MATCH--" regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg if {$status eq "200"} { set JR [json2dict $body] } @@ -115,13 +119,14 @@ } # handle the actual request flush stdout #exec $fossilexe - set RESULT [fossil_maybe_answer $request http {*}$args] + set RESULT [fossil_maybe_answer $request http {*}$args --ipaddr 127.0.0.1] # separate HTTP headers from body + set head ""; set body ""; set status "--NO_MATCH--" regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg if {$status eq "200"} { if {[string length $body] > 0} { set JR [json2dict $body] @@ -133,10 +138,14 @@ } # Inspect a dict for keys it must have and keys it must not have proc test_dict_keys {testname D okfields badfields} { + if {$D eq ""} { + test $testname-validJSON 0 + return + } set i 1 foreach f $okfields { test "$testname-$i" {[dict exists $D $f]} incr i } @@ -166,10 +175,13 @@ #### VERSION AKA HAI # The JSON API generally assumes we have a respository, so let it have one. test_setup + +# Stop backoffice from running during this test as it can cause hangs. +fossil settings backoffice-disable 1 # Check for basic envelope fields in the result with an error fossil_json -expectError test_json_envelope json-enverr [concat resultCode fossil timestamp \ resultText command procTimeUs procTimeMs] {} @@ -201,10 +213,12 @@ #### ARTIFACT # sha1 of 0 bytes and a file to match in a commit set UUID_empty da39a3ee5e6b4b0d3255bfef95601890afd80709 +# sha3 of 0 bytes and a file to match in a commit +set UUID_empty_64 a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a write_file empty "" fossil add empty fossil ci -m "empty file" # json artifact (checkin) @@ -213,11 +227,11 @@ test json-artifact-checkin {[dict get $JR payload type] eq "checkin"} test_json_payload json-artifact \ [concat type uuid isLeaf timestamp user comment parents tags files] {} # json artifact (file) -fossil_json [concat artifact $UUID_empty] +fossil_json [concat artifact $UUID_empty_64] test_json_envelope_ok json-artifact-file-env test json-artifact-file {[dict get $JR payload type] eq "file"} test_json_payload json-artifact [concat type uuid size checkins] {} # json artifact (wiki) @@ -301,28 +315,40 @@ # json cap via POST with authToken in request envelope set anon2 [read_file anon-2] fossil_post_json "/json/cap" $anon2 test json-cap-POSTenv-env-0 {[string length $JR] > 0} test_json_envelope_ok json-cap-POSTenv-env -test json-cap-POSTenv-name {[dict get $JR payload name] eq "anonymous"} knownBug +if {[catch {test json-cap-POSTenv-name \ + {[dict get $JR payload name] eq "anonymous"} knownBug} jerr]} then { + test json-cap-POSTenv-name-threw 0 + protOut "CAUGHT: $jerr" +} test json-cap-POSTenv-notsetup {![dict get $JR payload permissionFlags setup]} # json cap via GET with authToken in Cookie header fossil_post_json "/json/cap" {} $AnonCookie test json-cap-GETcookie-env-0 {[string length $JR] > 0} -test_json_envelope_ok json-cap-GETcookie-env -test json-cap-GETcookie-name {[dict get $JR payload name] eq "anonymous"} -test json-cap-GETcookie-notsetup {![dict get $JR payload permissionFlags setup]} +test_json_envelope_ok json-cap-GETcookie-env-0 +if {[catch {test json-cap-GETcookie-name-0 \ + {[dict get $JR payload name] eq "anonymous"}} jerr]} then { + test json-cap-GETcookie-name-0-threw 0 + protOut "CAUGHT: $jerr" +} +test json-cap-GETcookie-notsetup-0 {![dict get $JR payload permissionFlags setup]} # json cap via GET with authToken in a parameter fossil_post_json "/json/cap?authToken=[dict get $AuthAnon authToken]" {} -test json-cap-GETcookie-env-0 {[string length $JR] > 0} -test_json_envelope_ok json-cap-GETcookie-env -test json-cap-GETcookie-name {[dict get $JR payload name] eq "anonymous"} -test json-cap-GETcookie-notsetup {![dict get $JR payload permissionFlags setup]} +test json-cap-GETcookie-env-1 {[string length $JR] > 0} +test_json_envelope_ok json-cap-GETcookie-env-1 +if {[catch {test json-cap-GETcookie-name-1 \ + {[dict get $JR payload name] eq "anonymous"}} jerr]} then { + test json-cap-GETcookie-name-1-threw 0 + protOut "CAUGHT: $jerr" +} +test json-cap-GETcookie-notsetup-1 {![dict get $JR payload permissionFlags setup]} # whoami # via CLI with no auth token supplied fossil_json whoami @@ -669,27 +695,36 @@ # error happens before we have made the determination that the app is # in JSON mode or if the error handling is incorrectly not # recognizing JSON mode. # #test_setup x.fossil -#catch {exec chmod 444 .rep.fossil}; # Unix. What about Win? -fossil_http_json /json/timeline/checkin $U1Cookie +fossil_http_json /json/query?sql=PRAGMA%20repository.journal_mode%3Dwal $U1Cookie test json-ROrepo-1-1 {$CODE == 0} test json-ROrepo-1-2 {[regexp {\}\s*$} $RESULT]} test json-ROrepo-1-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} test_json_envelope_ok json-http-timeline1 +if {$is_windows} then { + catch {exec attrib +r .rep.fossil}; # Windows +} else { + catch {exec chmod 444 .rep.fossil}; # Unix +} protOut "chmod 444 repo" -catch {exec chmod 444 .rep.fossil}; # Unix -catch {exec attrib +r .rep.fossil}; # Windows -fossil_http_json /json/timeline/checkin $U1Cookie -expectError +fossil_http_json /json/query?sql=PRAGMA%20repository.journal_mode%3Ddelete $U1Cookie -expectError --json-preserve-rc test json-ROrepo-2-1 {$CODE != 0} -test json-ROrepo-2-2 {[regexp {\}\s*$} $RESULT]} knownBug -test json-ROrepo-2-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} knownBug +test json-ROrepo-2-2 {[regexp {\}\s*$} $RESULT]} +test json-ROrepo-2-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]} #test_json_envelope_ok json-http-timeline2 -catch {exec attrib -r .rep.fossil}; # Windows -catch {exec chmod 666 .rep.fossil}; # Unix - +if {$is_windows} then { + catch {exec attrib -r .rep.fossil}; # Windows + catch {exec attrib -r .rep.fossil-shm} + catch {exec attrib -r .rep.fossil-wal} +} else { + catch {exec chmod 666 .rep.fossil}; # Unix + catch {exec chmod 666 .rep.fossil-shm} + catch {exec chmod 666 .rep.fossil-wal} +} +protOut "chmod 666 repo" #### Result Codes # Test cases designed to stimulate each (documented) error code. # FOSSIL-0000 @@ -740,24 +775,34 @@ { "command":"no/such/endpoint" } } fossil_json --json-input e1102.json -expectError -test json-env-RC-1102-CLI-exit {$CODE != 0} -test_json_envelope json-env-RC-1102-env {fossil timestamp command procTimeUs \ +test json-env-RC-1102a-CLI-exit {$CODE != 0} +test_json_envelope json-env-RC-1102a-env {fossil timestamp command procTimeUs \ procTimeMs resultCode resultText} {payload} -test json-env-RC-1102-code {[dict get $JR resultCode] eq "FOSSIL-1102"} +test json-env-RC-1102a-code {[dict get $JR resultCode] eq "FOSSIL-1102"} # FOSSIL-1103 FSL_JSON_E_UNKNOWN # Unknown error write_file bad.sql { CREATE TABLE spam(a integer, b text); } exec $::fossilexe sqlite3 --no-repository bad.fossil +div.markdown table { + border: 2px solid black; + border-spacing: 0; +} +div.markdown th { + border-left: 1px solid black; + border-right: 1px solid black; + border-bottom: 1px solid black; + padding: 4px 1em 4px; + text-align: left; +} +div.markdown td { + border-left: 1px solid black; + border-right: 1px solid black; + padding: 4px 1em 4px; + text-align: left; +} + + +See + +| Id | Source Text | Actual Rendering | Correct Rendering | +----------------------------------------------------------------------------- +| 1:| `*foo bar*` | *foo bar* | foo bar | +| 2:| `a * foo bar*` | a * foo bar* | a * foo bar* | +| 3:| `a*"foo"*` | a*"foo"* | a*"foo"* | +| 4:| `* a *` | * a * | * a * | +| 5:| `foo*bar*` | foo*bar* | foobar | +| 6:| `5*6*78` | 5*6*78 | 5678 | +| 7:| `_foo bar_` | _foo bar_ | foo bar | +| 8:| `_ foo bar_` | _ foo bar_ | _ foo bar_ | +| 9:| `a_"foo"_` | a_"foo"_ | a_"foo"_ | +| 10:| `foo_bar_` | foo_bar_ | foo_bar_ | +| 11:| `5_6_78` | 5_6_78 | 5_6_78 | +| 12:| `aa_"bb"_cc` | aa_"bb"_cc | aa_"bb"_cc | +| 13:| `foo-_(bar)_` | foo-_(bar)_ | foo-(bar) | +| 14:| `*(*foo` | *(*foo | *(*foo | +| 15:| `*(*foo*)*` | *(*foo*)* | (foo) | +| 16:| `*foo*bar` | *foo*bar | foobar | +| 17:| `_foo bar _` | _foo bar _ | _foo bar _ | +| 18:| `_(_foo)` | _(_foo) | _(_foo) | +| 19:| `_(_foo_)_` | _(_foo_)_ | (foo) | +| 20:| `_foo_bar` | _foo_bar | _foo_bar | +| 21:| `_foo_bar_baz_` | _foo_bar_baz_ | foo_bar_baz | +| 22:| `foo_bar_baz` | foo_bar_baz | foo_bar_baz | +| 23:| `_(bar)_` | _(bar)_ | (bar) | + + +# Strong emphasis + + +| Id | Source Text | Actual Rendering | Correct Rendering | +------------------------------------------------------------------------------------------- +| 1:| `**foo bar**` | **foo bar** | foo bar | +| 2:| `a ** foo bar**` | a ** foo bar** | a ** foo bar** | +| 3:| `a**"foo"**` | a**"foo"** | a**"foo"** | +| 4:| `** a **` | ** a ** | ** a ** | +| 5:| `foo**bar**` | foo**bar** | foobar | +| 6:| `5**6**78` | 5**6**78 | 5678 | +| 7:| `__foo bar__` | __foo bar__ | foo bar | +| 8:| `__ foo bar__` | __ foo bar__ | __ foo bar__ | +| 9:| `a__"foo"__` | a__"foo"__ | a__"foo"__ | +| 10:| `foo__bar__` | foo__bar__ | foo__bar__ | +| 11:| `5__6__78` | 5__6__78 | 5__6__78 | +| 12:| `aa__"bb"__cc` | aa__"bb"__cc | aa__"bb"__cc | +| 13:| `foo-__(bar)__` | foo-__(bar)__ | foo-(bar) | +| 14:| `**(**foo` | **(**foo | **(**foo | +| 15:| `**(**foo**)**` | **(**foo**)** | (foo) | +| 16:| `**foo**bar` | **foo**bar | foobar | +| 17:| `__foo bar __` | __foo bar __ | __foo bar __ | +| 18:| `__(__foo)` | __(__foo) | __(__foo) | +| 19:| `__(__foo__)__` | __(__foo__)__ | (foo) | +| 20:| `__foo__bar` | __foo__bar | __foo__bar | +| 21:| `__foo__bar__baz__` | __foo__bar__baz__ | foo__bar__baz | +| 22:| `foo__bar__baz` | foo__bar__baz | foo__bar__baz | +| 23:| `__(bar)__` | __(bar)__ | (bar) | Index: test/merge5.test ================================================================== --- test/merge5.test +++ test/merge5.test @@ -15,10 +15,18 @@ # ############################################################################ # # Tests of the "merge" command # + +puts "Skipping Merge5 tests" +protOut { +fossil sqlite3 --no-repository reacts badly to SQL dumped from +repositories created from fossil older than version 2.0. +} +test merge5-sqlite3-issue false knownBug +test_cleanup_then_return # Verify the results of a check-out # proc checkout-test {testid expected_content} { set flist {} @@ -33,11 +41,11 @@ protOut " Expected:\n $expected" protOut " Got:\n $result" test merge5-$testid 0 } else { test merge5-$testid 1 - } + } } require_no_open_checkout; test_setup "" # Construct a test repository Index: test/merge_renames.test ================================================================== --- test/merge_renames.test +++ test/merge_renames.test @@ -465,10 +465,92 @@ fossil merge m test_status_list merge_renames-12-5 $RESULT {MERGE f1v} test_file_contents merge_renames-12-6 f1v "f1v\nm" fossil commit -m "merge m" + +################################################################# +# Test 13 # +# Merge in add+rename that happened on a branch, then merged # +# back to branch, and again to trunk, then merge in branch. # +################################################################# + +set repoDir [test_setup] +write_file f1 "line1" +fossil add f1 +fossil commit -m "add f1" --tag c1 + +write_file f2 "line1" +fossil add f2 +fossil commit -m "add f2 on branch" -b b --tag c2 +fossil update trunk +test_status_list merge_renames_13-1 $RESULT {REMOVE f2} +write_file f1 "line1\nline2\n" +fossil commit -m "edit f1 on trunk" --tag c3 + +fossil update b +test_status_list merge_renames_13-2 $RESULT { + UPDATE f1 + ADD f2 +} +fossil merge trunk +fossil commit -m "merge trunk" --tag c4 +fossil mv --hard f2 f2n +test_status_list merge_renames-13-3 $RESULT " + RENAME f2 f2n + MOVED_FILE $repoDir/f2 +" +fossil commit -m "renamed f2->f2n" --tag c5 + +fossil update trunk +fossil merge b +test_status_list merge_renames-13-4 $RESULT {ADDED f2n} +fossil commit -m "merge f2n" --tag m1 --tag c6 + +fossil update b +write_file f1 "line1\nline3\nline2" +fossil commit -m "edit f1 on b" --tag c7 + +fossil update trunk +write_file f1 "line1\nline3\nline2\nline4" +fossil commit -m "edit f1 on trunk" --tag c8 + +fossil update b +fossil merge trunk +test_status_list merge_renames-13-5 $RESULT {MERGE f1} +fossil commit -m "merge trunk" --tag c9 +write_file f1 "line1\nline3\nline4" +fossil commit -m "edit f1 on b" --tag c10 + +fossil update m1 +fossil merge b +test_status_list merge_renames-13-6 $RESULT { + UPDATE f1 + DELETE f2n + ADDED f2n +} +test_file_contents merge_renames-13-7 f2n "line1" + +fossil revert +test_status_list merge_renames-13-8 $RESULT { + REVERT f1 + REVERT f2n +} +fossil update trunk +fossil merge --integrate b +test_status_list merge_renames-13-9 $RESULT { + UPDATE f1 + DELETE f2n + ADDED f2n +} +test_file_contents merge_renames-13-10 f2n "line1" + +fossil revert +test_status_list merge_renames-13-11 $RESULT { + REVERT f1 + REVERT f2n +} ###################################### # # Tests for troubles not specifically linked with renames but that I'd like to # write: Index: test/mv-rm.test ================================================================== --- test/mv-rm.test +++ test/mv-rm.test @@ -50,11 +50,15 @@ file mkdir [file join $rootDir subdirC] write_file [file join $rootDir subdirC f10] "f10" write_file [file join $rootDir subdirC f11] "f11" write_file f12 "f12" +file mkdir [file join $rootDir subdirE a] +write_file [file join $rootDir subdirE a f14] "f14" + fossil add f1 f2 f3 f4 f5 f6 f7 f8 subdirB/f9 subdirC/f10 subdirC/f11 f12 +fossil add subdirE/a/f14 fossil commit -m "c1" ######################################## # Test 1: Soft Move Relative Directory # ######################################## @@ -413,28 +417,54 @@ # Test 18: Move Directory to New Directory # ############################################ fossil mv --hard subdirC subdirD test mv-file-new-directory-7 { - [normalize_result] eq "RENAME subdirC subdirD\nMOVED_FILE ${rootDir}/subdirC" + [normalize_result] eq "RENAME subdirC/f10 subdirD/f10\nRENAME subdirC/f11 subdirD/f11\nMOVED_FILE ${rootDir}/subdirC/f10\nMOVED_FILE ${rootDir}/subdirC/f11" } test mv-file-new-directory-8 {[file size subdirD/f10] == 3} test mv-file-new-directory-9 {[read_file subdirD/f10] eq "f10"} test mv-file-new-directory-10 {[file size subdirD/f11] == 3} test mv-file-new-directory-11 {[read_file subdirD/f11] eq "f11"} fossil revert test mv-file-new-directory-12 { - [normalize_result] eq "REVERT subdirC/f10\nREVERT subdirC/f11${undoMsg}" + [normalize_result] eq "DELETE subdirD/f10\nDELETE subdirD/f11\nREVERT subdirC/f10\nREVERT subdirC/f11${undoMsg}" } test mv-file-new-directory-13 {[file size subdirC/f10] == 3} test mv-file-new-directory-14 {[read_file subdirC/f10] eq "f10"} test mv-file-new-directory-15 {[file size subdirC/f11] == 3} test mv-file-new-directory-16 {[read_file subdirC/f11] eq "f11"} +cd $rootDir + +############################################################################### +# Test 19: Follow-up Soft Rename of a Directory Already Renamed on Filesystem # +############################################################################### + +file rename [file join $rootDir subdirE/a] [file join $rootDir subdirE/a_renamed] + +fossil mv subdirE/a subdirE/a_renamed +test mv-soft-already-renamed-directory-1 { + [normalize_result] eq "RENAME subdirE/a/f14 subdirE/a_renamed/f14" +} + +test mv-soft-already-renamed-directory-2 {[file size subdirE/a_renamed/f14] == 3} +test mv-soft-already-renamed-directory-3 {[read_file subdirE/a_renamed/f14] eq "f14"} + +fossil revert +test mv-soft-already-renamed-directory-4 { + [normalize_result] eq "DELETE subdirE/a_renamed/f14\nREVERT subdirE/a/f14${undoMsg}" +} + +test mv-soft-already-renamed-directory-5 {[file size subdirE/a/f14] == 3} +test mv-soft-already-renamed-directory-6 {[read_file subdirE/a/f14] eq "f14"} + +file delete -force [file join $rootDir subdirE/a_renamed] + cd $rootDir ############################################################################### test_cleanup Index: test/release-checklist.wiki ================================================================== --- test/release-checklist.wiki +++ test/release-checklist.wiki @@ -12,10 +12,20 @@
  • Click on each of the links in in the [./graph-test-1.wiki] document and verify that all graphs are rendered correctly. + +

  • +Click on each of the links in in the +[./graph-test-2.md] document and verify that all graphs are +rendered correctly. +

      +
    1. Also view the same check-ins on a /timeline +view by clicking on the date for each check-in in the /info +view, as the graph rendering is slightly different. +
  • Click on each of the links in in the [./diff-test-1.wiki] document and verify that all diffs are rendered correctly. Index: test/revert.test ================================================================== --- test/revert.test +++ test/revert.test @@ -15,11 +15,11 @@ # ############################################################################ # # # Tests for 'fossil revert' -# +# # # Test 'fossil revert' against expected results from 'fossil changes' and # 'fossil addremove -n', as well as by verifying the existence of files # on the file system. 'fossil undo' is called after each test @@ -186,9 +186,173 @@ test 3-mv-2 {![file exists f1new]} revert-test 3-1 {} { REVERT f1 DELETE f1new } -exists {f1} -notexists {f1n} + + +# Test reverting of files under a sub-directory +test_setup +file mkdir d +write_file d/f1 "d/f1" +write_file d/f2 "d/f2" +write_file d/f3 "d/f3" +write_file d/f4 "d/f4" + +fossil add d +fossil delete d/f1 +fossil commit -m "d/f2 d/f3 d/f4" + +## Changes to revert +fossil add d/f1 +write_file d/f2 "4-1:d/f2" +fossil changes d/f2 +fossil delete --soft d/f3 + +revert-test 4-1 {d/f1} { + UNMANAGE d/f1 +} -changes { + EDITED d/f2 + DELETED d/f3 +} -addremove { + ADDED d/f1 +} -exists {d/f1 d/f2 d/f3} + +revert-test 4-2 {d/f2} { + REVERT d/f2 +} -changes { + ADDED d/f1 + DELETED d/f3 +} -exists {d/f1 d/f2 d/f3} + +revert-test 4-3 {d/f3} { + REVERT d/f3 +} -changes { + ADDED d/f1 + EDITED d/f2 +} -exists {d/f1 d/f2 d/f3} + +fossil mv --soft d/f4 d/f4new +test 4-4-mv-1 {[file exists d/f4]} +test 4-4-mv-2 {![file exists d/f4new]} +revert-test 4-4 {d/f4} { + DELETE d/f4new + REVERT d/f4 +} -changes { + ADDED d/f1 + EDITED d/f2 + DELETED d/f3 +} -exists {d/f4} -notexists {d/f4new} + +## Commit changes before testing reverting of directory rename, +## otherwise there're could be sequencing issues +fossil redo +fossil commit -m "4-5:setup" + +fossil mv --soft d dnew +revert-test 4-5 {d/f1 d/f2 d/f3 d/f4} { + REVERT d/f1 + REVERT d/f2 + UNMANAGE d/f3 + REVERT d/f4 + DELETE dnew/f1 + DELETE dnew/f2 + DELETE dnew/f4 +} -addremove { + ADDED d/f3 +} -exists {d/f1 d/f2 d/f3 d/f4} -notexists {dnew} + + +## Test reverting of changes in whole sub-directory tree +test_setup +file mkdir d +write_file f0 "f0" +write_file d/f1 "d/f1" +write_file d/f2 "d/f2" +write_file d/f3 "d/f3" +write_file d/f4 "d/f4" + +fossil add f0 d +fossil delete d/f1 +fossil commit -m "f0 d/f2 d/f3 d/f4" + +## Changes to revert +fossil add d/f1 +write_file d/f2 "5-1:d/f2" +fossil changes d/f2 +fossil delete --soft d/f3 + +revert-test 5-1 {d} { + UNMANAGE d/f1 + REVERT d/f2 + REVERT d/f3 +} -addremove { + ADDED d/f1 +} -exists {f0 d/f1 d/f2 d/f3} + +write_file f0 "5-2:f0" +fossil changes f0 +revert-test 5-2 {f0 d} { + UNMANAGE d/f1 + REVERT d/f2 + REVERT d/f3 + REVERT f0 +} -addremove { + ADDED d/f1 +} -exists {f0 d/f1 d/f2 d/f3} + +## Commit changes before testing the revert of directory rename, +## otherwise there're could be sequencing issues +fossil commit -m "5-3:setup" + +fossil changes + +fossil mv --soft d dnew +revert-test 5-3 {d} { + REVERT d/f1 + REVERT d/f2 + REVERT d/f4 + DELETE dnew/f1 + DELETE dnew/f2 + DELETE dnew/f4 +} -addremove { + ADDED d/f3 +} -exists {f0 d/f1 d/f2 d/f3 d/f4} -notexists {dnew} + +## Reset/redo the undone results of revert to get to a clean checkout +fossil redo + +file mkdir d/e +file mkdir d/e/f +write_file d/e/fe1 "d/e/fe1" +write_file d/e/f/ff1 "d/e/f/ff1" + +file mkdir d1 +file mkdir d1/e +write_file d1/e/fe1 "d1/e/fe1" +write_file d1/e/fe2 "d1/e/fe2" + +fossil add d1/e/fe1 +fossil commit d1/e/fe1 -m "d1/e/fe1" + +write_file d1/e/fe1 "5-4:d1/e/fe1" +fossil changes d1/e/fe1 +fossil add d d1 + +revert-test 5-4 {d d1} { + UNMANAGE d/f3 + UNMANAGE d/e/fe1 + UNMANAGE d/e/f/ff1 + REVERT d1/e/fe1 + UNMANAGE d1/e/fe2 +} -addremove { + ADDED d/f3 + ADDED d/e/fe1 + ADDED d/e/f/ff1 + ADDED d1/e/fe2 +} -exists {d/f1 d/f2 d/f3 d/f4 d/e/fe1 d/e/fe1 d/e/f/ff1 + d1/e/fe1 d1/e/fe2} + ############################################################################### test_cleanup Index: test/set-manifest.test ================================================================== --- test/set-manifest.test +++ test/set-manifest.test @@ -16,16 +16,10 @@ ############################################################################ # # Test manifest setting # -# We need SHA1 to effectively test the manifest files produced by -# fossil. It looks like the one from tcllib is exactly what we need. -# On ActiveTcl, add it with teacup. On other platforms, YMMV. -# teacup install sha1 -package require sha1 - proc file_contains {fname match} { set fp [open $fname r] set contents [read $fp] close $fp set lines [split $contents "\n"] @@ -34,10 +28,19 @@ return 1 } } return 0 } + +# We need SHA1 to effectively test the manifest files produced by +# fossil. It looks like the one from tcllib is exactly what we need. +# On ActiveTcl, add it with teacup. On other platforms, YMMV. +# teacup install sha1 +if {[catch {package require sha1}] != 0} { + puts "The \"sha1\" package is not available." + test_cleanup_then_return +} # We need a respository, so let it have one. test_setup #### Verify classic behavior of the manifest setting @@ -62,23 +65,24 @@ } } # ... and manifest.uuid is the checkout's hash fossil info -regexp {(?m)^checkout:\s+([0-9a-f]{40})\s.*$} $RESULT ckoutline ckid +regexp {(?m)^checkout:\s+([0-9a-f]{40,64})\s.*$} $RESULT ckoutline ckid set uuid [string trim [read_file "manifest.uuid"]] -test "set-manifest-2-uuid" {$ckid eq $uuid} +test "set-manifest-2-uuid" {[same_uuid $ckid $uuid]} + # ... which is also the SHA1 of the file "manifest" before it was # sterilized by appending an extra line when writing the file. The # extra text begins with # and is a full line, so we'll just strip # it with a brute-force substitution. This probably has the right # effect even if the checkin was PGP-signed, but we don't have that # setting turned on for this manifest in any case. -regsub {(?m)^#.*\n} [read_file "manifest"] "" manifest -set muuid [::sha1::sha1 $manifest] -test "set-manifest-2-manifest" {$muuid eq $uuid} +#regsub {(?m)^#.*\n} [read_file "manifest"] "" manifest +#set muuid [::sha1::sha1 $manifest] +#test "set-manifest-2-manifest" {[same_uuid $muuid $uuid]} # Classic behavior: FALSE value removes manifest and manifest.uuid set falses [list false off 0] foreach v $falses { Index: test/settings.test ================================================================== --- test/settings.test +++ test/settings.test @@ -39,11 +39,11 @@ # proc extract_setting_names { data } { set names [list] foreach {dummy name} [regexp \ - -all -line -inline -- {^([a-z][a-z0-9\-]*) } $data] { + -all -line -inline -- {^([a-z][a-z0-9\-]*) ?.*$} $data] { lappend names $name } return $names } Index: test/stash.test ================================================================== --- test/stash.test +++ test/stash.test @@ -171,11 +171,11 @@ # fossil stash [g]diff ?STASHID? ?DIFF-OPTIONS? fossil stash show test stash-1-show {[normalize_result] eq $diff_stash_1} fossil stash diff -test stash-1-diff {[normalize_result] eq $diff_stash_1} +test stash-1-diff {[normalize_result] eq $diff_stash_1} knownBug ######## # fossil stash pop stash-test 2 pop { @@ -185,15 +185,13 @@ ADDED f0 } -changes { ADDED f0 MISSING f1 EDITED f2 - MISSING f3 + RENAMED f3n } -addremove { - ADDED f3n DELETED f1 - DELETED f3 } -exists {f0 f2 f3n} -notexists {f1 f3} # Confirm there is no longer a stash saved fossil stash list test stash-2-list {[first_data_line] eq "empty stash"} @@ -311,13 +309,11 @@ UPDATE f1 UPDATE f2n } -changes { RENAMED f2n } -addremove { - ADDED f2n - DELETED f2 -} -exists {f1 f2n} -notexists {f2} -knownbugs {-changes} +} -exists {f1 f2n} -notexists {f2} ######## # fossil stash snapshot ?-m|--comment COMMENT? ?FILES...? ADDED test/subdir with spaces/filename with spaces.txt Index: test/subdir with spaces/filename with spaces.txt ================================================================== --- /dev/null +++ test/subdir with spaces/filename with spaces.txt @@ -0,0 +1,2 @@ +This file has a name that contains spaces. It is used to help verify +that fossil can handle filenames that contain spaces. ADDED test/subdir/README.html Index: test/subdir/README.html ================================================================== --- /dev/null +++ test/subdir/README.html @@ -0,0 +1,15 @@ +

    An Example HTML Readme

    + +

    +The test/subdir/ directory and its children exist purely for testing +in the self-hosting Fossil repository. This particular file is used +to verify that a file name "README.html" is displayed correctly. +beneath the directory listing. +

    + +
    + + + +
    Thisis
    a<table>
    +
    ADDED test/subdir/one/readme.wiki Index: test/subdir/one/readme.wiki ================================================================== --- /dev/null +++ test/subdir/one/readme.wiki @@ -0,0 +1,9 @@ +Fossil Wiki Readme + +This is another test README file. The point of this file is to show that +lower-case "readme" is recognized, and the Fossil-Wiki formatting is +displayed correctly. + + * First bullet + + * Second bullet Index: test/tester.tcl ================================================================== --- test/tester.tcl +++ test/tester.tcl @@ -20,20 +20,32 @@ # tclsh ../test/tester.tcl ../bld/fossil # # Where ../test/tester.tcl is the name of this file and ../bld/fossil # is the name of the executable to be tested. # + +# We use some things introduced in 8.6 such as lmap. auto.def should +# have found us a suitable Tcl installation. +package require Tcl 8.6 set testfiledir [file normalize [file dirname [info script]]] set testrundir [pwd] set testdir [file normalize [file dirname $argv0]] set fossilexe [file normalize [lindex $argv 0]] +set is_windows [expr {$::tcl_platform(platform) eq "windows"}] -if {$tcl_platform(platform) eq "windows" && \ - [string length [file extension $fossilexe]] == 0} { - append fossilexe .exe +if {$::is_windows} { + if {[string length [file extension $fossilexe]] == 0} { + append fossilexe .exe + } + set outside_fossil_repo [expr ![file exists "$::testfiledir\\..\\_FOSSIL_"]] +} else { + set outside_fossil_repo [expr ![file exists "$::testfiledir/../.fslckout"]] } + +catch {exec $::fossilexe changes --changed} res +set dirty_ckout [string length $res] set argv [lrange $argv 1 end] set i [lsearch $argv -keep] if {$i>=0} { @@ -112,10 +124,21 @@ fconfigure $out -translation platform puts $out $msg close $out } } + +# write a dict with just enough formatting +# to make it human readable +# +proc protOutDict {dict {pattern *}} { + set longest [tcl::mathfunc::max 0 {*}[lmap key [dict keys $dict $pattern] {string length $key}]] + dict for {key value} $dict { + protOut [format "%-${longest}s = %s" $key $value] + } +} + # Run the Fossil program with the specified arguments. # # Consults the VERBOSE global variable to determine if # diagnostics should be emitted when no error is seen. @@ -136,35 +159,68 @@ # proc fossil_maybe_answer {answer args} { global fossilexe set cmd $fossilexe set expectError 0 - if {[lindex $args end] eq "-expectError"} { + set index [lsearch -exact $args -expectError] + if {$index != -1} { set expectError 1 - set args [lrange $args 0 end-1] + set args [lreplace $args $index $index] + } + set keepNewline 0 + set index [lsearch -exact $args -keepNewline] + if {$index != -1} { + set keepNewline 1 + set args [lreplace $args $index $index] + } + set whatIf 0 + set index [lsearch -exact $args -whatIf] + if {$index != -1} { + set whatIf 1 + set args [lreplace $args $index $index] } foreach a $args { lappend cmd $a } protOut $cmd flush stdout - if {[string length $answer] > 0} { - protOut $answer - set prompt_file [file join $::tempPath fossil_prompt_answer] - write_file $prompt_file $answer\n - set rc [catch {eval exec -keepnewline $cmd <$prompt_file} result] - file delete $prompt_file + if {$whatIf} { + protOut [pwd]; protOut $answer + set result WHAT-IF-MODE; set rc 42 } else { - set rc [catch {eval exec -keepnewline $cmd} result] + if {[string length $answer] > 0} { + protOut $answer + set prompt_file [file join $::tempPath fossil_prompt_answer] + write_file $prompt_file $answer\n + set execCmd [list eval exec] + if {$keepNewline} {lappend execCmd -keepnewline} + lappend execCmd $cmd <$prompt_file + set rc [catch $execCmd result] + file delete $prompt_file + } else { + set execCmd [list eval exec] + if {$keepNewline} {lappend execCmd -keepnewline} + lappend execCmd $cmd + set rc [catch $execCmd result] + } + } + set ab(str) {child process exited abnormally} + set ab(len) [string length $ab(str)] + set ab(off) [expr {$ab(len) - 1}] + if {$rc && $expectError && \ + [string range $result end-$ab(off) end] eq $ab(str)} { + set result [string range $result 0 end-$ab(len)] } global RESULT CODE set CODE $rc - if {($rc && !$expectError) || (!$rc && $expectError)} { - protOut "ERROR: $result" 1 - } elseif {$::VERBOSE} { - protOut "RESULT: $result" + if {!$whatIf} { + if {($rc && !$expectError) || (!$rc && $expectError)} { + protOut "ERROR ($rc): $result" 1 + } elseif {$::VERBOSE} { + protOut "RESULT ($rc): $result" + } } set RESULT $result } # Read a file into memory. @@ -198,25 +254,18 @@ # set result [list \ allow-symlinks \ binary-glob \ clean-glob \ + crlf-glob \ crnl-glob \ dotfiles \ empty-dirs \ encoding-glob \ ignore-glob \ keep-glob \ - manifest \ - th1-setup \ - th1-uri-regexp] - - fossil test-th-eval "hasfeature tcl" - - if {[normalize_result] eq "1"} { - lappend result tcl-setup - } + manifest] return [lsort -dictionary $result] } # Returns the list of all supported settings. @@ -233,45 +282,67 @@ auto-captcha \ auto-hyperlink \ auto-shun \ autosync \ autosync-tries \ + backoffice-disable \ + backoffice-logfile \ + backoffice-nodelay \ binary-glob \ case-sensitive \ clean-glob \ clearsign \ + comment-format \ + crlf-glob \ crnl-glob \ + default-csp \ default-perms \ diff-binary \ diff-command \ dont-push \ dotfiles \ editor \ + email-admin \ + email-self \ + email-send-command \ + email-send-db \ + email-send-dir \ + email-send-method \ + email-send-relayhost \ + email-subname \ + email-url \ empty-dirs \ encoding-glob \ exec-rel-paths \ + fileedit-glob \ + forbid-delta-manifests \ gdiff-command \ gmerge-command \ hash-digits \ http-port \ https-login \ ignore-glob \ keep-glob \ localauth \ + lock-timeout \ main-branch \ manifest \ max-loadavg \ max-upload \ + mimetypes \ mtime-changes \ pgp-command \ proxy \ + redirect-to-https \ relative-paths \ repo-cksum \ + repolist-skin \ self-register \ ssh-command \ ssl-ca-location \ ssl-identity \ + tclsh \ th1-setup \ th1-uri-regexp \ uv-sync \ web-browser] @@ -307,20 +378,51 @@ proc same_file {a b} { set x [read_file $a] regsub -all { +\n} $x \n x set y [read_file $b] regsub -all { +\n} $y \n y - return [expr {$x==$y}] + if {$x == $y} { + return 1 + } else { + if {$::VERBOSE} { + protOut "NOT_SAME_FILE($a): \{\n$x\n\}" + protOut "NOT_SAME_FILE($b): \{\n$y\n\}" + } + return 0 + } +} + +# Return true if two strings refer to the +# same uuid. That is, the shorter is a prefix +# of the longer. +# +proc same_uuid {a b} { + set na [string length $a] + set nb [string length $b] + if {$na == $nb} { + return [expr {$a eq $b}] + } + if {$na < $nb} { + return [string match "$a*" $b] + } + return [string match "$b*" $a] +} + +# Return a prefix of a uuid, defaulting to 10 chars. +# +proc short_uuid {uuid {len 10}} { + string range $uuid 0 $len-1 } + proc require_no_open_checkout {} { if {[info exists ::env(FOSSIL_TEST_DANGEROUS_IGNORE_OPEN_CHECKOUT)] && \ $::env(FOSSIL_TEST_DANGEROUS_IGNORE_OPEN_CHECKOUT) eq "YES_DO_IT"} { return } catch {exec $::fossilexe info} res - if {![regexp {use --repository} $res]} { + if {[regexp {local-root:} $res]} { set projectName set localRoot regexp -line -- {^project-name: (.*)$} $res dummy projectName set projectName [string trim $projectName] regexp -line -- {^local-root: (.*)$} $res dummy localRoot @@ -388,11 +490,11 @@ if {![info exists ::tempKeepHome]} {delete_temporary_home} } proc delete_temporary_home {} { if {$::KEEP} {return}; # All cleanup disabled? - if {$::tcl_platform(platform) eq "windows"} { + if {$::is_windows} { robust_delete [file join $::tempHomePath _fossil] } else { robust_delete [file join $::tempHomePath .fossil] } robust_delete $::tempHomePath @@ -434,10 +536,11 @@ if {[string length $filename] > 0} { exec $::fossilexe new $filename exec $::fossilexe open $filename exec $::fossilexe set mtime-changes off } + return $repoPath } # This procedure only returns non-zero if the Tcl integration feature was # enabled at compile-time and is now enabled at runtime. proc is_tcl_usable_by_fossil {} { @@ -460,26 +563,66 @@ fossil test-th-eval --open-config "setting th1-hooks" if {[normalize_result] eq "1"} {return 1} return [info exists ::env(TH1_ENABLE_HOOKS)] } -# This (rarely used) procedure is designed to run a test within the Fossil -# source checkout (e.g. one that does NOT modify any state), while saving -# and restoring the current directory (e.g. one used when running a test -# file outside of the Fossil source checkout). Please do NOT use this -# procedure unless you are absolutely sure it does not modify the state of -# the repository or source checkout in any way. +# Run the given command script inside the Fossil source repo checkout. +# +# Callers of this function must ensure two things: +# +# 1. This test run is in fact being done from within a Fossil repo +# checkout directory. If you are unsure, test $::outside_fossil_repo +# or call one of the test_* wrappers below which do that for you. +# +# As a rule, you should not be calling this function directly! +# +# 2. This test run is being done from a repo checkout directory that +# doesn't have any uncommitted changes. If it does, that affects the +# output of any test based on the output of "fossil status", +# "... diff", etc., which is likely to make the test appear to fail. +# If you must call this function directly, test $::dirty_ckout and +# skip the call if it's true. The test_* wrappers do this for you. # +# 3. The test does NOT modify the Fossil checkout tree in any way. proc run_in_checkout { script {dir ""} } { if {[string length $dir] == 0} {set dir $::testfiledir} set savedPwd [pwd]; cd $dir set code [catch { uplevel 1 $script } result] cd $savedPwd; unset savedPwd return -code $code $result } + +# Wrapper for the above function pair. The tscript parameter is an +# optional post-run test script. Some callers choose instead to put +# the tests inline with the rscript commands. +# +# Be sure to adhere to the requirements of run_in_checkout! +proc test_block_in_checkout { name rscript {tscript ""} } { + if {$::outside_fossil_repo || $::dirty_ckout} { + set $::CODE 0 + set $::RESULT "" + } else { + run_in_checkout $rscript + if {[string length $tscript] == 0} { + return "" + } else { + set code [catch { + uplevel 1 $tscript + } result] + return -code $code $result + } + } +} + +# Single-test wrapper for the above. +proc test_in_checkout { name rscript tscript } { + return test_block_in_checkout name rscript { + test $name $tscript + } +} # Normalize file status lists (like those returned by 'fossil changes') # so they can be compared using simple string comparison # proc normalize_status_list {list} { @@ -572,11 +715,11 @@ } # # NOTE: On non-Windows systems, fallback to /tmp if it is usable. # - if {$::tcl_platform(platform) ne "windows"} { + if {!$::is_windows} { set value /tmp if {[file exists $value] && [file isdirectory $value]} { return $value } @@ -668,11 +811,11 @@ lappend ignored_test $name } else { protOut "test $name FAILED!" 1 if {$::QUIET} {protOut "RESULT: $RESULT" 1} lappend bad_test $name - if {$::HALT} exit + if {$::HALT} {exit 1} } } } set bad_test {} set ignored_test {} @@ -734,76 +877,94 @@ } return [string range $out 1 end] } # This procedure executes the "fossil server" command. The return value -# is the new process identifier. The varName argument refers to a variable +# is a list comprised of the new process identifier and the port on which +# the server started. The varName argument refers to a variable # where the "stop argument" is to be stored. This value must eventually be # passed to the [test_stop_server] procedure. proc test_start_server { repository {varName ""} } { - global fossilexe - set command [list exec $fossilexe server] + global fossilexe tempPath + set command [list exec $fossilexe server --localhost] if {[string length $varName] > 0} { upvar 1 $varName stopArg } - if {$::tcl_platform(platform) eq "windows"} { + if {$::is_windows} { set stopArg [file join [getTemporaryPath] [appendArgs \ [string trim [clock seconds] -] _ [getSeqNo] .stopper]] lappend command --stopper $stopArg } - lappend command $repository & + set outFileName [file join $tempPath [appendArgs \ + fossil_server_ [string trim [clock seconds] -] _ \ + [getSeqNo]]].out + lappend command $repository >&$outFileName & set pid [eval $command] - if {$::tcl_platform(platform) ne "windows"} { + if {!$::is_windows} { set stopArg $pid } - return $pid + after 1000; # output might not be there yet + set output [read_file $outFileName] + if {![regexp {Listening.*TCP port (\d+)} $output dummy port]} { + puts stdout "Could not detect Fossil server port, using default..." + set port 8080; # return the default port just in case + } + return [list $pid $port $outFileName] } # This procedure stops a Fossil server instance that was previously started # by the [test_start_server] procedure. The value of the "stop argument" # will vary by platform as will the exact method used to stop the server. -proc test_stop_server { stopArg pid } { - if {$::tcl_platform(platform) eq "windows"} { +# The fileName argument is the name of a temporary output file to delete. +proc test_stop_server { stopArg pid fileName } { + if {$::is_windows} { # # NOTE: On Windows, the "stop argument" must be the name of a file # that does NOT already exist. # - if {![file exists $stopArg] && \ - [catch {write_file $stopArg [clock seconds]}] == 0} then { + if {[string length $stopArg] > 0 && \ + ![file exists $stopArg] && \ + [catch {write_file $stopArg [clock seconds]}] == 0} { while {1} { if {[catch { # # NOTE: Using the TaskList utility requires Windows XP or # later. # exec tasklist.exe /FI "PID eq $pid" - } result] != 0 || ![regexp -- " $pid " $result]} then { + } result] != 0 || ![regexp -- " $pid " $result]} { break } after 1000; # wait a bit... } file delete $stopArg + if {[string length $fileName] > 0} { + file delete $fileName + } return true } } else { # # NOTE: On Unix, the "stop argument" must be an integer identifier # that refers to an existing process. # if {[regexp {^(?:-)?\d+$} $stopArg] && \ - [catch {exec kill -TERM $stopArg}] == 0} then { + [catch {exec kill -TERM $stopArg}] == 0} { while {1} { if {[catch { # # TODO: Is this portable to all the supported variants of # Unix? It should be, it's POSIX. # exec ps -p $pid - } result] != 0 || ![regexp -- "(?:^$pid| $pid) " $result]} then { + } result] != 0 || ![regexp -- "(?:^$pid| $pid) " $result]} { break } after 1000; # wait a bit... + } + if {[string length $fileName] > 0} { + file delete $fileName } return true } } return false @@ -818,11 +979,14 @@ set inFileName [file join $::tempPath [appendArgs test-http-in- $suffix]] set outFileName [file join $::tempPath [appendArgs test-http-out- $suffix]] set data [subst [read_file $dataFileName]] write_file $inFileName $data - fossil http $inFileName $outFileName 127.0.0.1 $repository --localauth + + fossil http --in $inFileName --out $outFileName --ipaddr 127.0.0.1 \ + $repository --localauth --th-trace + set result [expr {[file exists $outFileName] ? [read_file $outFileName] : ""}] if {1} { catch {file delete $inFileName} catch {file delete $outFileName} @@ -880,11 +1044,11 @@ return [lindex [split [normalize_result] \n] end-2] } set tempPath [getTemporaryPath] -if {$tcl_platform(platform) eq "windows"} { +if {$is_windows} { set tempPath [string map [list \\ /] $tempPath] } if {[catch { set tempFile [file join $tempPath temporary.txt] @@ -900,16 +1064,23 @@ file mkdir $tempHomePath } error] != 0} { error "Could not make directory \"$tempHomePath\",\ please set TEMP variable in environment, error: $error" } + protInit $fossilexe set ::tempKeepHome 1 foreach testfile $argv { protOut "***** $testfile ******" - source $testdir/$testfile.test + if { [catch {source $testdir/$testfile.test} testerror testopts] } { + test test-framework-$testfile 0 + protOut "!!!!! $testfile: $testerror" + protOutDict $testopts" + } else { + test test-framework-$testfile 1 + } protOut "***** End of $testfile: [llength $bad_test] errors so far ******" } unset ::tempKeepHome; delete_temporary_home set nErr [llength $bad_test] if {$nErr>0 || !$::QUIET} { Index: test/th1-docs.test ================================================================== --- test/th1-docs.test +++ test/th1-docs.test @@ -18,21 +18,29 @@ # TH1 Docs # fossil test-th-eval "hasfeature th1Docs" -if {$::RESULT ne "1"} { +if {[normalize_result] ne "1"} { puts "Fossil was not compiled with TH1 docs support." test_cleanup_then_return } fossil test-th-eval "hasfeature tcl" -if {$::RESULT ne "1"} { +if {[normalize_result] ne "1"} { puts "Fossil was not compiled with Tcl support." test_cleanup_then_return } + +if {$::outside_fossil_repo} { + puts "Skipping th1-docs-* tests: not in Fossil repo checkout." + test_cleanup_then_return +} elseif ($::dirty_ckout) { + puts "Skipping th1-docs-* tests: uncommitted changes in Fossil checkout." + test_cleanup_then_return +} ############################################################################### test_setup "" @@ -61,11 +69,11 @@ set RESULT [test_fossil_http \ $repository $dataFileName /doc/trunk/test/fileStat.th1] } test th1-docs-1a {[regexp {Fossil: test/fileStat.th1} $RESULT]} -test th1-docs-1b {[regexp {>\[[0-9a-f]{40}\]<} $RESULT]} +test th1-docs-1b {[regexp {>\[[0-9a-f]{40,64}\]<} $RESULT]} test th1-docs-1c {[regexp { contains \d+ files\.} $RESULT]} ############################################################################### test_cleanup Index: test/th1-hooks.test ================================================================== --- test/th1-hooks.test +++ test/th1-hooks.test @@ -18,11 +18,11 @@ # TH1 Hooks # fossil test-th-eval "hasfeature th1Hooks" -if {$::RESULT ne "1"} { +if {[normalize_result] ne "1"} { puts "Fossil was not compiled with TH1 hooks support." test_cleanup_then_return } ############################################################################### @@ -70,17 +70,25 @@ } elseif {$::cmd_name eq "test3"} { emit_hook_log break "TH_BREAK return code" } elseif {$::cmd_name eq "test4"} { emit_hook_log - return -code 2 "TH_RETURN return code" + return -code 5 "TH_RETURN return code" } elseif {$::cmd_name eq "timeline"} { set length [llength $::cmd_args] set length [expr {$length - 1}] if {[lindex $::cmd_args $length] eq "custom"} { + append_hook_log "CUSTOM TIMELINE" emit_hook_log return "custom timeline" + } elseif {[lindex $::cmd_args $length] eq "custom2"} { + emit_hook_log + puts "+++ some stuff here +++" + continue "custom2 timeline" + } elseif {[lindex $::cmd_args $length] eq "custom3"} { + emit_hook_log + return -code 5 "TH_RETURN return code" } elseif {[lindex $::cmd_args $length] eq "now"} { emit_hook_log return "now timeline" } else { emit_hook_log @@ -118,20 +126,35 @@ set dataFileName [file join $::testdir th1-hooks-input.txt] ############################################################################### -saveTh1SetupFile; writeTh1SetupFile $testTh1Setup +set savedTh1Setup [fossil settings th1-setup] +fossil settings th1-setup $testTh1Setup ############################################################################### -fossil timeline custom; # NOTE: Bad "WHEN" argument. +fossil timeline custom -expectError; # NOTE: Bad "WHEN" argument. test th1-cmd-hooks-1a {[normalize_result] eq \ +{

    command_hook timeline CUSTOM TIMELINE

    +unknown check-in or invalid date: custom}} + +############################################################################### + +fossil timeline custom2; # NOTE: Bad "WHEN" argument. +test th1-cmd-hooks-1b {[normalize_result] eq \ {

    command_hook timeline

    -+++ no more data (0) +++ - ++++ some stuff here +++

    command_hook timeline command_notify timeline

    }} + +############################################################################### + +fossil timeline custom3; # NOTE: Bad "WHEN" argument. + +test th1-cmd-hooks-1c {[normalize_result] eq \ +{

    command_hook timeline

    +unknown check-in or invalid date: custom3}} ############################################################################### fossil timeline test th1-cmd-hooks-2a {[first_data_line] eq \ @@ -174,13 +197,20 @@ {

    command_hook test3

    }} ############################################################################### fossil test4 -test th1-custom-cmd-4a {[string trim $RESULT] eq \ + +test th1-custom-cmd-4a {[first_data_line] eq \ {

    command_hook test4

    }} +test th1-custom-cmd-4b {[regexp -- \ + {: unknown command: test4$} [second_data_line]]} + +test th1-custom-cmd-4d {[regexp -- \ + {: use "help" for more information$} [third_data_line]]} + ############################################################################### set RESULT [test_fossil_http $repository $dataFileName /timeline] test th1-web-hooks-1a {[regexp \ @@ -198,10 +228,10 @@ test th1-custom-web-1b {[last_data_line] eq \ {

    command_hook http webpage_hook test1 webpage_notify test1

    }} ############################################################################### -restoreTh1SetupFile +fossil settings th1-setup $savedTh1Setup ############################################################################### test_cleanup Index: test/th1-tcl.test ================================================================== --- test/th1-tcl.test +++ test/th1-tcl.test @@ -22,11 +22,11 @@ ############################################################################### fossil test-th-eval "hasfeature tcl" -if {$::RESULT ne "1"} { +if {[normalize_result] ne "1"} { puts "Fossil was not compiled with Tcl support." test_cleanup_then_return } ############################################################################### Index: test/th1.test ================================================================== --- test/th1.test +++ test/th1.test @@ -554,40 +554,58 @@ fossil test-th-eval "lindex list -0x" test th1-expr-49 {$RESULT eq {TH_ERROR: expected integer, got: "-0x"}} ############################################################################### -foreach perm [list a b c d e f g h i j k l m n o p q r s t u v w x y z] { +set skip_anycap 1 +if {$::outside_fossil_repo} { + puts "Skipping th1-anycap-*-1 perm tests: not in Fossil repo checkout." +} elseif ($::dirty_ckout) { + puts "Skipping th1-anycap-*-1 perm tests: uncommitted changes in Fossil checkout." +} else { + set skip_anycap 0 +} + +# NOTE: The 'd' permission is no longer used. +foreach perm [list \ + a b c e f g h i j k l m n o p q r s t u v w x y z \ + A D \ + 2 3 4 5 6 7 ] { if {$perm eq "u"} continue; # NOTE: Skip "reader" meta-permission. if {$perm eq "v"} continue; # NOTE: Skip "developer" meta-permission. + set ::env(TH1_TEST_USER_CAPS) sxy fossil test-th-eval "anycap $perm" test th1-anycap-no-$perm-1 {$RESULT eq {0}} fossil test-th-eval "hascap $perm" test th1-hascap-no-$perm-1 {$RESULT eq {0}} fossil test-th-eval "anoncap $perm" test th1-anoncap-no-$perm-1 {$RESULT eq {0}} + if {$skip_anycap} { continue } + run_in_checkout { + set ::env(TH1_TEST_USER_CAPS) sxy fossil test-th-eval --set-user-caps "anycap $perm" test th1-anycap-yes-$perm-1 {$RESULT eq {1}} set ::env(TH1_TEST_USER_CAPS) 1; # NOTE: Bad permission. fossil test-th-eval --set-user-caps "anycap $perm" test th1-anycap-no-$perm-1 {$RESULT eq {0}} - unset ::env(TH1_TEST_USER_CAPS) + set ::env(TH1_TEST_USER_CAPS) sxy fossil test-th-eval --set-user-caps "hascap $perm" test th1-hascap-yes-$perm-1 {$RESULT eq {1}} set ::env(TH1_TEST_USER_CAPS) 1; # NOTE: Bad permission. fossil test-th-eval --set-user-caps "hascap $perm" test th1-hascap-no-$perm-1 {$RESULT eq {0}} unset ::env(TH1_TEST_USER_CAPS) + set ::env(TH1_TEST_ANON_CAPS) sxy fossil test-th-eval --set-anon-caps "anoncap $perm" test th1-anoncap-yes-$perm-1 {$RESULT eq {1}} set ::env(TH1_TEST_ANON_CAPS) 1; # NOTE: Bad permission. fossil test-th-eval --set-anon-caps "anoncap $perm" @@ -621,11 +639,11 @@ fossil test-th-eval "anoncap o h" test th1-anoncap-no-multiple-2 {$RESULT eq {0}} ############################################################################### -run_in_checkout { +test_block_in_checkout "test-anoncap-*" { fossil test-th-eval --set-user-caps "anycap oh" test th1-anycap-yes-multiple-1 {$RESULT eq {1}} set ::env(TH1_TEST_USER_CAPS) o fossil test-th-eval --set-user-caps "anycap oh" @@ -665,29 +683,25 @@ unset ::env(TH1_TEST_ANON_CAPS) } ############################################################################### -run_in_checkout { +test_in_checkout th1-checkout-1 { # NOTE: The "1" here forces the checkout to be opened. fossil test-th-eval "checkout 1" -} - -test th1-checkout-1 {[string length $RESULT] > 0} +} {[string length $RESULT] > 0} ############################################################################### -run_in_checkout { +test_in_checkout th1-checkout-2 { if {$th1Hooks} { fossil test-th-eval "checkout" } else { # NOTE: No TH1 hooks, force checkout to be populated. fossil test-th-eval --open-config "checkout" } -} - -test th1-checkout-2 {[string length $RESULT] > 0} +} {[string length $RESULT] > 0} ############################################################################### set savedPwd [pwd]; cd / fossil test-th-eval "checkout 1" @@ -762,15 +776,13 @@ fossil test-th-eval "styleHeader {Page Title Here}" test th1-header-1 {$RESULT eq {TH_ERROR: repository unavailable}} ############################################################################### -run_in_checkout { +test_in_checkout th1-header-2 { fossil test-th-eval --open-config "styleHeader {Page Title Here}" -} - -test th1-header-2 {[regexp -- {Fossil: Page Title Here} $RESULT]} +} {[regexp -- {Fossil: Page Title Here} $RESULT]} ############################################################################### fossil test-th-eval "styleFooter" test th1-footer-1 {$RESULT eq {TH_ERROR: repository unavailable}} @@ -781,11 +793,11 @@ test th1-footer-2 {$RESULT eq {}} ############################################################################### fossil test-th-eval --open-config --cgi "styleHeader {}; styleFooter" -test th1-footer-3 {[regexp -- {} $RESULT]} +test th1-footer-3 {[regexp -- {\n} $RESULT]} ############################################################################### fossil test-th-eval "getParameter" test th1-get-parameter-1 {$RESULT eq \ @@ -848,15 +860,13 @@ fossil test-th-eval "artifact tip" test th1-artifact-2 {$RESULT eq {TH_ERROR: repository unavailable}} ############################################################################### -run_in_checkout { +test_in_checkout th1-artifact-3 { fossil test-th-eval --open-config "artifact tip" -} - -test th1-artifact-3 {[regexp -- {F test/th1\.test [0-9a-f]{40}} $RESULT]} +} {[regexp -- {F test/th1\.test [0-9a-f]{40,64}} $RESULT]} ############################################################################### fossil test-th-eval "artifact 0000000000" test th1-artifact-4 {$RESULT eq {TH_ERROR: repository unavailable}} @@ -871,15 +881,13 @@ fossil test-th-eval "artifact tip test/th1.test" test th1-artifact-6 {$RESULT eq {TH_ERROR: repository unavailable}} ############################################################################### -run_in_checkout { +test_in_checkout th1-artifact-7 { fossil test-th-eval --open-config "artifact tip test/th1.test" -} - -test th1-artifact-7 {[regexp -- {th1-artifact-7} $RESULT]} +} {[regexp -- {th1-artifact-7} $RESULT]} ############################################################################### fossil test-th-eval "artifact 0000000000 test/th1.test" test th1-artifact-8 {$RESULT eq {TH_ERROR: repository unavailable}} @@ -889,24 +897,22 @@ fossil test-th-eval --open-config "artifact 0000000000 test/th1.test" test th1-artifact-9 {$RESULT eq {TH_ERROR: manifest not found}} ############################################################################### -run_in_checkout { +test_in_checkout th1-globalState-1 { if {$th1Hooks} { fossil test-th-eval "globalState checkout" } else { # NOTE: No TH1 hooks, force checkout to be populated. fossil test-th-eval --open-config "globalState checkout" } -} - -test th1-globalState-1 {[string length $RESULT] > 0} +} {[string length $RESULT] > 0} ############################################################################### -run_in_checkout { +test_block_in_checkout th1-globalState-2 { if {$th1Hooks} { fossil test-th-eval "globalState checkout" test th1-globalState-2 {$RESULT eq [fossil test-th-eval checkout]} } else { # NOTE: No TH1 hooks, force checkout to be populated. @@ -942,24 +948,22 @@ fossil test-th-eval --errorlog foserrors.log "globalState log" test th1-globalState-7 {$RESULT eq "foserrors.log"} ############################################################################### -run_in_checkout { +test_in_checkout th1-globalState-8 { if {$th1Hooks} { fossil test-th-eval "globalState repository" } else { # NOTE: No TH1 hooks, force repository to be populated. fossil test-th-eval --open-config "globalState repository" } -} - -test th1-globalState-8 {[string length $RESULT] > 0} +} {[string length $RESULT] > 0} ############################################################################### -run_in_checkout { +test_block_in_checkout th1-globalState-9 { if {$th1Hooks} { fossil test-th-eval "globalState repository" test th1-globalState-9 {$RESULT eq [fossil test-th-eval repository]} } else { # NOTE: No TH1 hooks, force repository to be populated. @@ -1032,24 +1036,24 @@ # fossil test-th-eval "info commands" set sorted_result [lsort $RESULT] protOut "Sorted: $sorted_result" set base_commands {anoncap anycap array artifact break breakpoint catch\ - checkout combobox continue date decorate dir enable_output encode64\ - error expr for getParameter glob_match globalState hascap hasfeature\ - html htmlize http httpize if info insertCsrf lindex linecount list\ - llength lsearch markdown proc puts query randhex redirect regexp\ - reinitialize rename render repository return searchable set\ - setParameter setting stime string styleFooter styleHeader tclReady\ - trace unset uplevel upvar utime verifyCsrf wiki} + cgiHeaderLine checkout combobox continue copybtn date decorate dir \ + enable_output encode64 error expr for getParameter glob_match \ + globalState hascap hasfeature html htmlize http httpize if info \ + insertCsrf lindex linecount list llength lsearch markdown nonce proc \ + puts query randhex redirect regexp reinitialize rename render \ + repository return searchable set setParameter setting stime string \ + styleFooter styleHeader styleScript tclReady trace unset unversioned \ + uplevel upvar utime verifyCsrf verifyLogin wiki} set tcl_commands {tclEval tclExpr tclInvoke tclIsSafe tclMakeSafe} if {$th1Tcl} { test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands $tcl_commands"]} } else { test th1-info-commands-1 {$sorted_result eq [lsort "$base_commands"]} } - ############################################################################### fossil test-th-eval "info vars" @@ -1436,10 +1440,85 @@ fossil test-th-eval {string is integer 0xC0DEF00Z} test th1-string-is-31 {$RESULT eq "0"} ############################################################################### +fossil test-th-eval {string index "" -1} +test th1-string-index-1 {$RESULT eq ""} + +############################################################################### + +fossil test-th-eval {string index "" 0} +test th1-string-index-2 {$RESULT eq ""} + +############################################################################### + +fossil test-th-eval {string index "" 1} +test th1-string-index-3 {$RESULT eq ""} + +############################################################################### + +fossil test-th-eval {string index "" 2} +test th1-string-index-4 {$RESULT eq ""} + +############################################################################### + +fossil test-th-eval {string index "" end} +test th1-string-index-5 {$RESULT eq ""} + +############################################################################### + +fossil test-th-eval {string index A -1} +test th1-string-index-6 {$RESULT eq ""} + +############################################################################### + +fossil test-th-eval {string index A 0} +test th1-string-index-7 {$RESULT eq "A"} + +############################################################################### + +fossil test-th-eval {string index A 1} +test th1-string-index-8 {$RESULT eq ""} + +############################################################################### + +fossil test-th-eval {string index A 2} +test th1-string-index-9 {$RESULT eq ""} + +############################################################################### + +fossil test-th-eval {string index A end} +test th1-string-index-10 {$RESULT eq "A"} + +############################################################################### + +fossil test-th-eval {string index ABC -1} +test th1-string-index-11 {$RESULT eq ""} + +############################################################################### + +fossil test-th-eval {string index ABC 0} +test th1-string-index-12 {$RESULT eq "A"} + +############################################################################### + +fossil test-th-eval {string index ABC 1} +test th1-string-index-13 {$RESULT eq "B"} + +############################################################################### + +fossil test-th-eval {string index ABC 2} +test th1-string-index-14 {$RESULT eq "C"} + +############################################################################### + +fossil test-th-eval {string index ABC end} +test th1-string-index-15 {$RESULT eq "C"} + +############################################################################### + fossil test-th-eval {markdown} test th1-markdown-1 {$RESULT eq \ {TH_ERROR: wrong # args: should be "markdown STRING"}} ############################################################################### @@ -1504,10 +1583,23 @@ }}} ############################################################################### +# Verify that quoted delimiters like * and _ don't terminate their +# span. This was fixed by checkin [dd41f85acf]. +fossil test-th-eval {markdown "*This is\\*a test.*\n_second\\_test_"} +test th1-markdown-6 {[normalize_result] eq {{} {
    + +

    This is*a test. +second_test

    + +
    +}}} + +############################################################################### + fossil test-th-eval {encode64 test} test th1-encode64-1 {$RESULT eq "dGVzdA=="} ############################################################################### @@ -1515,21 +1607,20 @@ test th1-encode64-2 {$RESULT eq "dGVzdAA="} ############################################################################### # -# TODO: Modify the result of this test if the source file (i.e. -# "ajax/cgi-bin/fossil-json.cgi.example") changes. +# This test will fail if the Fossil source file named below changes. Update +# the expected result string below if that happens. # -run_in_checkout { +test_in_checkout th1-encode64-3 { fossil test-th-eval --open-config \ {encode64 [artifact trunk ajax/cgi-bin/fossil-json.cgi.example]} +} { + $RESULT eq "IyEvcGF0aC90by9mb3NzaWwvYmluYXJ5CnJlcG9zaXRvcnk6IC9wYXRoL3RvL3JlcG8uZnNsCg==" } -test th1-encode64-3 {$RESULT eq \ -"IyEvcGF0aC90by9mb3NzaWwvYmluYXJ5CnJlcG9zaXRvcnk6IC9wYXRoL3RvL3JlcG8uZnNsCg=="} - ############################################################################### fossil test-th-eval {array exists tcl_platform} test th1-platform-1 {$RESULT eq "1"} @@ -1562,9 +1653,29 @@ } fossil test-th-source $th1FileName test th1-source-1 {$RESULT eq {TH_RETURN: 0 1 2 3 4 5 6 7 8 9}} file delete $th1FileName + +############################################################################### + +# Tests for the TH1 unversioned command require at least one +# unversioned file in the repository. All tests run in a freshly +# created checkout of a freshly created repo, so we can just +# create a file or two for the purpose. +write_file ten.txt "0123456789" +fossil unversioned add ten.txt +fossil unversioned list + +# unversioned list +fossil test-th-eval --open-config "unversioned list" +test th1-unversioned-1 {[normalize_result] eq {ten.txt}} + +# unversioned content +fossil test-th-eval --open-config \ + {string length [unversioned content ten.txt]} +test th1-unversioned-2 {$RESULT eq {10}} + ############################################################################### test_cleanup Index: test/unversioned.test ================================================================== --- test/unversioned.test +++ test/unversioned.test @@ -18,11 +18,11 @@ # The "unversioned" command. # set path [file dirname [info script]] -if {[catch {package require sha1}] != 0} then { +if {[catch {package require sha1}] != 0} { puts "The \"sha1\" package is not available." test_cleanup_then_return } require_no_open_checkout @@ -119,11 +119,11 @@ ############################################################################### fossil unversioned add "unversioned space.txt" -expectError test unversioned-14 {[normalize_result] eq \ -{names of unversioned files may not contain whitespace}} +{unversioned filenames may not contain whitespace: 'unversioned space.txt'}} ############################################################################### fossil unversioned add "unversioned space.txt" --as unversioned3.txt test unversioned-15 {[normalize_result] eq {}} @@ -178,11 +178,11 @@ test unversioned-23 {[::sha1::sha1 $RESULT] eq \ {962f96ebd613e4fdd9aa2d20bd9fe21a64e925f2}} ############################################################################### -fossil unversioned cat unversioned3.txt +fossil unversioned cat unversioned3.txt -keepNewline test unversioned-24 {[::sha1::sha1 $RESULT] eq \ {c6b95509120d9703cc4fbe5cdfcb435b5912b3e4}} ############################################################################### @@ -240,19 +240,19 @@ {962f96ebd613e4fdd9aa2d20bd9fe21a64e925f2}} ############################################################################### fossil unversioned hash -test unversioned-36 {[regexp {^[0-9a-f]{40}$} [normalize_result]]} +test unversioned-36 {[regexp {^[0-9a-f]{40,64}$} [normalize_result]]} ############################################################################### fossil unversioned hash --debug test unversioned-37 {[regexp \ -{^unversioned2\.txt 2016-10-01 00:00:00 [0-9a-f]{40} -unversioned4\.txt 2016-10-01 00:00:00 [0-9a-f]{40} -[0-9a-f]{40}$} [normalize_result]]} +{^unversioned2\.txt 2016-10-01 00:00:00 [0-9a-f]{40,64} +unversioned4\.txt 2016-10-01 00:00:00 [0-9a-f]{40,64} +[0-9a-f]{40,64}$} [normalize_result]]} ############################################################################### fossil unversioned remove unversioned4.txt --mtime "2016-10-02 13:47:29" test unversioned-38 {[normalize_result] eq {}} @@ -305,28 +305,29 @@ unversioned5\.txt$} [normalize_result]]} ############################################################################### set password [string trim [clock seconds] -] -set remote [appendArgs http://uvtester: $password @localhost:8080/] fossil user new uvtester "Unversioned Test User" $password fossil user capabilities uvtester oy ############################################################################### -set pid [test_start_server $repository stopArg] -puts [appendArgs "Started Fossil server, pid \"" $pid \".] +foreach {pid port outTmpFile} [test_start_server $repository stopArg] {} +puts [appendArgs "Started Fossil server, pid \"" $pid \" ", port \"" $port \".] +set remote [appendArgs http://uvtester: $password @localhost: $port /] ############################################################################### set clientDir [file join $tempPath [appendArgs \ uvtest_ [string trim [clock seconds] -] _ [getSeqNo]]] set savedPwd [pwd] file mkdir $clientDir; cd $clientDir puts [appendArgs "Now in client directory \"" [pwd] \".] +write_file unversioned-client1.txt "This is unversioned client file #1." ############################################################################### fossil_maybe_answer y clone $remote uvrepo.fossil fossil open uvrepo.fossil @@ -342,11 +343,12 @@ test unversioned-46 {[regexp \ {Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 2 Artifacts sent: 0 received: 0 Round-trips: 2 Artifacts sent: 0 received: 2 -\n? done, sent: \d+ received: \d+ ip: 127.0.0.1} [normalize_result]]} +\n? done, sent: \d+ received: \d+ ip: (?:127\.0\.0\.1|::1)} \ +[normalize_result]]} ############################################################################### fossil unversioned ls test unversioned-47 {[normalize_result] eq {unversioned2.txt @@ -361,59 +363,98 @@ unset env(FAKE_EDITOR_SCRIPT) ############################################################################### +fossil unversioned cat unversioned2.txt +test unversioned-49 {[::sha1::sha1 $RESULT] eq \ +{e15d4b576fc04e3bb5e44a33d44d104dd5b19428}} + +############################################################################### + fossil unversioned remove unversioned5.txt -test unversioned-49 {[normalize_result] eq {}} +test unversioned-50 {[normalize_result] eq {}} ############################################################################### fossil unversioned list --all -test unversioned-50 {[regexp \ +test unversioned-51 {[regexp \ {^[0-9a-f]{12} \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} 44 44\ unversioned2\.txt \(deleted\) \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} 0 0\ unversioned5\.txt$} [normalize_result]]} ############################################################################### fossil_maybe_answer y unversioned revert $remote -test unversioned-51 {[regexp \ +test unversioned-52 {[regexp \ {Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 1 Artifacts sent: 0 received: 0 Round-trips: 2 Artifacts sent: 0 received: 0 Round-trips: 2 Artifacts sent: 0 received: 2 -\n? done, sent: \d+ received: \d+ ip: 127.0.0.1} [normalize_result]]} +\n? done, sent: \d+ received: \d+ ip: (?:127\.0\.0\.1|::1)} \ +[normalize_result]]} ############################################################################### fossil unversioned list -test unversioned-52 {[regexp \ +test unversioned-53 {[regexp \ {^[0-9a-f]{12} 2016-10-01 00:00:00 30 30\ unversioned2\.txt [0-9a-f]{12} \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} 28 28\ unversioned5\.txt$} [normalize_result]]} ############################################################################### +fossil unversioned add unversioned-client1.txt +test unversioned-54 {[normalize_result] eq {}} + +############################################################################### + +fossil_maybe_answer y unversioned sync $remote +test unversioned-55 {[regexp \ +{Round-trips: 1 Artifacts sent: 0 received: 0 +Round-trips: 1 Artifacts sent: 0 received: 0 +Round-trips: 2 Artifacts sent: 1 received: 0 +Round-trips: 2 Artifacts sent: 1 received: 0 +\n? done, sent: \d+ received: \d+ ip: (?:127\.0\.0\.1|::1)} \ +[normalize_result]]} + +############################################################################### + fossil close -test unversioned-53 {[normalize_result] eq {}} +test unversioned-56 {[normalize_result] eq {}} ############################################################################### cd $savedPwd; unset savedPwd file delete -force $clientDir puts [appendArgs "Now in server directory \"" [pwd] \".] ############################################################################### -set stopped [test_stop_server $stopArg $pid] +set stopped [test_stop_server $stopArg $pid $outTmpFile] puts [appendArgs \ [expr {$stopped ? "Stopped" : "Could not stop"}] \ " Fossil server, pid \"" $pid "\", using argument \"" \ $stopArg \".] + +############################################################################### + +fossil unversioned list +test unversioned-57 {[regexp \ +{^[0-9a-f]{12} \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} 35 35\ +unversioned-client1\.txt +[0-9a-f]{12} 2016-10-01 00:00:00 30 30 unversioned2\.txt +[0-9a-f]{12} \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} 28 28\ +unversioned5\.txt$} [normalize_result]]} + +############################################################################### + +fossil unversioned cat unversioned-client1.txt +test unversioned-58 {[::sha1::sha1 $RESULT] eq \ +{a34606f714afe309bb531fba6051eaf25201e8a2}} ############################################################################### test_cleanup Index: test/utf.test ================================================================== --- test/utf.test +++ test/utf.test @@ -141,42 +141,42 @@ 75 [appendArgs \x00 ABCD\x00\n] \ 76 [appendArgs \x00 A\x00\r\n] \ 77 [appendArgs \x00 AB\x00\r\n] \ 78 [appendArgs \x00 ABC\x00\r\n] \ 79 [appendArgs \x00 ABCD\x00\r\n] \ - 80 [string repeat A 8193] \ - 81 [string repeat A 8193]\r \ - 82 [string repeat A 8193]\n \ - 83 [string repeat A 8193]\r\n \ - 84 [string repeat ABCD 2049] \ - 85 [string repeat ABCD 2049]\r \ - 86 [string repeat ABCD 2049]\n \ - 87 [string repeat ABCD 2049]\r\n \ - 88 \x00[string repeat A 8193] \ - 89 \x00[string repeat A 8193]\r \ - 90 \x00[string repeat A 8193]\n \ - 91 \x00[string repeat A 8193]\r\n \ - 92 \x00[string repeat ABCD 2049] \ - 93 \x00[string repeat ABCD 2049]\r \ - 94 \x00[string repeat ABCD 2049]\n \ - 95 \x00[string repeat ABCD 2049]\r\n \ - 96 [string repeat A 8193]\x00 \ - 97 [string repeat A 8193]\x00\r \ - 98 [string repeat A 8193]\x00\n \ - 99 [string repeat A 8193]\x00\r\n \ - 100 [string repeat ABCD 2049]\x00 \ - 101 [string repeat ABCD 2049]\x00\r \ - 102 [string repeat ABCD 2049]\x00\n \ - 103 [string repeat ABCD 2049]\x00\r\n \ - 104 \x00[string repeat A 8193]\x00 \ - 105 \x00[string repeat A 8193]\x00\r \ - 106 \x00[string repeat A 8193]\x00\n \ - 107 \x00[string repeat A 8193]\x00\r\n \ - 108 \x00[string repeat ABCD 2049]\x00 \ - 109 \x00[string repeat ABCD 2049]\x00\r \ - 110 \x00[string repeat ABCD 2049]\x00\n \ - 111 \x00[string repeat ABCD 2049]\x00\r\n \ + 80 [string repeat A 32769] \ + 81 [string repeat A 32769]\r \ + 82 [string repeat A 32769]\n \ + 83 [string repeat A 32769]\r\n \ + 84 [string repeat ABCD 8196] \ + 85 [string repeat ABCD 8196]\r \ + 86 [string repeat ABCD 8196]\n \ + 87 [string repeat ABCD 8196]\r\n \ + 88 \x00[string repeat A 32769] \ + 89 \x00[string repeat A 32769]\r \ + 90 \x00[string repeat A 32769]\n \ + 91 \x00[string repeat A 32769]\r\n \ + 92 \x00[string repeat ABCD 8196] \ + 93 \x00[string repeat ABCD 8196]\r \ + 94 \x00[string repeat ABCD 8196]\n \ + 95 \x00[string repeat ABCD 8196]\r\n \ + 96 [string repeat A 32769]\x00 \ + 97 [string repeat A 32769]\x00\r \ + 98 [string repeat A 32769]\x00\n \ + 99 [string repeat A 32769]\x00\r\n \ + 100 [string repeat ABCD 8196]\x00 \ + 101 [string repeat ABCD 8196]\x00\r \ + 102 [string repeat ABCD 8196]\x00\n \ + 103 [string repeat ABCD 8196]\x00\r\n \ + 104 \x00[string repeat A 32769]\x00 \ + 105 \x00[string repeat A 32769]\x00\r \ + 106 \x00[string repeat A 32769]\x00\n \ + 107 \x00[string repeat A 32769]\x00\r\n \ + 108 \x00[string repeat ABCD 8196]\x00 \ + 109 \x00[string repeat ABCD 8196]\x00\r \ + 110 \x00[string repeat ABCD 8196]\x00\n \ + 111 \x00[string repeat ABCD 8196]\x00\r\n \ 112 \u000A\u000D \ 113 \u0A00\u0D00 \ 114 \u000D\u000A \ 115 \u0D00\u0A00 \ 116 \x00\u000A\u000D \ @@ -2906,11 +2906,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 260 utf-check-260-0-80-0.jnk \ -{File "%TEMP%/utf-check-260-0-80-0.jnk" has 8193 bytes. +{File "%TEMP%/utf-check-260-0-80-0.jnk" has 32769 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -2922,11 +2922,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 261 utf-check-261-0-80-1.jnk \ -{File "%TEMP%/utf-check-261-0-80-1.jnk" has 8194 bytes. +{File "%TEMP%/utf-check-261-0-80-1.jnk" has 32770 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -2938,11 +2938,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 262 utf-check-262-0-81-0.jnk \ -{File "%TEMP%/utf-check-262-0-81-0.jnk" has 8194 bytes. +{File "%TEMP%/utf-check-262-0-81-0.jnk" has 32770 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -2954,11 +2954,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 263 utf-check-263-0-81-1.jnk \ -{File "%TEMP%/utf-check-263-0-81-1.jnk" has 8195 bytes. +{File "%TEMP%/utf-check-263-0-81-1.jnk" has 32771 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -2970,11 +2970,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 264 utf-check-264-0-82-0.jnk \ -{File "%TEMP%/utf-check-264-0-82-0.jnk" has 8194 bytes. +{File "%TEMP%/utf-check-264-0-82-0.jnk" has 32770 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -2986,11 +2986,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 265 utf-check-265-0-82-1.jnk \ -{File "%TEMP%/utf-check-265-0-82-1.jnk" has 8195 bytes. +{File "%TEMP%/utf-check-265-0-82-1.jnk" has 32771 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -3002,11 +3002,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 266 utf-check-266-0-83-0.jnk \ -{File "%TEMP%/utf-check-266-0-83-0.jnk" has 8195 bytes. +{File "%TEMP%/utf-check-266-0-83-0.jnk" has 32771 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -3018,11 +3018,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 267 utf-check-267-0-83-1.jnk \ -{File "%TEMP%/utf-check-267-0-83-1.jnk" has 8196 bytes. +{File "%TEMP%/utf-check-267-0-83-1.jnk" has 32772 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -3034,11 +3034,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 268 utf-check-268-0-84-0.jnk \ -{File "%TEMP%/utf-check-268-0-84-0.jnk" has 8196 bytes. +{File "%TEMP%/utf-check-268-0-84-0.jnk" has 32784 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -3050,11 +3050,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 269 utf-check-269-0-84-1.jnk \ -{File "%TEMP%/utf-check-269-0-84-1.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-269-0-84-1.jnk" has 32785 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -3066,11 +3066,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 270 utf-check-270-0-85-0.jnk \ -{File "%TEMP%/utf-check-270-0-85-0.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-270-0-85-0.jnk" has 32785 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -3082,11 +3082,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 271 utf-check-271-0-85-1.jnk \ -{File "%TEMP%/utf-check-271-0-85-1.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-271-0-85-1.jnk" has 32786 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -3098,11 +3098,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 272 utf-check-272-0-86-0.jnk \ -{File "%TEMP%/utf-check-272-0-86-0.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-272-0-86-0.jnk" has 32785 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -3114,11 +3114,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 273 utf-check-273-0-86-1.jnk \ -{File "%TEMP%/utf-check-273-0-86-1.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-273-0-86-1.jnk" has 32786 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -3130,11 +3130,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 274 utf-check-274-0-87-0.jnk \ -{File "%TEMP%/utf-check-274-0-87-0.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-274-0-87-0.jnk" has 32786 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -3146,11 +3146,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 275 utf-check-275-0-87-1.jnk \ -{File "%TEMP%/utf-check-275-0-87-1.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-275-0-87-1.jnk" has 32787 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -3162,11 +3162,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 276 utf-check-276-0-88-0.jnk \ -{File "%TEMP%/utf-check-276-0-88-0.jnk" has 8194 bytes. +{File "%TEMP%/utf-check-276-0-88-0.jnk" has 32770 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3178,11 +3178,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 277 utf-check-277-0-88-1.jnk \ -{File "%TEMP%/utf-check-277-0-88-1.jnk" has 8195 bytes. +{File "%TEMP%/utf-check-277-0-88-1.jnk" has 32771 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3194,11 +3194,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 278 utf-check-278-0-89-0.jnk \ -{File "%TEMP%/utf-check-278-0-89-0.jnk" has 8195 bytes. +{File "%TEMP%/utf-check-278-0-89-0.jnk" has 32771 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3210,11 +3210,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 279 utf-check-279-0-89-1.jnk \ -{File "%TEMP%/utf-check-279-0-89-1.jnk" has 8196 bytes. +{File "%TEMP%/utf-check-279-0-89-1.jnk" has 32772 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3226,11 +3226,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 280 utf-check-280-0-90-0.jnk \ -{File "%TEMP%/utf-check-280-0-90-0.jnk" has 8195 bytes. +{File "%TEMP%/utf-check-280-0-90-0.jnk" has 32771 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3242,11 +3242,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 281 utf-check-281-0-90-1.jnk \ -{File "%TEMP%/utf-check-281-0-90-1.jnk" has 8196 bytes. +{File "%TEMP%/utf-check-281-0-90-1.jnk" has 32772 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3258,11 +3258,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 282 utf-check-282-0-91-0.jnk \ -{File "%TEMP%/utf-check-282-0-91-0.jnk" has 8196 bytes. +{File "%TEMP%/utf-check-282-0-91-0.jnk" has 32772 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3274,11 +3274,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 283 utf-check-283-0-91-1.jnk \ -{File "%TEMP%/utf-check-283-0-91-1.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-283-0-91-1.jnk" has 32773 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3290,11 +3290,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 284 utf-check-284-0-92-0.jnk \ -{File "%TEMP%/utf-check-284-0-92-0.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-284-0-92-0.jnk" has 32785 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3306,11 +3306,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 285 utf-check-285-0-92-1.jnk \ -{File "%TEMP%/utf-check-285-0-92-1.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-285-0-92-1.jnk" has 32786 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3322,11 +3322,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 286 utf-check-286-0-93-0.jnk \ -{File "%TEMP%/utf-check-286-0-93-0.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-286-0-93-0.jnk" has 32786 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3338,11 +3338,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 287 utf-check-287-0-93-1.jnk \ -{File "%TEMP%/utf-check-287-0-93-1.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-287-0-93-1.jnk" has 32787 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3354,11 +3354,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 288 utf-check-288-0-94-0.jnk \ -{File "%TEMP%/utf-check-288-0-94-0.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-288-0-94-0.jnk" has 32786 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3370,11 +3370,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 289 utf-check-289-0-94-1.jnk \ -{File "%TEMP%/utf-check-289-0-94-1.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-289-0-94-1.jnk" has 32787 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3386,11 +3386,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 290 utf-check-290-0-95-0.jnk \ -{File "%TEMP%/utf-check-290-0-95-0.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-290-0-95-0.jnk" has 32787 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3402,11 +3402,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 291 utf-check-291-0-95-1.jnk \ -{File "%TEMP%/utf-check-291-0-95-1.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-291-0-95-1.jnk" has 32788 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3418,11 +3418,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 292 utf-check-292-0-96-0.jnk \ -{File "%TEMP%/utf-check-292-0-96-0.jnk" has 8194 bytes. +{File "%TEMP%/utf-check-292-0-96-0.jnk" has 32770 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3434,11 +3434,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 293 utf-check-293-0-96-1.jnk \ -{File "%TEMP%/utf-check-293-0-96-1.jnk" has 8195 bytes. +{File "%TEMP%/utf-check-293-0-96-1.jnk" has 32771 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3450,11 +3450,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 294 utf-check-294-0-97-0.jnk \ -{File "%TEMP%/utf-check-294-0-97-0.jnk" has 8195 bytes. +{File "%TEMP%/utf-check-294-0-97-0.jnk" has 32771 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3466,11 +3466,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 295 utf-check-295-0-97-1.jnk \ -{File "%TEMP%/utf-check-295-0-97-1.jnk" has 8196 bytes. +{File "%TEMP%/utf-check-295-0-97-1.jnk" has 32772 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3482,11 +3482,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 296 utf-check-296-0-98-0.jnk \ -{File "%TEMP%/utf-check-296-0-98-0.jnk" has 8195 bytes. +{File "%TEMP%/utf-check-296-0-98-0.jnk" has 32771 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3498,11 +3498,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 297 utf-check-297-0-98-1.jnk \ -{File "%TEMP%/utf-check-297-0-98-1.jnk" has 8196 bytes. +{File "%TEMP%/utf-check-297-0-98-1.jnk" has 32772 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3514,11 +3514,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 298 utf-check-298-0-99-0.jnk \ -{File "%TEMP%/utf-check-298-0-99-0.jnk" has 8196 bytes. +{File "%TEMP%/utf-check-298-0-99-0.jnk" has 32772 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3530,11 +3530,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 299 utf-check-299-0-99-1.jnk \ -{File "%TEMP%/utf-check-299-0-99-1.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-299-0-99-1.jnk" has 32773 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3546,11 +3546,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 300 utf-check-300-0-100-0.jnk \ -{File "%TEMP%/utf-check-300-0-100-0.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-300-0-100-0.jnk" has 32785 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3562,11 +3562,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 301 utf-check-301-0-100-1.jnk \ -{File "%TEMP%/utf-check-301-0-100-1.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-301-0-100-1.jnk" has 32786 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3578,11 +3578,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 302 utf-check-302-0-101-0.jnk \ -{File "%TEMP%/utf-check-302-0-101-0.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-302-0-101-0.jnk" has 32786 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3594,11 +3594,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 303 utf-check-303-0-101-1.jnk \ -{File "%TEMP%/utf-check-303-0-101-1.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-303-0-101-1.jnk" has 32787 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3610,11 +3610,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 304 utf-check-304-0-102-0.jnk \ -{File "%TEMP%/utf-check-304-0-102-0.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-304-0-102-0.jnk" has 32786 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3626,11 +3626,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 305 utf-check-305-0-102-1.jnk \ -{File "%TEMP%/utf-check-305-0-102-1.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-305-0-102-1.jnk" has 32787 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3642,11 +3642,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 306 utf-check-306-0-103-0.jnk \ -{File "%TEMP%/utf-check-306-0-103-0.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-306-0-103-0.jnk" has 32787 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3658,11 +3658,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 307 utf-check-307-0-103-1.jnk \ -{File "%TEMP%/utf-check-307-0-103-1.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-307-0-103-1.jnk" has 32788 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3674,11 +3674,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 308 utf-check-308-0-104-0.jnk \ -{File "%TEMP%/utf-check-308-0-104-0.jnk" has 8195 bytes. +{File "%TEMP%/utf-check-308-0-104-0.jnk" has 32771 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3690,11 +3690,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 309 utf-check-309-0-104-1.jnk \ -{File "%TEMP%/utf-check-309-0-104-1.jnk" has 8196 bytes. +{File "%TEMP%/utf-check-309-0-104-1.jnk" has 32772 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3706,11 +3706,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 310 utf-check-310-0-105-0.jnk \ -{File "%TEMP%/utf-check-310-0-105-0.jnk" has 8196 bytes. +{File "%TEMP%/utf-check-310-0-105-0.jnk" has 32772 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3722,11 +3722,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 311 utf-check-311-0-105-1.jnk \ -{File "%TEMP%/utf-check-311-0-105-1.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-311-0-105-1.jnk" has 32773 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3738,11 +3738,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 312 utf-check-312-0-106-0.jnk \ -{File "%TEMP%/utf-check-312-0-106-0.jnk" has 8196 bytes. +{File "%TEMP%/utf-check-312-0-106-0.jnk" has 32772 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3754,11 +3754,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 313 utf-check-313-0-106-1.jnk \ -{File "%TEMP%/utf-check-313-0-106-1.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-313-0-106-1.jnk" has 32773 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3770,11 +3770,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 314 utf-check-314-0-107-0.jnk \ -{File "%TEMP%/utf-check-314-0-107-0.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-314-0-107-0.jnk" has 32773 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3786,11 +3786,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 315 utf-check-315-0-107-1.jnk \ -{File "%TEMP%/utf-check-315-0-107-1.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-315-0-107-1.jnk" has 32774 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3802,11 +3802,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 316 utf-check-316-0-108-0.jnk \ -{File "%TEMP%/utf-check-316-0-108-0.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-316-0-108-0.jnk" has 32786 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3818,11 +3818,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 317 utf-check-317-0-108-1.jnk \ -{File "%TEMP%/utf-check-317-0-108-1.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-317-0-108-1.jnk" has 32787 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3834,11 +3834,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 318 utf-check-318-0-109-0.jnk \ -{File "%TEMP%/utf-check-318-0-109-0.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-318-0-109-0.jnk" has 32787 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3850,11 +3850,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 319 utf-check-319-0-109-1.jnk \ -{File "%TEMP%/utf-check-319-0-109-1.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-319-0-109-1.jnk" has 32788 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3866,11 +3866,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 320 utf-check-320-0-110-0.jnk \ -{File "%TEMP%/utf-check-320-0-110-0.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-320-0-110-0.jnk" has 32787 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3882,11 +3882,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 321 utf-check-321-0-110-1.jnk \ -{File "%TEMP%/utf-check-321-0-110-1.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-321-0-110-1.jnk" has 32788 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -3898,11 +3898,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 322 utf-check-322-0-111-0.jnk \ -{File "%TEMP%/utf-check-322-0-111-0.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-322-0-111-0.jnk" has 32788 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -3914,11 +3914,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 323 utf-check-323-0-111-1.jnk \ -{File "%TEMP%/utf-check-323-0-111-1.jnk" has 8201 bytes. +{File "%TEMP%/utf-check-323-0-111-1.jnk" has 32789 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -9466,11 +9466,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 670 utf-check-670-1-80-0.jnk \ -{File "%TEMP%/utf-check-670-1-80-0.jnk" has 8196 bytes. +{File "%TEMP%/utf-check-670-1-80-0.jnk" has 32772 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -9482,11 +9482,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 671 utf-check-671-1-80-1.jnk \ -{File "%TEMP%/utf-check-671-1-80-1.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-671-1-80-1.jnk" has 32773 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -9498,11 +9498,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 672 utf-check-672-1-81-0.jnk \ -{File "%TEMP%/utf-check-672-1-81-0.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-672-1-81-0.jnk" has 32773 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -9514,11 +9514,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 673 utf-check-673-1-81-1.jnk \ -{File "%TEMP%/utf-check-673-1-81-1.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-673-1-81-1.jnk" has 32774 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -9530,11 +9530,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 674 utf-check-674-1-82-0.jnk \ -{File "%TEMP%/utf-check-674-1-82-0.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-674-1-82-0.jnk" has 32773 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -9546,11 +9546,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 675 utf-check-675-1-82-1.jnk \ -{File "%TEMP%/utf-check-675-1-82-1.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-675-1-82-1.jnk" has 32774 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -9562,11 +9562,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 676 utf-check-676-1-83-0.jnk \ -{File "%TEMP%/utf-check-676-1-83-0.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-676-1-83-0.jnk" has 32774 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -9578,11 +9578,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 677 utf-check-677-1-83-1.jnk \ -{File "%TEMP%/utf-check-677-1-83-1.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-677-1-83-1.jnk" has 32775 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -9594,11 +9594,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 678 utf-check-678-1-84-0.jnk \ -{File "%TEMP%/utf-check-678-1-84-0.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-678-1-84-0.jnk" has 32787 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -9610,11 +9610,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 679 utf-check-679-1-84-1.jnk \ -{File "%TEMP%/utf-check-679-1-84-1.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-679-1-84-1.jnk" has 32788 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -9626,11 +9626,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 680 utf-check-680-1-85-0.jnk \ -{File "%TEMP%/utf-check-680-1-85-0.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-680-1-85-0.jnk" has 32788 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -9642,11 +9642,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 681 utf-check-681-1-85-1.jnk \ -{File "%TEMP%/utf-check-681-1-85-1.jnk" has 8201 bytes. +{File "%TEMP%/utf-check-681-1-85-1.jnk" has 32789 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -9658,11 +9658,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 682 utf-check-682-1-86-0.jnk \ -{File "%TEMP%/utf-check-682-1-86-0.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-682-1-86-0.jnk" has 32788 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -9674,11 +9674,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 683 utf-check-683-1-86-1.jnk \ -{File "%TEMP%/utf-check-683-1-86-1.jnk" has 8201 bytes. +{File "%TEMP%/utf-check-683-1-86-1.jnk" has 32789 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -9690,11 +9690,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 684 utf-check-684-1-87-0.jnk \ -{File "%TEMP%/utf-check-684-1-87-0.jnk" has 8201 bytes. +{File "%TEMP%/utf-check-684-1-87-0.jnk" has 32789 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -9706,11 +9706,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 685 utf-check-685-1-87-1.jnk \ -{File "%TEMP%/utf-check-685-1-87-1.jnk" has 8202 bytes. +{File "%TEMP%/utf-check-685-1-87-1.jnk" has 32790 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -9722,11 +9722,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 686 utf-check-686-1-88-0.jnk \ -{File "%TEMP%/utf-check-686-1-88-0.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-686-1-88-0.jnk" has 32773 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -9738,11 +9738,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 687 utf-check-687-1-88-1.jnk \ -{File "%TEMP%/utf-check-687-1-88-1.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-687-1-88-1.jnk" has 32774 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -9754,11 +9754,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 688 utf-check-688-1-89-0.jnk \ -{File "%TEMP%/utf-check-688-1-89-0.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-688-1-89-0.jnk" has 32774 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -9770,11 +9770,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 689 utf-check-689-1-89-1.jnk \ -{File "%TEMP%/utf-check-689-1-89-1.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-689-1-89-1.jnk" has 32775 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -9786,11 +9786,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 690 utf-check-690-1-90-0.jnk \ -{File "%TEMP%/utf-check-690-1-90-0.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-690-1-90-0.jnk" has 32774 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -9802,11 +9802,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 691 utf-check-691-1-90-1.jnk \ -{File "%TEMP%/utf-check-691-1-90-1.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-691-1-90-1.jnk" has 32775 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -9818,11 +9818,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 692 utf-check-692-1-91-0.jnk \ -{File "%TEMP%/utf-check-692-1-91-0.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-692-1-91-0.jnk" has 32775 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -9834,11 +9834,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 693 utf-check-693-1-91-1.jnk \ -{File "%TEMP%/utf-check-693-1-91-1.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-693-1-91-1.jnk" has 32776 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -9850,11 +9850,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 694 utf-check-694-1-92-0.jnk \ -{File "%TEMP%/utf-check-694-1-92-0.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-694-1-92-0.jnk" has 32788 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -9866,11 +9866,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 695 utf-check-695-1-92-1.jnk \ -{File "%TEMP%/utf-check-695-1-92-1.jnk" has 8201 bytes. +{File "%TEMP%/utf-check-695-1-92-1.jnk" has 32789 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -9882,11 +9882,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 696 utf-check-696-1-93-0.jnk \ -{File "%TEMP%/utf-check-696-1-93-0.jnk" has 8201 bytes. +{File "%TEMP%/utf-check-696-1-93-0.jnk" has 32789 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -9898,11 +9898,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 697 utf-check-697-1-93-1.jnk \ -{File "%TEMP%/utf-check-697-1-93-1.jnk" has 8202 bytes. +{File "%TEMP%/utf-check-697-1-93-1.jnk" has 32790 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -9914,11 +9914,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 698 utf-check-698-1-94-0.jnk \ -{File "%TEMP%/utf-check-698-1-94-0.jnk" has 8201 bytes. +{File "%TEMP%/utf-check-698-1-94-0.jnk" has 32789 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -9930,11 +9930,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 699 utf-check-699-1-94-1.jnk \ -{File "%TEMP%/utf-check-699-1-94-1.jnk" has 8202 bytes. +{File "%TEMP%/utf-check-699-1-94-1.jnk" has 32790 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -9946,11 +9946,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 700 utf-check-700-1-95-0.jnk \ -{File "%TEMP%/utf-check-700-1-95-0.jnk" has 8202 bytes. +{File "%TEMP%/utf-check-700-1-95-0.jnk" has 32790 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -9962,11 +9962,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 701 utf-check-701-1-95-1.jnk \ -{File "%TEMP%/utf-check-701-1-95-1.jnk" has 8203 bytes. +{File "%TEMP%/utf-check-701-1-95-1.jnk" has 32791 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -9978,11 +9978,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 702 utf-check-702-1-96-0.jnk \ -{File "%TEMP%/utf-check-702-1-96-0.jnk" has 8197 bytes. +{File "%TEMP%/utf-check-702-1-96-0.jnk" has 32773 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -9994,11 +9994,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 703 utf-check-703-1-96-1.jnk \ -{File "%TEMP%/utf-check-703-1-96-1.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-703-1-96-1.jnk" has 32774 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10010,11 +10010,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 704 utf-check-704-1-97-0.jnk \ -{File "%TEMP%/utf-check-704-1-97-0.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-704-1-97-0.jnk" has 32774 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10026,11 +10026,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 705 utf-check-705-1-97-1.jnk \ -{File "%TEMP%/utf-check-705-1-97-1.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-705-1-97-1.jnk" has 32775 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10042,11 +10042,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 706 utf-check-706-1-98-0.jnk \ -{File "%TEMP%/utf-check-706-1-98-0.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-706-1-98-0.jnk" has 32774 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10058,11 +10058,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 707 utf-check-707-1-98-1.jnk \ -{File "%TEMP%/utf-check-707-1-98-1.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-707-1-98-1.jnk" has 32775 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10074,11 +10074,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 708 utf-check-708-1-99-0.jnk \ -{File "%TEMP%/utf-check-708-1-99-0.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-708-1-99-0.jnk" has 32775 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10090,11 +10090,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 709 utf-check-709-1-99-1.jnk \ -{File "%TEMP%/utf-check-709-1-99-1.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-709-1-99-1.jnk" has 32776 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10106,11 +10106,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 710 utf-check-710-1-100-0.jnk \ -{File "%TEMP%/utf-check-710-1-100-0.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-710-1-100-0.jnk" has 32788 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10122,11 +10122,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 711 utf-check-711-1-100-1.jnk \ -{File "%TEMP%/utf-check-711-1-100-1.jnk" has 8201 bytes. +{File "%TEMP%/utf-check-711-1-100-1.jnk" has 32789 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10138,11 +10138,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 712 utf-check-712-1-101-0.jnk \ -{File "%TEMP%/utf-check-712-1-101-0.jnk" has 8201 bytes. +{File "%TEMP%/utf-check-712-1-101-0.jnk" has 32789 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10154,11 +10154,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 713 utf-check-713-1-101-1.jnk \ -{File "%TEMP%/utf-check-713-1-101-1.jnk" has 8202 bytes. +{File "%TEMP%/utf-check-713-1-101-1.jnk" has 32790 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10170,11 +10170,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 714 utf-check-714-1-102-0.jnk \ -{File "%TEMP%/utf-check-714-1-102-0.jnk" has 8201 bytes. +{File "%TEMP%/utf-check-714-1-102-0.jnk" has 32789 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10186,11 +10186,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 715 utf-check-715-1-102-1.jnk \ -{File "%TEMP%/utf-check-715-1-102-1.jnk" has 8202 bytes. +{File "%TEMP%/utf-check-715-1-102-1.jnk" has 32790 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10202,11 +10202,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 716 utf-check-716-1-103-0.jnk \ -{File "%TEMP%/utf-check-716-1-103-0.jnk" has 8202 bytes. +{File "%TEMP%/utf-check-716-1-103-0.jnk" has 32790 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10218,11 +10218,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 717 utf-check-717-1-103-1.jnk \ -{File "%TEMP%/utf-check-717-1-103-1.jnk" has 8203 bytes. +{File "%TEMP%/utf-check-717-1-103-1.jnk" has 32791 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10234,11 +10234,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 718 utf-check-718-1-104-0.jnk \ -{File "%TEMP%/utf-check-718-1-104-0.jnk" has 8198 bytes. +{File "%TEMP%/utf-check-718-1-104-0.jnk" has 32774 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10250,11 +10250,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 719 utf-check-719-1-104-1.jnk \ -{File "%TEMP%/utf-check-719-1-104-1.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-719-1-104-1.jnk" has 32775 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10266,11 +10266,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 720 utf-check-720-1-105-0.jnk \ -{File "%TEMP%/utf-check-720-1-105-0.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-720-1-105-0.jnk" has 32775 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10282,11 +10282,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 721 utf-check-721-1-105-1.jnk \ -{File "%TEMP%/utf-check-721-1-105-1.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-721-1-105-1.jnk" has 32776 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10298,11 +10298,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 722 utf-check-722-1-106-0.jnk \ -{File "%TEMP%/utf-check-722-1-106-0.jnk" has 8199 bytes. +{File "%TEMP%/utf-check-722-1-106-0.jnk" has 32775 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10314,11 +10314,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 723 utf-check-723-1-106-1.jnk \ -{File "%TEMP%/utf-check-723-1-106-1.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-723-1-106-1.jnk" has 32776 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10330,11 +10330,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 724 utf-check-724-1-107-0.jnk \ -{File "%TEMP%/utf-check-724-1-107-0.jnk" has 8200 bytes. +{File "%TEMP%/utf-check-724-1-107-0.jnk" has 32776 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10346,11 +10346,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 725 utf-check-725-1-107-1.jnk \ -{File "%TEMP%/utf-check-725-1-107-1.jnk" has 8201 bytes. +{File "%TEMP%/utf-check-725-1-107-1.jnk" has 32777 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10362,11 +10362,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 726 utf-check-726-1-108-0.jnk \ -{File "%TEMP%/utf-check-726-1-108-0.jnk" has 8201 bytes. +{File "%TEMP%/utf-check-726-1-108-0.jnk" has 32789 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10378,11 +10378,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 727 utf-check-727-1-108-1.jnk \ -{File "%TEMP%/utf-check-727-1-108-1.jnk" has 8202 bytes. +{File "%TEMP%/utf-check-727-1-108-1.jnk" has 32790 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10394,11 +10394,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 728 utf-check-728-1-109-0.jnk \ -{File "%TEMP%/utf-check-728-1-109-0.jnk" has 8202 bytes. +{File "%TEMP%/utf-check-728-1-109-0.jnk" has 32790 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10410,11 +10410,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 729 utf-check-729-1-109-1.jnk \ -{File "%TEMP%/utf-check-729-1-109-1.jnk" has 8203 bytes. +{File "%TEMP%/utf-check-729-1-109-1.jnk" has 32791 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10426,11 +10426,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 730 utf-check-730-1-110-0.jnk \ -{File "%TEMP%/utf-check-730-1-110-0.jnk" has 8202 bytes. +{File "%TEMP%/utf-check-730-1-110-0.jnk" has 32790 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10442,11 +10442,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 731 utf-check-731-1-110-1.jnk \ -{File "%TEMP%/utf-check-731-1-110-1.jnk" has 8203 bytes. +{File "%TEMP%/utf-check-731-1-110-1.jnk" has 32791 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -10458,11 +10458,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 732 utf-check-732-1-111-0.jnk \ -{File "%TEMP%/utf-check-732-1-111-0.jnk" has 8203 bytes. +{File "%TEMP%/utf-check-732-1-111-0.jnk" has 32791 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -10474,11 +10474,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 733 utf-check-733-1-111-1.jnk \ -{File "%TEMP%/utf-check-733-1-111-1.jnk" has 8204 bytes. +{File "%TEMP%/utf-check-733-1-111-1.jnk" has 32792 bytes. Starts with UTF-8 BOM: yes Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16026,11 +16026,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1080 utf-check-1080-2-80-0.jnk \ -{File "%TEMP%/utf-check-1080-2-80-0.jnk" has 16388 bytes. +{File "%TEMP%/utf-check-1080-2-80-0.jnk" has 65540 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -16042,11 +16042,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1081 utf-check-1081-2-80-1.jnk \ -{File "%TEMP%/utf-check-1081-2-80-1.jnk" has 16389 bytes. +{File "%TEMP%/utf-check-1081-2-80-1.jnk" has 65541 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16058,11 +16058,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1082 utf-check-1082-2-81-0.jnk \ -{File "%TEMP%/utf-check-1082-2-81-0.jnk" has 16390 bytes. +{File "%TEMP%/utf-check-1082-2-81-0.jnk" has 65542 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -16074,11 +16074,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1083 utf-check-1083-2-81-1.jnk \ -{File "%TEMP%/utf-check-1083-2-81-1.jnk" has 16391 bytes. +{File "%TEMP%/utf-check-1083-2-81-1.jnk" has 65543 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16090,11 +16090,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1084 utf-check-1084-2-82-0.jnk \ -{File "%TEMP%/utf-check-1084-2-82-0.jnk" has 16390 bytes. +{File "%TEMP%/utf-check-1084-2-82-0.jnk" has 65542 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -16106,11 +16106,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1085 utf-check-1085-2-82-1.jnk \ -{File "%TEMP%/utf-check-1085-2-82-1.jnk" has 16391 bytes. +{File "%TEMP%/utf-check-1085-2-82-1.jnk" has 65543 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16122,11 +16122,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1086 utf-check-1086-2-83-0.jnk \ -{File "%TEMP%/utf-check-1086-2-83-0.jnk" has 16392 bytes. +{File "%TEMP%/utf-check-1086-2-83-0.jnk" has 65544 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -16138,11 +16138,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1087 utf-check-1087-2-83-1.jnk \ -{File "%TEMP%/utf-check-1087-2-83-1.jnk" has 16393 bytes. +{File "%TEMP%/utf-check-1087-2-83-1.jnk" has 65545 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16154,11 +16154,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1088 utf-check-1088-2-84-0.jnk \ -{File "%TEMP%/utf-check-1088-2-84-0.jnk" has 16394 bytes. +{File "%TEMP%/utf-check-1088-2-84-0.jnk" has 65570 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -16170,11 +16170,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1089 utf-check-1089-2-84-1.jnk \ -{File "%TEMP%/utf-check-1089-2-84-1.jnk" has 16395 bytes. +{File "%TEMP%/utf-check-1089-2-84-1.jnk" has 65571 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16186,11 +16186,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1090 utf-check-1090-2-85-0.jnk \ -{File "%TEMP%/utf-check-1090-2-85-0.jnk" has 16396 bytes. +{File "%TEMP%/utf-check-1090-2-85-0.jnk" has 65572 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -16202,11 +16202,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1091 utf-check-1091-2-85-1.jnk \ -{File "%TEMP%/utf-check-1091-2-85-1.jnk" has 16397 bytes. +{File "%TEMP%/utf-check-1091-2-85-1.jnk" has 65573 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16218,11 +16218,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1092 utf-check-1092-2-86-0.jnk \ -{File "%TEMP%/utf-check-1092-2-86-0.jnk" has 16396 bytes. +{File "%TEMP%/utf-check-1092-2-86-0.jnk" has 65572 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: no @@ -16234,11 +16234,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1093 utf-check-1093-2-86-1.jnk \ -{File "%TEMP%/utf-check-1093-2-86-1.jnk" has 16397 bytes. +{File "%TEMP%/utf-check-1093-2-86-1.jnk" has 65573 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16250,11 +16250,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1094 utf-check-1094-2-87-0.jnk \ -{File "%TEMP%/utf-check-1094-2-87-0.jnk" has 16398 bytes. +{File "%TEMP%/utf-check-1094-2-87-0.jnk" has 65574 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: no Has flag LOOK_CR: yes @@ -16266,11 +16266,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1095 utf-check-1095-2-87-1.jnk \ -{File "%TEMP%/utf-check-1095-2-87-1.jnk" has 16399 bytes. +{File "%TEMP%/utf-check-1095-2-87-1.jnk" has 65575 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16282,11 +16282,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1096 utf-check-1096-2-88-0.jnk \ -{File "%TEMP%/utf-check-1096-2-88-0.jnk" has 16390 bytes. +{File "%TEMP%/utf-check-1096-2-88-0.jnk" has 65542 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16298,11 +16298,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1097 utf-check-1097-2-88-1.jnk \ -{File "%TEMP%/utf-check-1097-2-88-1.jnk" has 16391 bytes. +{File "%TEMP%/utf-check-1097-2-88-1.jnk" has 65543 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16314,11 +16314,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1098 utf-check-1098-2-89-0.jnk \ -{File "%TEMP%/utf-check-1098-2-89-0.jnk" has 16392 bytes. +{File "%TEMP%/utf-check-1098-2-89-0.jnk" has 65544 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16330,11 +16330,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1099 utf-check-1099-2-89-1.jnk \ -{File "%TEMP%/utf-check-1099-2-89-1.jnk" has 16393 bytes. +{File "%TEMP%/utf-check-1099-2-89-1.jnk" has 65545 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16346,11 +16346,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1100 utf-check-1100-2-90-0.jnk \ -{File "%TEMP%/utf-check-1100-2-90-0.jnk" has 16392 bytes. +{File "%TEMP%/utf-check-1100-2-90-0.jnk" has 65544 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16362,11 +16362,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1101 utf-check-1101-2-90-1.jnk \ -{File "%TEMP%/utf-check-1101-2-90-1.jnk" has 16393 bytes. +{File "%TEMP%/utf-check-1101-2-90-1.jnk" has 65545 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16378,11 +16378,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1102 utf-check-1102-2-91-0.jnk \ -{File "%TEMP%/utf-check-1102-2-91-0.jnk" has 16394 bytes. +{File "%TEMP%/utf-check-1102-2-91-0.jnk" has 65546 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16394,11 +16394,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1103 utf-check-1103-2-91-1.jnk \ -{File "%TEMP%/utf-check-1103-2-91-1.jnk" has 16395 bytes. +{File "%TEMP%/utf-check-1103-2-91-1.jnk" has 65547 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16410,11 +16410,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1104 utf-check-1104-2-92-0.jnk \ -{File "%TEMP%/utf-check-1104-2-92-0.jnk" has 16396 bytes. +{File "%TEMP%/utf-check-1104-2-92-0.jnk" has 65572 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16426,11 +16426,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1105 utf-check-1105-2-92-1.jnk \ -{File "%TEMP%/utf-check-1105-2-92-1.jnk" has 16397 bytes. +{File "%TEMP%/utf-check-1105-2-92-1.jnk" has 65573 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16442,11 +16442,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1106 utf-check-1106-2-93-0.jnk \ -{File "%TEMP%/utf-check-1106-2-93-0.jnk" has 16398 bytes. +{File "%TEMP%/utf-check-1106-2-93-0.jnk" has 65574 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16458,11 +16458,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1107 utf-check-1107-2-93-1.jnk \ -{File "%TEMP%/utf-check-1107-2-93-1.jnk" has 16399 bytes. +{File "%TEMP%/utf-check-1107-2-93-1.jnk" has 65575 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16474,11 +16474,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1108 utf-check-1108-2-94-0.jnk \ -{File "%TEMP%/utf-check-1108-2-94-0.jnk" has 16398 bytes. +{File "%TEMP%/utf-check-1108-2-94-0.jnk" has 65574 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16490,11 +16490,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1109 utf-check-1109-2-94-1.jnk \ -{File "%TEMP%/utf-check-1109-2-94-1.jnk" has 16399 bytes. +{File "%TEMP%/utf-check-1109-2-94-1.jnk" has 65575 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16506,11 +16506,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1110 utf-check-1110-2-95-0.jnk \ -{File "%TEMP%/utf-check-1110-2-95-0.jnk" has 16400 bytes. +{File "%TEMP%/utf-check-1110-2-95-0.jnk" has 65576 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16522,11 +16522,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1111 utf-check-1111-2-95-1.jnk \ -{File "%TEMP%/utf-check-1111-2-95-1.jnk" has 16401 bytes. +{File "%TEMP%/utf-check-1111-2-95-1.jnk" has 65577 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16538,11 +16538,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1112 utf-check-1112-2-96-0.jnk \ -{File "%TEMP%/utf-check-1112-2-96-0.jnk" has 16390 bytes. +{File "%TEMP%/utf-check-1112-2-96-0.jnk" has 65542 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16554,11 +16554,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1113 utf-check-1113-2-96-1.jnk \ -{File "%TEMP%/utf-check-1113-2-96-1.jnk" has 16391 bytes. +{File "%TEMP%/utf-check-1113-2-96-1.jnk" has 65543 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16570,11 +16570,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1114 utf-check-1114-2-97-0.jnk \ -{File "%TEMP%/utf-check-1114-2-97-0.jnk" has 16392 bytes. +{File "%TEMP%/utf-check-1114-2-97-0.jnk" has 65544 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16586,11 +16586,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1115 utf-check-1115-2-97-1.jnk \ -{File "%TEMP%/utf-check-1115-2-97-1.jnk" has 16393 bytes. +{File "%TEMP%/utf-check-1115-2-97-1.jnk" has 65545 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16602,11 +16602,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1116 utf-check-1116-2-98-0.jnk \ -{File "%TEMP%/utf-check-1116-2-98-0.jnk" has 16392 bytes. +{File "%TEMP%/utf-check-1116-2-98-0.jnk" has 65544 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16618,11 +16618,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1117 utf-check-1117-2-98-1.jnk \ -{File "%TEMP%/utf-check-1117-2-98-1.jnk" has 16393 bytes. +{File "%TEMP%/utf-check-1117-2-98-1.jnk" has 65545 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16634,11 +16634,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1118 utf-check-1118-2-99-0.jnk \ -{File "%TEMP%/utf-check-1118-2-99-0.jnk" has 16394 bytes. +{File "%TEMP%/utf-check-1118-2-99-0.jnk" has 65546 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16650,11 +16650,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1119 utf-check-1119-2-99-1.jnk \ -{File "%TEMP%/utf-check-1119-2-99-1.jnk" has 16395 bytes. +{File "%TEMP%/utf-check-1119-2-99-1.jnk" has 65547 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16666,11 +16666,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1120 utf-check-1120-2-100-0.jnk \ -{File "%TEMP%/utf-check-1120-2-100-0.jnk" has 16396 bytes. +{File "%TEMP%/utf-check-1120-2-100-0.jnk" has 65572 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16682,11 +16682,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1121 utf-check-1121-2-100-1.jnk \ -{File "%TEMP%/utf-check-1121-2-100-1.jnk" has 16397 bytes. +{File "%TEMP%/utf-check-1121-2-100-1.jnk" has 65573 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16698,11 +16698,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1122 utf-check-1122-2-101-0.jnk \ -{File "%TEMP%/utf-check-1122-2-101-0.jnk" has 16398 bytes. +{File "%TEMP%/utf-check-1122-2-101-0.jnk" has 65574 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16714,11 +16714,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1123 utf-check-1123-2-101-1.jnk \ -{File "%TEMP%/utf-check-1123-2-101-1.jnk" has 16399 bytes. +{File "%TEMP%/utf-check-1123-2-101-1.jnk" has 65575 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16730,11 +16730,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1124 utf-check-1124-2-102-0.jnk \ -{File "%TEMP%/utf-check-1124-2-102-0.jnk" has 16398 bytes. +{File "%TEMP%/utf-check-1124-2-102-0.jnk" has 65574 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16746,11 +16746,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1125 utf-check-1125-2-102-1.jnk \ -{File "%TEMP%/utf-check-1125-2-102-1.jnk" has 16399 bytes. +{File "%TEMP%/utf-check-1125-2-102-1.jnk" has 65575 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16762,11 +16762,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1126 utf-check-1126-2-103-0.jnk \ -{File "%TEMP%/utf-check-1126-2-103-0.jnk" has 16400 bytes. +{File "%TEMP%/utf-check-1126-2-103-0.jnk" has 65576 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-16: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16778,11 +16778,11 @@ Has flag LOOK_INVALID: no Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1127 utf-check-1127-2-103-1.jnk \ -{File "%TEMP%/utf-check-1127-2-103-1.jnk" has 16401 bytes. +{File "%TEMP%/utf-check-1127-2-103-1.jnk" has 65577 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: yes Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16794,11 +16794,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1128 utf-check-1128-2-104-0.jnk \ -{File "%TEMP%/utf-check-1128-2-104-0.jnk" has 16392 bytes. +{File "%TEMP%/utf-check-1128-2-104-0.jnk" has 65544 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16810,11 +16810,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1129 utf-check-1129-2-104-1.jnk \ -{File "%TEMP%/utf-check-1129-2-104-1.jnk" has 16393 bytes. +{File "%TEMP%/utf-check-1129-2-104-1.jnk" has 65545 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16826,11 +16826,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1130 utf-check-1130-2-105-0.jnk \ -{File "%TEMP%/utf-check-1130-2-105-0.jnk" has 16394 bytes. +{File "%TEMP%/utf-check-1130-2-105-0.jnk" has 65546 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16842,11 +16842,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1131 utf-check-1131-2-105-1.jnk \ -{File "%TEMP%/utf-check-1131-2-105-1.jnk" has 16395 bytes. +{File "%TEMP%/utf-check-1131-2-105-1.jnk" has 65547 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16858,11 +16858,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1132 utf-check-1132-2-106-0.jnk \ -{File "%TEMP%/utf-check-1132-2-106-0.jnk" has 16394 bytes. +{File "%TEMP%/utf-check-1132-2-106-0.jnk" has 65546 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16874,11 +16874,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1133 utf-check-1133-2-106-1.jnk \ -{File "%TEMP%/utf-check-1133-2-106-1.jnk" has 16395 bytes. +{File "%TEMP%/utf-check-1133-2-106-1.jnk" has 65547 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16890,11 +16890,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1134 utf-check-1134-2-107-0.jnk \ -{File "%TEMP%/utf-check-1134-2-107-0.jnk" has 16396 bytes. +{File "%TEMP%/utf-check-1134-2-107-0.jnk" has 65548 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16906,11 +16906,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1135 utf-check-1135-2-107-1.jnk \ -{File "%TEMP%/utf-check-1135-2-107-1.jnk" has 16397 bytes. +{File "%TEMP%/utf-check-1135-2-107-1.jnk" has 65549 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16922,11 +16922,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1136 utf-check-1136-2-108-0.jnk \ -{File "%TEMP%/utf-check-1136-2-108-0.jnk" has 16398 bytes. +{File "%TEMP%/utf-check-1136-2-108-0.jnk" has 65574 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16938,11 +16938,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1137 utf-check-1137-2-108-1.jnk \ -{File "%TEMP%/utf-check-1137-2-108-1.jnk" has 16399 bytes. +{File "%TEMP%/utf-check-1137-2-108-1.jnk" has 65575 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -16954,11 +16954,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1138 utf-check-1138-2-109-0.jnk \ -{File "%TEMP%/utf-check-1138-2-109-0.jnk" has 16400 bytes. +{File "%TEMP%/utf-check-1138-2-109-0.jnk" has 65576 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16970,11 +16970,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1139 utf-check-1139-2-109-1.jnk \ -{File "%TEMP%/utf-check-1139-2-109-1.jnk" has 16401 bytes. +{File "%TEMP%/utf-check-1139-2-109-1.jnk" has 65577 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -16986,11 +16986,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1140 utf-check-1140-2-110-0.jnk \ -{File "%TEMP%/utf-check-1140-2-110-0.jnk" has 16400 bytes. +{File "%TEMP%/utf-check-1140-2-110-0.jnk" has 65576 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -17002,11 +17002,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1141 utf-check-1141-2-110-1.jnk \ -{File "%TEMP%/utf-check-1141-2-110-1.jnk" has 16401 bytes. +{File "%TEMP%/utf-check-1141-2-110-1.jnk" has 65577 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -17018,11 +17018,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1142 utf-check-1142-2-111-0.jnk \ -{File "%TEMP%/utf-check-1142-2-111-0.jnk" has 16402 bytes. +{File "%TEMP%/utf-check-1142-2-111-0.jnk" has 65578 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -17034,11 +17034,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1143 utf-check-1143-2-111-1.jnk \ -{File "%TEMP%/utf-check-1143-2-111-1.jnk" has 16403 bytes. +{File "%TEMP%/utf-check-1143-2-111-1.jnk" has 65579 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: yes @@ -22586,11 +22586,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1490 utf-check-1490-3-80-0.jnk \ -{File "%TEMP%/utf-check-1490-3-80-0.jnk" has 16388 bytes. +{File "%TEMP%/utf-check-1490-3-80-0.jnk" has 65540 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22602,11 +22602,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1491 utf-check-1491-3-80-1.jnk \ -{File "%TEMP%/utf-check-1491-3-80-1.jnk" has 16389 bytes. +{File "%TEMP%/utf-check-1491-3-80-1.jnk" has 65541 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22618,11 +22618,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1492 utf-check-1492-3-81-0.jnk \ -{File "%TEMP%/utf-check-1492-3-81-0.jnk" has 16390 bytes. +{File "%TEMP%/utf-check-1492-3-81-0.jnk" has 65542 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22634,11 +22634,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1493 utf-check-1493-3-81-1.jnk \ -{File "%TEMP%/utf-check-1493-3-81-1.jnk" has 16391 bytes. +{File "%TEMP%/utf-check-1493-3-81-1.jnk" has 65543 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22650,11 +22650,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1494 utf-check-1494-3-82-0.jnk \ -{File "%TEMP%/utf-check-1494-3-82-0.jnk" has 16390 bytes. +{File "%TEMP%/utf-check-1494-3-82-0.jnk" has 65542 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22666,11 +22666,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1495 utf-check-1495-3-82-1.jnk \ -{File "%TEMP%/utf-check-1495-3-82-1.jnk" has 16391 bytes. +{File "%TEMP%/utf-check-1495-3-82-1.jnk" has 65543 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22682,11 +22682,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1496 utf-check-1496-3-83-0.jnk \ -{File "%TEMP%/utf-check-1496-3-83-0.jnk" has 16392 bytes. +{File "%TEMP%/utf-check-1496-3-83-0.jnk" has 65544 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22698,11 +22698,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1497 utf-check-1497-3-83-1.jnk \ -{File "%TEMP%/utf-check-1497-3-83-1.jnk" has 16393 bytes. +{File "%TEMP%/utf-check-1497-3-83-1.jnk" has 65545 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22714,11 +22714,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1498 utf-check-1498-3-84-0.jnk \ -{File "%TEMP%/utf-check-1498-3-84-0.jnk" has 16394 bytes. +{File "%TEMP%/utf-check-1498-3-84-0.jnk" has 65570 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22730,11 +22730,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1499 utf-check-1499-3-84-1.jnk \ -{File "%TEMP%/utf-check-1499-3-84-1.jnk" has 16395 bytes. +{File "%TEMP%/utf-check-1499-3-84-1.jnk" has 65571 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22746,11 +22746,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1500 utf-check-1500-3-85-0.jnk \ -{File "%TEMP%/utf-check-1500-3-85-0.jnk" has 16396 bytes. +{File "%TEMP%/utf-check-1500-3-85-0.jnk" has 65572 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22762,11 +22762,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1501 utf-check-1501-3-85-1.jnk \ -{File "%TEMP%/utf-check-1501-3-85-1.jnk" has 16397 bytes. +{File "%TEMP%/utf-check-1501-3-85-1.jnk" has 65573 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22778,11 +22778,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1502 utf-check-1502-3-86-0.jnk \ -{File "%TEMP%/utf-check-1502-3-86-0.jnk" has 16396 bytes. +{File "%TEMP%/utf-check-1502-3-86-0.jnk" has 65572 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22794,11 +22794,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1503 utf-check-1503-3-86-1.jnk \ -{File "%TEMP%/utf-check-1503-3-86-1.jnk" has 16397 bytes. +{File "%TEMP%/utf-check-1503-3-86-1.jnk" has 65573 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22810,11 +22810,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1504 utf-check-1504-3-87-0.jnk \ -{File "%TEMP%/utf-check-1504-3-87-0.jnk" has 16398 bytes. +{File "%TEMP%/utf-check-1504-3-87-0.jnk" has 65574 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22826,11 +22826,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1505 utf-check-1505-3-87-1.jnk \ -{File "%TEMP%/utf-check-1505-3-87-1.jnk" has 16399 bytes. +{File "%TEMP%/utf-check-1505-3-87-1.jnk" has 65575 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22842,11 +22842,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1506 utf-check-1506-3-88-0.jnk \ -{File "%TEMP%/utf-check-1506-3-88-0.jnk" has 16390 bytes. +{File "%TEMP%/utf-check-1506-3-88-0.jnk" has 65542 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22858,11 +22858,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1507 utf-check-1507-3-88-1.jnk \ -{File "%TEMP%/utf-check-1507-3-88-1.jnk" has 16391 bytes. +{File "%TEMP%/utf-check-1507-3-88-1.jnk" has 65543 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22874,11 +22874,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1508 utf-check-1508-3-89-0.jnk \ -{File "%TEMP%/utf-check-1508-3-89-0.jnk" has 16392 bytes. +{File "%TEMP%/utf-check-1508-3-89-0.jnk" has 65544 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22890,11 +22890,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1509 utf-check-1509-3-89-1.jnk \ -{File "%TEMP%/utf-check-1509-3-89-1.jnk" has 16393 bytes. +{File "%TEMP%/utf-check-1509-3-89-1.jnk" has 65545 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22906,11 +22906,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1510 utf-check-1510-3-90-0.jnk \ -{File "%TEMP%/utf-check-1510-3-90-0.jnk" has 16392 bytes. +{File "%TEMP%/utf-check-1510-3-90-0.jnk" has 65544 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22922,11 +22922,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1511 utf-check-1511-3-90-1.jnk \ -{File "%TEMP%/utf-check-1511-3-90-1.jnk" has 16393 bytes. +{File "%TEMP%/utf-check-1511-3-90-1.jnk" has 65545 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22938,11 +22938,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1512 utf-check-1512-3-91-0.jnk \ -{File "%TEMP%/utf-check-1512-3-91-0.jnk" has 16394 bytes. +{File "%TEMP%/utf-check-1512-3-91-0.jnk" has 65546 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22954,11 +22954,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1513 utf-check-1513-3-91-1.jnk \ -{File "%TEMP%/utf-check-1513-3-91-1.jnk" has 16395 bytes. +{File "%TEMP%/utf-check-1513-3-91-1.jnk" has 65547 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22970,11 +22970,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1514 utf-check-1514-3-92-0.jnk \ -{File "%TEMP%/utf-check-1514-3-92-0.jnk" has 16396 bytes. +{File "%TEMP%/utf-check-1514-3-92-0.jnk" has 65572 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -22986,11 +22986,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1515 utf-check-1515-3-92-1.jnk \ -{File "%TEMP%/utf-check-1515-3-92-1.jnk" has 16397 bytes. +{File "%TEMP%/utf-check-1515-3-92-1.jnk" has 65573 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23002,11 +23002,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1516 utf-check-1516-3-93-0.jnk \ -{File "%TEMP%/utf-check-1516-3-93-0.jnk" has 16398 bytes. +{File "%TEMP%/utf-check-1516-3-93-0.jnk" has 65574 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23018,11 +23018,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1517 utf-check-1517-3-93-1.jnk \ -{File "%TEMP%/utf-check-1517-3-93-1.jnk" has 16399 bytes. +{File "%TEMP%/utf-check-1517-3-93-1.jnk" has 65575 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23034,11 +23034,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1518 utf-check-1518-3-94-0.jnk \ -{File "%TEMP%/utf-check-1518-3-94-0.jnk" has 16398 bytes. +{File "%TEMP%/utf-check-1518-3-94-0.jnk" has 65574 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23050,11 +23050,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1519 utf-check-1519-3-94-1.jnk \ -{File "%TEMP%/utf-check-1519-3-94-1.jnk" has 16399 bytes. +{File "%TEMP%/utf-check-1519-3-94-1.jnk" has 65575 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23066,11 +23066,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1520 utf-check-1520-3-95-0.jnk \ -{File "%TEMP%/utf-check-1520-3-95-0.jnk" has 16400 bytes. +{File "%TEMP%/utf-check-1520-3-95-0.jnk" has 65576 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23082,11 +23082,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1521 utf-check-1521-3-95-1.jnk \ -{File "%TEMP%/utf-check-1521-3-95-1.jnk" has 16401 bytes. +{File "%TEMP%/utf-check-1521-3-95-1.jnk" has 65577 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23098,11 +23098,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1522 utf-check-1522-3-96-0.jnk \ -{File "%TEMP%/utf-check-1522-3-96-0.jnk" has 16390 bytes. +{File "%TEMP%/utf-check-1522-3-96-0.jnk" has 65542 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23114,11 +23114,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1523 utf-check-1523-3-96-1.jnk \ -{File "%TEMP%/utf-check-1523-3-96-1.jnk" has 16391 bytes. +{File "%TEMP%/utf-check-1523-3-96-1.jnk" has 65543 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23130,11 +23130,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1524 utf-check-1524-3-97-0.jnk \ -{File "%TEMP%/utf-check-1524-3-97-0.jnk" has 16392 bytes. +{File "%TEMP%/utf-check-1524-3-97-0.jnk" has 65544 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23146,11 +23146,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1525 utf-check-1525-3-97-1.jnk \ -{File "%TEMP%/utf-check-1525-3-97-1.jnk" has 16393 bytes. +{File "%TEMP%/utf-check-1525-3-97-1.jnk" has 65545 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23162,11 +23162,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1526 utf-check-1526-3-98-0.jnk \ -{File "%TEMP%/utf-check-1526-3-98-0.jnk" has 16392 bytes. +{File "%TEMP%/utf-check-1526-3-98-0.jnk" has 65544 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23178,11 +23178,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1527 utf-check-1527-3-98-1.jnk \ -{File "%TEMP%/utf-check-1527-3-98-1.jnk" has 16393 bytes. +{File "%TEMP%/utf-check-1527-3-98-1.jnk" has 65545 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23194,11 +23194,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1528 utf-check-1528-3-99-0.jnk \ -{File "%TEMP%/utf-check-1528-3-99-0.jnk" has 16394 bytes. +{File "%TEMP%/utf-check-1528-3-99-0.jnk" has 65546 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23210,11 +23210,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1529 utf-check-1529-3-99-1.jnk \ -{File "%TEMP%/utf-check-1529-3-99-1.jnk" has 16395 bytes. +{File "%TEMP%/utf-check-1529-3-99-1.jnk" has 65547 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23226,11 +23226,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1530 utf-check-1530-3-100-0.jnk \ -{File "%TEMP%/utf-check-1530-3-100-0.jnk" has 16396 bytes. +{File "%TEMP%/utf-check-1530-3-100-0.jnk" has 65572 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23242,11 +23242,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1531 utf-check-1531-3-100-1.jnk \ -{File "%TEMP%/utf-check-1531-3-100-1.jnk" has 16397 bytes. +{File "%TEMP%/utf-check-1531-3-100-1.jnk" has 65573 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23258,11 +23258,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1532 utf-check-1532-3-101-0.jnk \ -{File "%TEMP%/utf-check-1532-3-101-0.jnk" has 16398 bytes. +{File "%TEMP%/utf-check-1532-3-101-0.jnk" has 65574 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23274,11 +23274,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1533 utf-check-1533-3-101-1.jnk \ -{File "%TEMP%/utf-check-1533-3-101-1.jnk" has 16399 bytes. +{File "%TEMP%/utf-check-1533-3-101-1.jnk" has 65575 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23290,11 +23290,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1534 utf-check-1534-3-102-0.jnk \ -{File "%TEMP%/utf-check-1534-3-102-0.jnk" has 16398 bytes. +{File "%TEMP%/utf-check-1534-3-102-0.jnk" has 65574 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23306,11 +23306,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1535 utf-check-1535-3-102-1.jnk \ -{File "%TEMP%/utf-check-1535-3-102-1.jnk" has 16399 bytes. +{File "%TEMP%/utf-check-1535-3-102-1.jnk" has 65575 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23322,11 +23322,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1536 utf-check-1536-3-103-0.jnk \ -{File "%TEMP%/utf-check-1536-3-103-0.jnk" has 16400 bytes. +{File "%TEMP%/utf-check-1536-3-103-0.jnk" has 65576 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23338,11 +23338,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1537 utf-check-1537-3-103-1.jnk \ -{File "%TEMP%/utf-check-1537-3-103-1.jnk" has 16401 bytes. +{File "%TEMP%/utf-check-1537-3-103-1.jnk" has 65577 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23354,11 +23354,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1538 utf-check-1538-3-104-0.jnk \ -{File "%TEMP%/utf-check-1538-3-104-0.jnk" has 16392 bytes. +{File "%TEMP%/utf-check-1538-3-104-0.jnk" has 65544 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23370,11 +23370,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1539 utf-check-1539-3-104-1.jnk \ -{File "%TEMP%/utf-check-1539-3-104-1.jnk" has 16393 bytes. +{File "%TEMP%/utf-check-1539-3-104-1.jnk" has 65545 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23386,11 +23386,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1540 utf-check-1540-3-105-0.jnk \ -{File "%TEMP%/utf-check-1540-3-105-0.jnk" has 16394 bytes. +{File "%TEMP%/utf-check-1540-3-105-0.jnk" has 65546 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23402,11 +23402,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1541 utf-check-1541-3-105-1.jnk \ -{File "%TEMP%/utf-check-1541-3-105-1.jnk" has 16395 bytes. +{File "%TEMP%/utf-check-1541-3-105-1.jnk" has 65547 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23418,11 +23418,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1542 utf-check-1542-3-106-0.jnk \ -{File "%TEMP%/utf-check-1542-3-106-0.jnk" has 16394 bytes. +{File "%TEMP%/utf-check-1542-3-106-0.jnk" has 65546 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23434,11 +23434,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1543 utf-check-1543-3-106-1.jnk \ -{File "%TEMP%/utf-check-1543-3-106-1.jnk" has 16395 bytes. +{File "%TEMP%/utf-check-1543-3-106-1.jnk" has 65547 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23450,11 +23450,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1544 utf-check-1544-3-107-0.jnk \ -{File "%TEMP%/utf-check-1544-3-107-0.jnk" has 16396 bytes. +{File "%TEMP%/utf-check-1544-3-107-0.jnk" has 65548 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23466,11 +23466,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1545 utf-check-1545-3-107-1.jnk \ -{File "%TEMP%/utf-check-1545-3-107-1.jnk" has 16397 bytes. +{File "%TEMP%/utf-check-1545-3-107-1.jnk" has 65549 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23482,11 +23482,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1546 utf-check-1546-3-108-0.jnk \ -{File "%TEMP%/utf-check-1546-3-108-0.jnk" has 16398 bytes. +{File "%TEMP%/utf-check-1546-3-108-0.jnk" has 65574 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23498,11 +23498,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1547 utf-check-1547-3-108-1.jnk \ -{File "%TEMP%/utf-check-1547-3-108-1.jnk" has 16399 bytes. +{File "%TEMP%/utf-check-1547-3-108-1.jnk" has 65575 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23514,11 +23514,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1548 utf-check-1548-3-109-0.jnk \ -{File "%TEMP%/utf-check-1548-3-109-0.jnk" has 16400 bytes. +{File "%TEMP%/utf-check-1548-3-109-0.jnk" has 65576 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23530,11 +23530,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1549 utf-check-1549-3-109-1.jnk \ -{File "%TEMP%/utf-check-1549-3-109-1.jnk" has 16401 bytes. +{File "%TEMP%/utf-check-1549-3-109-1.jnk" has 65577 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23546,11 +23546,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1550 utf-check-1550-3-110-0.jnk \ -{File "%TEMP%/utf-check-1550-3-110-0.jnk" has 16400 bytes. +{File "%TEMP%/utf-check-1550-3-110-0.jnk" has 65576 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23562,11 +23562,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1551 utf-check-1551-3-110-1.jnk \ -{File "%TEMP%/utf-check-1551-3-110-1.jnk" has 16401 bytes. +{File "%TEMP%/utf-check-1551-3-110-1.jnk" has 65577 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23578,11 +23578,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1552 utf-check-1552-3-111-0.jnk \ -{File "%TEMP%/utf-check-1552-3-111-0.jnk" has 16402 bytes. +{File "%TEMP%/utf-check-1552-3-111-0.jnk" has 65578 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no @@ -23594,11 +23594,11 @@ Has flag LOOK_INVALID: yes Has flag LOOK_ODD: no Has flag LOOK_SHORT: no} utf-check 1553 utf-check-1553-3-111-1.jnk \ -{File "%TEMP%/utf-check-1553-3-111-1.jnk" has 16403 bytes. +{File "%TEMP%/utf-check-1553-3-111-1.jnk" has 65579 bytes. Starts with UTF-8 BOM: no Starts with UTF-16 BOM: no Looks like UTF-8: no Has flag LOOK_NUL: yes Has flag LOOK_CR: no Index: test/wiki.test ================================================================== --- test/wiki.test +++ test/wiki.test @@ -21,16 +21,22 @@ test_setup # Return true if two files are similar (i.e. not only compress trailing spaces # from a line, but remove any final LF from the file as well) proc similar_file {a b} { - set x [read_file $a] - regsub -all { +\n} $x \n x - regsub -all {\n$} $x {} x - set y [read_file $b] - regsub -all { +\n} $y \n y - regsub -all {\n$} $y {} y + set x "" + if {[file exists $a]} { + set x [read_file $a] + regsub -all { +\n} $x \n x + regsub -all {\n$} $x {} x + } + set y "" + if {[file exists $b]} { + set y [read_file $b] + regsub -all { +\n} $y \n y + regsub -all {\n$} $y {} y + } return [expr {$x==$y}] } # Return the mime type in the manifest for a given wiki page # Defaults to "error: some text" if the manifest can't be located and @@ -39,25 +45,25 @@ # Note: Makes fossil calls, so $CODE and $RESULT will be corrupted proc get_mime_type {name} { global CODE RESULT fossil http << "GET /wiki?name=$name" if {$CODE != 0} { - return error: /wiki?name=$name $CODE $RESULT" + return "error: /wiki?name=$name $CODE $RESULT" + } + fossil whatis --type w $name + if {$CODE != 0} { + return "error: fossil whatis --type w $name $CODE $RESULT" } - set CODE [regexp {href="/info/([0-9a-f]+)"} $RESULT match info] + set CODE [regexp -line {^artifact:\s*([0-9a-f]+)$} $RESULT match info] if {$CODE == 0} { - return "error: No info link found for wiki page $name" + return "error: whatis returned no info for wiki page $name" } - fossil http << "GET /artifact/$info" + fossil artifact $info if {$CODE != 0} { - return "error: /artifact/$info $CODE $RESULT" + return "error: fossil artifact $info $CODE $RESULT" } - set CODE [regexp {
    (.*)
    } $RESULT match pre] - if {$CODE == 0} { - return "error: No pre block in /artifact/$info" - } - set CODE [regexp -line {^N (.*)$} $pre match mimetype] + set CODE [regexp -line {^N (.*)$} $RESULT match mimetype] if {$CODE == 0} { return "text/x-fossil-wiki" } return $mimetype } ADDED tools/decode-email.c Index: tools/decode-email.c ================================================================== --- /dev/null +++ tools/decode-email.c @@ -0,0 +1,163 @@ +/* +** This program reads a raw email file and attempts to decode it into +** a more human-readable format. The following decodings are done: +** +** (1) Header values are prefixed by "| " at the left margin. +** +** (2) Content-Transfer-Encoding is recognized and the content is +** decoded for display. +*/ +#define _GNU_SOURCE +#include +#include +#include + +#define BINARY 0 +#define BASE64 1 +#define QUOTED 2 + +static int decode_hex(char c){ + if( c>='0' && c<='9' ) return c - '0'; + if( c>='A' && c<='F' ) return c - 'A' + 10; + if( c>='a' && c<='f' ) return c - 'a' + 10; + return -1; +} + +static void convert_file(const char *zFilename, FILE *in){ + int inHdr = 1; + int n; + int nBoundary; + int decodeType = 0; + int textMimetype = 1; + char *zB; + char zBoundary[200]; + char zLine[5000]; + char zOut[5000]; + while( fgets(zLine, sizeof(zLine), in) ){ + if( !inHdr + && zLine[0]=='-' + && zLine[1]=='-' + && strncmp(zLine+2,zBoundary,nBoundary)==0 + ){ + printf("|----------------- end of body section ---------|\n"); + inHdr = 1; + } + if( !inHdr ){ + if( textMimetype && decodeType==BASE64 ){ + int ii, jj, c, x, y; + int bits = 0; + for(ii=jj=0; (c = zLine[ii])!=0; ii++){ + if( c>='A' && c<='Z' ){ + x = c - 'A'; + }else if( c>='a' && c<='z' ){ + x = c - 'a' + 26; + }else if( c>='0' && c<='9' ){ + x = c - '0' + 52; + }else if( c=='+' ){ + x = 62; + }else if( c=='/' ){ + x = 63; + }else if( c=='=' ){ + x = 0; + }else{ + continue; + } + if( bits==0 ){ + y = x; + bits = 6; + }else if( bits==6 ){ + zOut[jj++] = ((y<<2) & 0xfc) | ((x>>4) & 0x03); + y = x & 0xf; + bits = 4; + }else if( bits==4 ){ + zOut[jj++] = ((y<<4) & 0xf0) | ((x>>2) & 0x0f); + y = x & 0x3; + bits = 2; + }else if( bits==2 ){ + zOut[jj++] = ((y<<6) & 0xc0) | (x & 0x3f); + bits = 0; + } + } + zOut[jj] = 0; + printf("%s", zOut); + }else if( textMimetype && decodeType==QUOTED ){ + int ii, jj, c; + for(ii=jj=0; (c = zLine[ii])!=0; ii++){ + if( c=='=' ){ + int x1 = decode_hex(zLine[ii+1]); + int x2 = decode_hex(zLine[ii+2]); + if( x1>=0 && x2>=0 ){ + zOut[jj++] = (x1<<4) | x2; + ii += 2; + }else if( zLine[ii+1]=='\r' && zLine[ii+2]=='\n' ){ + ii += 2; + } + }else{ + zOut[jj++] = c; + } + } + zOut[jj] = 0; + printf("%s", zOut); + }else{ + printf("%s", zLine); + } + continue; + } + n = (int)strlen(zLine); + while( n>0 && isspace(zLine[n-1]) ){ n--; } + zLine[n] = 0; + if( n==0 ){ + inHdr = 0; + printf("|----------------- end of header ---------------|\n"); + continue; + } + printf("| %s\n", zLine); + if( strncasecmp(zLine,"Content-Type:", 13)==0 ){ + textMimetype = strstr(zLine, "text/")!=0; + printf("|** %s content type **|\n", + textMimetype ? "Text" : "Non-text"); + } + if( strncasecmp(zLine,"Content-Transfer-Encoding:", 26)==0 ){ + if( strcasestr(zLine, "base64") ){ + decodeType = BASE64; + }else if( strcasestr(zLine, "quoted-printable") ){ + decodeType = QUOTED; + }else{ + decodeType = BINARY; + } + printf("|** Content encoding %s **|\n", + decodeType==BASE64 ? "BASE64" : + decodeType==QUOTED ? "QUOTED" : "BINARY"); + } + zB = strstr(zLine, "boundary=\""); + if( zB ){ + int kk; + zB += 10; + for(kk=0; zB[kk] && zB[kk]!='"' && kk", stdin); + return 0; + }else{ + int i; + for(i=1; i0} { + db eval {DELETE FROM email} + } + # Hold the write lock a little longer in order to exercise + # the SQLITE_BUSY handling logic on the writing inside of + # Fossil. Probably comment-out this line for production use. + after 100 + } + after $POLLING_INTERVAL +} ADDED tools/email-sender.tcl Index: tools/email-sender.tcl ================================================================== --- /dev/null +++ tools/email-sender.tcl @@ -0,0 +1,41 @@ +#!/usr/bin/tcl +# +# Monitor the database file named by the DBFILE variable +# looking for email messages sent by Fossil. Forward each +# to /usr/sbin/sendmail. +# +set POLLING_INTERVAL 10000 ;# milliseconds +set DBFILE /home/www/fossil/emailqueue.db +set PIPE "/usr/sbin/sendmail -ti" + +package require sqlite3 +# puts "SQLite version [sqlite3 -version]" +sqlite3 db $DBFILE +db timeout 5000 +catch {db eval {PRAGMA journal_mode=WAL}} +db eval { + CREATE TABLE IF NOT EXISTS email( + emailid INTEGER PRIMARY KEY, + msg TXT + ); +} +while {1} { + db transaction immediate { + set n 0 + db eval {SELECT msg FROM email} { + set pipe $PIPE + if {[regexp {\nFrom:[^\n]*<([^>]+)>} $msg all addr]} { + append pipe " -f $addr" + } + set out [open |$pipe w] + puts -nonewline $out $msg + flush $out + close $out + incr n + } + if {$n>0} { + db eval {DELETE FROM email} + } + } + after $POLLING_INTERVAL +} Index: tools/fossil-autocomplete.bash ================================================================== --- tools/fossil-autocomplete.bash +++ tools/fossil-autocomplete.bash @@ -3,13 +3,13 @@ function _fossil() { local cur commands cur=${COMP_WORDS[COMP_CWORD]} commands=$(fossil help --all) if [ $COMP_CWORD -eq 1 ] || [ ${COMP_WORDS[1]} = help ]; then - # Command name completion for 1st argument or 2nd if help command. + # Command name completion for 1st argument or 2nd if help command. COMPREPLY=( $(compgen -W "$commands" $cur) ) else - # File name completion for other arguments. - COMPREPLY=( $(compgen -f $cur) ) + # File name completion for other arguments. + COMPREPLY=( $(compgen -f $cur{}) ) fi } complete -o default -F _fossil fossil f ADDED tools/fossil-diff-log Index: tools/fossil-diff-log ================================================================== --- /dev/null +++ tools/fossil-diff-log @@ -0,0 +1,72 @@ +#!/usr/bin/env perl +# Fossil emulation of the "git log --patch / -p" feature: emit a stream +# of diffs from one version to the next for each file named on the +# command line. +# +# LIMITATIONS: It does not assume "all files" if you give no args, and +# it cannot take a directory to mean "all files under this parent". +# +# PREREQUISITES: This script needs several CPAN modules to run properly. +# There are multiple methods to install them: +# +# sudo dnf install perl-File-Which perl-IO-Interactive +# sudo apt install libfile-which-perl libio-interactive-perl +# sudo cpanm File::Which IO::Interactive +# ...etc... + +use strict; +use warnings; + +use Carp; +use File::Which; +use IO::Interactive qw(is_interactive); + +die "usage: $0 \n\n" unless @ARGV; + +my $out; +if (is_interactive()) { + my $pager = $ENV{PAGER} || which('less') || which('more'); + open $out, '|-', $pager or croak "Cannot pipe to $pager: $!"; +} +else { + $out = *STDOUT; +} + +open my $bcmd, '-|', 'fossil branch current' + or die "Cannot get branch: $!\n"; +my $cbranch = <$bcmd>; +chomp $cbranch; +close $bcmd; + +for my $file (@ARGV) { + my $lastckid; + open my $finfo, '-|', "fossil finfo --brief --limit 0 '$file'" + or die "Failed to get file info: $!\n"; + my @filines = <$finfo>; + close $finfo; + + for my $line (@filines) { + my ($currckid, $date, $user, $branch, @cwords) = split ' ', $line; + next unless $branch eq $cbranch; + if (defined $lastckid and defined $branch) { + my $comment = join ' ', @cwords; + open my $diff, '-|', 'fossil', 'diff', $file, + '--from', $currckid, + '--to', $lastckid, + or die "Failed to diff $currckid -> $lastckid: $!\n"; + my @dl = <$diff>; + close $diff; + my $patch = join '', @dl; + + print $out <<"OUT" +Checkin ID $currckid to $branch by $user on $date +Comment: $comment + +$patch + +OUT + } + + $lastckid = $currckid; + } +} ADDED tools/fossil-stress.tcl Index: tools/fossil-stress.tcl ================================================================== --- /dev/null +++ tools/fossil-stress.tcl @@ -0,0 +1,144 @@ +#!/usr/bin/tclsh +# +# Run this script, giving the url of a Fossil server instances as the +# argument, and this script will start sending HTTP requests into the +# that server instance as fast as it can, as a stress test for the +# server implementation. +# +set nthread 10 +for {set i 0} {$i<[llength $argv]} {incr i} { + set x [lindex $argv $i] + if {[regexp {^--[a-z]} $x]} { + set x [string range $x 1 end] + } + if {$x=="-threads"} { + incr i + set nthread [lindex $argv $i] + } elseif {[string index $x 0]=="-"} { + error "unknown option \"$x\"" + } elseif {[info exists url]} { + error "unknown argment \"$x\"" + } else { + set url $x + } +} +if {![info exists url]} { + error "Usage: $argv0 [-threads N] URL" +} +if {![regexp {^https?://([^/:]+)(:\d+)?(/.*)$} $url all domain port path]} { + error "could not parse the URL [list $url] -- should be of the\ + form \"http://domain/path\"" +} +set useragent {Mozilla/5.0 (fossil-stress.tcl) Gecko/20100101 Firefox/57.0} +set path [string trimright $path /] +set port [string trimleft $port :] +if {$port==""} {set port 80} + +proc send_one_request {tid domain port path} { + while {[catch { + set x [socket $domain $port] + fconfigure $x -translation binary -blocking 0 + puts $x "GET $path HTTP/1.0\r" + if {$port==80} { + puts $x "Host: $domain\r" + } else { + puts $x "Host: $domain:$port\r" + } + puts $x "User-Agent: $::useragent\r" + puts $x "Accept: text/html,q=0.9,*/*;q=0.8\r" + puts $x "Accept-Language: en-US,en;q=0.5\r" + puts $x "Connection: close\r" + puts $x "\r" + } msg]} { + puts "ERROR: $msg" + after 1000 + } + global cnt stime threadid + set cnt($x) 0 + set stime($x) [clock seconds] + set threadid($x) $tid + flush $x + fileevent $x readable [list get_reply $tid $path $x] +} + +proc close_connection {x} { + global cnt stime tid + close $x + unset -nocomplain cnt($x) + unset -nocomplain stime($x) + unset -nocomplain threadid($x) +} + +proc get_reply {tid info x} { + global cnt + if {[eof $x]} { + puts "[format %3d: $tid] $info ($cnt($x) bytes)" + flush stdout + close_connection $x + start_another_request $tid + } else { + incr cnt($x) [string length [read $x]] + } +} + +set pages { + /timeline?n=20 + /timeline?n=20&a=1970-01-01 + /home + /brlist + /info/trunk + /info/2015-01-01 + /vdiff?from=2015-01-01&to=trunk&diff=0 + /wcontent + /fileage + /dir + /tree + /uvlist + /stat + /test_env + /sitemap + /hash-collisions + /artifact_stats + /bloblist + /bigbloblist + /wiki_rules + /md_rules + /help + /test-all-help + /timewarps + /taglist +} + +set pageidx 0 +proc start_another_request {tid} { + global pages pageidx domain port path + set p [lindex $pages $pageidx] + incr pageidx + if {$pageidx>=[llength $pages]} {set pageidx 0} + send_one_request $tid $domain $port $path$p +} + +proc unhang_stalled_threads {} { + global stime threadid + set now [clock seconds] + # puts "checking for stalled threads...." + foreach x [array names stime] { + # puts -nonewline " $threadid($x)=[expr {$now-$stime($x)}]" + if {$stime($x)+0<$now-10} { + set t $threadid($x) + puts "RESTART thread $t" + flush stdout + close_connection $x + start_another_request $t + } + } + # puts "" + flush stdout + after 10000 unhang_stalled_threads +} + +unhang_stalled_threads +for {set i 1} {$i<=$nthread} {incr i} { + start_another_request $i +} +vwait forever ADDED tools/fslsrv Index: tools/fslsrv ================================================================== --- /dev/null +++ tools/fslsrv @@ -0,0 +1,53 @@ +#!/bin/bash +BASEPORT=12345 +FOSSIL=fossil +OLDPID=`pgrep -P 1 fossil` +PGARGS="-P 1" + +if [ "$1" = "-f" ] ; then PGARGS= ; shift ; fi + +if [ -n "$OLDPID" ] +then + echo "Killing running Fossil server first..." + pkill $PGARGS fossil + + for i in $(seq 30) + do + if [ -n "$(pgrep $PGARGS fossil)" ] + then + if [ $i -eq 1 ] + then + echo -n "Waiting for it to die..." + else + echo -n . + fi + sleep '0.1' + else + break + fi + echo + done + + killall -9 fossil 2> /dev/null +fi + +if [ -x ./fossil ] +then + # We're running from a build tree, so use that version instead + FOSSIL=./fossil +fi + +function start_one() { + bn=$1 + port=$(($BASEPORT + $2)) + url="$3" + if [ -n "$url" ] ; then baseurl="--baseurl $url" ; fi + + $FOSSIL server --localhost --port $port --scgi $baseurl \ + --errorlog ~/log/fossil/$bn-errors.log \ + ~/museum/$bn.fossil > ~/log/fossil/$bn-stdout.log & + echo Fossil server running for $bn, PID $!, port $port. +} + +start_one example 0 https://example.com/code +start_one foo 1 # https://foo.net ADDED tools/man_page_command_list.tcl Index: tools/man_page_command_list.tcl ================================================================== --- /dev/null +++ tools/man_page_command_list.tcl @@ -0,0 +1,68 @@ +#!/usr/bin/env tclsh +# man_page_command_list.tcl - generates common command list for fossil.1 + +# Tunable configuration. +set columns 5 +set width 15 + +# The only supported command-line argument is the optional output filename. +if {[llength $argv] == 1} { + set file [lindex $argv 0] +} + +# Get list of common commands. +set commands [exec fossil help] +regsub -nocase {.*?\ncommon commands:.*\n} $commands {} commands +regsub -nocase {\nthis is fossil version.*} $commands {} commands +regsub -all {\s+} $commands " " commands +set commands [lsort $commands] + +# Compute number of rows. +set rows [expr {([llength $commands] + $columns - 1) / $columns}] + +# Generate text one line at a time. +set text {} +for {set row 0} {$row < $rows} {incr row} { + # Separate rows with line break. + if {$row} { + append text .br\n + } + + # Generate the row of commands. + for {set col 0} {$col < $columns} {incr col} { + set i [expr {$col * $rows + $row}] + if {$i < [llength $commands]} { + append text [format %-*s $width [lindex $commands $i]] + } + } + append text \n +} + +# Strip trailing whitespace from each line. +regsub -all {\s+\n} $text \n text + +# Output text. +if {[info exists file]} { + # If a filename was specified, read the file for use as a template. + set chan [open $file] + set data [read $chan] + close $chan + + # Locate the part of the file to replace. + if {[regexp -indices {\n\.SH Common COMMANDs:\n\n(.*?)\n\.SH} $data\ + _ range]} { + # If found, replace with the updated command list. + set chan [open $file w] + puts -nonewline $chan [string replace $data\ + [lindex $range 0] [lindex $range 1] $text] + close $chan + } else { + # If not found, abort. + error "could not find command list in man file \"$file\"" + } +} else { + # If no filename was specified, write to stdout. + puts $text +} + +# vim: set sts=4 sw=4 tw=80 et ft=tcl: Index: win/Makefile.PellesCGMake ================================================================== --- win/Makefile.PellesCGMake +++ win/Makefile.PellesCGMake @@ -58,11 +58,11 @@ WINDIR=$(B)/win/ ZLIBSRCDIR=../../zlib/ # define linker command and options LINK=$(PellesCDir)/bin/polink.exe -LINKFLAGS=-subsystem:console -machine:$(TARGETMACHINE_LN) /LIBPATH:$(PellesCDir)\lib\win$(TARGETEXTEND) /LIBPATH:$(PellesCDir)\lib kernel32.lib advapi32.lib delayimp$(TARGETEXTEND).lib Wsock32.lib Crtmt$(TARGETEXTEND).lib +LINKFLAGS=-subsystem:console -machine:$(TARGETMACHINE_LN) /LIBPATH:$(PellesCDir)\lib\win$(TARGETEXTEND) /LIBPATH:$(PellesCDir)\lib kernel32.lib advapi32.lib delayimp$(TARGETEXTEND).lib Wsock32.lib dnsapi.lib Crtmt$(TARGETEXTEND).lib # define standard C-compiler and flags, used to compile # the fossil binary. Some special definitions follow for # special files follow CC=$(PellesCDir)\bin\pocc.exe @@ -83,17 +83,17 @@ # define the SQLite files, which need special flags on compile SQLITESRC=sqlite3.c ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) -SQLITEDEFINES=-DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_WIN32_NO_ANSI +SQLITEDEFINES=-DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -DSQLITE_WIN32_NO_ANSI # define the SQLite shell files, which need special flags on compile SQLITESHELLSRC=shell.c ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf)) SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj)) -SQLITESHELLDEFINES=-Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen +SQLITESHELLDEFINES=-DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen # define the th scripting files, which need special flags on compile THSRC=th.c th_lang.c ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf)) THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj)) @@ -148,11 +148,11 @@ # extracting version info from manifest VERSION.h: version.exe ..\manifest.uuid ..\manifest ..\VERSION version.exe ..\manifest.uuid ..\manifest ..\VERSION >$@ # generate the simplified headers -headers: makeheaders.exe page_index.h builtin_data.h VERSION.h ../src/sqlite3.h ../src/th.h VERSION.h +headers: makeheaders.exe page_index.h builtin_data.h VERSION.h ../src/sqlite3.h ../src/th.h makeheaders.exe $(foreach ts,$(TRANSLATEDSRC),$(ts):$(ts:_.c=.h)) ../src/sqlite3.h ../src/th.h VERSION.h echo Done >$@ # compile C sources with relevant options @@ -181,14 +181,14 @@ # cleanup .PHONY: clean clean: - del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj - del /F $(TRANSLATEDSRC) - del /F *.h headers - del /F $(RESOURCE) + -del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj + -del /F $(TRANSLATEDSRC) + -del /F *.h headers + -del /F $(RESOURCE) .PHONY: clobber clobber: clean - del /F *.exe + -del /F *.exe Index: win/Makefile.dmc ================================================================== --- win/Makefile.dmc +++ win/Makefile.dmc @@ -22,19 +22,19 @@ SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) -LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 - -SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 - -SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen - -SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fshell_.c fusefs_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c - -OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O +LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 dnsapi + +SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 + +SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen + +SRC = add_.c ajax_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c terminal_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c + +OBJ = $(OBJDIR)\add$O $(OBJDIR)\ajax$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\terminal$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O RC=$(DMDIR)\bin\rcc RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ @@ -49,11 +49,11 @@ $(OBJDIR)\fossil.res: $B\win\fossil.rc $(RC) $(RCFLAGS) -o$@ $** $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res - +echo add allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd dispatch doc encode event export file finfo foci fshell fusefs glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@ + +echo add ajax alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file fileedit finfo foci forum fshell fusefs fuzz glob graph gzip hname http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar terminal th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@ +echo fossil >> $@ +echo fossil >> $@ +echo $(LIBS) >> $@ +echo. >> $@ +echo fossil >> $@ @@ -122,16 +122,27 @@ $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h - $(OBJDIR)\add$O : add_.c add.h $(TCC) -o$@ -c add_.c add_.c : $(SRCDIR)\add.c +translate$E $** > $@ + +$(OBJDIR)\ajax$O : ajax_.c ajax.h + $(TCC) -o$@ -c ajax_.c + +ajax_.c : $(SRCDIR)\ajax.c + +translate$E $** > $@ + +$(OBJDIR)\alerts$O : alerts_.c alerts.h + $(TCC) -o$@ -c alerts_.c + +alerts_.c : $(SRCDIR)\alerts.c + +translate$E $** > $@ $(OBJDIR)\allrepo$O : allrepo_.c allrepo.h $(TCC) -o$@ -c allrepo_.c allrepo_.c : $(SRCDIR)\allrepo.c @@ -140,10 +151,22 @@ $(OBJDIR)\attach$O : attach_.c attach.h $(TCC) -o$@ -c attach_.c attach_.c : $(SRCDIR)\attach.c +translate$E $** > $@ + +$(OBJDIR)\backlink$O : backlink_.c backlink.h + $(TCC) -o$@ -c backlink_.c + +backlink_.c : $(SRCDIR)\backlink.c + +translate$E $** > $@ + +$(OBJDIR)\backoffice$O : backoffice_.c backoffice.h + $(TCC) -o$@ -c backoffice_.c + +backoffice_.c : $(SRCDIR)\backoffice.c + +translate$E $** > $@ $(OBJDIR)\bag$O : bag_.c bag.h $(TCC) -o$@ -c bag_.c bag_.c : $(SRCDIR)\bag.c @@ -188,10 +211,16 @@ $(OBJDIR)\cache$O : cache_.c cache.h $(TCC) -o$@ -c cache_.c cache_.c : $(SRCDIR)\cache.c +translate$E $** > $@ + +$(OBJDIR)\capabilities$O : capabilities_.c capabilities.h + $(TCC) -o$@ -c capabilities_.c + +capabilities_.c : $(SRCDIR)\capabilities.c + +translate$E $** > $@ $(OBJDIR)\captcha$O : captcha_.c captcha.h $(TCC) -o$@ -c captcha_.c captcha_.c : $(SRCDIR)\captcha.c @@ -242,10 +271,16 @@ $(OBJDIR)\content$O : content_.c content.h $(TCC) -o$@ -c content_.c content_.c : $(SRCDIR)\content.c +translate$E $** > $@ + +$(OBJDIR)\cookies$O : cookies_.c cookies.h + $(TCC) -o$@ -c cookies_.c + +cookies_.c : $(SRCDIR)\cookies.c + +translate$E $** > $@ $(OBJDIR)\db$O : db_.c db.h $(TCC) -o$@ -c db_.c db_.c : $(SRCDIR)\db.c @@ -260,10 +295,16 @@ $(OBJDIR)\deltacmd$O : deltacmd_.c deltacmd.h $(TCC) -o$@ -c deltacmd_.c deltacmd_.c : $(SRCDIR)\deltacmd.c +translate$E $** > $@ + +$(OBJDIR)\deltafunc$O : deltafunc_.c deltafunc.h + $(TCC) -o$@ -c deltafunc_.c + +deltafunc_.c : $(SRCDIR)\deltafunc.c + +translate$E $** > $@ $(OBJDIR)\descendants$O : descendants_.c descendants.h $(TCC) -o$@ -c descendants_.c descendants_.c : $(SRCDIR)\descendants.c @@ -296,10 +337,16 @@ $(OBJDIR)\encode$O : encode_.c encode.h $(TCC) -o$@ -c encode_.c encode_.c : $(SRCDIR)\encode.c +translate$E $** > $@ + +$(OBJDIR)\etag$O : etag_.c etag.h + $(TCC) -o$@ -c etag_.c + +etag_.c : $(SRCDIR)\etag.c + +translate$E $** > $@ $(OBJDIR)\event$O : event_.c event.h $(TCC) -o$@ -c event_.c event_.c : $(SRCDIR)\event.c @@ -308,16 +355,28 @@ $(OBJDIR)\export$O : export_.c export.h $(TCC) -o$@ -c export_.c export_.c : $(SRCDIR)\export.c +translate$E $** > $@ + +$(OBJDIR)\extcgi$O : extcgi_.c extcgi.h + $(TCC) -o$@ -c extcgi_.c + +extcgi_.c : $(SRCDIR)\extcgi.c + +translate$E $** > $@ $(OBJDIR)\file$O : file_.c file.h $(TCC) -o$@ -c file_.c file_.c : $(SRCDIR)\file.c +translate$E $** > $@ + +$(OBJDIR)\fileedit$O : fileedit_.c fileedit.h + $(TCC) -o$@ -c fileedit_.c + +fileedit_.c : $(SRCDIR)\fileedit.c + +translate$E $** > $@ $(OBJDIR)\finfo$O : finfo_.c finfo.h $(TCC) -o$@ -c finfo_.c finfo_.c : $(SRCDIR)\finfo.c @@ -326,10 +385,16 @@ $(OBJDIR)\foci$O : foci_.c foci.h $(TCC) -o$@ -c foci_.c foci_.c : $(SRCDIR)\foci.c +translate$E $** > $@ + +$(OBJDIR)\forum$O : forum_.c forum.h + $(TCC) -o$@ -c forum_.c + +forum_.c : $(SRCDIR)\forum.c + +translate$E $** > $@ $(OBJDIR)\fshell$O : fshell_.c fshell.h $(TCC) -o$@ -c fshell_.c fshell_.c : $(SRCDIR)\fshell.c @@ -338,10 +403,16 @@ $(OBJDIR)\fusefs$O : fusefs_.c fusefs.h $(TCC) -o$@ -c fusefs_.c fusefs_.c : $(SRCDIR)\fusefs.c +translate$E $** > $@ + +$(OBJDIR)\fuzz$O : fuzz_.c fuzz.h + $(TCC) -o$@ -c fuzz_.c + +fuzz_.c : $(SRCDIR)\fuzz.c + +translate$E $** > $@ $(OBJDIR)\glob$O : glob_.c glob.h $(TCC) -o$@ -c glob_.c glob_.c : $(SRCDIR)\glob.c @@ -356,10 +427,16 @@ $(OBJDIR)\gzip$O : gzip_.c gzip.h $(TCC) -o$@ -c gzip_.c gzip_.c : $(SRCDIR)\gzip.c +translate$E $** > $@ + +$(OBJDIR)\hname$O : hname_.c hname.h + $(TCC) -o$@ -c hname_.c + +hname_.c : $(SRCDIR)\hname.c + +translate$E $** > $@ $(OBJDIR)\http$O : http_.c http.h $(TCC) -o$@ -c http_.c http_.c : $(SRCDIR)\http.c @@ -620,10 +697,16 @@ $(OBJDIR)\regexp$O : regexp_.c regexp.h $(TCC) -o$@ -c regexp_.c regexp_.c : $(SRCDIR)\regexp.c +translate$E $** > $@ + +$(OBJDIR)\repolist$O : repolist_.c repolist.h + $(TCC) -o$@ -c repolist_.c + +repolist_.c : $(SRCDIR)\repolist.c + +translate$E $** > $@ $(OBJDIR)\report$O : report_.c report.h $(TCC) -o$@ -c report_.c report_.c : $(SRCDIR)\report.c @@ -644,22 +727,46 @@ $(OBJDIR)\search$O : search_.c search.h $(TCC) -o$@ -c search_.c search_.c : $(SRCDIR)\search.c +translate$E $** > $@ + +$(OBJDIR)\security_audit$O : security_audit_.c security_audit.h + $(TCC) -o$@ -c security_audit_.c + +security_audit_.c : $(SRCDIR)\security_audit.c + +translate$E $** > $@ $(OBJDIR)\setup$O : setup_.c setup.h $(TCC) -o$@ -c setup_.c setup_.c : $(SRCDIR)\setup.c +translate$E $** > $@ + +$(OBJDIR)\setupuser$O : setupuser_.c setupuser.h + $(TCC) -o$@ -c setupuser_.c + +setupuser_.c : $(SRCDIR)\setupuser.c + +translate$E $** > $@ $(OBJDIR)\sha1$O : sha1_.c sha1.h $(TCC) -o$@ -c sha1_.c sha1_.c : $(SRCDIR)\sha1.c +translate$E $** > $@ + +$(OBJDIR)\sha1hard$O : sha1hard_.c sha1hard.h + $(TCC) -o$@ -c sha1hard_.c + +sha1hard_.c : $(SRCDIR)\sha1hard.c + +translate$E $** > $@ + +$(OBJDIR)\sha3$O : sha3_.c sha3.h + $(TCC) -o$@ -c sha3_.c + +sha3_.c : $(SRCDIR)\sha3.c + +translate$E $** > $@ $(OBJDIR)\shun$O : shun_.c shun.h $(TCC) -o$@ -c shun_.c shun_.c : $(SRCDIR)\shun.c @@ -674,10 +781,16 @@ $(OBJDIR)\skins$O : skins_.c skins.h $(TCC) -o$@ -c skins_.c skins_.c : $(SRCDIR)\skins.c +translate$E $** > $@ + +$(OBJDIR)\smtp$O : smtp_.c smtp.h + $(TCC) -o$@ -c smtp_.c + +smtp_.c : $(SRCDIR)\smtp.c + +translate$E $** > $@ $(OBJDIR)\sqlcmd$O : sqlcmd_.c sqlcmd.h $(TCC) -o$@ -c sqlcmd_.c sqlcmd_.c : $(SRCDIR)\sqlcmd.c @@ -722,10 +835,16 @@ $(OBJDIR)\tar$O : tar_.c tar.h $(TCC) -o$@ -c tar_.c tar_.c : $(SRCDIR)\tar.c +translate$E $** > $@ + +$(OBJDIR)\terminal$O : terminal_.c terminal.h + $(TCC) -o$@ -c terminal_.c + +terminal_.c : $(SRCDIR)\terminal.c + +translate$E $** > $@ $(OBJDIR)\th_main$O : th_main_.c th_main.h $(TCC) -o$@ -c th_main_.c th_main_.c : $(SRCDIR)\th_main.c @@ -806,10 +925,16 @@ $(OBJDIR)\vfile$O : vfile_.c vfile.h $(TCC) -o$@ -c vfile_.c vfile_.c : $(SRCDIR)\vfile.c +translate$E $** > $@ + +$(OBJDIR)\webmail$O : webmail_.c webmail.h + $(TCC) -o$@ -c webmail_.c + +webmail_.c : $(SRCDIR)\webmail.c + +translate$E $** > $@ $(OBJDIR)\wiki$O : wiki_.c wiki.h $(TCC) -o$@ -c wiki_.c wiki_.c : $(SRCDIR)\wiki.c @@ -856,7 +981,7 @@ zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h builtin_data.h VERSION.h - +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fshell_.c:fshell.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h + +makeheaders$E add_.c:add.h ajax_.c:ajax.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h fileedit_.c:fileedit.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h terminal_.c:terminal.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h @copy /Y nul: headers Index: win/Makefile.mingw ================================================================== --- win/Makefile.mingw +++ win/Makefile.mingw @@ -71,11 +71,11 @@ # # FOSSIL_ENABLE_EXEC_REL_PATHS = 1 #### Enable legacy treatment of mv/rm (skip checkout files) # -# FOSSIL_ENABLE_LEGACY_MV_RM = 1 +FOSSIL_ENABLE_LEGACY_MV_RM = 1 #### Enable TH1 scripts in embedded documentation files # # FOSSIL_ENABLE_TH1_DOCS = 1 @@ -96,10 +96,14 @@ # FOSSIL_ENABLE_TCL_PRIVATE_STUBS = 1 #### Use 'system' SQLite # # USE_SYSTEM_SQLITE = 1 + +#### Use POSIX memory APIs from "sys/mman.h" +# +# USE_MMAN_H = 1 #### Use the SQLite Encryption Extension # # USE_SEE = 1 @@ -154,13 +158,13 @@ ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support -# for both SSLv2 and SSLv3 (i.e. thereby forcing the use of TLS). +# for SSLv3 (i.e. thereby forcing the use of TLS). # -SSLCONFIG += no-ssl2 no-ssl3 no-shared +SSLCONFIG += no-ssl3 no-weak-ssl-ciphers no-shared #### When using zlib, make sure that OpenSSL is configured to use the zlib # that Fossil knows about (i.e. the one within the source tree). # ifndef FOSSIL_ENABLE_MINIZ @@ -170,11 +174,11 @@ #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2j +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1g OPENSSLINCDIR = $(OPENSSLDIR)/include OPENSSLLIBDIR = $(OPENSSLDIR) #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro @@ -225,11 +229,11 @@ # run on the target platform. This is usually the almost the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # -TCC = $(PREFIX)$(TCCEXE) -Wall +TCC = $(PREFIX)$(TCCEXE) -Wall -Wdeclaration-after-statement #### Add the necessary command line options to build with debugging # symbols, if enabled. # ifdef FOSSIL_ENABLE_SYMBOLS @@ -333,10 +337,16 @@ # With JSON support ifdef FOSSIL_ENABLE_JSON TCC += -DFOSSIL_ENABLE_JSON=1 RCC += -DFOSSIL_ENABLE_JSON=1 endif + +# With "sys/mman.h" support +ifdef USE_MMAN_H +TCC += -DUSE_MMAN_H=1 +RCC += -DUSE_MMAN_H=1 +endif # With SQLite Encryption Extension support ifdef USE_SEE TCC += -DUSE_SEE=1 RCC += -DUSE_SEE=1 @@ -397,10 +407,14 @@ LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32 endif else LIB += -lkernel32 -lws2_32 endif + +#### Library required for DNS lookups. +# +LIB += -ldnsapi #### Tcl shell for use in running the fossil test suite. This is only # used for testing. # TCLSH = tclsh @@ -418,52 +432,66 @@ -include config.w32 # STOP HERE # You should not need to change anything below this line #-------------------------------------------------------- +XBCC = $(BCC) $(CFLAGS) XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) SRC = \ $(SRCDIR)/add.c \ + $(SRCDIR)/ajax.c \ + $(SRCDIR)/alerts.c \ $(SRCDIR)/allrepo.c \ $(SRCDIR)/attach.c \ + $(SRCDIR)/backlink.c \ + $(SRCDIR)/backoffice.c \ $(SRCDIR)/bag.c \ $(SRCDIR)/bisect.c \ $(SRCDIR)/blob.c \ $(SRCDIR)/branch.c \ $(SRCDIR)/browse.c \ $(SRCDIR)/builtin.c \ $(SRCDIR)/bundle.c \ $(SRCDIR)/cache.c \ + $(SRCDIR)/capabilities.c \ $(SRCDIR)/captcha.c \ $(SRCDIR)/cgi.c \ $(SRCDIR)/checkin.c \ $(SRCDIR)/checkout.c \ $(SRCDIR)/clearsign.c \ $(SRCDIR)/clone.c \ $(SRCDIR)/comformat.c \ $(SRCDIR)/configure.c \ $(SRCDIR)/content.c \ + $(SRCDIR)/cookies.c \ $(SRCDIR)/db.c \ $(SRCDIR)/delta.c \ $(SRCDIR)/deltacmd.c \ + $(SRCDIR)/deltafunc.c \ $(SRCDIR)/descendants.c \ $(SRCDIR)/diff.c \ $(SRCDIR)/diffcmd.c \ $(SRCDIR)/dispatch.c \ $(SRCDIR)/doc.c \ $(SRCDIR)/encode.c \ + $(SRCDIR)/etag.c \ $(SRCDIR)/event.c \ $(SRCDIR)/export.c \ + $(SRCDIR)/extcgi.c \ $(SRCDIR)/file.c \ + $(SRCDIR)/fileedit.c \ $(SRCDIR)/finfo.c \ $(SRCDIR)/foci.c \ + $(SRCDIR)/forum.c \ $(SRCDIR)/fshell.c \ $(SRCDIR)/fusefs.c \ + $(SRCDIR)/fuzz.c \ $(SRCDIR)/glob.c \ $(SRCDIR)/graph.c \ $(SRCDIR)/gzip.c \ + $(SRCDIR)/hname.c \ $(SRCDIR)/http.c \ $(SRCDIR)/http_socket.c \ $(SRCDIR)/http_ssl.c \ $(SRCDIR)/http_transport.c \ $(SRCDIR)/import.c \ @@ -504,27 +532,34 @@ $(SRCDIR)/printf.c \ $(SRCDIR)/publish.c \ $(SRCDIR)/purge.c \ $(SRCDIR)/rebuild.c \ $(SRCDIR)/regexp.c \ + $(SRCDIR)/repolist.c \ $(SRCDIR)/report.c \ $(SRCDIR)/rss.c \ $(SRCDIR)/schema.c \ $(SRCDIR)/search.c \ + $(SRCDIR)/security_audit.c \ $(SRCDIR)/setup.c \ + $(SRCDIR)/setupuser.c \ $(SRCDIR)/sha1.c \ + $(SRCDIR)/sha1hard.c \ + $(SRCDIR)/sha3.c \ $(SRCDIR)/shun.c \ $(SRCDIR)/sitemap.c \ $(SRCDIR)/skins.c \ + $(SRCDIR)/smtp.c \ $(SRCDIR)/sqlcmd.c \ $(SRCDIR)/stash.c \ $(SRCDIR)/stat.c \ $(SRCDIR)/statrep.c \ $(SRCDIR)/style.c \ $(SRCDIR)/sync.c \ $(SRCDIR)/tag.c \ $(SRCDIR)/tar.c \ + $(SRCDIR)/terminal.c \ $(SRCDIR)/th_main.c \ $(SRCDIR)/timeline.c \ $(SRCDIR)/tkt.c \ $(SRCDIR)/tktsetup.c \ $(SRCDIR)/undo.c \ @@ -535,10 +570,11 @@ $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ + $(SRCDIR)/webmail.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winfile.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ @@ -546,10 +582,14 @@ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c EXTRA_FILES = \ $(SRCDIR)/../skins/aht/details.txt \ + $(SRCDIR)/../skins/ardoise/css.txt \ + $(SRCDIR)/../skins/ardoise/details.txt \ + $(SRCDIR)/../skins/ardoise/footer.txt \ + $(SRCDIR)/../skins/ardoise/header.txt \ $(SRCDIR)/../skins/black_and_white/css.txt \ $(SRCDIR)/../skins/black_and_white/details.txt \ $(SRCDIR)/../skins/black_and_white/footer.txt \ $(SRCDIR)/../skins/black_and_white/header.txt \ $(SRCDIR)/../skins/blitz/css.txt \ @@ -560,14 +600,19 @@ $(SRCDIR)/../skins/blitz_no_logo/css.txt \ $(SRCDIR)/../skins/blitz_no_logo/details.txt \ $(SRCDIR)/../skins/blitz_no_logo/footer.txt \ $(SRCDIR)/../skins/blitz_no_logo/header.txt \ $(SRCDIR)/../skins/blitz_no_logo/ticket.txt \ + $(SRCDIR)/../skins/bootstrap/css.txt \ + $(SRCDIR)/../skins/bootstrap/details.txt \ + $(SRCDIR)/../skins/bootstrap/footer.txt \ + $(SRCDIR)/../skins/bootstrap/header.txt \ $(SRCDIR)/../skins/default/css.txt \ $(SRCDIR)/../skins/default/details.txt \ $(SRCDIR)/../skins/default/footer.txt \ $(SRCDIR)/../skins/default/header.txt \ + $(SRCDIR)/../skins/default/js.txt \ $(SRCDIR)/../skins/eagle/css.txt \ $(SRCDIR)/../skins/eagle/details.txt \ $(SRCDIR)/../skins/eagle/footer.txt \ $(SRCDIR)/../skins/eagle/header.txt \ $(SRCDIR)/../skins/enhanced1/css.txt \ @@ -592,53 +637,107 @@ $(SRCDIR)/../skins/rounded1/header.txt \ $(SRCDIR)/../skins/xekri/css.txt \ $(SRCDIR)/../skins/xekri/details.txt \ $(SRCDIR)/../skins/xekri/footer.txt \ $(SRCDIR)/../skins/xekri/header.txt \ + $(SRCDIR)/accordion.js \ + $(SRCDIR)/ci_edit.js \ + $(SRCDIR)/copybtn.js \ + $(SRCDIR)/default.css \ $(SRCDIR)/diff.tcl \ - $(SRCDIR)/markdown.md + $(SRCDIR)/forum.js \ + $(SRCDIR)/fossil.bootstrap.js \ + $(SRCDIR)/fossil.confirmer.js \ + $(SRCDIR)/fossil.dom.js \ + $(SRCDIR)/fossil.fetch.js \ + $(SRCDIR)/fossil.page.fileedit.js \ + $(SRCDIR)/fossil.storage.js \ + $(SRCDIR)/fossil.tabs.js \ + $(SRCDIR)/graph.js \ + $(SRCDIR)/href.js \ + $(SRCDIR)/login.js \ + $(SRCDIR)/markdown.md \ + $(SRCDIR)/menu.js \ + $(SRCDIR)/sbsdiff.js \ + $(SRCDIR)/scroll.js \ + $(SRCDIR)/skin.js \ + $(SRCDIR)/sorttable.js \ + $(SRCDIR)/sounds/0.wav \ + $(SRCDIR)/sounds/1.wav \ + $(SRCDIR)/sounds/2.wav \ + $(SRCDIR)/sounds/3.wav \ + $(SRCDIR)/sounds/4.wav \ + $(SRCDIR)/sounds/5.wav \ + $(SRCDIR)/sounds/6.wav \ + $(SRCDIR)/sounds/7.wav \ + $(SRCDIR)/sounds/8.wav \ + $(SRCDIR)/sounds/9.wav \ + $(SRCDIR)/sounds/a.wav \ + $(SRCDIR)/sounds/b.wav \ + $(SRCDIR)/sounds/c.wav \ + $(SRCDIR)/sounds/d.wav \ + $(SRCDIR)/sounds/e.wav \ + $(SRCDIR)/sounds/f.wav \ + $(SRCDIR)/style.admin_log.css \ + $(SRCDIR)/style.fileedit.css \ + $(SRCDIR)/tree.js \ + $(SRCDIR)/useredit.js \ + $(SRCDIR)/wiki.wiki TRANS_SRC = \ $(OBJDIR)/add_.c \ + $(OBJDIR)/ajax_.c \ + $(OBJDIR)/alerts_.c \ $(OBJDIR)/allrepo_.c \ $(OBJDIR)/attach_.c \ + $(OBJDIR)/backlink_.c \ + $(OBJDIR)/backoffice_.c \ $(OBJDIR)/bag_.c \ $(OBJDIR)/bisect_.c \ $(OBJDIR)/blob_.c \ $(OBJDIR)/branch_.c \ $(OBJDIR)/browse_.c \ $(OBJDIR)/builtin_.c \ $(OBJDIR)/bundle_.c \ $(OBJDIR)/cache_.c \ + $(OBJDIR)/capabilities_.c \ $(OBJDIR)/captcha_.c \ $(OBJDIR)/cgi_.c \ $(OBJDIR)/checkin_.c \ $(OBJDIR)/checkout_.c \ $(OBJDIR)/clearsign_.c \ $(OBJDIR)/clone_.c \ $(OBJDIR)/comformat_.c \ $(OBJDIR)/configure_.c \ $(OBJDIR)/content_.c \ + $(OBJDIR)/cookies_.c \ $(OBJDIR)/db_.c \ $(OBJDIR)/delta_.c \ $(OBJDIR)/deltacmd_.c \ + $(OBJDIR)/deltafunc_.c \ $(OBJDIR)/descendants_.c \ $(OBJDIR)/diff_.c \ $(OBJDIR)/diffcmd_.c \ $(OBJDIR)/dispatch_.c \ $(OBJDIR)/doc_.c \ $(OBJDIR)/encode_.c \ + $(OBJDIR)/etag_.c \ $(OBJDIR)/event_.c \ $(OBJDIR)/export_.c \ + $(OBJDIR)/extcgi_.c \ $(OBJDIR)/file_.c \ + $(OBJDIR)/fileedit_.c \ $(OBJDIR)/finfo_.c \ $(OBJDIR)/foci_.c \ + $(OBJDIR)/forum_.c \ $(OBJDIR)/fshell_.c \ $(OBJDIR)/fusefs_.c \ + $(OBJDIR)/fuzz_.c \ $(OBJDIR)/glob_.c \ $(OBJDIR)/graph_.c \ $(OBJDIR)/gzip_.c \ + $(OBJDIR)/hname_.c \ $(OBJDIR)/http_.c \ $(OBJDIR)/http_socket_.c \ $(OBJDIR)/http_ssl_.c \ $(OBJDIR)/http_transport_.c \ $(OBJDIR)/import_.c \ @@ -679,27 +778,34 @@ $(OBJDIR)/printf_.c \ $(OBJDIR)/publish_.c \ $(OBJDIR)/purge_.c \ $(OBJDIR)/rebuild_.c \ $(OBJDIR)/regexp_.c \ + $(OBJDIR)/repolist_.c \ $(OBJDIR)/report_.c \ $(OBJDIR)/rss_.c \ $(OBJDIR)/schema_.c \ $(OBJDIR)/search_.c \ + $(OBJDIR)/security_audit_.c \ $(OBJDIR)/setup_.c \ + $(OBJDIR)/setupuser_.c \ $(OBJDIR)/sha1_.c \ + $(OBJDIR)/sha1hard_.c \ + $(OBJDIR)/sha3_.c \ $(OBJDIR)/shun_.c \ $(OBJDIR)/sitemap_.c \ $(OBJDIR)/skins_.c \ + $(OBJDIR)/smtp_.c \ $(OBJDIR)/sqlcmd_.c \ $(OBJDIR)/stash_.c \ $(OBJDIR)/stat_.c \ $(OBJDIR)/statrep_.c \ $(OBJDIR)/style_.c \ $(OBJDIR)/sync_.c \ $(OBJDIR)/tag_.c \ $(OBJDIR)/tar_.c \ + $(OBJDIR)/terminal_.c \ $(OBJDIR)/th_main_.c \ $(OBJDIR)/timeline_.c \ $(OBJDIR)/tkt_.c \ $(OBJDIR)/tktsetup_.c \ $(OBJDIR)/undo_.c \ @@ -710,10 +816,11 @@ $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ + $(OBJDIR)/webmail_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winfile_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ @@ -721,48 +828,61 @@ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ $(OBJDIR)/add.o \ + $(OBJDIR)/ajax.o \ + $(OBJDIR)/alerts.o \ $(OBJDIR)/allrepo.o \ $(OBJDIR)/attach.o \ + $(OBJDIR)/backlink.o \ + $(OBJDIR)/backoffice.o \ $(OBJDIR)/bag.o \ $(OBJDIR)/bisect.o \ $(OBJDIR)/blob.o \ $(OBJDIR)/branch.o \ $(OBJDIR)/browse.o \ $(OBJDIR)/builtin.o \ $(OBJDIR)/bundle.o \ $(OBJDIR)/cache.o \ + $(OBJDIR)/capabilities.o \ $(OBJDIR)/captcha.o \ $(OBJDIR)/cgi.o \ $(OBJDIR)/checkin.o \ $(OBJDIR)/checkout.o \ $(OBJDIR)/clearsign.o \ $(OBJDIR)/clone.o \ $(OBJDIR)/comformat.o \ $(OBJDIR)/configure.o \ $(OBJDIR)/content.o \ + $(OBJDIR)/cookies.o \ $(OBJDIR)/db.o \ $(OBJDIR)/delta.o \ $(OBJDIR)/deltacmd.o \ + $(OBJDIR)/deltafunc.o \ $(OBJDIR)/descendants.o \ $(OBJDIR)/diff.o \ $(OBJDIR)/diffcmd.o \ $(OBJDIR)/dispatch.o \ $(OBJDIR)/doc.o \ $(OBJDIR)/encode.o \ + $(OBJDIR)/etag.o \ $(OBJDIR)/event.o \ $(OBJDIR)/export.o \ + $(OBJDIR)/extcgi.o \ $(OBJDIR)/file.o \ + $(OBJDIR)/fileedit.o \ $(OBJDIR)/finfo.o \ $(OBJDIR)/foci.o \ + $(OBJDIR)/forum.o \ $(OBJDIR)/fshell.o \ $(OBJDIR)/fusefs.o \ + $(OBJDIR)/fuzz.o \ $(OBJDIR)/glob.o \ $(OBJDIR)/graph.o \ $(OBJDIR)/gzip.o \ + $(OBJDIR)/hname.o \ $(OBJDIR)/http.o \ $(OBJDIR)/http_socket.o \ $(OBJDIR)/http_ssl.o \ $(OBJDIR)/http_transport.o \ $(OBJDIR)/import.o \ @@ -803,27 +923,34 @@ $(OBJDIR)/printf.o \ $(OBJDIR)/publish.o \ $(OBJDIR)/purge.o \ $(OBJDIR)/rebuild.o \ $(OBJDIR)/regexp.o \ + $(OBJDIR)/repolist.o \ $(OBJDIR)/report.o \ $(OBJDIR)/rss.o \ $(OBJDIR)/schema.o \ $(OBJDIR)/search.o \ + $(OBJDIR)/security_audit.o \ $(OBJDIR)/setup.o \ + $(OBJDIR)/setupuser.o \ $(OBJDIR)/sha1.o \ + $(OBJDIR)/sha1hard.o \ + $(OBJDIR)/sha3.o \ $(OBJDIR)/shun.o \ $(OBJDIR)/sitemap.o \ $(OBJDIR)/skins.o \ + $(OBJDIR)/smtp.o \ $(OBJDIR)/sqlcmd.o \ $(OBJDIR)/stash.o \ $(OBJDIR)/stat.o \ $(OBJDIR)/statrep.o \ $(OBJDIR)/style.o \ $(OBJDIR)/sync.o \ $(OBJDIR)/tag.o \ $(OBJDIR)/tar.o \ + $(OBJDIR)/terminal.o \ $(OBJDIR)/th_main.o \ $(OBJDIR)/timeline.o \ $(OBJDIR)/tkt.o \ $(OBJDIR)/tktsetup.o \ $(OBJDIR)/undo.o \ @@ -834,10 +961,11 @@ $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ + $(OBJDIR)/webmail.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winfile.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ @@ -902,14 +1030,14 @@ $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(INSTALLDIR)) - $(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) + $(CP) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) else $(MKDIR) $(INSTALLDIR) - $(MV) $(APPNAME) $(INSTALLDIR) + $(CP) $(APPNAME) $(INSTALLDIR) endif $(OBJDIR): ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(OBJDIR)) @@ -916,26 +1044,26 @@ else $(MKDIR) $(OBJDIR) endif $(TRANSLATE): $(SRCDIR)/translate.c - $(BCC) -o $@ $(SRCDIR)/translate.c + $(XBCC) -o $@ $(SRCDIR)/translate.c $(MAKEHEADERS): $(SRCDIR)/makeheaders.c - $(BCC) -o $@ $(SRCDIR)/makeheaders.c + $(XBCC) -o $@ $(SRCDIR)/makeheaders.c $(MKINDEX): $(SRCDIR)/mkindex.c - $(BCC) -o $@ $(SRCDIR)/mkindex.c + $(XBCC) -o $@ $(SRCDIR)/mkindex.c $(MKBUILTIN): $(SRCDIR)/mkbuiltin.c - $(BCC) -o $@ $(SRCDIR)/mkbuiltin.c + $(XBCC) -o $@ $(SRCDIR)/mkbuiltin.c $(MKVERSION): $(SRCDIR)/mkversion.c - $(BCC) -o $@ $(SRCDIR)/mkversion.c + $(XBCC) -o $@ $(SRCDIR)/mkversion.c $(CODECHECK1): $(SRCDIR)/codecheck1.c - $(BCC) -o $@ $(SRCDIR)/codecheck1.c + $(XBCC) -o $@ $(SRCDIR)/codecheck1.c # WARNING. DANGER. Running the test suite modifies the repository the # build is done from, i.e. the checkout belongs to. Do not sync/push # the repository after running the tests. test: $(OBJDIR) $(APPNAME) @@ -970,11 +1098,11 @@ SQLITE3_SHELL_SRC.0 = shell.c SQLITE3_SHELL_SRC.1 = shell-see.c SQLITE3_SHELL_SRC. = shell.c SQLITE3_SHELL_SRC = $(SRCDIR)/$(SQLITE3_SHELL_SRC.$(USE_SEE)) SEE_FLAGS.0 = -SEE_FLAGS.1 = -DSQLITE_HAS_CODEC +SEE_FLAGS.1 = -DSQLITE_HAS_CODEC -DSQLITE_SHELL_DBKEY_PROC=fossil_key SEE_FLAGS. = SEE_FLAGS = $(SEE_FLAGS.$(USE_SEE)) EXTRAOBJ = \ @@ -1005,10 +1133,11 @@ BLDTARGETS = zlib endif openssl: $(BLDTARGETS) cd $(OPENSSLLIBDIR);./Configure --cross-compile-prefix=$(PREFIX) $(SSLCONFIG) + sed -i -e 's/^PERL=C:\\.*$$/PERL=perl.exe/i' $(OPENSSLLIBDIR)/Makefile $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) build_libs clean-openssl: $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) clean @@ -1056,48 +1185,61 @@ $(OBJDIR)/builtin_data.h: $(MKBUILTIN) $(EXTRA_FILES) $(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \ + $(OBJDIR)/ajax_.c:$(OBJDIR)/ajax.h \ + $(OBJDIR)/alerts_.c:$(OBJDIR)/alerts.h \ $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \ $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \ + $(OBJDIR)/backlink_.c:$(OBJDIR)/backlink.h \ + $(OBJDIR)/backoffice_.c:$(OBJDIR)/backoffice.h \ $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \ $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \ $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h \ $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h \ $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \ $(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \ $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \ $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \ + $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \ $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \ $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \ $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \ $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \ $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \ $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \ $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \ $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h \ $(OBJDIR)/content_.c:$(OBJDIR)/content.h \ + $(OBJDIR)/cookies_.c:$(OBJDIR)/cookies.h \ $(OBJDIR)/db_.c:$(OBJDIR)/db.h \ $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h \ $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h \ + $(OBJDIR)/deltafunc_.c:$(OBJDIR)/deltafunc.h \ $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h \ $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h \ $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h \ $(OBJDIR)/dispatch_.c:$(OBJDIR)/dispatch.h \ $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h \ $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h \ + $(OBJDIR)/etag_.c:$(OBJDIR)/etag.h \ $(OBJDIR)/event_.c:$(OBJDIR)/event.h \ $(OBJDIR)/export_.c:$(OBJDIR)/export.h \ + $(OBJDIR)/extcgi_.c:$(OBJDIR)/extcgi.h \ $(OBJDIR)/file_.c:$(OBJDIR)/file.h \ + $(OBJDIR)/fileedit_.c:$(OBJDIR)/fileedit.h \ $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h \ $(OBJDIR)/foci_.c:$(OBJDIR)/foci.h \ + $(OBJDIR)/forum_.c:$(OBJDIR)/forum.h \ $(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \ $(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \ + $(OBJDIR)/fuzz_.c:$(OBJDIR)/fuzz.h \ $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \ $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \ $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \ + $(OBJDIR)/hname_.c:$(OBJDIR)/hname.h \ $(OBJDIR)/http_.c:$(OBJDIR)/http.h \ $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h \ $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h \ $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h \ $(OBJDIR)/import_.c:$(OBJDIR)/import.h \ @@ -1138,27 +1280,34 @@ $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \ $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \ $(OBJDIR)/purge_.c:$(OBJDIR)/purge.h \ $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \ $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \ + $(OBJDIR)/repolist_.c:$(OBJDIR)/repolist.h \ $(OBJDIR)/report_.c:$(OBJDIR)/report.h \ $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \ $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \ $(OBJDIR)/search_.c:$(OBJDIR)/search.h \ + $(OBJDIR)/security_audit_.c:$(OBJDIR)/security_audit.h \ $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \ + $(OBJDIR)/setupuser_.c:$(OBJDIR)/setupuser.h \ $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \ + $(OBJDIR)/sha1hard_.c:$(OBJDIR)/sha1hard.h \ + $(OBJDIR)/sha3_.c:$(OBJDIR)/sha3.h \ $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h \ $(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \ $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \ + $(OBJDIR)/smtp_.c:$(OBJDIR)/smtp.h \ $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \ $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \ $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \ $(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \ $(OBJDIR)/style_.c:$(OBJDIR)/style.h \ $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \ $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \ $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \ + $(OBJDIR)/terminal_.c:$(OBJDIR)/terminal.h \ $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \ $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \ $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \ $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \ $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \ @@ -1169,10 +1318,11 @@ $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \ $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \ + $(OBJDIR)/webmail_.c:$(OBJDIR)/webmail.h \ $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \ $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \ $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \ $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \ $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \ @@ -1193,10 +1343,26 @@ $(OBJDIR)/add.o: $(OBJDIR)/add_.c $(OBJDIR)/add.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/add.o -c $(OBJDIR)/add_.c $(OBJDIR)/add.h: $(OBJDIR)/headers + +$(OBJDIR)/ajax_.c: $(SRCDIR)/ajax.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/ajax.c >$@ + +$(OBJDIR)/ajax.o: $(OBJDIR)/ajax_.c $(OBJDIR)/ajax.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/ajax.o -c $(OBJDIR)/ajax_.c + +$(OBJDIR)/ajax.h: $(OBJDIR)/headers + +$(OBJDIR)/alerts_.c: $(SRCDIR)/alerts.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/alerts.c >$@ + +$(OBJDIR)/alerts.o: $(OBJDIR)/alerts_.c $(OBJDIR)/alerts.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/alerts.o -c $(OBJDIR)/alerts_.c + +$(OBJDIR)/alerts.h: $(OBJDIR)/headers $(OBJDIR)/allrepo_.c: $(SRCDIR)/allrepo.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/allrepo.c >$@ $(OBJDIR)/allrepo.o: $(OBJDIR)/allrepo_.c $(OBJDIR)/allrepo.h $(SRCDIR)/config.h @@ -1209,10 +1375,26 @@ $(OBJDIR)/attach.o: $(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c $(OBJDIR)/attach.h: $(OBJDIR)/headers + +$(OBJDIR)/backlink_.c: $(SRCDIR)/backlink.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/backlink.c >$@ + +$(OBJDIR)/backlink.o: $(OBJDIR)/backlink_.c $(OBJDIR)/backlink.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/backlink.o -c $(OBJDIR)/backlink_.c + +$(OBJDIR)/backlink.h: $(OBJDIR)/headers + +$(OBJDIR)/backoffice_.c: $(SRCDIR)/backoffice.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/backoffice.c >$@ + +$(OBJDIR)/backoffice.o: $(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/backoffice.o -c $(OBJDIR)/backoffice_.c + +$(OBJDIR)/backoffice.h: $(OBJDIR)/headers $(OBJDIR)/bag_.c: $(SRCDIR)/bag.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/bag.c >$@ $(OBJDIR)/bag.o: $(OBJDIR)/bag_.c $(OBJDIR)/bag.h $(SRCDIR)/config.h @@ -1273,10 +1455,18 @@ $(OBJDIR)/cache.o: $(OBJDIR)/cache_.c $(OBJDIR)/cache.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/cache.o -c $(OBJDIR)/cache_.c $(OBJDIR)/cache.h: $(OBJDIR)/headers + +$(OBJDIR)/capabilities_.c: $(SRCDIR)/capabilities.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/capabilities.c >$@ + +$(OBJDIR)/capabilities.o: $(OBJDIR)/capabilities_.c $(OBJDIR)/capabilities.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/capabilities.o -c $(OBJDIR)/capabilities_.c + +$(OBJDIR)/capabilities.h: $(OBJDIR)/headers $(OBJDIR)/captcha_.c: $(SRCDIR)/captcha.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/captcha.c >$@ $(OBJDIR)/captcha.o: $(OBJDIR)/captcha_.c $(OBJDIR)/captcha.h $(SRCDIR)/config.h @@ -1345,10 +1535,18 @@ $(OBJDIR)/content.o: $(OBJDIR)/content_.c $(OBJDIR)/content.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/content.o -c $(OBJDIR)/content_.c $(OBJDIR)/content.h: $(OBJDIR)/headers + +$(OBJDIR)/cookies_.c: $(SRCDIR)/cookies.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/cookies.c >$@ + +$(OBJDIR)/cookies.o: $(OBJDIR)/cookies_.c $(OBJDIR)/cookies.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/cookies.o -c $(OBJDIR)/cookies_.c + +$(OBJDIR)/cookies.h: $(OBJDIR)/headers $(OBJDIR)/db_.c: $(SRCDIR)/db.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/db.c >$@ $(OBJDIR)/db.o: $(OBJDIR)/db_.c $(OBJDIR)/db.h $(SRCDIR)/config.h @@ -1369,10 +1567,18 @@ $(OBJDIR)/deltacmd.o: $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/deltacmd.o -c $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h: $(OBJDIR)/headers + +$(OBJDIR)/deltafunc_.c: $(SRCDIR)/deltafunc.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/deltafunc.c >$@ + +$(OBJDIR)/deltafunc.o: $(OBJDIR)/deltafunc_.c $(OBJDIR)/deltafunc.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/deltafunc.o -c $(OBJDIR)/deltafunc_.c + +$(OBJDIR)/deltafunc.h: $(OBJDIR)/headers $(OBJDIR)/descendants_.c: $(SRCDIR)/descendants.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/descendants.c >$@ $(OBJDIR)/descendants.o: $(OBJDIR)/descendants_.c $(OBJDIR)/descendants.h $(SRCDIR)/config.h @@ -1417,10 +1623,18 @@ $(OBJDIR)/encode.o: $(OBJDIR)/encode_.c $(OBJDIR)/encode.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/encode.o -c $(OBJDIR)/encode_.c $(OBJDIR)/encode.h: $(OBJDIR)/headers + +$(OBJDIR)/etag_.c: $(SRCDIR)/etag.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/etag.c >$@ + +$(OBJDIR)/etag.o: $(OBJDIR)/etag_.c $(OBJDIR)/etag.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/etag.o -c $(OBJDIR)/etag_.c + +$(OBJDIR)/etag.h: $(OBJDIR)/headers $(OBJDIR)/event_.c: $(SRCDIR)/event.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/event.c >$@ $(OBJDIR)/event.o: $(OBJDIR)/event_.c $(OBJDIR)/event.h $(SRCDIR)/config.h @@ -1433,18 +1647,34 @@ $(OBJDIR)/export.o: $(OBJDIR)/export_.c $(OBJDIR)/export.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/export.o -c $(OBJDIR)/export_.c $(OBJDIR)/export.h: $(OBJDIR)/headers + +$(OBJDIR)/extcgi_.c: $(SRCDIR)/extcgi.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/extcgi.c >$@ + +$(OBJDIR)/extcgi.o: $(OBJDIR)/extcgi_.c $(OBJDIR)/extcgi.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/extcgi.o -c $(OBJDIR)/extcgi_.c + +$(OBJDIR)/extcgi.h: $(OBJDIR)/headers $(OBJDIR)/file_.c: $(SRCDIR)/file.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/file.c >$@ $(OBJDIR)/file.o: $(OBJDIR)/file_.c $(OBJDIR)/file.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/file.o -c $(OBJDIR)/file_.c $(OBJDIR)/file.h: $(OBJDIR)/headers + +$(OBJDIR)/fileedit_.c: $(SRCDIR)/fileedit.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/fileedit.c >$@ + +$(OBJDIR)/fileedit.o: $(OBJDIR)/fileedit_.c $(OBJDIR)/fileedit.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/fileedit.o -c $(OBJDIR)/fileedit_.c + +$(OBJDIR)/fileedit.h: $(OBJDIR)/headers $(OBJDIR)/finfo_.c: $(SRCDIR)/finfo.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/finfo.c >$@ $(OBJDIR)/finfo.o: $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h $(SRCDIR)/config.h @@ -1457,10 +1687,18 @@ $(OBJDIR)/foci.o: $(OBJDIR)/foci_.c $(OBJDIR)/foci.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/foci.o -c $(OBJDIR)/foci_.c $(OBJDIR)/foci.h: $(OBJDIR)/headers + +$(OBJDIR)/forum_.c: $(SRCDIR)/forum.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/forum.c >$@ + +$(OBJDIR)/forum.o: $(OBJDIR)/forum_.c $(OBJDIR)/forum.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/forum.o -c $(OBJDIR)/forum_.c + +$(OBJDIR)/forum.h: $(OBJDIR)/headers $(OBJDIR)/fshell_.c: $(SRCDIR)/fshell.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/fshell.c >$@ $(OBJDIR)/fshell.o: $(OBJDIR)/fshell_.c $(OBJDIR)/fshell.h $(SRCDIR)/config.h @@ -1473,10 +1711,18 @@ $(OBJDIR)/fusefs.o: $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/fusefs.o -c $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h: $(OBJDIR)/headers + +$(OBJDIR)/fuzz_.c: $(SRCDIR)/fuzz.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/fuzz.c >$@ + +$(OBJDIR)/fuzz.o: $(OBJDIR)/fuzz_.c $(OBJDIR)/fuzz.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/fuzz.o -c $(OBJDIR)/fuzz_.c + +$(OBJDIR)/fuzz.h: $(OBJDIR)/headers $(OBJDIR)/glob_.c: $(SRCDIR)/glob.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/glob.c >$@ $(OBJDIR)/glob.o: $(OBJDIR)/glob_.c $(OBJDIR)/glob.h $(SRCDIR)/config.h @@ -1497,10 +1743,18 @@ $(OBJDIR)/gzip.o: $(OBJDIR)/gzip_.c $(OBJDIR)/gzip.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/gzip.o -c $(OBJDIR)/gzip_.c $(OBJDIR)/gzip.h: $(OBJDIR)/headers + +$(OBJDIR)/hname_.c: $(SRCDIR)/hname.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/hname.c >$@ + +$(OBJDIR)/hname.o: $(OBJDIR)/hname_.c $(OBJDIR)/hname.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/hname.o -c $(OBJDIR)/hname_.c + +$(OBJDIR)/hname.h: $(OBJDIR)/headers $(OBJDIR)/http_.c: $(SRCDIR)/http.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/http.c >$@ $(OBJDIR)/http.o: $(OBJDIR)/http_.c $(OBJDIR)/http.h $(SRCDIR)/config.h @@ -1849,10 +2103,18 @@ $(OBJDIR)/regexp.o: $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/regexp.o -c $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h: $(OBJDIR)/headers + +$(OBJDIR)/repolist_.c: $(SRCDIR)/repolist.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/repolist.c >$@ + +$(OBJDIR)/repolist.o: $(OBJDIR)/repolist_.c $(OBJDIR)/repolist.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/repolist.o -c $(OBJDIR)/repolist_.c + +$(OBJDIR)/repolist.h: $(OBJDIR)/headers $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/report.c >$@ $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h @@ -1881,26 +2143,58 @@ $(OBJDIR)/search.o: $(OBJDIR)/search_.c $(OBJDIR)/search.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/search.o -c $(OBJDIR)/search_.c $(OBJDIR)/search.h: $(OBJDIR)/headers + +$(OBJDIR)/security_audit_.c: $(SRCDIR)/security_audit.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/security_audit.c >$@ + +$(OBJDIR)/security_audit.o: $(OBJDIR)/security_audit_.c $(OBJDIR)/security_audit.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/security_audit.o -c $(OBJDIR)/security_audit_.c + +$(OBJDIR)/security_audit.h: $(OBJDIR)/headers $(OBJDIR)/setup_.c: $(SRCDIR)/setup.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/setup.c >$@ $(OBJDIR)/setup.o: $(OBJDIR)/setup_.c $(OBJDIR)/setup.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/setup.o -c $(OBJDIR)/setup_.c $(OBJDIR)/setup.h: $(OBJDIR)/headers + +$(OBJDIR)/setupuser_.c: $(SRCDIR)/setupuser.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/setupuser.c >$@ + +$(OBJDIR)/setupuser.o: $(OBJDIR)/setupuser_.c $(OBJDIR)/setupuser.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/setupuser.o -c $(OBJDIR)/setupuser_.c + +$(OBJDIR)/setupuser.h: $(OBJDIR)/headers $(OBJDIR)/sha1_.c: $(SRCDIR)/sha1.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/sha1.c >$@ $(OBJDIR)/sha1.o: $(OBJDIR)/sha1_.c $(OBJDIR)/sha1.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/sha1.o -c $(OBJDIR)/sha1_.c $(OBJDIR)/sha1.h: $(OBJDIR)/headers + +$(OBJDIR)/sha1hard_.c: $(SRCDIR)/sha1hard.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/sha1hard.c >$@ + +$(OBJDIR)/sha1hard.o: $(OBJDIR)/sha1hard_.c $(OBJDIR)/sha1hard.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/sha1hard.o -c $(OBJDIR)/sha1hard_.c + +$(OBJDIR)/sha1hard.h: $(OBJDIR)/headers + +$(OBJDIR)/sha3_.c: $(SRCDIR)/sha3.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/sha3.c >$@ + +$(OBJDIR)/sha3.o: $(OBJDIR)/sha3_.c $(OBJDIR)/sha3.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/sha3.o -c $(OBJDIR)/sha3_.c + +$(OBJDIR)/sha3.h: $(OBJDIR)/headers $(OBJDIR)/shun_.c: $(SRCDIR)/shun.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/shun.c >$@ $(OBJDIR)/shun.o: $(OBJDIR)/shun_.c $(OBJDIR)/shun.h $(SRCDIR)/config.h @@ -1921,10 +2215,18 @@ $(OBJDIR)/skins.o: $(OBJDIR)/skins_.c $(OBJDIR)/skins.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/skins.o -c $(OBJDIR)/skins_.c $(OBJDIR)/skins.h: $(OBJDIR)/headers + +$(OBJDIR)/smtp_.c: $(SRCDIR)/smtp.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/smtp.c >$@ + +$(OBJDIR)/smtp.o: $(OBJDIR)/smtp_.c $(OBJDIR)/smtp.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/smtp.o -c $(OBJDIR)/smtp_.c + +$(OBJDIR)/smtp.h: $(OBJDIR)/headers $(OBJDIR)/sqlcmd_.c: $(SRCDIR)/sqlcmd.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/sqlcmd.c >$@ $(OBJDIR)/sqlcmd.o: $(OBJDIR)/sqlcmd_.c $(OBJDIR)/sqlcmd.h $(SRCDIR)/config.h @@ -1985,10 +2287,18 @@ $(OBJDIR)/tar.o: $(OBJDIR)/tar_.c $(OBJDIR)/tar.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/tar.o -c $(OBJDIR)/tar_.c $(OBJDIR)/tar.h: $(OBJDIR)/headers + +$(OBJDIR)/terminal_.c: $(SRCDIR)/terminal.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/terminal.c >$@ + +$(OBJDIR)/terminal.o: $(OBJDIR)/terminal_.c $(OBJDIR)/terminal.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/terminal.o -c $(OBJDIR)/terminal_.c + +$(OBJDIR)/terminal.h: $(OBJDIR)/headers $(OBJDIR)/th_main_.c: $(SRCDIR)/th_main.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/th_main.c >$@ $(OBJDIR)/th_main.o: $(OBJDIR)/th_main_.c $(OBJDIR)/th_main.h $(SRCDIR)/config.h @@ -2097,10 +2407,18 @@ $(OBJDIR)/vfile.o: $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/vfile.o -c $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h: $(OBJDIR)/headers + +$(OBJDIR)/webmail_.c: $(SRCDIR)/webmail.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/webmail.c >$@ + +$(OBJDIR)/webmail.o: $(OBJDIR)/webmail_.c $(OBJDIR)/webmail.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/webmail.o -c $(OBJDIR)/webmail_.c + +$(OBJDIR)/webmail.h: $(OBJDIR)/headers $(OBJDIR)/wiki_.c: $(SRCDIR)/wiki.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/wiki.c >$@ $(OBJDIR)/wiki.o: $(OBJDIR)/wiki_.c $(OBJDIR)/wiki.h $(SRCDIR)/config.h @@ -2165,10 +2483,11 @@ $(OBJDIR)/zip.h: $(OBJDIR)/headers MINGW_OPTIONS = -D_HAVE__MINGW_H SQLITE_OPTIONS = -DNDEBUG=1 \ + -DSQLITE_DQS=0 \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_DEFAULT_MEMSTATUS=0 \ -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ -DSQLITE_OMIT_DECLTYPE \ @@ -2180,24 +2499,54 @@ -DSQLITE_USE_ALLOCA \ -DSQLITE_ENABLE_LOCKING_STYLE=0 \ -DSQLITE_DEFAULT_FILE_FORMAT=4 \ -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ -DSQLITE_ENABLE_FTS4 \ - -DSQLITE_ENABLE_FTS3_PARENTHESIS \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_JSON1 \ -DSQLITE_ENABLE_FTS5 \ + -DSQLITE_ENABLE_STMTVTAB \ + -DSQLITE_HAVE_ZLIB \ + -DSQLITE_INTROSPECTION_PRAGMAS \ + -DSQLITE_ENABLE_DBPAGE_VTAB \ + -DSQLITE_TRUSTED_SCHEMA=0 \ -DSQLITE_WIN32_NO_ANSI \ $(MINGW_OPTIONS) \ -DSQLITE_USE_MALLOC_H \ -DSQLITE_USE_MSIZE -SHELL_OPTIONS = -Dmain=sqlite3_shell \ +SHELL_OPTIONS = -DNDEBUG=1 \ + -DSQLITE_DQS=0 \ + -DSQLITE_THREADSAFE=0 \ + -DSQLITE_DEFAULT_MEMSTATUS=0 \ + -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ + -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ + -DSQLITE_OMIT_DECLTYPE \ + -DSQLITE_OMIT_DEPRECATED \ + -DSQLITE_OMIT_PROGRESS_CALLBACK \ + -DSQLITE_OMIT_SHARED_CACHE \ + -DSQLITE_OMIT_LOAD_EXTENSION \ + -DSQLITE_MAX_EXPR_DEPTH=0 \ + -DSQLITE_USE_ALLOCA \ + -DSQLITE_ENABLE_LOCKING_STYLE=0 \ + -DSQLITE_DEFAULT_FILE_FORMAT=4 \ + -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ + -DSQLITE_ENABLE_FTS4 \ + -DSQLITE_ENABLE_DBSTAT_VTAB \ + -DSQLITE_ENABLE_JSON1 \ + -DSQLITE_ENABLE_FTS5 \ + -DSQLITE_ENABLE_STMTVTAB \ + -DSQLITE_HAVE_ZLIB \ + -DSQLITE_INTROSPECTION_PRAGMAS \ + -DSQLITE_ENABLE_DBPAGE_VTAB \ + -DSQLITE_TRUSTED_SCHEMA=0 \ + -Dmain=sqlite3_shell \ -DSQLITE_SHELL_IS_UTF8=1 \ -DSQLITE_OMIT_LOAD_EXTENSION=1 \ -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \ - -DSQLITE_SHELL_DBNAME_PROC=fossil_open \ + -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \ + -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \ -Daccess=file_access \ -Dsystem=fossil_system \ -Dgetenv=fossil_getenv \ -Dfopen=fossil_fopen @@ -2213,11 +2562,11 @@ $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $@ $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h $(OBJDIR)/shell.o: $(SQLITE3_SHELL_SRC) $(SRCDIR)/sqlite3.h $(SRCDIR)/../win/Makefile.mingw - $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SQLITE3_SHELL_SRC) -o $@ + $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) $(SEE_FLAGS) -c $(SQLITE3_SHELL_SRC) -o $@ $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $@ $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c Index: win/Makefile.mingw.mistachkin ================================================================== --- win/Makefile.mingw.mistachkin +++ win/Makefile.mingw.mistachkin @@ -96,10 +96,14 @@ FOSSIL_ENABLE_TCL_PRIVATE_STUBS = 1 #### Use 'system' SQLite # # USE_SYSTEM_SQLITE = 1 + +#### Use POSIX memory APIs from "sys/mman.h" +# +# USE_MMAN_H = 1 #### Use the SQLite Encryption Extension # # USE_SEE = 1 @@ -154,13 +158,13 @@ ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support -# for both SSLv2 and SSLv3 (i.e. thereby forcing the use of TLS). +# for SSLv3 (i.e. thereby forcing the use of TLS). # -SSLCONFIG += no-ssl2 no-ssl3 no-shared +SSLCONFIG += no-ssl3 no-weak-ssl-ciphers no-shared #### When using zlib, make sure that OpenSSL is configured to use the zlib # that Fossil knows about (i.e. the one within the source tree). # ifndef FOSSIL_ENABLE_MINIZ @@ -170,11 +174,11 @@ #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2j +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1g OPENSSLINCDIR = $(OPENSSLDIR)/include OPENSSLLIBDIR = $(OPENSSLDIR) #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro @@ -225,11 +229,11 @@ # run on the target platform. This is usually the almost the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # -TCC = $(PREFIX)$(TCCEXE) -Wall +TCC = $(PREFIX)$(TCCEXE) -Wall -Wdeclaration-after-statement #### Add the necessary command line options to build with debugging # symbols, if enabled. # ifdef FOSSIL_ENABLE_SYMBOLS @@ -333,10 +337,16 @@ # With JSON support ifdef FOSSIL_ENABLE_JSON TCC += -DFOSSIL_ENABLE_JSON=1 RCC += -DFOSSIL_ENABLE_JSON=1 endif + +# With "sys/mman.h" support +ifdef USE_MMAN_H +TCC += -DUSE_MMAN_H=1 +RCC += -DUSE_MMAN_H=1 +endif # With SQLite Encryption Extension support ifdef USE_SEE TCC += -DUSE_SEE=1 RCC += -DUSE_SEE=1 @@ -397,10 +407,14 @@ LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32 endif else LIB += -lkernel32 -lws2_32 endif + +#### Library required for DNS lookups. +# +LIB += -ldnsapi #### Tcl shell for use in running the fossil test suite. This is only # used for testing. # TCLSH = tclsh @@ -418,52 +432,66 @@ -include config.w32 # STOP HERE # You should not need to change anything below this line #-------------------------------------------------------- +XBCC = $(BCC) $(CFLAGS) XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) SRC = \ $(SRCDIR)/add.c \ + $(SRCDIR)/ajax.c \ + $(SRCDIR)/alerts.c \ $(SRCDIR)/allrepo.c \ $(SRCDIR)/attach.c \ + $(SRCDIR)/backlink.c \ + $(SRCDIR)/backoffice.c \ $(SRCDIR)/bag.c \ $(SRCDIR)/bisect.c \ $(SRCDIR)/blob.c \ $(SRCDIR)/branch.c \ $(SRCDIR)/browse.c \ $(SRCDIR)/builtin.c \ $(SRCDIR)/bundle.c \ $(SRCDIR)/cache.c \ + $(SRCDIR)/capabilities.c \ $(SRCDIR)/captcha.c \ $(SRCDIR)/cgi.c \ $(SRCDIR)/checkin.c \ $(SRCDIR)/checkout.c \ $(SRCDIR)/clearsign.c \ $(SRCDIR)/clone.c \ $(SRCDIR)/comformat.c \ $(SRCDIR)/configure.c \ $(SRCDIR)/content.c \ + $(SRCDIR)/cookies.c \ $(SRCDIR)/db.c \ $(SRCDIR)/delta.c \ $(SRCDIR)/deltacmd.c \ + $(SRCDIR)/deltafunc.c \ $(SRCDIR)/descendants.c \ $(SRCDIR)/diff.c \ $(SRCDIR)/diffcmd.c \ $(SRCDIR)/dispatch.c \ $(SRCDIR)/doc.c \ $(SRCDIR)/encode.c \ + $(SRCDIR)/etag.c \ $(SRCDIR)/event.c \ $(SRCDIR)/export.c \ + $(SRCDIR)/extcgi.c \ $(SRCDIR)/file.c \ + $(SRCDIR)/fileedit.c \ $(SRCDIR)/finfo.c \ $(SRCDIR)/foci.c \ + $(SRCDIR)/forum.c \ $(SRCDIR)/fshell.c \ $(SRCDIR)/fusefs.c \ + $(SRCDIR)/fuzz.c \ $(SRCDIR)/glob.c \ $(SRCDIR)/graph.c \ $(SRCDIR)/gzip.c \ + $(SRCDIR)/hname.c \ $(SRCDIR)/http.c \ $(SRCDIR)/http_socket.c \ $(SRCDIR)/http_ssl.c \ $(SRCDIR)/http_transport.c \ $(SRCDIR)/import.c \ @@ -504,27 +532,34 @@ $(SRCDIR)/printf.c \ $(SRCDIR)/publish.c \ $(SRCDIR)/purge.c \ $(SRCDIR)/rebuild.c \ $(SRCDIR)/regexp.c \ + $(SRCDIR)/repolist.c \ $(SRCDIR)/report.c \ $(SRCDIR)/rss.c \ $(SRCDIR)/schema.c \ $(SRCDIR)/search.c \ + $(SRCDIR)/security_audit.c \ $(SRCDIR)/setup.c \ + $(SRCDIR)/setupuser.c \ $(SRCDIR)/sha1.c \ + $(SRCDIR)/sha1hard.c \ + $(SRCDIR)/sha3.c \ $(SRCDIR)/shun.c \ $(SRCDIR)/sitemap.c \ $(SRCDIR)/skins.c \ + $(SRCDIR)/smtp.c \ $(SRCDIR)/sqlcmd.c \ $(SRCDIR)/stash.c \ $(SRCDIR)/stat.c \ $(SRCDIR)/statrep.c \ $(SRCDIR)/style.c \ $(SRCDIR)/sync.c \ $(SRCDIR)/tag.c \ $(SRCDIR)/tar.c \ + $(SRCDIR)/terminal.c \ $(SRCDIR)/th_main.c \ $(SRCDIR)/timeline.c \ $(SRCDIR)/tkt.c \ $(SRCDIR)/tktsetup.c \ $(SRCDIR)/undo.c \ @@ -535,10 +570,11 @@ $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ + $(SRCDIR)/webmail.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winfile.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ @@ -546,10 +582,14 @@ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c EXTRA_FILES = \ $(SRCDIR)/../skins/aht/details.txt \ + $(SRCDIR)/../skins/ardoise/css.txt \ + $(SRCDIR)/../skins/ardoise/details.txt \ + $(SRCDIR)/../skins/ardoise/footer.txt \ + $(SRCDIR)/../skins/ardoise/header.txt \ $(SRCDIR)/../skins/black_and_white/css.txt \ $(SRCDIR)/../skins/black_and_white/details.txt \ $(SRCDIR)/../skins/black_and_white/footer.txt \ $(SRCDIR)/../skins/black_and_white/header.txt \ $(SRCDIR)/../skins/blitz/css.txt \ @@ -560,14 +600,19 @@ $(SRCDIR)/../skins/blitz_no_logo/css.txt \ $(SRCDIR)/../skins/blitz_no_logo/details.txt \ $(SRCDIR)/../skins/blitz_no_logo/footer.txt \ $(SRCDIR)/../skins/blitz_no_logo/header.txt \ $(SRCDIR)/../skins/blitz_no_logo/ticket.txt \ + $(SRCDIR)/../skins/bootstrap/css.txt \ + $(SRCDIR)/../skins/bootstrap/details.txt \ + $(SRCDIR)/../skins/bootstrap/footer.txt \ + $(SRCDIR)/../skins/bootstrap/header.txt \ $(SRCDIR)/../skins/default/css.txt \ $(SRCDIR)/../skins/default/details.txt \ $(SRCDIR)/../skins/default/footer.txt \ $(SRCDIR)/../skins/default/header.txt \ + $(SRCDIR)/../skins/default/js.txt \ $(SRCDIR)/../skins/eagle/css.txt \ $(SRCDIR)/../skins/eagle/details.txt \ $(SRCDIR)/../skins/eagle/footer.txt \ $(SRCDIR)/../skins/eagle/header.txt \ $(SRCDIR)/../skins/enhanced1/css.txt \ @@ -592,53 +637,107 @@ $(SRCDIR)/../skins/rounded1/header.txt \ $(SRCDIR)/../skins/xekri/css.txt \ $(SRCDIR)/../skins/xekri/details.txt \ $(SRCDIR)/../skins/xekri/footer.txt \ $(SRCDIR)/../skins/xekri/header.txt \ + $(SRCDIR)/accordion.js \ + $(SRCDIR)/ci_edit.js \ + $(SRCDIR)/copybtn.js \ + $(SRCDIR)/default.css \ $(SRCDIR)/diff.tcl \ - $(SRCDIR)/markdown.md + $(SRCDIR)/forum.js \ + $(SRCDIR)/fossil.bootstrap.js \ + $(SRCDIR)/fossil.confirmer.js \ + $(SRCDIR)/fossil.dom.js \ + $(SRCDIR)/fossil.fetch.js \ + $(SRCDIR)/fossil.page.fileedit.js \ + $(SRCDIR)/fossil.storage.js \ + $(SRCDIR)/fossil.tabs.js \ + $(SRCDIR)/graph.js \ + $(SRCDIR)/href.js \ + $(SRCDIR)/login.js \ + $(SRCDIR)/markdown.md \ + $(SRCDIR)/menu.js \ + $(SRCDIR)/sbsdiff.js \ + $(SRCDIR)/scroll.js \ + $(SRCDIR)/skin.js \ + $(SRCDIR)/sorttable.js \ + $(SRCDIR)/sounds/0.wav \ + $(SRCDIR)/sounds/1.wav \ + $(SRCDIR)/sounds/2.wav \ + $(SRCDIR)/sounds/3.wav \ + $(SRCDIR)/sounds/4.wav \ + $(SRCDIR)/sounds/5.wav \ + $(SRCDIR)/sounds/6.wav \ + $(SRCDIR)/sounds/7.wav \ + $(SRCDIR)/sounds/8.wav \ + $(SRCDIR)/sounds/9.wav \ + $(SRCDIR)/sounds/a.wav \ + $(SRCDIR)/sounds/b.wav \ + $(SRCDIR)/sounds/c.wav \ + $(SRCDIR)/sounds/d.wav \ + $(SRCDIR)/sounds/e.wav \ + $(SRCDIR)/sounds/f.wav \ + $(SRCDIR)/style.admin_log.css \ + $(SRCDIR)/style.fileedit.css \ + $(SRCDIR)/tree.js \ + $(SRCDIR)/useredit.js \ + $(SRCDIR)/wiki.wiki TRANS_SRC = \ $(OBJDIR)/add_.c \ + $(OBJDIR)/ajax_.c \ + $(OBJDIR)/alerts_.c \ $(OBJDIR)/allrepo_.c \ $(OBJDIR)/attach_.c \ + $(OBJDIR)/backlink_.c \ + $(OBJDIR)/backoffice_.c \ $(OBJDIR)/bag_.c \ $(OBJDIR)/bisect_.c \ $(OBJDIR)/blob_.c \ $(OBJDIR)/branch_.c \ $(OBJDIR)/browse_.c \ $(OBJDIR)/builtin_.c \ $(OBJDIR)/bundle_.c \ $(OBJDIR)/cache_.c \ + $(OBJDIR)/capabilities_.c \ $(OBJDIR)/captcha_.c \ $(OBJDIR)/cgi_.c \ $(OBJDIR)/checkin_.c \ $(OBJDIR)/checkout_.c \ $(OBJDIR)/clearsign_.c \ $(OBJDIR)/clone_.c \ $(OBJDIR)/comformat_.c \ $(OBJDIR)/configure_.c \ $(OBJDIR)/content_.c \ + $(OBJDIR)/cookies_.c \ $(OBJDIR)/db_.c \ $(OBJDIR)/delta_.c \ $(OBJDIR)/deltacmd_.c \ + $(OBJDIR)/deltafunc_.c \ $(OBJDIR)/descendants_.c \ $(OBJDIR)/diff_.c \ $(OBJDIR)/diffcmd_.c \ $(OBJDIR)/dispatch_.c \ $(OBJDIR)/doc_.c \ $(OBJDIR)/encode_.c \ + $(OBJDIR)/etag_.c \ $(OBJDIR)/event_.c \ $(OBJDIR)/export_.c \ + $(OBJDIR)/extcgi_.c \ $(OBJDIR)/file_.c \ + $(OBJDIR)/fileedit_.c \ $(OBJDIR)/finfo_.c \ $(OBJDIR)/foci_.c \ + $(OBJDIR)/forum_.c \ $(OBJDIR)/fshell_.c \ $(OBJDIR)/fusefs_.c \ + $(OBJDIR)/fuzz_.c \ $(OBJDIR)/glob_.c \ $(OBJDIR)/graph_.c \ $(OBJDIR)/gzip_.c \ + $(OBJDIR)/hname_.c \ $(OBJDIR)/http_.c \ $(OBJDIR)/http_socket_.c \ $(OBJDIR)/http_ssl_.c \ $(OBJDIR)/http_transport_.c \ $(OBJDIR)/import_.c \ @@ -679,27 +778,34 @@ $(OBJDIR)/printf_.c \ $(OBJDIR)/publish_.c \ $(OBJDIR)/purge_.c \ $(OBJDIR)/rebuild_.c \ $(OBJDIR)/regexp_.c \ + $(OBJDIR)/repolist_.c \ $(OBJDIR)/report_.c \ $(OBJDIR)/rss_.c \ $(OBJDIR)/schema_.c \ $(OBJDIR)/search_.c \ + $(OBJDIR)/security_audit_.c \ $(OBJDIR)/setup_.c \ + $(OBJDIR)/setupuser_.c \ $(OBJDIR)/sha1_.c \ + $(OBJDIR)/sha1hard_.c \ + $(OBJDIR)/sha3_.c \ $(OBJDIR)/shun_.c \ $(OBJDIR)/sitemap_.c \ $(OBJDIR)/skins_.c \ + $(OBJDIR)/smtp_.c \ $(OBJDIR)/sqlcmd_.c \ $(OBJDIR)/stash_.c \ $(OBJDIR)/stat_.c \ $(OBJDIR)/statrep_.c \ $(OBJDIR)/style_.c \ $(OBJDIR)/sync_.c \ $(OBJDIR)/tag_.c \ $(OBJDIR)/tar_.c \ + $(OBJDIR)/terminal_.c \ $(OBJDIR)/th_main_.c \ $(OBJDIR)/timeline_.c \ $(OBJDIR)/tkt_.c \ $(OBJDIR)/tktsetup_.c \ $(OBJDIR)/undo_.c \ @@ -710,10 +816,11 @@ $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ + $(OBJDIR)/webmail_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winfile_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ @@ -721,48 +828,61 @@ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ $(OBJDIR)/add.o \ + $(OBJDIR)/ajax.o \ + $(OBJDIR)/alerts.o \ $(OBJDIR)/allrepo.o \ $(OBJDIR)/attach.o \ + $(OBJDIR)/backlink.o \ + $(OBJDIR)/backoffice.o \ $(OBJDIR)/bag.o \ $(OBJDIR)/bisect.o \ $(OBJDIR)/blob.o \ $(OBJDIR)/branch.o \ $(OBJDIR)/browse.o \ $(OBJDIR)/builtin.o \ $(OBJDIR)/bundle.o \ $(OBJDIR)/cache.o \ + $(OBJDIR)/capabilities.o \ $(OBJDIR)/captcha.o \ $(OBJDIR)/cgi.o \ $(OBJDIR)/checkin.o \ $(OBJDIR)/checkout.o \ $(OBJDIR)/clearsign.o \ $(OBJDIR)/clone.o \ $(OBJDIR)/comformat.o \ $(OBJDIR)/configure.o \ $(OBJDIR)/content.o \ + $(OBJDIR)/cookies.o \ $(OBJDIR)/db.o \ $(OBJDIR)/delta.o \ $(OBJDIR)/deltacmd.o \ + $(OBJDIR)/deltafunc.o \ $(OBJDIR)/descendants.o \ $(OBJDIR)/diff.o \ $(OBJDIR)/diffcmd.o \ $(OBJDIR)/dispatch.o \ $(OBJDIR)/doc.o \ $(OBJDIR)/encode.o \ + $(OBJDIR)/etag.o \ $(OBJDIR)/event.o \ $(OBJDIR)/export.o \ + $(OBJDIR)/extcgi.o \ $(OBJDIR)/file.o \ + $(OBJDIR)/fileedit.o \ $(OBJDIR)/finfo.o \ $(OBJDIR)/foci.o \ + $(OBJDIR)/forum.o \ $(OBJDIR)/fshell.o \ $(OBJDIR)/fusefs.o \ + $(OBJDIR)/fuzz.o \ $(OBJDIR)/glob.o \ $(OBJDIR)/graph.o \ $(OBJDIR)/gzip.o \ + $(OBJDIR)/hname.o \ $(OBJDIR)/http.o \ $(OBJDIR)/http_socket.o \ $(OBJDIR)/http_ssl.o \ $(OBJDIR)/http_transport.o \ $(OBJDIR)/import.o \ @@ -803,27 +923,34 @@ $(OBJDIR)/printf.o \ $(OBJDIR)/publish.o \ $(OBJDIR)/purge.o \ $(OBJDIR)/rebuild.o \ $(OBJDIR)/regexp.o \ + $(OBJDIR)/repolist.o \ $(OBJDIR)/report.o \ $(OBJDIR)/rss.o \ $(OBJDIR)/schema.o \ $(OBJDIR)/search.o \ + $(OBJDIR)/security_audit.o \ $(OBJDIR)/setup.o \ + $(OBJDIR)/setupuser.o \ $(OBJDIR)/sha1.o \ + $(OBJDIR)/sha1hard.o \ + $(OBJDIR)/sha3.o \ $(OBJDIR)/shun.o \ $(OBJDIR)/sitemap.o \ $(OBJDIR)/skins.o \ + $(OBJDIR)/smtp.o \ $(OBJDIR)/sqlcmd.o \ $(OBJDIR)/stash.o \ $(OBJDIR)/stat.o \ $(OBJDIR)/statrep.o \ $(OBJDIR)/style.o \ $(OBJDIR)/sync.o \ $(OBJDIR)/tag.o \ $(OBJDIR)/tar.o \ + $(OBJDIR)/terminal.o \ $(OBJDIR)/th_main.o \ $(OBJDIR)/timeline.o \ $(OBJDIR)/tkt.o \ $(OBJDIR)/tktsetup.o \ $(OBJDIR)/undo.o \ @@ -834,10 +961,11 @@ $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ + $(OBJDIR)/webmail.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winfile.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ @@ -902,14 +1030,14 @@ $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(INSTALLDIR)) - $(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) + $(CP) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) else $(MKDIR) $(INSTALLDIR) - $(MV) $(APPNAME) $(INSTALLDIR) + $(CP) $(APPNAME) $(INSTALLDIR) endif $(OBJDIR): ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(OBJDIR)) @@ -916,26 +1044,26 @@ else $(MKDIR) $(OBJDIR) endif $(TRANSLATE): $(SRCDIR)/translate.c - $(BCC) -o $@ $(SRCDIR)/translate.c + $(XBCC) -o $@ $(SRCDIR)/translate.c $(MAKEHEADERS): $(SRCDIR)/makeheaders.c - $(BCC) -o $@ $(SRCDIR)/makeheaders.c + $(XBCC) -o $@ $(SRCDIR)/makeheaders.c $(MKINDEX): $(SRCDIR)/mkindex.c - $(BCC) -o $@ $(SRCDIR)/mkindex.c + $(XBCC) -o $@ $(SRCDIR)/mkindex.c $(MKBUILTIN): $(SRCDIR)/mkbuiltin.c - $(BCC) -o $@ $(SRCDIR)/mkbuiltin.c + $(XBCC) -o $@ $(SRCDIR)/mkbuiltin.c $(MKVERSION): $(SRCDIR)/mkversion.c - $(BCC) -o $@ $(SRCDIR)/mkversion.c + $(XBCC) -o $@ $(SRCDIR)/mkversion.c $(CODECHECK1): $(SRCDIR)/codecheck1.c - $(BCC) -o $@ $(SRCDIR)/codecheck1.c + $(XBCC) -o $@ $(SRCDIR)/codecheck1.c # WARNING. DANGER. Running the test suite modifies the repository the # build is done from, i.e. the checkout belongs to. Do not sync/push # the repository after running the tests. test: $(OBJDIR) $(APPNAME) @@ -970,11 +1098,11 @@ SQLITE3_SHELL_SRC.0 = shell.c SQLITE3_SHELL_SRC.1 = shell-see.c SQLITE3_SHELL_SRC. = shell.c SQLITE3_SHELL_SRC = $(SRCDIR)/$(SQLITE3_SHELL_SRC.$(USE_SEE)) SEE_FLAGS.0 = -SEE_FLAGS.1 = -DSQLITE_HAS_CODEC +SEE_FLAGS.1 = -DSQLITE_HAS_CODEC -DSQLITE_SHELL_DBKEY_PROC=fossil_key SEE_FLAGS. = SEE_FLAGS = $(SEE_FLAGS.$(USE_SEE)) EXTRAOBJ = \ @@ -1005,10 +1133,11 @@ BLDTARGETS = zlib endif openssl: $(BLDTARGETS) cd $(OPENSSLLIBDIR);./Configure --cross-compile-prefix=$(PREFIX) $(SSLCONFIG) + sed -i -e 's/^PERL=C:\\.*$$/PERL=perl.exe/i' $(OPENSSLLIBDIR)/Makefile $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) build_libs clean-openssl: $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) clean @@ -1056,48 +1185,61 @@ $(OBJDIR)/builtin_data.h: $(MKBUILTIN) $(EXTRA_FILES) $(MKBUILTIN) --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(MAKEHEADERS) $(OBJDIR)/VERSION.h $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h \ + $(OBJDIR)/ajax_.c:$(OBJDIR)/ajax.h \ + $(OBJDIR)/alerts_.c:$(OBJDIR)/alerts.h \ $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \ $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \ + $(OBJDIR)/backlink_.c:$(OBJDIR)/backlink.h \ + $(OBJDIR)/backoffice_.c:$(OBJDIR)/backoffice.h \ $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \ $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \ $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h \ $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h \ $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \ $(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \ $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \ $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \ + $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \ $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \ $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \ $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \ $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \ $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \ $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \ $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \ $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h \ $(OBJDIR)/content_.c:$(OBJDIR)/content.h \ + $(OBJDIR)/cookies_.c:$(OBJDIR)/cookies.h \ $(OBJDIR)/db_.c:$(OBJDIR)/db.h \ $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h \ $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h \ + $(OBJDIR)/deltafunc_.c:$(OBJDIR)/deltafunc.h \ $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h \ $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h \ $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h \ $(OBJDIR)/dispatch_.c:$(OBJDIR)/dispatch.h \ $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h \ $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h \ + $(OBJDIR)/etag_.c:$(OBJDIR)/etag.h \ $(OBJDIR)/event_.c:$(OBJDIR)/event.h \ $(OBJDIR)/export_.c:$(OBJDIR)/export.h \ + $(OBJDIR)/extcgi_.c:$(OBJDIR)/extcgi.h \ $(OBJDIR)/file_.c:$(OBJDIR)/file.h \ + $(OBJDIR)/fileedit_.c:$(OBJDIR)/fileedit.h \ $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h \ $(OBJDIR)/foci_.c:$(OBJDIR)/foci.h \ + $(OBJDIR)/forum_.c:$(OBJDIR)/forum.h \ $(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \ $(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \ + $(OBJDIR)/fuzz_.c:$(OBJDIR)/fuzz.h \ $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \ $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \ $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \ + $(OBJDIR)/hname_.c:$(OBJDIR)/hname.h \ $(OBJDIR)/http_.c:$(OBJDIR)/http.h \ $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h \ $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h \ $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h \ $(OBJDIR)/import_.c:$(OBJDIR)/import.h \ @@ -1138,27 +1280,34 @@ $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \ $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \ $(OBJDIR)/purge_.c:$(OBJDIR)/purge.h \ $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \ $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \ + $(OBJDIR)/repolist_.c:$(OBJDIR)/repolist.h \ $(OBJDIR)/report_.c:$(OBJDIR)/report.h \ $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \ $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \ $(OBJDIR)/search_.c:$(OBJDIR)/search.h \ + $(OBJDIR)/security_audit_.c:$(OBJDIR)/security_audit.h \ $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \ + $(OBJDIR)/setupuser_.c:$(OBJDIR)/setupuser.h \ $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \ + $(OBJDIR)/sha1hard_.c:$(OBJDIR)/sha1hard.h \ + $(OBJDIR)/sha3_.c:$(OBJDIR)/sha3.h \ $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h \ $(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \ $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \ + $(OBJDIR)/smtp_.c:$(OBJDIR)/smtp.h \ $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \ $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \ $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \ $(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \ $(OBJDIR)/style_.c:$(OBJDIR)/style.h \ $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \ $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \ $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \ + $(OBJDIR)/terminal_.c:$(OBJDIR)/terminal.h \ $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \ $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \ $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \ $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \ $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \ @@ -1169,10 +1318,11 @@ $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \ $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \ + $(OBJDIR)/webmail_.c:$(OBJDIR)/webmail.h \ $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \ $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \ $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \ $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \ $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \ @@ -1193,10 +1343,26 @@ $(OBJDIR)/add.o: $(OBJDIR)/add_.c $(OBJDIR)/add.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/add.o -c $(OBJDIR)/add_.c $(OBJDIR)/add.h: $(OBJDIR)/headers + +$(OBJDIR)/ajax_.c: $(SRCDIR)/ajax.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/ajax.c >$@ + +$(OBJDIR)/ajax.o: $(OBJDIR)/ajax_.c $(OBJDIR)/ajax.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/ajax.o -c $(OBJDIR)/ajax_.c + +$(OBJDIR)/ajax.h: $(OBJDIR)/headers + +$(OBJDIR)/alerts_.c: $(SRCDIR)/alerts.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/alerts.c >$@ + +$(OBJDIR)/alerts.o: $(OBJDIR)/alerts_.c $(OBJDIR)/alerts.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/alerts.o -c $(OBJDIR)/alerts_.c + +$(OBJDIR)/alerts.h: $(OBJDIR)/headers $(OBJDIR)/allrepo_.c: $(SRCDIR)/allrepo.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/allrepo.c >$@ $(OBJDIR)/allrepo.o: $(OBJDIR)/allrepo_.c $(OBJDIR)/allrepo.h $(SRCDIR)/config.h @@ -1209,10 +1375,26 @@ $(OBJDIR)/attach.o: $(OBJDIR)/attach_.c $(OBJDIR)/attach.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/attach.o -c $(OBJDIR)/attach_.c $(OBJDIR)/attach.h: $(OBJDIR)/headers + +$(OBJDIR)/backlink_.c: $(SRCDIR)/backlink.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/backlink.c >$@ + +$(OBJDIR)/backlink.o: $(OBJDIR)/backlink_.c $(OBJDIR)/backlink.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/backlink.o -c $(OBJDIR)/backlink_.c + +$(OBJDIR)/backlink.h: $(OBJDIR)/headers + +$(OBJDIR)/backoffice_.c: $(SRCDIR)/backoffice.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/backoffice.c >$@ + +$(OBJDIR)/backoffice.o: $(OBJDIR)/backoffice_.c $(OBJDIR)/backoffice.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/backoffice.o -c $(OBJDIR)/backoffice_.c + +$(OBJDIR)/backoffice.h: $(OBJDIR)/headers $(OBJDIR)/bag_.c: $(SRCDIR)/bag.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/bag.c >$@ $(OBJDIR)/bag.o: $(OBJDIR)/bag_.c $(OBJDIR)/bag.h $(SRCDIR)/config.h @@ -1273,10 +1455,18 @@ $(OBJDIR)/cache.o: $(OBJDIR)/cache_.c $(OBJDIR)/cache.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/cache.o -c $(OBJDIR)/cache_.c $(OBJDIR)/cache.h: $(OBJDIR)/headers + +$(OBJDIR)/capabilities_.c: $(SRCDIR)/capabilities.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/capabilities.c >$@ + +$(OBJDIR)/capabilities.o: $(OBJDIR)/capabilities_.c $(OBJDIR)/capabilities.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/capabilities.o -c $(OBJDIR)/capabilities_.c + +$(OBJDIR)/capabilities.h: $(OBJDIR)/headers $(OBJDIR)/captcha_.c: $(SRCDIR)/captcha.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/captcha.c >$@ $(OBJDIR)/captcha.o: $(OBJDIR)/captcha_.c $(OBJDIR)/captcha.h $(SRCDIR)/config.h @@ -1345,10 +1535,18 @@ $(OBJDIR)/content.o: $(OBJDIR)/content_.c $(OBJDIR)/content.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/content.o -c $(OBJDIR)/content_.c $(OBJDIR)/content.h: $(OBJDIR)/headers + +$(OBJDIR)/cookies_.c: $(SRCDIR)/cookies.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/cookies.c >$@ + +$(OBJDIR)/cookies.o: $(OBJDIR)/cookies_.c $(OBJDIR)/cookies.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/cookies.o -c $(OBJDIR)/cookies_.c + +$(OBJDIR)/cookies.h: $(OBJDIR)/headers $(OBJDIR)/db_.c: $(SRCDIR)/db.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/db.c >$@ $(OBJDIR)/db.o: $(OBJDIR)/db_.c $(OBJDIR)/db.h $(SRCDIR)/config.h @@ -1369,10 +1567,18 @@ $(OBJDIR)/deltacmd.o: $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/deltacmd.o -c $(OBJDIR)/deltacmd_.c $(OBJDIR)/deltacmd.h: $(OBJDIR)/headers + +$(OBJDIR)/deltafunc_.c: $(SRCDIR)/deltafunc.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/deltafunc.c >$@ + +$(OBJDIR)/deltafunc.o: $(OBJDIR)/deltafunc_.c $(OBJDIR)/deltafunc.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/deltafunc.o -c $(OBJDIR)/deltafunc_.c + +$(OBJDIR)/deltafunc.h: $(OBJDIR)/headers $(OBJDIR)/descendants_.c: $(SRCDIR)/descendants.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/descendants.c >$@ $(OBJDIR)/descendants.o: $(OBJDIR)/descendants_.c $(OBJDIR)/descendants.h $(SRCDIR)/config.h @@ -1417,10 +1623,18 @@ $(OBJDIR)/encode.o: $(OBJDIR)/encode_.c $(OBJDIR)/encode.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/encode.o -c $(OBJDIR)/encode_.c $(OBJDIR)/encode.h: $(OBJDIR)/headers + +$(OBJDIR)/etag_.c: $(SRCDIR)/etag.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/etag.c >$@ + +$(OBJDIR)/etag.o: $(OBJDIR)/etag_.c $(OBJDIR)/etag.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/etag.o -c $(OBJDIR)/etag_.c + +$(OBJDIR)/etag.h: $(OBJDIR)/headers $(OBJDIR)/event_.c: $(SRCDIR)/event.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/event.c >$@ $(OBJDIR)/event.o: $(OBJDIR)/event_.c $(OBJDIR)/event.h $(SRCDIR)/config.h @@ -1433,18 +1647,34 @@ $(OBJDIR)/export.o: $(OBJDIR)/export_.c $(OBJDIR)/export.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/export.o -c $(OBJDIR)/export_.c $(OBJDIR)/export.h: $(OBJDIR)/headers + +$(OBJDIR)/extcgi_.c: $(SRCDIR)/extcgi.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/extcgi.c >$@ + +$(OBJDIR)/extcgi.o: $(OBJDIR)/extcgi_.c $(OBJDIR)/extcgi.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/extcgi.o -c $(OBJDIR)/extcgi_.c + +$(OBJDIR)/extcgi.h: $(OBJDIR)/headers $(OBJDIR)/file_.c: $(SRCDIR)/file.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/file.c >$@ $(OBJDIR)/file.o: $(OBJDIR)/file_.c $(OBJDIR)/file.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/file.o -c $(OBJDIR)/file_.c $(OBJDIR)/file.h: $(OBJDIR)/headers + +$(OBJDIR)/fileedit_.c: $(SRCDIR)/fileedit.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/fileedit.c >$@ + +$(OBJDIR)/fileedit.o: $(OBJDIR)/fileedit_.c $(OBJDIR)/fileedit.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/fileedit.o -c $(OBJDIR)/fileedit_.c + +$(OBJDIR)/fileedit.h: $(OBJDIR)/headers $(OBJDIR)/finfo_.c: $(SRCDIR)/finfo.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/finfo.c >$@ $(OBJDIR)/finfo.o: $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h $(SRCDIR)/config.h @@ -1457,10 +1687,18 @@ $(OBJDIR)/foci.o: $(OBJDIR)/foci_.c $(OBJDIR)/foci.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/foci.o -c $(OBJDIR)/foci_.c $(OBJDIR)/foci.h: $(OBJDIR)/headers + +$(OBJDIR)/forum_.c: $(SRCDIR)/forum.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/forum.c >$@ + +$(OBJDIR)/forum.o: $(OBJDIR)/forum_.c $(OBJDIR)/forum.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/forum.o -c $(OBJDIR)/forum_.c + +$(OBJDIR)/forum.h: $(OBJDIR)/headers $(OBJDIR)/fshell_.c: $(SRCDIR)/fshell.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/fshell.c >$@ $(OBJDIR)/fshell.o: $(OBJDIR)/fshell_.c $(OBJDIR)/fshell.h $(SRCDIR)/config.h @@ -1473,10 +1711,18 @@ $(OBJDIR)/fusefs.o: $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/fusefs.o -c $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h: $(OBJDIR)/headers + +$(OBJDIR)/fuzz_.c: $(SRCDIR)/fuzz.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/fuzz.c >$@ + +$(OBJDIR)/fuzz.o: $(OBJDIR)/fuzz_.c $(OBJDIR)/fuzz.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/fuzz.o -c $(OBJDIR)/fuzz_.c + +$(OBJDIR)/fuzz.h: $(OBJDIR)/headers $(OBJDIR)/glob_.c: $(SRCDIR)/glob.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/glob.c >$@ $(OBJDIR)/glob.o: $(OBJDIR)/glob_.c $(OBJDIR)/glob.h $(SRCDIR)/config.h @@ -1497,10 +1743,18 @@ $(OBJDIR)/gzip.o: $(OBJDIR)/gzip_.c $(OBJDIR)/gzip.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/gzip.o -c $(OBJDIR)/gzip_.c $(OBJDIR)/gzip.h: $(OBJDIR)/headers + +$(OBJDIR)/hname_.c: $(SRCDIR)/hname.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/hname.c >$@ + +$(OBJDIR)/hname.o: $(OBJDIR)/hname_.c $(OBJDIR)/hname.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/hname.o -c $(OBJDIR)/hname_.c + +$(OBJDIR)/hname.h: $(OBJDIR)/headers $(OBJDIR)/http_.c: $(SRCDIR)/http.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/http.c >$@ $(OBJDIR)/http.o: $(OBJDIR)/http_.c $(OBJDIR)/http.h $(SRCDIR)/config.h @@ -1849,10 +2103,18 @@ $(OBJDIR)/regexp.o: $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/regexp.o -c $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h: $(OBJDIR)/headers + +$(OBJDIR)/repolist_.c: $(SRCDIR)/repolist.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/repolist.c >$@ + +$(OBJDIR)/repolist.o: $(OBJDIR)/repolist_.c $(OBJDIR)/repolist.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/repolist.o -c $(OBJDIR)/repolist_.c + +$(OBJDIR)/repolist.h: $(OBJDIR)/headers $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/report.c >$@ $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h @@ -1881,26 +2143,58 @@ $(OBJDIR)/search.o: $(OBJDIR)/search_.c $(OBJDIR)/search.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/search.o -c $(OBJDIR)/search_.c $(OBJDIR)/search.h: $(OBJDIR)/headers + +$(OBJDIR)/security_audit_.c: $(SRCDIR)/security_audit.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/security_audit.c >$@ + +$(OBJDIR)/security_audit.o: $(OBJDIR)/security_audit_.c $(OBJDIR)/security_audit.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/security_audit.o -c $(OBJDIR)/security_audit_.c + +$(OBJDIR)/security_audit.h: $(OBJDIR)/headers $(OBJDIR)/setup_.c: $(SRCDIR)/setup.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/setup.c >$@ $(OBJDIR)/setup.o: $(OBJDIR)/setup_.c $(OBJDIR)/setup.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/setup.o -c $(OBJDIR)/setup_.c $(OBJDIR)/setup.h: $(OBJDIR)/headers + +$(OBJDIR)/setupuser_.c: $(SRCDIR)/setupuser.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/setupuser.c >$@ + +$(OBJDIR)/setupuser.o: $(OBJDIR)/setupuser_.c $(OBJDIR)/setupuser.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/setupuser.o -c $(OBJDIR)/setupuser_.c + +$(OBJDIR)/setupuser.h: $(OBJDIR)/headers $(OBJDIR)/sha1_.c: $(SRCDIR)/sha1.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/sha1.c >$@ $(OBJDIR)/sha1.o: $(OBJDIR)/sha1_.c $(OBJDIR)/sha1.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/sha1.o -c $(OBJDIR)/sha1_.c $(OBJDIR)/sha1.h: $(OBJDIR)/headers + +$(OBJDIR)/sha1hard_.c: $(SRCDIR)/sha1hard.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/sha1hard.c >$@ + +$(OBJDIR)/sha1hard.o: $(OBJDIR)/sha1hard_.c $(OBJDIR)/sha1hard.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/sha1hard.o -c $(OBJDIR)/sha1hard_.c + +$(OBJDIR)/sha1hard.h: $(OBJDIR)/headers + +$(OBJDIR)/sha3_.c: $(SRCDIR)/sha3.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/sha3.c >$@ + +$(OBJDIR)/sha3.o: $(OBJDIR)/sha3_.c $(OBJDIR)/sha3.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/sha3.o -c $(OBJDIR)/sha3_.c + +$(OBJDIR)/sha3.h: $(OBJDIR)/headers $(OBJDIR)/shun_.c: $(SRCDIR)/shun.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/shun.c >$@ $(OBJDIR)/shun.o: $(OBJDIR)/shun_.c $(OBJDIR)/shun.h $(SRCDIR)/config.h @@ -1921,10 +2215,18 @@ $(OBJDIR)/skins.o: $(OBJDIR)/skins_.c $(OBJDIR)/skins.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/skins.o -c $(OBJDIR)/skins_.c $(OBJDIR)/skins.h: $(OBJDIR)/headers + +$(OBJDIR)/smtp_.c: $(SRCDIR)/smtp.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/smtp.c >$@ + +$(OBJDIR)/smtp.o: $(OBJDIR)/smtp_.c $(OBJDIR)/smtp.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/smtp.o -c $(OBJDIR)/smtp_.c + +$(OBJDIR)/smtp.h: $(OBJDIR)/headers $(OBJDIR)/sqlcmd_.c: $(SRCDIR)/sqlcmd.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/sqlcmd.c >$@ $(OBJDIR)/sqlcmd.o: $(OBJDIR)/sqlcmd_.c $(OBJDIR)/sqlcmd.h $(SRCDIR)/config.h @@ -1985,10 +2287,18 @@ $(OBJDIR)/tar.o: $(OBJDIR)/tar_.c $(OBJDIR)/tar.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/tar.o -c $(OBJDIR)/tar_.c $(OBJDIR)/tar.h: $(OBJDIR)/headers + +$(OBJDIR)/terminal_.c: $(SRCDIR)/terminal.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/terminal.c >$@ + +$(OBJDIR)/terminal.o: $(OBJDIR)/terminal_.c $(OBJDIR)/terminal.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/terminal.o -c $(OBJDIR)/terminal_.c + +$(OBJDIR)/terminal.h: $(OBJDIR)/headers $(OBJDIR)/th_main_.c: $(SRCDIR)/th_main.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/th_main.c >$@ $(OBJDIR)/th_main.o: $(OBJDIR)/th_main_.c $(OBJDIR)/th_main.h $(SRCDIR)/config.h @@ -2097,10 +2407,18 @@ $(OBJDIR)/vfile.o: $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/vfile.o -c $(OBJDIR)/vfile_.c $(OBJDIR)/vfile.h: $(OBJDIR)/headers + +$(OBJDIR)/webmail_.c: $(SRCDIR)/webmail.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/webmail.c >$@ + +$(OBJDIR)/webmail.o: $(OBJDIR)/webmail_.c $(OBJDIR)/webmail.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/webmail.o -c $(OBJDIR)/webmail_.c + +$(OBJDIR)/webmail.h: $(OBJDIR)/headers $(OBJDIR)/wiki_.c: $(SRCDIR)/wiki.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/wiki.c >$@ $(OBJDIR)/wiki.o: $(OBJDIR)/wiki_.c $(OBJDIR)/wiki.h $(SRCDIR)/config.h @@ -2165,10 +2483,11 @@ $(OBJDIR)/zip.h: $(OBJDIR)/headers MINGW_OPTIONS = -D_HAVE__MINGW_H SQLITE_OPTIONS = -DNDEBUG=1 \ + -DSQLITE_DQS=0 \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_DEFAULT_MEMSTATUS=0 \ -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ -DSQLITE_OMIT_DECLTYPE \ @@ -2180,24 +2499,54 @@ -DSQLITE_USE_ALLOCA \ -DSQLITE_ENABLE_LOCKING_STYLE=0 \ -DSQLITE_DEFAULT_FILE_FORMAT=4 \ -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ -DSQLITE_ENABLE_FTS4 \ - -DSQLITE_ENABLE_FTS3_PARENTHESIS \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_JSON1 \ -DSQLITE_ENABLE_FTS5 \ + -DSQLITE_ENABLE_STMTVTAB \ + -DSQLITE_HAVE_ZLIB \ + -DSQLITE_INTROSPECTION_PRAGMAS \ + -DSQLITE_ENABLE_DBPAGE_VTAB \ + -DSQLITE_TRUSTED_SCHEMA=0 \ -DSQLITE_WIN32_NO_ANSI \ $(MINGW_OPTIONS) \ -DSQLITE_USE_MALLOC_H \ -DSQLITE_USE_MSIZE -SHELL_OPTIONS = -Dmain=sqlite3_shell \ +SHELL_OPTIONS = -DNDEBUG=1 \ + -DSQLITE_DQS=0 \ + -DSQLITE_THREADSAFE=0 \ + -DSQLITE_DEFAULT_MEMSTATUS=0 \ + -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ + -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ + -DSQLITE_OMIT_DECLTYPE \ + -DSQLITE_OMIT_DEPRECATED \ + -DSQLITE_OMIT_PROGRESS_CALLBACK \ + -DSQLITE_OMIT_SHARED_CACHE \ + -DSQLITE_OMIT_LOAD_EXTENSION \ + -DSQLITE_MAX_EXPR_DEPTH=0 \ + -DSQLITE_USE_ALLOCA \ + -DSQLITE_ENABLE_LOCKING_STYLE=0 \ + -DSQLITE_DEFAULT_FILE_FORMAT=4 \ + -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ + -DSQLITE_ENABLE_FTS4 \ + -DSQLITE_ENABLE_DBSTAT_VTAB \ + -DSQLITE_ENABLE_JSON1 \ + -DSQLITE_ENABLE_FTS5 \ + -DSQLITE_ENABLE_STMTVTAB \ + -DSQLITE_HAVE_ZLIB \ + -DSQLITE_INTROSPECTION_PRAGMAS \ + -DSQLITE_ENABLE_DBPAGE_VTAB \ + -DSQLITE_TRUSTED_SCHEMA=0 \ + -Dmain=sqlite3_shell \ -DSQLITE_SHELL_IS_UTF8=1 \ -DSQLITE_OMIT_LOAD_EXTENSION=1 \ -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \ - -DSQLITE_SHELL_DBNAME_PROC=fossil_open \ + -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \ + -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \ -Daccess=file_access \ -Dsystem=fossil_system \ -Dgetenv=fossil_getenv \ -Dfopen=fossil_fopen @@ -2213,11 +2562,11 @@ $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $@ $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h $(OBJDIR)/shell.o: $(SQLITE3_SHELL_SRC) $(SRCDIR)/sqlite3.h $(SRCDIR)/../win/Makefile.mingw.mistachkin - $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SQLITE3_SHELL_SRC) -o $@ + $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) $(SEE_FLAGS) -c $(SQLITE3_SHELL_SRC) -o $@ $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $@ $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c Index: win/Makefile.msc ================================================================== --- win/Makefile.msc +++ win/Makefile.msc @@ -1,39 +1,52 @@ # ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # -# This Makefile will only function correctly if used from a sub-directory -# that is a direct child of the top-level directory for this project. -# -!if !exist("..\.fossil-settings") -!error "Please change the current directory to the one containing this file." -!endif - # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # B = .. -SRCDIR = $B\src -OBJDIR = . -OX = . +SRCDIR = $(B)\src +T = . +OBJDIR = $(T) +OX = $(OBJDIR) O = .obj E = .exe P = .pdb -# Perl is only necessary if OpenSSL support is enabled and it must -# be built from source code. The PERLDIR variable should point to -# the directory containing the main Perl binary (i.e. "perl.exe"). -PERLDIR = C:\Perl\bin +INSTALLDIR = . +!ifdef DESTDIR +INSTALLDIR = $(DESTDIR)\$(INSTALLDIR) +!endif + +# When building out of source, this Makefile needs to know the path to the base +# top-level directory for this project. Pass it on NMAKE command line via make +# variable B: +# NMAKE /f "path\to\this\Makefile" B="path/to/fossil/root" +# +# NOTE: Make sure B path has no trailing backslash, UNIX-style path is OK too. +# +!if !exist("$(B)\.fossil-settings") +!error Please specify path to project base directory: B="path/to/fossil" +!endif + +# Perl is only necessary if OpenSSL support is enabled and it is built from +# source code. The PERLDIR environment variable, if it exists, should point +# to the directory containing the main Perl executable specified here (i.e. +# "perl.exe"). PERL = perl.exe # Enable debugging symbols? !ifndef DEBUG DEBUG = 0 +!endif +!ifdef FOSSIL_DEBUG +DEBUG = 1 !endif # Build the OpenSSL libraries? !ifndef FOSSIL_BUILD_SSL FOSSIL_BUILD_SSL = 0 @@ -59,11 +72,11 @@ FOSSIL_ENABLE_JSON = 0 !endif # Enable legacy treatment of the mv/rm commands? !ifndef FOSSIL_ENABLE_LEGACY_MV_RM -FOSSIL_ENABLE_LEGACY_MV_RM = 0 +FOSSIL_ENABLE_LEGACY_MV_RM = 1 !endif # Enable use of miniz instead of zlib? !ifndef FOSSIL_ENABLE_MINIZ FOSSIL_ENABLE_MINIZ = 0 @@ -98,78 +111,42 @@ !ifndef USE_SEE USE_SEE = 0 !endif !if $(FOSSIL_ENABLE_SSL)!=0 -SSLDIR = $(B)\compat\openssl-1.0.2j -SSLINCDIR = $(SSLDIR)\inc32 -!if $(FOSSIL_DYNAMIC_BUILD)!=0 -SSLLIBDIR = $(SSLDIR)\out32dll -!else -SSLLIBDIR = $(SSLDIR)\out32 -!endif -SSLLFLAGS = /nologo /opt:ref /debug -SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib crypt32.lib -!if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" -!message Using 'x64' platform for OpenSSL... -# BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. -# SSLCONFIG = VC-WIN64A no-asm no-ssl2 no-ssl3 -SSLCONFIG = VC-WIN64A no-asm -!if $(FOSSIL_DYNAMIC_BUILD)!=0 -SSLCONFIG = $(SSLCONFIG) shared -!else -SSLCONFIG = $(SSLCONFIG) no-shared -!endif -SSLSETUP = ms\do_win64a.bat -!if $(FOSSIL_DYNAMIC_BUILD)!=0 -SSLNMAKE = ms\ntdll.mak all -!else -SSLNMAKE = ms\nt.mak all -!endif -# BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. -!if $(FOSSIL_DYNAMIC_BUILD)==0 -SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 -!endif -!elseif "$(PLATFORM)"=="ia64" -!message Using 'ia64' platform for OpenSSL... -# BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. -# SSLCONFIG = VC-WIN64I no-asm no-ssl2 no-ssl3 -SSLCONFIG = VC-WIN64I no-asm -!if $(FOSSIL_DYNAMIC_BUILD)!=0 -SSLCONFIG = $(SSLCONFIG) shared -!else -SSLCONFIG = $(SSLCONFIG) no-shared -!endif -SSLSETUP = ms\do_win64i.bat -!if $(FOSSIL_DYNAMIC_BUILD)!=0 -SSLNMAKE = ms\ntdll.mak all -!else -SSLNMAKE = ms\nt.mak all -!endif -# BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. -!if $(FOSSIL_DYNAMIC_BUILD)==0 -SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 -!endif -!else -!message Assuming 'x86' platform for OpenSSL... -# BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. -# SSLCONFIG = VC-WIN32 no-asm no-ssl2 no-ssl3 -SSLCONFIG = VC-WIN32 no-asm -!if $(FOSSIL_DYNAMIC_BUILD)!=0 -SSLCONFIG = $(SSLCONFIG) shared -!else -SSLCONFIG = $(SSLCONFIG) no-shared -!endif -SSLSETUP = ms\do_ms.bat -!if $(FOSSIL_DYNAMIC_BUILD)!=0 -SSLNMAKE = ms\ntdll.mak all -!else -SSLNMAKE = ms\nt.mak all -!endif -# BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. -!if $(FOSSIL_DYNAMIC_BUILD)==0 -SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 +SSLDIR = $(B)\compat\openssl-1.1.1g +SSLINCDIR = $(SSLDIR)\include +!if $(FOSSIL_DYNAMIC_BUILD)!=0 +SSLLIBDIR = $(SSLDIR) +!else +SSLLIBDIR = $(SSLDIR) +!endif +SSLLFLAGS = /nologo /opt:ref /debug +SSLLIB = libssl.lib libcrypto.lib user32.lib gdi32.lib crypt32.lib +!if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" +!message Using 'x64' platform for OpenSSL... +SSLCONFIG = VC-WIN64A no-asm no-ssl3 no-weak-ssl-ciphers +!if $(FOSSIL_DYNAMIC_BUILD)!=0 +SSLCONFIG = $(SSLCONFIG) shared +!else +SSLCONFIG = $(SSLCONFIG) no-shared +!endif +!elseif "$(PLATFORM)"=="ia64" +!message Using 'ia64' platform for OpenSSL... +SSLCONFIG = VC-WIN64I no-asm no-ssl3 no-weak-ssl-ciphers +!if $(FOSSIL_DYNAMIC_BUILD)!=0 +SSLCONFIG = $(SSLCONFIG) shared +!else +SSLCONFIG = $(SSLCONFIG) no-shared +!endif +!else +!message Assuming 'x86' platform for OpenSSL... +SSLCONFIG = VC-WIN32 no-asm no-ssl3 no-weak-ssl-ciphers +!if $(FOSSIL_DYNAMIC_BUILD)!=0 +SSLCONFIG = $(SSLCONFIG) shared +!else +SSLCONFIG = $(SSLCONFIG) no-shared !endif !endif !endif !if $(FOSSIL_ENABLE_TCL)!=0 @@ -186,35 +163,38 @@ ZLIB = zdll.lib !else ZLIB = zlib.lib !endif -INCL = /I. /I$(SRCDIR) /I$B\win\include +INCL = /I. /I"$(OX)" /I"$(SRCDIR)" /I"$(B)\win\include" !if $(FOSSIL_ENABLE_MINIZ)==0 -INCL = $(INCL) /I$(ZINCDIR) +INCL = $(INCL) /I"$(ZINCDIR)" !endif !if $(FOSSIL_ENABLE_SSL)!=0 -INCL = $(INCL) /I$(SSLINCDIR) +INCL = $(INCL) /I"$(SSLINCDIR)" !endif !if $(FOSSIL_ENABLE_TCL)!=0 -INCL = $(INCL) /I$(TCLINCDIR) +INCL = $(INCL) /I"$(TCLINCDIR)" !endif CFLAGS = /nologo LDFLAGS = +CFLAGS = $(CFLAGS) /D_CRT_SECURE_NO_DEPRECATE /D_CRT_SECURE_NO_WARNINGS +CFLAGS = $(CFLAGS) /D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_NONSTDC_NO_WARNINGS + !if $(FOSSIL_DYNAMIC_BUILD)!=0 LDFLAGS = $(LDFLAGS) /MANIFEST !else LDFLAGS = $(LDFLAGS) /NODEFAULTLIB:msvcrt /MANIFEST:NO !endif !if $(FOSSIL_ENABLE_WINXP)!=0 -XPCFLAGS = $(XPCFLAGS) /D_USING_V110_SDK71_=1 +XPCFLAGS = $(XPCFLAGS) /D_WIN32_WINNT=0x0501 /D_USING_V110_SDK71_=1 CFLAGS = $(CFLAGS) $(XPCFLAGS) !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" XPLDFLAGS = $(XPLDFLAGS) /SUBSYSTEM:CONSOLE,5.02 !else XPLDFLAGS = $(XPLDFLAGS) /SUBSYSTEM:CONSOLE,5.01 @@ -235,31 +215,31 @@ CRTFLAGS = /MT !endif !endif !if $(DEBUG)!=0 -CFLAGS = $(CFLAGS) /Zi $(CRTFLAGS) /Od +CFLAGS = $(CFLAGS) /Zi $(CRTFLAGS) /Od /DFOSSIL_DEBUG LDFLAGS = $(LDFLAGS) /DEBUG !else CFLAGS = $(CFLAGS) $(CRTFLAGS) /O2 !endif BCC = $(CC) $(CFLAGS) TCC = $(CC) /c $(CFLAGS) $(MSCDEF) $(INCL) RCC = $(RC) /D_WIN32 /D_MSC_VER $(MSCDEF) $(INCL) MTC = mt -LIBS = ws2_32.lib advapi32.lib +LIBS = ws2_32.lib advapi32.lib dnsapi.lib LIBDIR = !if $(FOSSIL_DYNAMIC_BUILD)!=0 TCC = $(TCC) /DFOSSIL_DYNAMIC_BUILD=1 RCC = $(RCC) /DFOSSIL_DYNAMIC_BUILD=1 !endif !if $(FOSSIL_ENABLE_MINIZ)==0 LIBS = $(LIBS) $(ZLIB) -LIBDIR = $(LIBDIR) /LIBPATH:$(ZLIBDIR) +LIBDIR = $(LIBDIR) /LIBPATH:"$(ZLIBDIR)" !endif !if $(FOSSIL_ENABLE_MINIZ)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_MINIZ=1 RCC = $(RCC) /DFOSSIL_ENABLE_MINIZ=1 @@ -272,11 +252,11 @@ !if $(FOSSIL_ENABLE_SSL)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_SSL=1 RCC = $(RCC) /DFOSSIL_ENABLE_SSL=1 LIBS = $(LIBS) $(SSLLIB) -LIBDIR = $(LIBDIR) /LIBPATH:$(SSLLIBDIR) +LIBDIR = $(LIBDIR) /LIBPATH:"$(SSLLIBDIR)" !endif !if $(FOSSIL_ENABLE_EXEC_REL_PATHS)!=0 TCC = $(TCC) /DFOSSIL_ENABLE_EXEC_REL_PATHS=1 RCC = $(RCC) /DFOSSIL_ENABLE_EXEC_REL_PATHS=1 @@ -312,10 +292,11 @@ TCC = $(TCC) /DUSE_SEE=1 RCC = $(RCC) /DUSE_SEE=1 !endif SQLITE_OPTIONS = /DNDEBUG=1 \ + /DSQLITE_DQS=0 \ /DSQLITE_THREADSAFE=0 \ /DSQLITE_DEFAULT_MEMSTATUS=0 \ /DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ /DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ /DSQLITE_OMIT_DECLTYPE \ @@ -327,364 +308,509 @@ /DSQLITE_USE_ALLOCA \ /DSQLITE_ENABLE_LOCKING_STYLE=0 \ /DSQLITE_DEFAULT_FILE_FORMAT=4 \ /DSQLITE_ENABLE_EXPLAIN_COMMENTS \ /DSQLITE_ENABLE_FTS4 \ - /DSQLITE_ENABLE_FTS3_PARENTHESIS \ /DSQLITE_ENABLE_DBSTAT_VTAB \ /DSQLITE_ENABLE_JSON1 \ /DSQLITE_ENABLE_FTS5 \ + /DSQLITE_ENABLE_STMTVTAB \ + /DSQLITE_HAVE_ZLIB \ + /DSQLITE_INTROSPECTION_PRAGMAS \ + /DSQLITE_ENABLE_DBPAGE_VTAB \ + /DSQLITE_TRUSTED_SCHEMA=0 \ /DSQLITE_WIN32_NO_ANSI -SHELL_OPTIONS = /Dmain=sqlite3_shell \ +SHELL_OPTIONS = /DNDEBUG=1 \ + /DSQLITE_DQS=0 \ + /DSQLITE_THREADSAFE=0 \ + /DSQLITE_DEFAULT_MEMSTATUS=0 \ + /DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ + /DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ + /DSQLITE_OMIT_DECLTYPE \ + /DSQLITE_OMIT_DEPRECATED \ + /DSQLITE_OMIT_PROGRESS_CALLBACK \ + /DSQLITE_OMIT_SHARED_CACHE \ + /DSQLITE_OMIT_LOAD_EXTENSION \ + /DSQLITE_MAX_EXPR_DEPTH=0 \ + /DSQLITE_USE_ALLOCA \ + /DSQLITE_ENABLE_LOCKING_STYLE=0 \ + /DSQLITE_DEFAULT_FILE_FORMAT=4 \ + /DSQLITE_ENABLE_EXPLAIN_COMMENTS \ + /DSQLITE_ENABLE_FTS4 \ + /DSQLITE_ENABLE_DBSTAT_VTAB \ + /DSQLITE_ENABLE_JSON1 \ + /DSQLITE_ENABLE_FTS5 \ + /DSQLITE_ENABLE_STMTVTAB \ + /DSQLITE_HAVE_ZLIB \ + /DSQLITE_INTROSPECTION_PRAGMAS \ + /DSQLITE_ENABLE_DBPAGE_VTAB \ + /DSQLITE_TRUSTED_SCHEMA=0 \ + /Dmain=sqlite3_shell \ /DSQLITE_SHELL_IS_UTF8=1 \ /DSQLITE_OMIT_LOAD_EXTENSION=1 \ /DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \ - /DSQLITE_SHELL_DBNAME_PROC=fossil_open \ + /DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname \ + /DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc \ /Daccess=file_access \ /Dsystem=fossil_system \ /Dgetenv=fossil_getenv \ /Dfopen=fossil_fopen MINIZ_OPTIONS = /DMINIZ_NO_STDIO \ /DMINIZ_NO_TIME \ /DMINIZ_NO_ARCHIVE_APIS -SRC = add_.c \ - allrepo_.c \ - attach_.c \ - bag_.c \ - bisect_.c \ - blob_.c \ - branch_.c \ - browse_.c \ - builtin_.c \ - bundle_.c \ - cache_.c \ - captcha_.c \ - cgi_.c \ - checkin_.c \ - checkout_.c \ - clearsign_.c \ - clone_.c \ - comformat_.c \ - configure_.c \ - content_.c \ - db_.c \ - delta_.c \ - deltacmd_.c \ - descendants_.c \ - diff_.c \ - diffcmd_.c \ - dispatch_.c \ - doc_.c \ - encode_.c \ - event_.c \ - export_.c \ - file_.c \ - finfo_.c \ - foci_.c \ - fshell_.c \ - fusefs_.c \ - glob_.c \ - graph_.c \ - gzip_.c \ - http_.c \ - http_socket_.c \ - http_ssl_.c \ - http_transport_.c \ - import_.c \ - info_.c \ - json_.c \ - json_artifact_.c \ - json_branch_.c \ - json_config_.c \ - json_diff_.c \ - json_dir_.c \ - json_finfo_.c \ - json_login_.c \ - json_query_.c \ - json_report_.c \ - json_status_.c \ - json_tag_.c \ - json_timeline_.c \ - json_user_.c \ - json_wiki_.c \ - leaf_.c \ - loadctrl_.c \ - login_.c \ - lookslike_.c \ - main_.c \ - manifest_.c \ - markdown_.c \ - markdown_html_.c \ - md5_.c \ - merge_.c \ - merge3_.c \ - moderate_.c \ - name_.c \ - path_.c \ - piechart_.c \ - pivot_.c \ - popen_.c \ - pqueue_.c \ - printf_.c \ - publish_.c \ - purge_.c \ - rebuild_.c \ - regexp_.c \ - report_.c \ - rss_.c \ - schema_.c \ - search_.c \ - setup_.c \ - sha1_.c \ - shun_.c \ - sitemap_.c \ - skins_.c \ - sqlcmd_.c \ - stash_.c \ - stat_.c \ - statrep_.c \ - style_.c \ - sync_.c \ - tag_.c \ - tar_.c \ - th_main_.c \ - timeline_.c \ - tkt_.c \ - tktsetup_.c \ - undo_.c \ - unicode_.c \ - unversioned_.c \ - update_.c \ - url_.c \ - user_.c \ - utf8_.c \ - util_.c \ - verify_.c \ - vfile_.c \ - wiki_.c \ - wikiformat_.c \ - winfile_.c \ - winhttp_.c \ - wysiwyg_.c \ - xfer_.c \ - xfersetup_.c \ - zip_.c - -EXTRA_FILES = $(SRCDIR)\../skins/aht/details.txt \ - $(SRCDIR)\../skins/black_and_white/css.txt \ - $(SRCDIR)\../skins/black_and_white/details.txt \ - $(SRCDIR)\../skins/black_and_white/footer.txt \ - $(SRCDIR)\../skins/black_and_white/header.txt \ - $(SRCDIR)\../skins/blitz/css.txt \ - $(SRCDIR)\../skins/blitz/details.txt \ - $(SRCDIR)\../skins/blitz/footer.txt \ - $(SRCDIR)\../skins/blitz/header.txt \ - $(SRCDIR)\../skins/blitz/ticket.txt \ - $(SRCDIR)\../skins/blitz_no_logo/css.txt \ - $(SRCDIR)\../skins/blitz_no_logo/details.txt \ - $(SRCDIR)\../skins/blitz_no_logo/footer.txt \ - $(SRCDIR)\../skins/blitz_no_logo/header.txt \ - $(SRCDIR)\../skins/blitz_no_logo/ticket.txt \ - $(SRCDIR)\../skins/default/css.txt \ - $(SRCDIR)\../skins/default/details.txt \ - $(SRCDIR)\../skins/default/footer.txt \ - $(SRCDIR)\../skins/default/header.txt \ - $(SRCDIR)\../skins/eagle/css.txt \ - $(SRCDIR)\../skins/eagle/details.txt \ - $(SRCDIR)\../skins/eagle/footer.txt \ - $(SRCDIR)\../skins/eagle/header.txt \ - $(SRCDIR)\../skins/enhanced1/css.txt \ - $(SRCDIR)\../skins/enhanced1/details.txt \ - $(SRCDIR)\../skins/enhanced1/footer.txt \ - $(SRCDIR)\../skins/enhanced1/header.txt \ - $(SRCDIR)\../skins/khaki/css.txt \ - $(SRCDIR)\../skins/khaki/details.txt \ - $(SRCDIR)\../skins/khaki/footer.txt \ - $(SRCDIR)\../skins/khaki/header.txt \ - $(SRCDIR)\../skins/original/css.txt \ - $(SRCDIR)\../skins/original/details.txt \ - $(SRCDIR)\../skins/original/footer.txt \ - $(SRCDIR)\../skins/original/header.txt \ - $(SRCDIR)\../skins/plain_gray/css.txt \ - $(SRCDIR)\../skins/plain_gray/details.txt \ - $(SRCDIR)\../skins/plain_gray/footer.txt \ - $(SRCDIR)\../skins/plain_gray/header.txt \ - $(SRCDIR)\../skins/rounded1/css.txt \ - $(SRCDIR)\../skins/rounded1/details.txt \ - $(SRCDIR)\../skins/rounded1/footer.txt \ - $(SRCDIR)\../skins/rounded1/header.txt \ - $(SRCDIR)\../skins/xekri/css.txt \ - $(SRCDIR)\../skins/xekri/details.txt \ - $(SRCDIR)\../skins/xekri/footer.txt \ - $(SRCDIR)\../skins/xekri/header.txt \ - $(SRCDIR)\diff.tcl \ - $(SRCDIR)\markdown.md - -OBJ = $(OX)\add$O \ - $(OX)\allrepo$O \ - $(OX)\attach$O \ - $(OX)\bag$O \ - $(OX)\bisect$O \ - $(OX)\blob$O \ - $(OX)\branch$O \ - $(OX)\browse$O \ - $(OX)\builtin$O \ - $(OX)\bundle$O \ - $(OX)\cache$O \ - $(OX)\captcha$O \ - $(OX)\cgi$O \ - $(OX)\checkin$O \ - $(OX)\checkout$O \ - $(OX)\clearsign$O \ - $(OX)\clone$O \ - $(OX)\comformat$O \ - $(OX)\configure$O \ - $(OX)\content$O \ - $(OX)\cson_amalgamation$O \ - $(OX)\db$O \ - $(OX)\delta$O \ - $(OX)\deltacmd$O \ - $(OX)\descendants$O \ - $(OX)\diff$O \ - $(OX)\diffcmd$O \ - $(OX)\dispatch$O \ - $(OX)\doc$O \ - $(OX)\encode$O \ - $(OX)\event$O \ - $(OX)\export$O \ - $(OX)\file$O \ - $(OX)\finfo$O \ - $(OX)\foci$O \ - $(OX)\fshell$O \ - $(OX)\fusefs$O \ - $(OX)\glob$O \ - $(OX)\graph$O \ - $(OX)\gzip$O \ - $(OX)\http$O \ - $(OX)\http_socket$O \ - $(OX)\http_ssl$O \ - $(OX)\http_transport$O \ - $(OX)\import$O \ - $(OX)\info$O \ - $(OX)\json$O \ - $(OX)\json_artifact$O \ - $(OX)\json_branch$O \ - $(OX)\json_config$O \ - $(OX)\json_diff$O \ - $(OX)\json_dir$O \ - $(OX)\json_finfo$O \ - $(OX)\json_login$O \ - $(OX)\json_query$O \ - $(OX)\json_report$O \ - $(OX)\json_status$O \ - $(OX)\json_tag$O \ - $(OX)\json_timeline$O \ - $(OX)\json_user$O \ - $(OX)\json_wiki$O \ - $(OX)\leaf$O \ - $(OX)\loadctrl$O \ - $(OX)\login$O \ - $(OX)\lookslike$O \ - $(OX)\main$O \ - $(OX)\manifest$O \ - $(OX)\markdown$O \ - $(OX)\markdown_html$O \ - $(OX)\md5$O \ - $(OX)\merge$O \ - $(OX)\merge3$O \ - $(OX)\moderate$O \ - $(OX)\name$O \ - $(OX)\path$O \ - $(OX)\piechart$O \ - $(OX)\pivot$O \ - $(OX)\popen$O \ - $(OX)\pqueue$O \ - $(OX)\printf$O \ - $(OX)\publish$O \ - $(OX)\purge$O \ - $(OX)\rebuild$O \ - $(OX)\regexp$O \ - $(OX)\report$O \ - $(OX)\rss$O \ - $(OX)\schema$O \ - $(OX)\search$O \ - $(OX)\setup$O \ - $(OX)\sha1$O \ - $(OX)\shell$O \ - $(OX)\shun$O \ - $(OX)\sitemap$O \ - $(OX)\skins$O \ - $(OX)\sqlcmd$O \ - $(OX)\sqlite3$O \ - $(OX)\stash$O \ - $(OX)\stat$O \ - $(OX)\statrep$O \ - $(OX)\style$O \ - $(OX)\sync$O \ - $(OX)\tag$O \ - $(OX)\tar$O \ - $(OX)\th$O \ - $(OX)\th_lang$O \ - $(OX)\th_main$O \ - $(OX)\th_tcl$O \ - $(OX)\timeline$O \ - $(OX)\tkt$O \ - $(OX)\tktsetup$O \ - $(OX)\undo$O \ - $(OX)\unicode$O \ - $(OX)\unversioned$O \ - $(OX)\update$O \ - $(OX)\url$O \ - $(OX)\user$O \ - $(OX)\utf8$O \ - $(OX)\util$O \ - $(OX)\verify$O \ - $(OX)\vfile$O \ - $(OX)\wiki$O \ - $(OX)\wikiformat$O \ - $(OX)\winfile$O \ - $(OX)\winhttp$O \ - $(OX)\wysiwyg$O \ - $(OX)\xfer$O \ - $(OX)\xfersetup$O \ - $(OX)\zip$O \ +SRC = "$(OX)\add_.c" \ + "$(OX)\ajax_.c" \ + "$(OX)\alerts_.c" \ + "$(OX)\allrepo_.c" \ + "$(OX)\attach_.c" \ + "$(OX)\backlink_.c" \ + "$(OX)\backoffice_.c" \ + "$(OX)\bag_.c" \ + "$(OX)\bisect_.c" \ + "$(OX)\blob_.c" \ + "$(OX)\branch_.c" \ + "$(OX)\browse_.c" \ + "$(OX)\builtin_.c" \ + "$(OX)\bundle_.c" \ + "$(OX)\cache_.c" \ + "$(OX)\capabilities_.c" \ + "$(OX)\captcha_.c" \ + "$(OX)\cgi_.c" \ + "$(OX)\checkin_.c" \ + "$(OX)\checkout_.c" \ + "$(OX)\clearsign_.c" \ + "$(OX)\clone_.c" \ + "$(OX)\comformat_.c" \ + "$(OX)\configure_.c" \ + "$(OX)\content_.c" \ + "$(OX)\cookies_.c" \ + "$(OX)\db_.c" \ + "$(OX)\delta_.c" \ + "$(OX)\deltacmd_.c" \ + "$(OX)\deltafunc_.c" \ + "$(OX)\descendants_.c" \ + "$(OX)\diff_.c" \ + "$(OX)\diffcmd_.c" \ + "$(OX)\dispatch_.c" \ + "$(OX)\doc_.c" \ + "$(OX)\encode_.c" \ + "$(OX)\etag_.c" \ + "$(OX)\event_.c" \ + "$(OX)\export_.c" \ + "$(OX)\extcgi_.c" \ + "$(OX)\file_.c" \ + "$(OX)\fileedit_.c" \ + "$(OX)\finfo_.c" \ + "$(OX)\foci_.c" \ + "$(OX)\forum_.c" \ + "$(OX)\fshell_.c" \ + "$(OX)\fusefs_.c" \ + "$(OX)\fuzz_.c" \ + "$(OX)\glob_.c" \ + "$(OX)\graph_.c" \ + "$(OX)\gzip_.c" \ + "$(OX)\hname_.c" \ + "$(OX)\http_.c" \ + "$(OX)\http_socket_.c" \ + "$(OX)\http_ssl_.c" \ + "$(OX)\http_transport_.c" \ + "$(OX)\import_.c" \ + "$(OX)\info_.c" \ + "$(OX)\json_.c" \ + "$(OX)\json_artifact_.c" \ + "$(OX)\json_branch_.c" \ + "$(OX)\json_config_.c" \ + "$(OX)\json_diff_.c" \ + "$(OX)\json_dir_.c" \ + "$(OX)\json_finfo_.c" \ + "$(OX)\json_login_.c" \ + "$(OX)\json_query_.c" \ + "$(OX)\json_report_.c" \ + "$(OX)\json_status_.c" \ + "$(OX)\json_tag_.c" \ + "$(OX)\json_timeline_.c" \ + "$(OX)\json_user_.c" \ + "$(OX)\json_wiki_.c" \ + "$(OX)\leaf_.c" \ + "$(OX)\loadctrl_.c" \ + "$(OX)\login_.c" \ + "$(OX)\lookslike_.c" \ + "$(OX)\main_.c" \ + "$(OX)\manifest_.c" \ + "$(OX)\markdown_.c" \ + "$(OX)\markdown_html_.c" \ + "$(OX)\md5_.c" \ + "$(OX)\merge_.c" \ + "$(OX)\merge3_.c" \ + "$(OX)\moderate_.c" \ + "$(OX)\name_.c" \ + "$(OX)\path_.c" \ + "$(OX)\piechart_.c" \ + "$(OX)\pivot_.c" \ + "$(OX)\popen_.c" \ + "$(OX)\pqueue_.c" \ + "$(OX)\printf_.c" \ + "$(OX)\publish_.c" \ + "$(OX)\purge_.c" \ + "$(OX)\rebuild_.c" \ + "$(OX)\regexp_.c" \ + "$(OX)\repolist_.c" \ + "$(OX)\report_.c" \ + "$(OX)\rss_.c" \ + "$(OX)\schema_.c" \ + "$(OX)\search_.c" \ + "$(OX)\security_audit_.c" \ + "$(OX)\setup_.c" \ + "$(OX)\setupuser_.c" \ + "$(OX)\sha1_.c" \ + "$(OX)\sha1hard_.c" \ + "$(OX)\sha3_.c" \ + "$(OX)\shun_.c" \ + "$(OX)\sitemap_.c" \ + "$(OX)\skins_.c" \ + "$(OX)\smtp_.c" \ + "$(OX)\sqlcmd_.c" \ + "$(OX)\stash_.c" \ + "$(OX)\stat_.c" \ + "$(OX)\statrep_.c" \ + "$(OX)\style_.c" \ + "$(OX)\sync_.c" \ + "$(OX)\tag_.c" \ + "$(OX)\tar_.c" \ + "$(OX)\terminal_.c" \ + "$(OX)\th_main_.c" \ + "$(OX)\timeline_.c" \ + "$(OX)\tkt_.c" \ + "$(OX)\tktsetup_.c" \ + "$(OX)\undo_.c" \ + "$(OX)\unicode_.c" \ + "$(OX)\unversioned_.c" \ + "$(OX)\update_.c" \ + "$(OX)\url_.c" \ + "$(OX)\user_.c" \ + "$(OX)\utf8_.c" \ + "$(OX)\util_.c" \ + "$(OX)\verify_.c" \ + "$(OX)\vfile_.c" \ + "$(OX)\webmail_.c" \ + "$(OX)\wiki_.c" \ + "$(OX)\wikiformat_.c" \ + "$(OX)\winfile_.c" \ + "$(OX)\winhttp_.c" \ + "$(OX)\wysiwyg_.c" \ + "$(OX)\xfer_.c" \ + "$(OX)\xfersetup_.c" \ + "$(OX)\zip_.c" + +EXTRA_FILES = "$(SRCDIR)\..\skins\aht\details.txt" \ + "$(SRCDIR)\..\skins\ardoise\css.txt" \ + "$(SRCDIR)\..\skins\ardoise\details.txt" \ + "$(SRCDIR)\..\skins\ardoise\footer.txt" \ + "$(SRCDIR)\..\skins\ardoise\header.txt" \ + "$(SRCDIR)\..\skins\black_and_white\css.txt" \ + "$(SRCDIR)\..\skins\black_and_white\details.txt" \ + "$(SRCDIR)\..\skins\black_and_white\footer.txt" \ + "$(SRCDIR)\..\skins\black_and_white\header.txt" \ + "$(SRCDIR)\..\skins\blitz\css.txt" \ + "$(SRCDIR)\..\skins\blitz\details.txt" \ + "$(SRCDIR)\..\skins\blitz\footer.txt" \ + "$(SRCDIR)\..\skins\blitz\header.txt" \ + "$(SRCDIR)\..\skins\blitz\ticket.txt" \ + "$(SRCDIR)\..\skins\blitz_no_logo\css.txt" \ + "$(SRCDIR)\..\skins\blitz_no_logo\details.txt" \ + "$(SRCDIR)\..\skins\blitz_no_logo\footer.txt" \ + "$(SRCDIR)\..\skins\blitz_no_logo\header.txt" \ + "$(SRCDIR)\..\skins\blitz_no_logo\ticket.txt" \ + "$(SRCDIR)\..\skins\bootstrap\css.txt" \ + "$(SRCDIR)\..\skins\bootstrap\details.txt" \ + "$(SRCDIR)\..\skins\bootstrap\footer.txt" \ + "$(SRCDIR)\..\skins\bootstrap\header.txt" \ + "$(SRCDIR)\..\skins\default\css.txt" \ + "$(SRCDIR)\..\skins\default\details.txt" \ + "$(SRCDIR)\..\skins\default\footer.txt" \ + "$(SRCDIR)\..\skins\default\header.txt" \ + "$(SRCDIR)\..\skins\default\js.txt" \ + "$(SRCDIR)\..\skins\eagle\css.txt" \ + "$(SRCDIR)\..\skins\eagle\details.txt" \ + "$(SRCDIR)\..\skins\eagle\footer.txt" \ + "$(SRCDIR)\..\skins\eagle\header.txt" \ + "$(SRCDIR)\..\skins\enhanced1\css.txt" \ + "$(SRCDIR)\..\skins\enhanced1\details.txt" \ + "$(SRCDIR)\..\skins\enhanced1\footer.txt" \ + "$(SRCDIR)\..\skins\enhanced1\header.txt" \ + "$(SRCDIR)\..\skins\khaki\css.txt" \ + "$(SRCDIR)\..\skins\khaki\details.txt" \ + "$(SRCDIR)\..\skins\khaki\footer.txt" \ + "$(SRCDIR)\..\skins\khaki\header.txt" \ + "$(SRCDIR)\..\skins\original\css.txt" \ + "$(SRCDIR)\..\skins\original\details.txt" \ + "$(SRCDIR)\..\skins\original\footer.txt" \ + "$(SRCDIR)\..\skins\original\header.txt" \ + "$(SRCDIR)\..\skins\plain_gray\css.txt" \ + "$(SRCDIR)\..\skins\plain_gray\details.txt" \ + "$(SRCDIR)\..\skins\plain_gray\footer.txt" \ + "$(SRCDIR)\..\skins\plain_gray\header.txt" \ + "$(SRCDIR)\..\skins\rounded1\css.txt" \ + "$(SRCDIR)\..\skins\rounded1\details.txt" \ + "$(SRCDIR)\..\skins\rounded1\footer.txt" \ + "$(SRCDIR)\..\skins\rounded1\header.txt" \ + "$(SRCDIR)\..\skins\xekri\css.txt" \ + "$(SRCDIR)\..\skins\xekri\details.txt" \ + "$(SRCDIR)\..\skins\xekri\footer.txt" \ + "$(SRCDIR)\..\skins\xekri\header.txt" \ + "$(SRCDIR)\accordion.js" \ + "$(SRCDIR)\ci_edit.js" \ + "$(SRCDIR)\copybtn.js" \ + "$(SRCDIR)\default.css" \ + "$(SRCDIR)\diff.tcl" \ + "$(SRCDIR)\forum.js" \ + "$(SRCDIR)\fossil.bootstrap.js" \ + "$(SRCDIR)\fossil.confirmer.js" \ + "$(SRCDIR)\fossil.dom.js" \ + "$(SRCDIR)\fossil.fetch.js" \ + "$(SRCDIR)\fossil.page.fileedit.js" \ + "$(SRCDIR)\fossil.storage.js" \ + "$(SRCDIR)\fossil.tabs.js" \ + "$(SRCDIR)\graph.js" \ + "$(SRCDIR)\href.js" \ + "$(SRCDIR)\login.js" \ + "$(SRCDIR)\markdown.md" \ + "$(SRCDIR)\menu.js" \ + "$(SRCDIR)\sbsdiff.js" \ + "$(SRCDIR)\scroll.js" \ + "$(SRCDIR)\skin.js" \ + "$(SRCDIR)\sorttable.js" \ + "$(SRCDIR)\sounds\0.wav" \ + "$(SRCDIR)\sounds\1.wav" \ + "$(SRCDIR)\sounds\2.wav" \ + "$(SRCDIR)\sounds\3.wav" \ + "$(SRCDIR)\sounds\4.wav" \ + "$(SRCDIR)\sounds\5.wav" \ + "$(SRCDIR)\sounds\6.wav" \ + "$(SRCDIR)\sounds\7.wav" \ + "$(SRCDIR)\sounds\8.wav" \ + "$(SRCDIR)\sounds\9.wav" \ + "$(SRCDIR)\sounds\a.wav" \ + "$(SRCDIR)\sounds\b.wav" \ + "$(SRCDIR)\sounds\c.wav" \ + "$(SRCDIR)\sounds\d.wav" \ + "$(SRCDIR)\sounds\e.wav" \ + "$(SRCDIR)\sounds\f.wav" \ + "$(SRCDIR)\style.admin_log.css" \ + "$(SRCDIR)\style.fileedit.css" \ + "$(SRCDIR)\tree.js" \ + "$(SRCDIR)\useredit.js" \ + "$(SRCDIR)\wiki.wiki" + +OBJ = "$(OX)\add$O" \ + "$(OX)\ajax$O" \ + "$(OX)\alerts$O" \ + "$(OX)\allrepo$O" \ + "$(OX)\attach$O" \ + "$(OX)\backlink$O" \ + "$(OX)\backoffice$O" \ + "$(OX)\bag$O" \ + "$(OX)\bisect$O" \ + "$(OX)\blob$O" \ + "$(OX)\branch$O" \ + "$(OX)\browse$O" \ + "$(OX)\builtin$O" \ + "$(OX)\bundle$O" \ + "$(OX)\cache$O" \ + "$(OX)\capabilities$O" \ + "$(OX)\captcha$O" \ + "$(OX)\cgi$O" \ + "$(OX)\checkin$O" \ + "$(OX)\checkout$O" \ + "$(OX)\clearsign$O" \ + "$(OX)\clone$O" \ + "$(OX)\comformat$O" \ + "$(OX)\configure$O" \ + "$(OX)\content$O" \ + "$(OX)\cookies$O" \ + "$(OX)\cson_amalgamation$O" \ + "$(OX)\db$O" \ + "$(OX)\delta$O" \ + "$(OX)\deltacmd$O" \ + "$(OX)\deltafunc$O" \ + "$(OX)\descendants$O" \ + "$(OX)\diff$O" \ + "$(OX)\diffcmd$O" \ + "$(OX)\dispatch$O" \ + "$(OX)\doc$O" \ + "$(OX)\encode$O" \ + "$(OX)\etag$O" \ + "$(OX)\event$O" \ + "$(OX)\export$O" \ + "$(OX)\extcgi$O" \ + "$(OX)\file$O" \ + "$(OX)\fileedit$O" \ + "$(OX)\finfo$O" \ + "$(OX)\foci$O" \ + "$(OX)\forum$O" \ + "$(OX)\fshell$O" \ + "$(OX)\fusefs$O" \ + "$(OX)\fuzz$O" \ + "$(OX)\glob$O" \ + "$(OX)\graph$O" \ + "$(OX)\gzip$O" \ + "$(OX)\hname$O" \ + "$(OX)\http$O" \ + "$(OX)\http_socket$O" \ + "$(OX)\http_ssl$O" \ + "$(OX)\http_transport$O" \ + "$(OX)\import$O" \ + "$(OX)\info$O" \ + "$(OX)\json$O" \ + "$(OX)\json_artifact$O" \ + "$(OX)\json_branch$O" \ + "$(OX)\json_config$O" \ + "$(OX)\json_diff$O" \ + "$(OX)\json_dir$O" \ + "$(OX)\json_finfo$O" \ + "$(OX)\json_login$O" \ + "$(OX)\json_query$O" \ + "$(OX)\json_report$O" \ + "$(OX)\json_status$O" \ + "$(OX)\json_tag$O" \ + "$(OX)\json_timeline$O" \ + "$(OX)\json_user$O" \ + "$(OX)\json_wiki$O" \ + "$(OX)\leaf$O" \ + "$(OX)\loadctrl$O" \ + "$(OX)\login$O" \ + "$(OX)\lookslike$O" \ + "$(OX)\main$O" \ + "$(OX)\manifest$O" \ + "$(OX)\markdown$O" \ + "$(OX)\markdown_html$O" \ + "$(OX)\md5$O" \ + "$(OX)\merge$O" \ + "$(OX)\merge3$O" \ + "$(OX)\moderate$O" \ + "$(OX)\name$O" \ + "$(OX)\path$O" \ + "$(OX)\piechart$O" \ + "$(OX)\pivot$O" \ + "$(OX)\popen$O" \ + "$(OX)\pqueue$O" \ + "$(OX)\printf$O" \ + "$(OX)\publish$O" \ + "$(OX)\purge$O" \ + "$(OX)\rebuild$O" \ + "$(OX)\regexp$O" \ + "$(OX)\repolist$O" \ + "$(OX)\report$O" \ + "$(OX)\rss$O" \ + "$(OX)\schema$O" \ + "$(OX)\search$O" \ + "$(OX)\security_audit$O" \ + "$(OX)\setup$O" \ + "$(OX)\setupuser$O" \ + "$(OX)\sha1$O" \ + "$(OX)\sha1hard$O" \ + "$(OX)\sha3$O" \ + "$(OX)\shell$O" \ + "$(OX)\shun$O" \ + "$(OX)\sitemap$O" \ + "$(OX)\skins$O" \ + "$(OX)\smtp$O" \ + "$(OX)\sqlcmd$O" \ + "$(OX)\sqlite3$O" \ + "$(OX)\stash$O" \ + "$(OX)\stat$O" \ + "$(OX)\statrep$O" \ + "$(OX)\style$O" \ + "$(OX)\sync$O" \ + "$(OX)\tag$O" \ + "$(OX)\tar$O" \ + "$(OX)\terminal$O" \ + "$(OX)\th$O" \ + "$(OX)\th_lang$O" \ + "$(OX)\th_main$O" \ + "$(OX)\th_tcl$O" \ + "$(OX)\timeline$O" \ + "$(OX)\tkt$O" \ + "$(OX)\tktsetup$O" \ + "$(OX)\undo$O" \ + "$(OX)\unicode$O" \ + "$(OX)\unversioned$O" \ + "$(OX)\update$O" \ + "$(OX)\url$O" \ + "$(OX)\user$O" \ + "$(OX)\utf8$O" \ + "$(OX)\util$O" \ + "$(OX)\verify$O" \ + "$(OX)\vfile$O" \ + "$(OX)\webmail$O" \ + "$(OX)\wiki$O" \ + "$(OX)\wikiformat$O" \ + "$(OX)\winfile$O" \ + "$(OX)\winhttp$O" \ + "$(OX)\wysiwyg$O" \ + "$(OX)\xfer$O" \ + "$(OX)\xfersetup$O" \ + "$(OX)\zip$O" \ !if $(FOSSIL_ENABLE_MINIZ)!=0 - $(OX)\miniz$O \ + "$(OX)\miniz$O" \ +!endif + "$(OX)\fossil.res" + + +!ifndef BASEAPPNAME +BASEAPPNAME = fossil +!endif + +APPNAME = $(OX)\$(BASEAPPNAME)$(E) +PDBNAME = $(OX)\$(BASEAPPNAME)$(P) +APPTARGETS = + +all: "$(OX)" "$(APPNAME)" + +$(BASEAPPNAME): "$(APPNAME)" + +$(BASEAPPNAME)$(E): "$(APPNAME)" + +install: "$(APPNAME)" + echo F | xcopy /Y "$(APPNAME)" "$(INSTALLDIR)"\* +!if $(DEBUG)!=0 + echo F | xcopy /Y "$(PDBNAME)" "$(INSTALLDIR)"\* !endif - $(OX)\fossil.res - - -APPNAME = $(OX)\fossil$(E) -PDBNAME = $(OX)\fossil$(P) -APPTARGETS = - -all: $(OX) $(APPNAME) + +$(OX): + @-mkdir $@ zlib: @echo Building zlib from "$(ZLIBDIR)"... !if $(FOSSIL_ENABLE_WINXP)!=0 @pushd "$(ZLIBDIR)" && $(MAKE) /f win32\Makefile.msc $(ZLIB) "CC=cl $(XPCFLAGS)" "LD=link $(XPLDFLAGS)" && popd !else @pushd "$(ZLIBDIR)" && $(MAKE) /f win32\Makefile.msc $(ZLIB) && popd !endif +clean-zlib: + @pushd "$(ZLIBDIR)" && $(MAKE) /f win32\Makefile.msc clean && popd + !if $(FOSSIL_ENABLE_SSL)!=0 openssl: @echo Building OpenSSL from "$(SSLDIR)"... -!if "$(PERLDIR)" != "" - @set PATH=$(PERLDIR);$(PATH) +!ifdef PERLDIR + @pushd "$(SSLDIR)" && "$(PERLDIR)\$(PERL)" Configure $(SSLCONFIG) && popd +!else + @pushd "$(SSLDIR)" && "$(PERL)" Configure $(SSLCONFIG) && popd !endif - @pushd "$(SSLDIR)" && $(PERL) Configure $(SSLCONFIG) && popd - @pushd "$(SSLDIR)" && call $(SSLSETUP) && popd !if $(FOSSIL_ENABLE_WINXP)!=0 - @pushd "$(SSLDIR)" && $(MAKE) /f $(SSLNMAKE) "CC=cl $(SSLCFLAGS) $(XPCFLAGS)" "LFLAGS=$(SSLLFLAGS) $(XPLDFLAGS)" && popd + @pushd "$(SSLDIR)" && $(MAKE) "CC=cl $(XPCFLAGS)" "LFLAGS=$(XPLDFLAGS)" && popd !else - @pushd "$(SSLDIR)" && $(MAKE) /f $(SSLNMAKE) "CC=cl $(SSLCFLAGS)" && popd + @pushd "$(SSLDIR)" && $(MAKE) && popd !endif + +clean-openssl: + @pushd "$(SSLDIR)" && $(MAKE) clean && popd !endif !if $(FOSSIL_ENABLE_MINIZ)==0 !if $(FOSSIL_BUILD_ZLIB)!=0 APPTARGETS = $(APPTARGETS) zlib @@ -695,1115 +821,1384 @@ !if $(FOSSIL_BUILD_SSL)!=0 APPTARGETS = $(APPTARGETS) openssl !endif !endif -$(APPNAME) : $(APPTARGETS) translate$E mkindex$E codecheck1$E headers $(OBJ) $(OX)\linkopts - cd $(OX) - codecheck1$E $(SRC) - link $(LDFLAGS) /OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts - if exist $@.manifest \ - $(MTC) -nologo -manifest $@.manifest -outputresource:$@;1 - -$(OX)\linkopts: $B\win\Makefile.msc - echo $(OX)\add.obj > $@ - echo $(OX)\allrepo.obj >> $@ - echo $(OX)\attach.obj >> $@ - echo $(OX)\bag.obj >> $@ - echo $(OX)\bisect.obj >> $@ - echo $(OX)\blob.obj >> $@ - echo $(OX)\branch.obj >> $@ - echo $(OX)\browse.obj >> $@ - echo $(OX)\builtin.obj >> $@ - echo $(OX)\bundle.obj >> $@ - echo $(OX)\cache.obj >> $@ - echo $(OX)\captcha.obj >> $@ - echo $(OX)\cgi.obj >> $@ - echo $(OX)\checkin.obj >> $@ - echo $(OX)\checkout.obj >> $@ - echo $(OX)\clearsign.obj >> $@ - echo $(OX)\clone.obj >> $@ - echo $(OX)\comformat.obj >> $@ - echo $(OX)\configure.obj >> $@ - echo $(OX)\content.obj >> $@ - echo $(OX)\cson_amalgamation.obj >> $@ - echo $(OX)\db.obj >> $@ - echo $(OX)\delta.obj >> $@ - echo $(OX)\deltacmd.obj >> $@ - echo $(OX)\descendants.obj >> $@ - echo $(OX)\diff.obj >> $@ - echo $(OX)\diffcmd.obj >> $@ - echo $(OX)\dispatch.obj >> $@ - echo $(OX)\doc.obj >> $@ - echo $(OX)\encode.obj >> $@ - echo $(OX)\event.obj >> $@ - echo $(OX)\export.obj >> $@ - echo $(OX)\file.obj >> $@ - echo $(OX)\finfo.obj >> $@ - echo $(OX)\foci.obj >> $@ - echo $(OX)\fshell.obj >> $@ - echo $(OX)\fusefs.obj >> $@ - echo $(OX)\glob.obj >> $@ - echo $(OX)\graph.obj >> $@ - echo $(OX)\gzip.obj >> $@ - echo $(OX)\http.obj >> $@ - echo $(OX)\http_socket.obj >> $@ - echo $(OX)\http_ssl.obj >> $@ - echo $(OX)\http_transport.obj >> $@ - echo $(OX)\import.obj >> $@ - echo $(OX)\info.obj >> $@ - echo $(OX)\json.obj >> $@ - echo $(OX)\json_artifact.obj >> $@ - echo $(OX)\json_branch.obj >> $@ - echo $(OX)\json_config.obj >> $@ - echo $(OX)\json_diff.obj >> $@ - echo $(OX)\json_dir.obj >> $@ - echo $(OX)\json_finfo.obj >> $@ - echo $(OX)\json_login.obj >> $@ - echo $(OX)\json_query.obj >> $@ - echo $(OX)\json_report.obj >> $@ - echo $(OX)\json_status.obj >> $@ - echo $(OX)\json_tag.obj >> $@ - echo $(OX)\json_timeline.obj >> $@ - echo $(OX)\json_user.obj >> $@ - echo $(OX)\json_wiki.obj >> $@ - echo $(OX)\leaf.obj >> $@ - echo $(OX)\loadctrl.obj >> $@ - echo $(OX)\login.obj >> $@ - echo $(OX)\lookslike.obj >> $@ - echo $(OX)\main.obj >> $@ - echo $(OX)\manifest.obj >> $@ - echo $(OX)\markdown.obj >> $@ - echo $(OX)\markdown_html.obj >> $@ - echo $(OX)\md5.obj >> $@ - echo $(OX)\merge.obj >> $@ - echo $(OX)\merge3.obj >> $@ - echo $(OX)\moderate.obj >> $@ - echo $(OX)\name.obj >> $@ - echo $(OX)\path.obj >> $@ - echo $(OX)\piechart.obj >> $@ - echo $(OX)\pivot.obj >> $@ - echo $(OX)\popen.obj >> $@ - echo $(OX)\pqueue.obj >> $@ - echo $(OX)\printf.obj >> $@ - echo $(OX)\publish.obj >> $@ - echo $(OX)\purge.obj >> $@ - echo $(OX)\rebuild.obj >> $@ - echo $(OX)\regexp.obj >> $@ - echo $(OX)\report.obj >> $@ - echo $(OX)\rss.obj >> $@ - echo $(OX)\schema.obj >> $@ - echo $(OX)\search.obj >> $@ - echo $(OX)\setup.obj >> $@ - echo $(OX)\sha1.obj >> $@ - echo $(OX)\shell.obj >> $@ - echo $(OX)\shun.obj >> $@ - echo $(OX)\sitemap.obj >> $@ - echo $(OX)\skins.obj >> $@ - echo $(OX)\sqlcmd.obj >> $@ - echo $(OX)\sqlite3.obj >> $@ - echo $(OX)\stash.obj >> $@ - echo $(OX)\stat.obj >> $@ - echo $(OX)\statrep.obj >> $@ - echo $(OX)\style.obj >> $@ - echo $(OX)\sync.obj >> $@ - echo $(OX)\tag.obj >> $@ - echo $(OX)\tar.obj >> $@ - echo $(OX)\th.obj >> $@ - echo $(OX)\th_lang.obj >> $@ - echo $(OX)\th_main.obj >> $@ - echo $(OX)\th_tcl.obj >> $@ - echo $(OX)\timeline.obj >> $@ - echo $(OX)\tkt.obj >> $@ - echo $(OX)\tktsetup.obj >> $@ - echo $(OX)\undo.obj >> $@ - echo $(OX)\unicode.obj >> $@ - echo $(OX)\unversioned.obj >> $@ - echo $(OX)\update.obj >> $@ - echo $(OX)\url.obj >> $@ - echo $(OX)\user.obj >> $@ - echo $(OX)\utf8.obj >> $@ - echo $(OX)\util.obj >> $@ - echo $(OX)\verify.obj >> $@ - echo $(OX)\vfile.obj >> $@ - echo $(OX)\wiki.obj >> $@ - echo $(OX)\wikiformat.obj >> $@ - echo $(OX)\winfile.obj >> $@ - echo $(OX)\winhttp.obj >> $@ - echo $(OX)\wysiwyg.obj >> $@ - echo $(OX)\xfer.obj >> $@ - echo $(OX)\xfersetup.obj >> $@ - echo $(OX)\zip.obj >> $@ +"$(APPNAME)" : $(APPTARGETS) "$(OBJDIR)\translate$E" "$(OBJDIR)\mkindex$E" "$(OBJDIR)\codecheck1$E" "$(OX)\headers" $(OBJ) "$(OX)\linkopts" + "$(OBJDIR)\codecheck1$E" $(SRC) + link $(LDFLAGS) /OUT:$@ /PDB:$(@D)\ $(LIBDIR) Wsetargv.obj "$(OX)\fossil.res" @"$(OX)\linkopts" + if exist "$(B)\win\fossil.exe.manifest" \ + $(MTC) -nologo -manifest "$(B)\win\fossil.exe.manifest" -outputresource:$@;1 + +"$(OX)\linkopts": "$(B)\win\Makefile.msc" + echo "$(OX)\add.obj" > $@ + echo "$(OX)\ajax.obj" >> $@ + echo "$(OX)\alerts.obj" >> $@ + echo "$(OX)\allrepo.obj" >> $@ + echo "$(OX)\attach.obj" >> $@ + echo "$(OX)\backlink.obj" >> $@ + echo "$(OX)\backoffice.obj" >> $@ + echo "$(OX)\bag.obj" >> $@ + echo "$(OX)\bisect.obj" >> $@ + echo "$(OX)\blob.obj" >> $@ + echo "$(OX)\branch.obj" >> $@ + echo "$(OX)\browse.obj" >> $@ + echo "$(OX)\builtin.obj" >> $@ + echo "$(OX)\bundle.obj" >> $@ + echo "$(OX)\cache.obj" >> $@ + echo "$(OX)\capabilities.obj" >> $@ + echo "$(OX)\captcha.obj" >> $@ + echo "$(OX)\cgi.obj" >> $@ + echo "$(OX)\checkin.obj" >> $@ + echo "$(OX)\checkout.obj" >> $@ + echo "$(OX)\clearsign.obj" >> $@ + echo "$(OX)\clone.obj" >> $@ + echo "$(OX)\comformat.obj" >> $@ + echo "$(OX)\configure.obj" >> $@ + echo "$(OX)\content.obj" >> $@ + echo "$(OX)\cookies.obj" >> $@ + echo "$(OX)\cson_amalgamation.obj" >> $@ + echo "$(OX)\db.obj" >> $@ + echo "$(OX)\delta.obj" >> $@ + echo "$(OX)\deltacmd.obj" >> $@ + echo "$(OX)\deltafunc.obj" >> $@ + echo "$(OX)\descendants.obj" >> $@ + echo "$(OX)\diff.obj" >> $@ + echo "$(OX)\diffcmd.obj" >> $@ + echo "$(OX)\dispatch.obj" >> $@ + echo "$(OX)\doc.obj" >> $@ + echo "$(OX)\encode.obj" >> $@ + echo "$(OX)\etag.obj" >> $@ + echo "$(OX)\event.obj" >> $@ + echo "$(OX)\export.obj" >> $@ + echo "$(OX)\extcgi.obj" >> $@ + echo "$(OX)\file.obj" >> $@ + echo "$(OX)\fileedit.obj" >> $@ + echo "$(OX)\finfo.obj" >> $@ + echo "$(OX)\foci.obj" >> $@ + echo "$(OX)\forum.obj" >> $@ + echo "$(OX)\fshell.obj" >> $@ + echo "$(OX)\fusefs.obj" >> $@ + echo "$(OX)\fuzz.obj" >> $@ + echo "$(OX)\glob.obj" >> $@ + echo "$(OX)\graph.obj" >> $@ + echo "$(OX)\gzip.obj" >> $@ + echo "$(OX)\hname.obj" >> $@ + echo "$(OX)\http.obj" >> $@ + echo "$(OX)\http_socket.obj" >> $@ + echo "$(OX)\http_ssl.obj" >> $@ + echo "$(OX)\http_transport.obj" >> $@ + echo "$(OX)\import.obj" >> $@ + echo "$(OX)\info.obj" >> $@ + echo "$(OX)\json.obj" >> $@ + echo "$(OX)\json_artifact.obj" >> $@ + echo "$(OX)\json_branch.obj" >> $@ + echo "$(OX)\json_config.obj" >> $@ + echo "$(OX)\json_diff.obj" >> $@ + echo "$(OX)\json_dir.obj" >> $@ + echo "$(OX)\json_finfo.obj" >> $@ + echo "$(OX)\json_login.obj" >> $@ + echo "$(OX)\json_query.obj" >> $@ + echo "$(OX)\json_report.obj" >> $@ + echo "$(OX)\json_status.obj" >> $@ + echo "$(OX)\json_tag.obj" >> $@ + echo "$(OX)\json_timeline.obj" >> $@ + echo "$(OX)\json_user.obj" >> $@ + echo "$(OX)\json_wiki.obj" >> $@ + echo "$(OX)\leaf.obj" >> $@ + echo "$(OX)\loadctrl.obj" >> $@ + echo "$(OX)\login.obj" >> $@ + echo "$(OX)\lookslike.obj" >> $@ + echo "$(OX)\main.obj" >> $@ + echo "$(OX)\manifest.obj" >> $@ + echo "$(OX)\markdown.obj" >> $@ + echo "$(OX)\markdown_html.obj" >> $@ + echo "$(OX)\md5.obj" >> $@ + echo "$(OX)\merge.obj" >> $@ + echo "$(OX)\merge3.obj" >> $@ + echo "$(OX)\moderate.obj" >> $@ + echo "$(OX)\name.obj" >> $@ + echo "$(OX)\path.obj" >> $@ + echo "$(OX)\piechart.obj" >> $@ + echo "$(OX)\pivot.obj" >> $@ + echo "$(OX)\popen.obj" >> $@ + echo "$(OX)\pqueue.obj" >> $@ + echo "$(OX)\printf.obj" >> $@ + echo "$(OX)\publish.obj" >> $@ + echo "$(OX)\purge.obj" >> $@ + echo "$(OX)\rebuild.obj" >> $@ + echo "$(OX)\regexp.obj" >> $@ + echo "$(OX)\repolist.obj" >> $@ + echo "$(OX)\report.obj" >> $@ + echo "$(OX)\rss.obj" >> $@ + echo "$(OX)\schema.obj" >> $@ + echo "$(OX)\search.obj" >> $@ + echo "$(OX)\security_audit.obj" >> $@ + echo "$(OX)\setup.obj" >> $@ + echo "$(OX)\setupuser.obj" >> $@ + echo "$(OX)\sha1.obj" >> $@ + echo "$(OX)\sha1hard.obj" >> $@ + echo "$(OX)\sha3.obj" >> $@ + echo "$(OX)\shell.obj" >> $@ + echo "$(OX)\shun.obj" >> $@ + echo "$(OX)\sitemap.obj" >> $@ + echo "$(OX)\skins.obj" >> $@ + echo "$(OX)\smtp.obj" >> $@ + echo "$(OX)\sqlcmd.obj" >> $@ + echo "$(OX)\sqlite3.obj" >> $@ + echo "$(OX)\stash.obj" >> $@ + echo "$(OX)\stat.obj" >> $@ + echo "$(OX)\statrep.obj" >> $@ + echo "$(OX)\style.obj" >> $@ + echo "$(OX)\sync.obj" >> $@ + echo "$(OX)\tag.obj" >> $@ + echo "$(OX)\tar.obj" >> $@ + echo "$(OX)\terminal.obj" >> $@ + echo "$(OX)\th.obj" >> $@ + echo "$(OX)\th_lang.obj" >> $@ + echo "$(OX)\th_main.obj" >> $@ + echo "$(OX)\th_tcl.obj" >> $@ + echo "$(OX)\timeline.obj" >> $@ + echo "$(OX)\tkt.obj" >> $@ + echo "$(OX)\tktsetup.obj" >> $@ + echo "$(OX)\undo.obj" >> $@ + echo "$(OX)\unicode.obj" >> $@ + echo "$(OX)\unversioned.obj" >> $@ + echo "$(OX)\update.obj" >> $@ + echo "$(OX)\url.obj" >> $@ + echo "$(OX)\user.obj" >> $@ + echo "$(OX)\utf8.obj" >> $@ + echo "$(OX)\util.obj" >> $@ + echo "$(OX)\verify.obj" >> $@ + echo "$(OX)\vfile.obj" >> $@ + echo "$(OX)\webmail.obj" >> $@ + echo "$(OX)\wiki.obj" >> $@ + echo "$(OX)\wikiformat.obj" >> $@ + echo "$(OX)\winfile.obj" >> $@ + echo "$(OX)\winhttp.obj" >> $@ + echo "$(OX)\wysiwyg.obj" >> $@ + echo "$(OX)\xfer.obj" >> $@ + echo "$(OX)\xfersetup.obj" >> $@ + echo "$(OX)\zip.obj" >> $@ !if $(FOSSIL_ENABLE_MINIZ)!=0 - echo $(OX)\miniz.obj >> $@ + echo "$(OX)\miniz.obj" >> $@ !endif echo $(LIBS) >> $@ -$(OX): - @-mkdir $@ - -translate$E: $(SRCDIR)\translate.c - $(BCC) $** - -makeheaders$E: $(SRCDIR)\makeheaders.c - $(BCC) $** - -mkindex$E: $(SRCDIR)\mkindex.c - $(BCC) $** - -mkbuiltin$E: $(SRCDIR)\mkbuiltin.c - $(BCC) $** - -mkversion$E: $(SRCDIR)\mkversion.c - $(BCC) $** - -codecheck1$E: $(SRCDIR)\codecheck1.c - $(BCC) $** - -!if $(USE_SEE)!=0 -SQLITE3_SHELL_SRC = $(SRCDIR)\shell-see.c -!else -SQLITE3_SHELL_SRC = $(SRCDIR)\shell.c -!endif - -$(OX)\shell$O : $(SQLITE3_SHELL_SRC) $B\win\Makefile.msc - $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) -c $(SQLITE3_SHELL_SRC) - -!if $(USE_SEE)!=0 -SQLITE3_SRC = $(SRCDIR)\sqlite3-see.c -!else +"$(OBJDIR)\translate$E": "$(SRCDIR)\translate.c" + $(BCC) /Fe$@ /Fo$(@D)\ /Fd$(@D)\ $** + +"$(OBJDIR)\makeheaders$E": "$(SRCDIR)\makeheaders.c" + $(BCC) /Fe$@ /Fo$(@D)\ /Fd$(@D)\ $** + +"$(OBJDIR)\mkindex$E": "$(SRCDIR)\mkindex.c" + $(BCC) /Fe$@ /Fo$(@D)\ /Fd$(@D)\ $** + +"$(OBJDIR)\mkbuiltin$E": "$(SRCDIR)\mkbuiltin.c" + $(BCC) /Fe$@ /Fo$(@D)\ /Fd$(@D)\ $** + +"$(OBJDIR)\mkversion$E": "$(SRCDIR)\mkversion.c" + $(BCC) /Fe$@ /Fo$(@D)\ /Fd$(@D)\ $** + +"$(OBJDIR)\codecheck1$E": "$(SRCDIR)\codecheck1.c" + $(BCC) /Fe$@ /Fo$(@D)\ /Fd$(@D)\ $** + +!if $(USE_SEE)!=0 +SEE_FLAGS = /DSQLITE_HAS_CODEC=1 /DSQLITE_SHELL_DBKEY_PROC=fossil_key +SQLITE3_SHELL_SRC = $(SRCDIR)\shell-see.c +SQLITE3_SRC = $(SRCDIR)\sqlite3-see.c +!else +SEE_FLAGS = +SQLITE3_SHELL_SRC = $(SRCDIR)\shell.c SQLITE3_SRC = $(SRCDIR)\sqlite3.c !endif -$(OX)\sqlite3$O : $(SQLITE3_SRC) $B\win\Makefile.msc - $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SEE_FLAGS) $(SQLITE3_SRC) - -$(OX)\th$O : $(SRCDIR)\th.c - $(TCC) /Fo$@ -c $** - -$(OX)\th_lang$O : $(SRCDIR)\th_lang.c - $(TCC) /Fo$@ -c $** - -$(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c - $(TCC) /Fo$@ -c $** - -$(OX)\miniz$O : $(SRCDIR)\miniz.c - $(TCC) /Fo$@ -c $(MINIZ_OPTIONS) $(SRCDIR)\miniz.c - -VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION - $** > $@ -$(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c - $(TCC) /Fo$@ /c $** - -page_index.h: mkindex$E $(SRC) - $** > $@ - -builtin_data.h: mkbuiltin$E $(EXTRA_FILES) - mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@ - -clean: - del $(OX)\*.obj 2>NUL - del *.obj 2>NUL - del *_.c 2>NUL - del *.h 2>NUL - del *.ilk 2>NUL - del *.map 2>NUL - del *.res 2>NUL - del headers 2>NUL - del linkopts 2>NUL - del vc*.pdb 2>NUL - -realclean: clean - del $(APPNAME) 2>NUL - del $(PDBNAME) 2>NUL - del translate$E 2>NUL - del translate$P 2>NUL - del mkindex$E 2>NUL - del mkindex$P 2>NUL - del makeheaders$E 2>NUL - del makeheaders$P 2>NUL - del mkversion$E 2>NUL - del mkversion$P 2>NUL - del codecheck1$E 2>NUL - del codecheck1$P 2>NUL - del mkbuiltin$E 2>NUL - del mkbuiltin$P 2>NUL - -$(OBJDIR)\json$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_status$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h -$(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h - -$(OX)\add$O : add_.c add.h - $(TCC) /Fo$@ -c add_.c - -add_.c : $(SRCDIR)\add.c - translate$E $** > $@ - -$(OX)\allrepo$O : allrepo_.c allrepo.h - $(TCC) /Fo$@ -c allrepo_.c - -allrepo_.c : $(SRCDIR)\allrepo.c - translate$E $** > $@ - -$(OX)\attach$O : attach_.c attach.h - $(TCC) /Fo$@ -c attach_.c - -attach_.c : $(SRCDIR)\attach.c - translate$E $** > $@ - -$(OX)\bag$O : bag_.c bag.h - $(TCC) /Fo$@ -c bag_.c - -bag_.c : $(SRCDIR)\bag.c - translate$E $** > $@ - -$(OX)\bisect$O : bisect_.c bisect.h - $(TCC) /Fo$@ -c bisect_.c - -bisect_.c : $(SRCDIR)\bisect.c - translate$E $** > $@ - -$(OX)\blob$O : blob_.c blob.h - $(TCC) /Fo$@ -c blob_.c - -blob_.c : $(SRCDIR)\blob.c - translate$E $** > $@ - -$(OX)\branch$O : branch_.c branch.h - $(TCC) /Fo$@ -c branch_.c - -branch_.c : $(SRCDIR)\branch.c - translate$E $** > $@ - -$(OX)\browse$O : browse_.c browse.h - $(TCC) /Fo$@ -c browse_.c - -browse_.c : $(SRCDIR)\browse.c - translate$E $** > $@ - -$(OX)\builtin$O : builtin_.c builtin.h - $(TCC) /Fo$@ -c builtin_.c - -builtin_.c : $(SRCDIR)\builtin.c - translate$E $** > $@ - -$(OX)\bundle$O : bundle_.c bundle.h - $(TCC) /Fo$@ -c bundle_.c - -bundle_.c : $(SRCDIR)\bundle.c - translate$E $** > $@ - -$(OX)\cache$O : cache_.c cache.h - $(TCC) /Fo$@ -c cache_.c - -cache_.c : $(SRCDIR)\cache.c - translate$E $** > $@ - -$(OX)\captcha$O : captcha_.c captcha.h - $(TCC) /Fo$@ -c captcha_.c - -captcha_.c : $(SRCDIR)\captcha.c - translate$E $** > $@ - -$(OX)\cgi$O : cgi_.c cgi.h - $(TCC) /Fo$@ -c cgi_.c - -cgi_.c : $(SRCDIR)\cgi.c - translate$E $** > $@ - -$(OX)\checkin$O : checkin_.c checkin.h - $(TCC) /Fo$@ -c checkin_.c - -checkin_.c : $(SRCDIR)\checkin.c - translate$E $** > $@ - -$(OX)\checkout$O : checkout_.c checkout.h - $(TCC) /Fo$@ -c checkout_.c - -checkout_.c : $(SRCDIR)\checkout.c - translate$E $** > $@ - -$(OX)\clearsign$O : clearsign_.c clearsign.h - $(TCC) /Fo$@ -c clearsign_.c - -clearsign_.c : $(SRCDIR)\clearsign.c - translate$E $** > $@ - -$(OX)\clone$O : clone_.c clone.h - $(TCC) /Fo$@ -c clone_.c - -clone_.c : $(SRCDIR)\clone.c - translate$E $** > $@ - -$(OX)\comformat$O : comformat_.c comformat.h - $(TCC) /Fo$@ -c comformat_.c - -comformat_.c : $(SRCDIR)\comformat.c - translate$E $** > $@ - -$(OX)\configure$O : configure_.c configure.h - $(TCC) /Fo$@ -c configure_.c - -configure_.c : $(SRCDIR)\configure.c - translate$E $** > $@ - -$(OX)\content$O : content_.c content.h - $(TCC) /Fo$@ -c content_.c - -content_.c : $(SRCDIR)\content.c - translate$E $** > $@ - -$(OX)\db$O : db_.c db.h - $(TCC) /Fo$@ -c db_.c - -db_.c : $(SRCDIR)\db.c - translate$E $** > $@ - -$(OX)\delta$O : delta_.c delta.h - $(TCC) /Fo$@ -c delta_.c - -delta_.c : $(SRCDIR)\delta.c - translate$E $** > $@ - -$(OX)\deltacmd$O : deltacmd_.c deltacmd.h - $(TCC) /Fo$@ -c deltacmd_.c - -deltacmd_.c : $(SRCDIR)\deltacmd.c - translate$E $** > $@ - -$(OX)\descendants$O : descendants_.c descendants.h - $(TCC) /Fo$@ -c descendants_.c - -descendants_.c : $(SRCDIR)\descendants.c - translate$E $** > $@ - -$(OX)\diff$O : diff_.c diff.h - $(TCC) /Fo$@ -c diff_.c - -diff_.c : $(SRCDIR)\diff.c - translate$E $** > $@ - -$(OX)\diffcmd$O : diffcmd_.c diffcmd.h - $(TCC) /Fo$@ -c diffcmd_.c - -diffcmd_.c : $(SRCDIR)\diffcmd.c - translate$E $** > $@ - -$(OX)\dispatch$O : dispatch_.c dispatch.h - $(TCC) /Fo$@ -c dispatch_.c - -dispatch_.c : $(SRCDIR)\dispatch.c - translate$E $** > $@ - -$(OX)\doc$O : doc_.c doc.h - $(TCC) /Fo$@ -c doc_.c - -doc_.c : $(SRCDIR)\doc.c - translate$E $** > $@ - -$(OX)\encode$O : encode_.c encode.h - $(TCC) /Fo$@ -c encode_.c - -encode_.c : $(SRCDIR)\encode.c - translate$E $** > $@ - -$(OX)\event$O : event_.c event.h - $(TCC) /Fo$@ -c event_.c - -event_.c : $(SRCDIR)\event.c - translate$E $** > $@ - -$(OX)\export$O : export_.c export.h - $(TCC) /Fo$@ -c export_.c - -export_.c : $(SRCDIR)\export.c - translate$E $** > $@ - -$(OX)\file$O : file_.c file.h - $(TCC) /Fo$@ -c file_.c - -file_.c : $(SRCDIR)\file.c - translate$E $** > $@ - -$(OX)\finfo$O : finfo_.c finfo.h - $(TCC) /Fo$@ -c finfo_.c - -finfo_.c : $(SRCDIR)\finfo.c - translate$E $** > $@ - -$(OX)\foci$O : foci_.c foci.h - $(TCC) /Fo$@ -c foci_.c - -foci_.c : $(SRCDIR)\foci.c - translate$E $** > $@ - -$(OX)\fshell$O : fshell_.c fshell.h - $(TCC) /Fo$@ -c fshell_.c - -fshell_.c : $(SRCDIR)\fshell.c - translate$E $** > $@ - -$(OX)\fusefs$O : fusefs_.c fusefs.h - $(TCC) /Fo$@ -c fusefs_.c - -fusefs_.c : $(SRCDIR)\fusefs.c - translate$E $** > $@ - -$(OX)\glob$O : glob_.c glob.h - $(TCC) /Fo$@ -c glob_.c - -glob_.c : $(SRCDIR)\glob.c - translate$E $** > $@ - -$(OX)\graph$O : graph_.c graph.h - $(TCC) /Fo$@ -c graph_.c - -graph_.c : $(SRCDIR)\graph.c - translate$E $** > $@ - -$(OX)\gzip$O : gzip_.c gzip.h - $(TCC) /Fo$@ -c gzip_.c - -gzip_.c : $(SRCDIR)\gzip.c - translate$E $** > $@ - -$(OX)\http$O : http_.c http.h - $(TCC) /Fo$@ -c http_.c - -http_.c : $(SRCDIR)\http.c - translate$E $** > $@ - -$(OX)\http_socket$O : http_socket_.c http_socket.h - $(TCC) /Fo$@ -c http_socket_.c - -http_socket_.c : $(SRCDIR)\http_socket.c - translate$E $** > $@ - -$(OX)\http_ssl$O : http_ssl_.c http_ssl.h - $(TCC) /Fo$@ -c http_ssl_.c - -http_ssl_.c : $(SRCDIR)\http_ssl.c - translate$E $** > $@ - -$(OX)\http_transport$O : http_transport_.c http_transport.h - $(TCC) /Fo$@ -c http_transport_.c - -http_transport_.c : $(SRCDIR)\http_transport.c - translate$E $** > $@ - -$(OX)\import$O : import_.c import.h - $(TCC) /Fo$@ -c import_.c - -import_.c : $(SRCDIR)\import.c - translate$E $** > $@ - -$(OX)\info$O : info_.c info.h - $(TCC) /Fo$@ -c info_.c - -info_.c : $(SRCDIR)\info.c - translate$E $** > $@ - -$(OX)\json$O : json_.c json.h - $(TCC) /Fo$@ -c json_.c - -json_.c : $(SRCDIR)\json.c - translate$E $** > $@ - -$(OX)\json_artifact$O : json_artifact_.c json_artifact.h - $(TCC) /Fo$@ -c json_artifact_.c - -json_artifact_.c : $(SRCDIR)\json_artifact.c - translate$E $** > $@ - -$(OX)\json_branch$O : json_branch_.c json_branch.h - $(TCC) /Fo$@ -c json_branch_.c - -json_branch_.c : $(SRCDIR)\json_branch.c - translate$E $** > $@ - -$(OX)\json_config$O : json_config_.c json_config.h - $(TCC) /Fo$@ -c json_config_.c - -json_config_.c : $(SRCDIR)\json_config.c - translate$E $** > $@ - -$(OX)\json_diff$O : json_diff_.c json_diff.h - $(TCC) /Fo$@ -c json_diff_.c - -json_diff_.c : $(SRCDIR)\json_diff.c - translate$E $** > $@ - -$(OX)\json_dir$O : json_dir_.c json_dir.h - $(TCC) /Fo$@ -c json_dir_.c - -json_dir_.c : $(SRCDIR)\json_dir.c - translate$E $** > $@ - -$(OX)\json_finfo$O : json_finfo_.c json_finfo.h - $(TCC) /Fo$@ -c json_finfo_.c - -json_finfo_.c : $(SRCDIR)\json_finfo.c - translate$E $** > $@ - -$(OX)\json_login$O : json_login_.c json_login.h - $(TCC) /Fo$@ -c json_login_.c - -json_login_.c : $(SRCDIR)\json_login.c - translate$E $** > $@ - -$(OX)\json_query$O : json_query_.c json_query.h - $(TCC) /Fo$@ -c json_query_.c - -json_query_.c : $(SRCDIR)\json_query.c - translate$E $** > $@ - -$(OX)\json_report$O : json_report_.c json_report.h - $(TCC) /Fo$@ -c json_report_.c - -json_report_.c : $(SRCDIR)\json_report.c - translate$E $** > $@ - -$(OX)\json_status$O : json_status_.c json_status.h - $(TCC) /Fo$@ -c json_status_.c - -json_status_.c : $(SRCDIR)\json_status.c - translate$E $** > $@ - -$(OX)\json_tag$O : json_tag_.c json_tag.h - $(TCC) /Fo$@ -c json_tag_.c - -json_tag_.c : $(SRCDIR)\json_tag.c - translate$E $** > $@ - -$(OX)\json_timeline$O : json_timeline_.c json_timeline.h - $(TCC) /Fo$@ -c json_timeline_.c - -json_timeline_.c : $(SRCDIR)\json_timeline.c - translate$E $** > $@ - -$(OX)\json_user$O : json_user_.c json_user.h - $(TCC) /Fo$@ -c json_user_.c - -json_user_.c : $(SRCDIR)\json_user.c - translate$E $** > $@ - -$(OX)\json_wiki$O : json_wiki_.c json_wiki.h - $(TCC) /Fo$@ -c json_wiki_.c - -json_wiki_.c : $(SRCDIR)\json_wiki.c - translate$E $** > $@ - -$(OX)\leaf$O : leaf_.c leaf.h - $(TCC) /Fo$@ -c leaf_.c - -leaf_.c : $(SRCDIR)\leaf.c - translate$E $** > $@ - -$(OX)\loadctrl$O : loadctrl_.c loadctrl.h - $(TCC) /Fo$@ -c loadctrl_.c - -loadctrl_.c : $(SRCDIR)\loadctrl.c - translate$E $** > $@ - -$(OX)\login$O : login_.c login.h - $(TCC) /Fo$@ -c login_.c - -login_.c : $(SRCDIR)\login.c - translate$E $** > $@ - -$(OX)\lookslike$O : lookslike_.c lookslike.h - $(TCC) /Fo$@ -c lookslike_.c - -lookslike_.c : $(SRCDIR)\lookslike.c - translate$E $** > $@ - -$(OX)\main$O : main_.c main.h - $(TCC) /Fo$@ -c main_.c - -main_.c : $(SRCDIR)\main.c - translate$E $** > $@ - -$(OX)\manifest$O : manifest_.c manifest.h - $(TCC) /Fo$@ -c manifest_.c - -manifest_.c : $(SRCDIR)\manifest.c - translate$E $** > $@ - -$(OX)\markdown$O : markdown_.c markdown.h - $(TCC) /Fo$@ -c markdown_.c - -markdown_.c : $(SRCDIR)\markdown.c - translate$E $** > $@ - -$(OX)\markdown_html$O : markdown_html_.c markdown_html.h - $(TCC) /Fo$@ -c markdown_html_.c - -markdown_html_.c : $(SRCDIR)\markdown_html.c - translate$E $** > $@ - -$(OX)\md5$O : md5_.c md5.h - $(TCC) /Fo$@ -c md5_.c - -md5_.c : $(SRCDIR)\md5.c - translate$E $** > $@ - -$(OX)\merge$O : merge_.c merge.h - $(TCC) /Fo$@ -c merge_.c - -merge_.c : $(SRCDIR)\merge.c - translate$E $** > $@ - -$(OX)\merge3$O : merge3_.c merge3.h - $(TCC) /Fo$@ -c merge3_.c - -merge3_.c : $(SRCDIR)\merge3.c - translate$E $** > $@ - -$(OX)\moderate$O : moderate_.c moderate.h - $(TCC) /Fo$@ -c moderate_.c - -moderate_.c : $(SRCDIR)\moderate.c - translate$E $** > $@ - -$(OX)\name$O : name_.c name.h - $(TCC) /Fo$@ -c name_.c - -name_.c : $(SRCDIR)\name.c - translate$E $** > $@ - -$(OX)\path$O : path_.c path.h - $(TCC) /Fo$@ -c path_.c - -path_.c : $(SRCDIR)\path.c - translate$E $** > $@ - -$(OX)\piechart$O : piechart_.c piechart.h - $(TCC) /Fo$@ -c piechart_.c - -piechart_.c : $(SRCDIR)\piechart.c - translate$E $** > $@ - -$(OX)\pivot$O : pivot_.c pivot.h - $(TCC) /Fo$@ -c pivot_.c - -pivot_.c : $(SRCDIR)\pivot.c - translate$E $** > $@ - -$(OX)\popen$O : popen_.c popen.h - $(TCC) /Fo$@ -c popen_.c - -popen_.c : $(SRCDIR)\popen.c - translate$E $** > $@ - -$(OX)\pqueue$O : pqueue_.c pqueue.h - $(TCC) /Fo$@ -c pqueue_.c - -pqueue_.c : $(SRCDIR)\pqueue.c - translate$E $** > $@ - -$(OX)\printf$O : printf_.c printf.h - $(TCC) /Fo$@ -c printf_.c - -printf_.c : $(SRCDIR)\printf.c - translate$E $** > $@ - -$(OX)\publish$O : publish_.c publish.h - $(TCC) /Fo$@ -c publish_.c - -publish_.c : $(SRCDIR)\publish.c - translate$E $** > $@ - -$(OX)\purge$O : purge_.c purge.h - $(TCC) /Fo$@ -c purge_.c - -purge_.c : $(SRCDIR)\purge.c - translate$E $** > $@ - -$(OX)\rebuild$O : rebuild_.c rebuild.h - $(TCC) /Fo$@ -c rebuild_.c - -rebuild_.c : $(SRCDIR)\rebuild.c - translate$E $** > $@ - -$(OX)\regexp$O : regexp_.c regexp.h - $(TCC) /Fo$@ -c regexp_.c - -regexp_.c : $(SRCDIR)\regexp.c - translate$E $** > $@ - -$(OX)\report$O : report_.c report.h - $(TCC) /Fo$@ -c report_.c - -report_.c : $(SRCDIR)\report.c - translate$E $** > $@ - -$(OX)\rss$O : rss_.c rss.h - $(TCC) /Fo$@ -c rss_.c - -rss_.c : $(SRCDIR)\rss.c - translate$E $** > $@ - -$(OX)\schema$O : schema_.c schema.h - $(TCC) /Fo$@ -c schema_.c - -schema_.c : $(SRCDIR)\schema.c - translate$E $** > $@ - -$(OX)\search$O : search_.c search.h - $(TCC) /Fo$@ -c search_.c - -search_.c : $(SRCDIR)\search.c - translate$E $** > $@ - -$(OX)\setup$O : setup_.c setup.h - $(TCC) /Fo$@ -c setup_.c - -setup_.c : $(SRCDIR)\setup.c - translate$E $** > $@ - -$(OX)\sha1$O : sha1_.c sha1.h - $(TCC) /Fo$@ -c sha1_.c - -sha1_.c : $(SRCDIR)\sha1.c - translate$E $** > $@ - -$(OX)\shun$O : shun_.c shun.h - $(TCC) /Fo$@ -c shun_.c - -shun_.c : $(SRCDIR)\shun.c - translate$E $** > $@ - -$(OX)\sitemap$O : sitemap_.c sitemap.h - $(TCC) /Fo$@ -c sitemap_.c - -sitemap_.c : $(SRCDIR)\sitemap.c - translate$E $** > $@ - -$(OX)\skins$O : skins_.c skins.h - $(TCC) /Fo$@ -c skins_.c - -skins_.c : $(SRCDIR)\skins.c - translate$E $** > $@ - -$(OX)\sqlcmd$O : sqlcmd_.c sqlcmd.h - $(TCC) /Fo$@ -c sqlcmd_.c - -sqlcmd_.c : $(SRCDIR)\sqlcmd.c - translate$E $** > $@ - -$(OX)\stash$O : stash_.c stash.h - $(TCC) /Fo$@ -c stash_.c - -stash_.c : $(SRCDIR)\stash.c - translate$E $** > $@ - -$(OX)\stat$O : stat_.c stat.h - $(TCC) /Fo$@ -c stat_.c - -stat_.c : $(SRCDIR)\stat.c - translate$E $** > $@ - -$(OX)\statrep$O : statrep_.c statrep.h - $(TCC) /Fo$@ -c statrep_.c - -statrep_.c : $(SRCDIR)\statrep.c - translate$E $** > $@ - -$(OX)\style$O : style_.c style.h - $(TCC) /Fo$@ -c style_.c - -style_.c : $(SRCDIR)\style.c - translate$E $** > $@ - -$(OX)\sync$O : sync_.c sync.h - $(TCC) /Fo$@ -c sync_.c - -sync_.c : $(SRCDIR)\sync.c - translate$E $** > $@ - -$(OX)\tag$O : tag_.c tag.h - $(TCC) /Fo$@ -c tag_.c - -tag_.c : $(SRCDIR)\tag.c - translate$E $** > $@ - -$(OX)\tar$O : tar_.c tar.h - $(TCC) /Fo$@ -c tar_.c - -tar_.c : $(SRCDIR)\tar.c - translate$E $** > $@ - -$(OX)\th_main$O : th_main_.c th_main.h - $(TCC) /Fo$@ -c th_main_.c - -th_main_.c : $(SRCDIR)\th_main.c - translate$E $** > $@ - -$(OX)\timeline$O : timeline_.c timeline.h - $(TCC) /Fo$@ -c timeline_.c - -timeline_.c : $(SRCDIR)\timeline.c - translate$E $** > $@ - -$(OX)\tkt$O : tkt_.c tkt.h - $(TCC) /Fo$@ -c tkt_.c - -tkt_.c : $(SRCDIR)\tkt.c - translate$E $** > $@ - -$(OX)\tktsetup$O : tktsetup_.c tktsetup.h - $(TCC) /Fo$@ -c tktsetup_.c - -tktsetup_.c : $(SRCDIR)\tktsetup.c - translate$E $** > $@ - -$(OX)\undo$O : undo_.c undo.h - $(TCC) /Fo$@ -c undo_.c - -undo_.c : $(SRCDIR)\undo.c - translate$E $** > $@ - -$(OX)\unicode$O : unicode_.c unicode.h - $(TCC) /Fo$@ -c unicode_.c - -unicode_.c : $(SRCDIR)\unicode.c - translate$E $** > $@ - -$(OX)\unversioned$O : unversioned_.c unversioned.h - $(TCC) /Fo$@ -c unversioned_.c - -unversioned_.c : $(SRCDIR)\unversioned.c - translate$E $** > $@ - -$(OX)\update$O : update_.c update.h - $(TCC) /Fo$@ -c update_.c - -update_.c : $(SRCDIR)\update.c - translate$E $** > $@ - -$(OX)\url$O : url_.c url.h - $(TCC) /Fo$@ -c url_.c - -url_.c : $(SRCDIR)\url.c - translate$E $** > $@ - -$(OX)\user$O : user_.c user.h - $(TCC) /Fo$@ -c user_.c - -user_.c : $(SRCDIR)\user.c - translate$E $** > $@ - -$(OX)\utf8$O : utf8_.c utf8.h - $(TCC) /Fo$@ -c utf8_.c - -utf8_.c : $(SRCDIR)\utf8.c - translate$E $** > $@ - -$(OX)\util$O : util_.c util.h - $(TCC) /Fo$@ -c util_.c - -util_.c : $(SRCDIR)\util.c - translate$E $** > $@ - -$(OX)\verify$O : verify_.c verify.h - $(TCC) /Fo$@ -c verify_.c - -verify_.c : $(SRCDIR)\verify.c - translate$E $** > $@ - -$(OX)\vfile$O : vfile_.c vfile.h - $(TCC) /Fo$@ -c vfile_.c - -vfile_.c : $(SRCDIR)\vfile.c - translate$E $** > $@ - -$(OX)\wiki$O : wiki_.c wiki.h - $(TCC) /Fo$@ -c wiki_.c - -wiki_.c : $(SRCDIR)\wiki.c - translate$E $** > $@ - -$(OX)\wikiformat$O : wikiformat_.c wikiformat.h - $(TCC) /Fo$@ -c wikiformat_.c - -wikiformat_.c : $(SRCDIR)\wikiformat.c - translate$E $** > $@ - -$(OX)\winfile$O : winfile_.c winfile.h - $(TCC) /Fo$@ -c winfile_.c - -winfile_.c : $(SRCDIR)\winfile.c - translate$E $** > $@ - -$(OX)\winhttp$O : winhttp_.c winhttp.h - $(TCC) /Fo$@ -c winhttp_.c - -winhttp_.c : $(SRCDIR)\winhttp.c - translate$E $** > $@ - -$(OX)\wysiwyg$O : wysiwyg_.c wysiwyg.h - $(TCC) /Fo$@ -c wysiwyg_.c - -wysiwyg_.c : $(SRCDIR)\wysiwyg.c - translate$E $** > $@ - -$(OX)\xfer$O : xfer_.c xfer.h - $(TCC) /Fo$@ -c xfer_.c - -xfer_.c : $(SRCDIR)\xfer.c - translate$E $** > $@ - -$(OX)\xfersetup$O : xfersetup_.c xfersetup.h - $(TCC) /Fo$@ -c xfersetup_.c - -xfersetup_.c : $(SRCDIR)\xfersetup.c - translate$E $** > $@ - -$(OX)\zip$O : zip_.c zip.h - $(TCC) /Fo$@ -c zip_.c - -zip_.c : $(SRCDIR)\zip.c - translate$E $** > $@ - -fossil.res : $B\win\fossil.rc - $(RCC) /fo $@ $** - -headers: makeheaders$E page_index.h builtin_data.h VERSION.h - makeheaders$E add_.c:add.h \ - allrepo_.c:allrepo.h \ - attach_.c:attach.h \ - bag_.c:bag.h \ - bisect_.c:bisect.h \ - blob_.c:blob.h \ - branch_.c:branch.h \ - browse_.c:browse.h \ - builtin_.c:builtin.h \ - bundle_.c:bundle.h \ - cache_.c:cache.h \ - captcha_.c:captcha.h \ - cgi_.c:cgi.h \ - checkin_.c:checkin.h \ - checkout_.c:checkout.h \ - clearsign_.c:clearsign.h \ - clone_.c:clone.h \ - comformat_.c:comformat.h \ - configure_.c:configure.h \ - content_.c:content.h \ - db_.c:db.h \ - delta_.c:delta.h \ - deltacmd_.c:deltacmd.h \ - descendants_.c:descendants.h \ - diff_.c:diff.h \ - diffcmd_.c:diffcmd.h \ - dispatch_.c:dispatch.h \ - doc_.c:doc.h \ - encode_.c:encode.h \ - event_.c:event.h \ - export_.c:export.h \ - file_.c:file.h \ - finfo_.c:finfo.h \ - foci_.c:foci.h \ - fshell_.c:fshell.h \ - fusefs_.c:fusefs.h \ - glob_.c:glob.h \ - graph_.c:graph.h \ - gzip_.c:gzip.h \ - http_.c:http.h \ - http_socket_.c:http_socket.h \ - http_ssl_.c:http_ssl.h \ - http_transport_.c:http_transport.h \ - import_.c:import.h \ - info_.c:info.h \ - json_.c:json.h \ - json_artifact_.c:json_artifact.h \ - json_branch_.c:json_branch.h \ - json_config_.c:json_config.h \ - json_diff_.c:json_diff.h \ - json_dir_.c:json_dir.h \ - json_finfo_.c:json_finfo.h \ - json_login_.c:json_login.h \ - json_query_.c:json_query.h \ - json_report_.c:json_report.h \ - json_status_.c:json_status.h \ - json_tag_.c:json_tag.h \ - json_timeline_.c:json_timeline.h \ - json_user_.c:json_user.h \ - json_wiki_.c:json_wiki.h \ - leaf_.c:leaf.h \ - loadctrl_.c:loadctrl.h \ - login_.c:login.h \ - lookslike_.c:lookslike.h \ - main_.c:main.h \ - manifest_.c:manifest.h \ - markdown_.c:markdown.h \ - markdown_html_.c:markdown_html.h \ - md5_.c:md5.h \ - merge_.c:merge.h \ - merge3_.c:merge3.h \ - moderate_.c:moderate.h \ - name_.c:name.h \ - path_.c:path.h \ - piechart_.c:piechart.h \ - pivot_.c:pivot.h \ - popen_.c:popen.h \ - pqueue_.c:pqueue.h \ - printf_.c:printf.h \ - publish_.c:publish.h \ - purge_.c:purge.h \ - rebuild_.c:rebuild.h \ - regexp_.c:regexp.h \ - report_.c:report.h \ - rss_.c:rss.h \ - schema_.c:schema.h \ - search_.c:search.h \ - setup_.c:setup.h \ - sha1_.c:sha1.h \ - shun_.c:shun.h \ - sitemap_.c:sitemap.h \ - skins_.c:skins.h \ - sqlcmd_.c:sqlcmd.h \ - stash_.c:stash.h \ - stat_.c:stat.h \ - statrep_.c:statrep.h \ - style_.c:style.h \ - sync_.c:sync.h \ - tag_.c:tag.h \ - tar_.c:tar.h \ - th_main_.c:th_main.h \ - timeline_.c:timeline.h \ - tkt_.c:tkt.h \ - tktsetup_.c:tktsetup.h \ - undo_.c:undo.h \ - unicode_.c:unicode.h \ - unversioned_.c:unversioned.h \ - update_.c:update.h \ - url_.c:url.h \ - user_.c:user.h \ - utf8_.c:utf8.h \ - util_.c:util.h \ - verify_.c:verify.h \ - vfile_.c:vfile.h \ - wiki_.c:wiki.h \ - wikiformat_.c:wikiformat.h \ - winfile_.c:winfile.h \ - winhttp_.c:winhttp.h \ - wysiwyg_.c:wysiwyg.h \ - xfer_.c:xfer.h \ - xfersetup_.c:xfersetup.h \ - zip_.c:zip.h \ - $(SRCDIR)\sqlite3.h \ - $(SRCDIR)\th.h \ - VERSION.h \ - $(SRCDIR)\cson_amalgamation.h - @copy /Y nul: headers +"$(OX)\shell$O" : "$(SQLITE3_SHELL_SRC)" "$(B)\win\Makefile.msc" + $(TCC) /Fo$@ /Fd$(@D)\ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) $(SEE_FLAGS) -c "$(SQLITE3_SHELL_SRC)" + +"$(OX)\sqlite3$O" : "$(SQLITE3_SRC)" "$(B)\win\Makefile.msc" + $(TCC) /Fo$@ /Fd$(@D)\ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SEE_FLAGS) "$(SQLITE3_SRC)" + +"$(OX)\th$O" : "$(SRCDIR)\th.c" + $(TCC) /Fo$@ /Fd$(@D)\ -c $** + +"$(OX)\th_lang$O" : "$(SRCDIR)\th_lang.c" + $(TCC) /Fo$@ /Fd$(@D)\ -c $** + +"$(OX)\th_tcl$O" : "$(SRCDIR)\th_tcl.c" + $(TCC) /Fo$@ /Fd$(@D)\ -c $** + +"$(OX)\miniz$O" : "$(SRCDIR)\miniz.c" + $(TCC) /Fo$@ /Fd$(@D)\ -c $(MINIZ_OPTIONS) $** + +"$(OX)\VERSION.h" : "$(OBJDIR)\mkversion$E" "$(B)\manifest.uuid" "$(B)\manifest" "$(B)\VERSION" + $** > $@ + +"$(OX)\cson_amalgamation$O" : "$(SRCDIR)\cson_amalgamation.c" + $(TCC) /Fo$@ /Fd$(@D)\ -c $** + +"$(OX)\page_index.h": "$(OBJDIR)\mkindex$E" $(SRC) + $** > $@ + +"$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" + "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ + +cleanx: + -del "$(OX)\*.obj" 2>NUL + -del "$(OBJDIR)\*.obj" 2>NUL + -del "$(OX)\*_.c" 2>NUL + -del "$(OX)\*.h" 2>NUL + -del "$(OX)\*.ilk" 2>NUL + -del "$(OX)\*.map" 2>NUL + -del "$(OX)\*.res" 2>NUL + -del "$(OX)\*.reslist" 2>NUL + -del "$(OX)\headers" 2>NUL + -del "$(OX)\linkopts" 2>NUL + -del "$(OX)\vc*.pdb" 2>NUL + +clean: cleanx + -del "$(APPNAME)" 2>NUL + -del "$(PDBNAME)" 2>NUL + -del "$(OBJDIR)\translate$E" 2>NUL + -del "$(OBJDIR)\translate$P" 2>NUL + -del "$(OBJDIR)\mkindex$E" 2>NUL + -del "$(OBJDIR)\mkindex$P" 2>NUL + -del "$(OBJDIR)\makeheaders$E" 2>NUL + -del "$(OBJDIR)\makeheaders$P" 2>NUL + -del "$(OBJDIR)\mkversion$E" 2>NUL + -del "$(OBJDIR)\mkversion$P" 2>NUL + -del "$(OBJDIR)\mkcss$E" 2>NUL + -del "$(OBJDIR)\mkcss$P" 2>NUL + -del "$(OBJDIR)\codecheck1$E" 2>NUL + -del "$(OBJDIR)\codecheck1$P" 2>NUL + -del "$(OBJDIR)\mkbuiltin$E" 2>NUL + -del "$(OBJDIR)\mkbuiltin$P" 2>NUL + +realclean: clean + +"$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_branch$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_config$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_diff$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_dir$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_finfo$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_login$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_query$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_report$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_status$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_tag$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_timeline$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_user$O" : "$(SRCDIR)\json_detail.h" +"$(OBJDIR)\json_wiki$O" : "$(SRCDIR)\json_detail.h" + +"$(OX)\builtin_data.reslist": $(EXTRA_FILES) "$(B)\win\Makefile.msc" + echo "$(SRCDIR)\../skins/aht/details.txt" > $@ + echo "$(SRCDIR)\../skins/ardoise/css.txt" >> $@ + echo "$(SRCDIR)\../skins/ardoise/details.txt" >> $@ + echo "$(SRCDIR)\../skins/ardoise/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/ardoise/header.txt" >> $@ + echo "$(SRCDIR)\../skins/black_and_white/css.txt" >> $@ + echo "$(SRCDIR)\../skins/black_and_white/details.txt" >> $@ + echo "$(SRCDIR)\../skins/black_and_white/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/black_and_white/header.txt" >> $@ + echo "$(SRCDIR)\../skins/blitz/css.txt" >> $@ + echo "$(SRCDIR)\../skins/blitz/details.txt" >> $@ + echo "$(SRCDIR)\../skins/blitz/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/blitz/header.txt" >> $@ + echo "$(SRCDIR)\../skins/blitz/ticket.txt" >> $@ + echo "$(SRCDIR)\../skins/blitz_no_logo/css.txt" >> $@ + echo "$(SRCDIR)\../skins/blitz_no_logo/details.txt" >> $@ + echo "$(SRCDIR)\../skins/blitz_no_logo/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/blitz_no_logo/header.txt" >> $@ + echo "$(SRCDIR)\../skins/blitz_no_logo/ticket.txt" >> $@ + echo "$(SRCDIR)\../skins/bootstrap/css.txt" >> $@ + echo "$(SRCDIR)\../skins/bootstrap/details.txt" >> $@ + echo "$(SRCDIR)\../skins/bootstrap/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/bootstrap/header.txt" >> $@ + echo "$(SRCDIR)\../skins/default/css.txt" >> $@ + echo "$(SRCDIR)\../skins/default/details.txt" >> $@ + echo "$(SRCDIR)\../skins/default/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/default/header.txt" >> $@ + echo "$(SRCDIR)\../skins/default/js.txt" >> $@ + echo "$(SRCDIR)\../skins/eagle/css.txt" >> $@ + echo "$(SRCDIR)\../skins/eagle/details.txt" >> $@ + echo "$(SRCDIR)\../skins/eagle/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/eagle/header.txt" >> $@ + echo "$(SRCDIR)\../skins/enhanced1/css.txt" >> $@ + echo "$(SRCDIR)\../skins/enhanced1/details.txt" >> $@ + echo "$(SRCDIR)\../skins/enhanced1/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/enhanced1/header.txt" >> $@ + echo "$(SRCDIR)\../skins/khaki/css.txt" >> $@ + echo "$(SRCDIR)\../skins/khaki/details.txt" >> $@ + echo "$(SRCDIR)\../skins/khaki/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/khaki/header.txt" >> $@ + echo "$(SRCDIR)\../skins/original/css.txt" >> $@ + echo "$(SRCDIR)\../skins/original/details.txt" >> $@ + echo "$(SRCDIR)\../skins/original/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/original/header.txt" >> $@ + echo "$(SRCDIR)\../skins/plain_gray/css.txt" >> $@ + echo "$(SRCDIR)\../skins/plain_gray/details.txt" >> $@ + echo "$(SRCDIR)\../skins/plain_gray/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/plain_gray/header.txt" >> $@ + echo "$(SRCDIR)\../skins/rounded1/css.txt" >> $@ + echo "$(SRCDIR)\../skins/rounded1/details.txt" >> $@ + echo "$(SRCDIR)\../skins/rounded1/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/rounded1/header.txt" >> $@ + echo "$(SRCDIR)\../skins/xekri/css.txt" >> $@ + echo "$(SRCDIR)\../skins/xekri/details.txt" >> $@ + echo "$(SRCDIR)\../skins/xekri/footer.txt" >> $@ + echo "$(SRCDIR)\../skins/xekri/header.txt" >> $@ + echo "$(SRCDIR)\accordion.js" >> $@ + echo "$(SRCDIR)\ci_edit.js" >> $@ + echo "$(SRCDIR)\copybtn.js" >> $@ + echo "$(SRCDIR)\default.css" >> $@ + echo "$(SRCDIR)\diff.tcl" >> $@ + echo "$(SRCDIR)\forum.js" >> $@ + echo "$(SRCDIR)\fossil.bootstrap.js" >> $@ + echo "$(SRCDIR)\fossil.confirmer.js" >> $@ + echo "$(SRCDIR)\fossil.dom.js" >> $@ + echo "$(SRCDIR)\fossil.fetch.js" >> $@ + echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@ + echo "$(SRCDIR)\fossil.storage.js" >> $@ + echo "$(SRCDIR)\fossil.tabs.js" >> $@ + echo "$(SRCDIR)\graph.js" >> $@ + echo "$(SRCDIR)\href.js" >> $@ + echo "$(SRCDIR)\login.js" >> $@ + echo "$(SRCDIR)\markdown.md" >> $@ + echo "$(SRCDIR)\menu.js" >> $@ + echo "$(SRCDIR)\sbsdiff.js" >> $@ + echo "$(SRCDIR)\scroll.js" >> $@ + echo "$(SRCDIR)\skin.js" >> $@ + echo "$(SRCDIR)\sorttable.js" >> $@ + echo "$(SRCDIR)\sounds/0.wav" >> $@ + echo "$(SRCDIR)\sounds/1.wav" >> $@ + echo "$(SRCDIR)\sounds/2.wav" >> $@ + echo "$(SRCDIR)\sounds/3.wav" >> $@ + echo "$(SRCDIR)\sounds/4.wav" >> $@ + echo "$(SRCDIR)\sounds/5.wav" >> $@ + echo "$(SRCDIR)\sounds/6.wav" >> $@ + echo "$(SRCDIR)\sounds/7.wav" >> $@ + echo "$(SRCDIR)\sounds/8.wav" >> $@ + echo "$(SRCDIR)\sounds/9.wav" >> $@ + echo "$(SRCDIR)\sounds/a.wav" >> $@ + echo "$(SRCDIR)\sounds/b.wav" >> $@ + echo "$(SRCDIR)\sounds/c.wav" >> $@ + echo "$(SRCDIR)\sounds/d.wav" >> $@ + echo "$(SRCDIR)\sounds/e.wav" >> $@ + echo "$(SRCDIR)\sounds/f.wav" >> $@ + echo "$(SRCDIR)\style.admin_log.css" >> $@ + echo "$(SRCDIR)\style.fileedit.css" >> $@ + echo "$(SRCDIR)\tree.js" >> $@ + echo "$(SRCDIR)\useredit.js" >> $@ + echo "$(SRCDIR)\wiki.wiki" >> $@ + +"$(OX)\add$O" : "$(OX)\add_.c" "$(OX)\add.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\add_.c" + +"$(OX)\add_.c" : "$(SRCDIR)\add.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\ajax$O" : "$(OX)\ajax_.c" "$(OX)\ajax.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\ajax_.c" + +"$(OX)\ajax_.c" : "$(SRCDIR)\ajax.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\alerts$O" : "$(OX)\alerts_.c" "$(OX)\alerts.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\alerts_.c" + +"$(OX)\alerts_.c" : "$(SRCDIR)\alerts.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\allrepo$O" : "$(OX)\allrepo_.c" "$(OX)\allrepo.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\allrepo_.c" + +"$(OX)\allrepo_.c" : "$(SRCDIR)\allrepo.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\attach$O" : "$(OX)\attach_.c" "$(OX)\attach.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\attach_.c" + +"$(OX)\attach_.c" : "$(SRCDIR)\attach.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\backlink$O" : "$(OX)\backlink_.c" "$(OX)\backlink.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\backlink_.c" + +"$(OX)\backlink_.c" : "$(SRCDIR)\backlink.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\backoffice$O" : "$(OX)\backoffice_.c" "$(OX)\backoffice.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\backoffice_.c" + +"$(OX)\backoffice_.c" : "$(SRCDIR)\backoffice.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\bag$O" : "$(OX)\bag_.c" "$(OX)\bag.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\bag_.c" + +"$(OX)\bag_.c" : "$(SRCDIR)\bag.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\bisect$O" : "$(OX)\bisect_.c" "$(OX)\bisect.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\bisect_.c" + +"$(OX)\bisect_.c" : "$(SRCDIR)\bisect.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\blob$O" : "$(OX)\blob_.c" "$(OX)\blob.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\blob_.c" + +"$(OX)\blob_.c" : "$(SRCDIR)\blob.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\branch$O" : "$(OX)\branch_.c" "$(OX)\branch.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\branch_.c" + +"$(OX)\branch_.c" : "$(SRCDIR)\branch.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\browse$O" : "$(OX)\browse_.c" "$(OX)\browse.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\browse_.c" + +"$(OX)\browse_.c" : "$(SRCDIR)\browse.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\builtin$O" : "$(OX)\builtin_.c" "$(OX)\builtin.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\builtin_.c" + +"$(OX)\builtin_.c" : "$(SRCDIR)\builtin.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\bundle$O" : "$(OX)\bundle_.c" "$(OX)\bundle.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\bundle_.c" + +"$(OX)\bundle_.c" : "$(SRCDIR)\bundle.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\cache$O" : "$(OX)\cache_.c" "$(OX)\cache.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\cache_.c" + +"$(OX)\cache_.c" : "$(SRCDIR)\cache.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\capabilities$O" : "$(OX)\capabilities_.c" "$(OX)\capabilities.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\capabilities_.c" + +"$(OX)\capabilities_.c" : "$(SRCDIR)\capabilities.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\captcha$O" : "$(OX)\captcha_.c" "$(OX)\captcha.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\captcha_.c" + +"$(OX)\captcha_.c" : "$(SRCDIR)\captcha.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\cgi$O" : "$(OX)\cgi_.c" "$(OX)\cgi.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\cgi_.c" + +"$(OX)\cgi_.c" : "$(SRCDIR)\cgi.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\checkin$O" : "$(OX)\checkin_.c" "$(OX)\checkin.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\checkin_.c" + +"$(OX)\checkin_.c" : "$(SRCDIR)\checkin.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\checkout$O" : "$(OX)\checkout_.c" "$(OX)\checkout.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\checkout_.c" + +"$(OX)\checkout_.c" : "$(SRCDIR)\checkout.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\clearsign$O" : "$(OX)\clearsign_.c" "$(OX)\clearsign.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\clearsign_.c" + +"$(OX)\clearsign_.c" : "$(SRCDIR)\clearsign.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\clone$O" : "$(OX)\clone_.c" "$(OX)\clone.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\clone_.c" + +"$(OX)\clone_.c" : "$(SRCDIR)\clone.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\comformat$O" : "$(OX)\comformat_.c" "$(OX)\comformat.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\comformat_.c" + +"$(OX)\comformat_.c" : "$(SRCDIR)\comformat.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\configure$O" : "$(OX)\configure_.c" "$(OX)\configure.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\configure_.c" + +"$(OX)\configure_.c" : "$(SRCDIR)\configure.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\content$O" : "$(OX)\content_.c" "$(OX)\content.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\content_.c" + +"$(OX)\content_.c" : "$(SRCDIR)\content.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\cookies$O" : "$(OX)\cookies_.c" "$(OX)\cookies.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\cookies_.c" + +"$(OX)\cookies_.c" : "$(SRCDIR)\cookies.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\db$O" : "$(OX)\db_.c" "$(OX)\db.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\db_.c" + +"$(OX)\db_.c" : "$(SRCDIR)\db.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\delta$O" : "$(OX)\delta_.c" "$(OX)\delta.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\delta_.c" + +"$(OX)\delta_.c" : "$(SRCDIR)\delta.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\deltacmd$O" : "$(OX)\deltacmd_.c" "$(OX)\deltacmd.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\deltacmd_.c" + +"$(OX)\deltacmd_.c" : "$(SRCDIR)\deltacmd.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\deltafunc$O" : "$(OX)\deltafunc_.c" "$(OX)\deltafunc.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\deltafunc_.c" + +"$(OX)\deltafunc_.c" : "$(SRCDIR)\deltafunc.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\descendants$O" : "$(OX)\descendants_.c" "$(OX)\descendants.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\descendants_.c" + +"$(OX)\descendants_.c" : "$(SRCDIR)\descendants.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\diff$O" : "$(OX)\diff_.c" "$(OX)\diff.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\diff_.c" + +"$(OX)\diff_.c" : "$(SRCDIR)\diff.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\diffcmd$O" : "$(OX)\diffcmd_.c" "$(OX)\diffcmd.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\diffcmd_.c" + +"$(OX)\diffcmd_.c" : "$(SRCDIR)\diffcmd.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\dispatch$O" : "$(OX)\dispatch_.c" "$(OX)\dispatch.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\dispatch_.c" + +"$(OX)\dispatch_.c" : "$(SRCDIR)\dispatch.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\doc$O" : "$(OX)\doc_.c" "$(OX)\doc.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\doc_.c" + +"$(OX)\doc_.c" : "$(SRCDIR)\doc.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\encode$O" : "$(OX)\encode_.c" "$(OX)\encode.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\encode_.c" + +"$(OX)\encode_.c" : "$(SRCDIR)\encode.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\etag$O" : "$(OX)\etag_.c" "$(OX)\etag.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\etag_.c" + +"$(OX)\etag_.c" : "$(SRCDIR)\etag.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\event$O" : "$(OX)\event_.c" "$(OX)\event.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\event_.c" + +"$(OX)\event_.c" : "$(SRCDIR)\event.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\export$O" : "$(OX)\export_.c" "$(OX)\export.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\export_.c" + +"$(OX)\export_.c" : "$(SRCDIR)\export.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\extcgi$O" : "$(OX)\extcgi_.c" "$(OX)\extcgi.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\extcgi_.c" + +"$(OX)\extcgi_.c" : "$(SRCDIR)\extcgi.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\file$O" : "$(OX)\file_.c" "$(OX)\file.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\file_.c" + +"$(OX)\file_.c" : "$(SRCDIR)\file.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\fileedit$O" : "$(OX)\fileedit_.c" "$(OX)\fileedit.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\fileedit_.c" + +"$(OX)\fileedit_.c" : "$(SRCDIR)\fileedit.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\finfo$O" : "$(OX)\finfo_.c" "$(OX)\finfo.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\finfo_.c" + +"$(OX)\finfo_.c" : "$(SRCDIR)\finfo.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\foci$O" : "$(OX)\foci_.c" "$(OX)\foci.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\foci_.c" + +"$(OX)\foci_.c" : "$(SRCDIR)\foci.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\forum$O" : "$(OX)\forum_.c" "$(OX)\forum.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\forum_.c" + +"$(OX)\forum_.c" : "$(SRCDIR)\forum.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\fshell$O" : "$(OX)\fshell_.c" "$(OX)\fshell.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\fshell_.c" + +"$(OX)\fshell_.c" : "$(SRCDIR)\fshell.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\fusefs$O" : "$(OX)\fusefs_.c" "$(OX)\fusefs.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\fusefs_.c" + +"$(OX)\fusefs_.c" : "$(SRCDIR)\fusefs.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\fuzz$O" : "$(OX)\fuzz_.c" "$(OX)\fuzz.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\fuzz_.c" + +"$(OX)\fuzz_.c" : "$(SRCDIR)\fuzz.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\glob$O" : "$(OX)\glob_.c" "$(OX)\glob.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\glob_.c" + +"$(OX)\glob_.c" : "$(SRCDIR)\glob.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\graph$O" : "$(OX)\graph_.c" "$(OX)\graph.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\graph_.c" + +"$(OX)\graph_.c" : "$(SRCDIR)\graph.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\gzip$O" : "$(OX)\gzip_.c" "$(OX)\gzip.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\gzip_.c" + +"$(OX)\gzip_.c" : "$(SRCDIR)\gzip.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\hname$O" : "$(OX)\hname_.c" "$(OX)\hname.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\hname_.c" + +"$(OX)\hname_.c" : "$(SRCDIR)\hname.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\http$O" : "$(OX)\http_.c" "$(OX)\http.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\http_.c" + +"$(OX)\http_.c" : "$(SRCDIR)\http.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\http_socket$O" : "$(OX)\http_socket_.c" "$(OX)\http_socket.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\http_socket_.c" + +"$(OX)\http_socket_.c" : "$(SRCDIR)\http_socket.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\http_ssl$O" : "$(OX)\http_ssl_.c" "$(OX)\http_ssl.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\http_ssl_.c" + +"$(OX)\http_ssl_.c" : "$(SRCDIR)\http_ssl.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\http_transport$O" : "$(OX)\http_transport_.c" "$(OX)\http_transport.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\http_transport_.c" + +"$(OX)\http_transport_.c" : "$(SRCDIR)\http_transport.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\import$O" : "$(OX)\import_.c" "$(OX)\import.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\import_.c" + +"$(OX)\import_.c" : "$(SRCDIR)\import.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\info$O" : "$(OX)\info_.c" "$(OX)\info.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\info_.c" + +"$(OX)\info_.c" : "$(SRCDIR)\info.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json$O" : "$(OX)\json_.c" "$(OX)\json.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_.c" + +"$(OX)\json_.c" : "$(SRCDIR)\json.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_artifact$O" : "$(OX)\json_artifact_.c" "$(OX)\json_artifact.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_artifact_.c" + +"$(OX)\json_artifact_.c" : "$(SRCDIR)\json_artifact.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_branch$O" : "$(OX)\json_branch_.c" "$(OX)\json_branch.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_branch_.c" + +"$(OX)\json_branch_.c" : "$(SRCDIR)\json_branch.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_config$O" : "$(OX)\json_config_.c" "$(OX)\json_config.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_config_.c" + +"$(OX)\json_config_.c" : "$(SRCDIR)\json_config.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_diff$O" : "$(OX)\json_diff_.c" "$(OX)\json_diff.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_diff_.c" + +"$(OX)\json_diff_.c" : "$(SRCDIR)\json_diff.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_dir$O" : "$(OX)\json_dir_.c" "$(OX)\json_dir.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_dir_.c" + +"$(OX)\json_dir_.c" : "$(SRCDIR)\json_dir.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_finfo$O" : "$(OX)\json_finfo_.c" "$(OX)\json_finfo.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_finfo_.c" + +"$(OX)\json_finfo_.c" : "$(SRCDIR)\json_finfo.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_login$O" : "$(OX)\json_login_.c" "$(OX)\json_login.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_login_.c" + +"$(OX)\json_login_.c" : "$(SRCDIR)\json_login.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_query$O" : "$(OX)\json_query_.c" "$(OX)\json_query.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_query_.c" + +"$(OX)\json_query_.c" : "$(SRCDIR)\json_query.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_report$O" : "$(OX)\json_report_.c" "$(OX)\json_report.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_report_.c" + +"$(OX)\json_report_.c" : "$(SRCDIR)\json_report.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_status$O" : "$(OX)\json_status_.c" "$(OX)\json_status.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_status_.c" + +"$(OX)\json_status_.c" : "$(SRCDIR)\json_status.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_tag$O" : "$(OX)\json_tag_.c" "$(OX)\json_tag.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_tag_.c" + +"$(OX)\json_tag_.c" : "$(SRCDIR)\json_tag.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_timeline$O" : "$(OX)\json_timeline_.c" "$(OX)\json_timeline.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_timeline_.c" + +"$(OX)\json_timeline_.c" : "$(SRCDIR)\json_timeline.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_user$O" : "$(OX)\json_user_.c" "$(OX)\json_user.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_user_.c" + +"$(OX)\json_user_.c" : "$(SRCDIR)\json_user.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\json_wiki$O" : "$(OX)\json_wiki_.c" "$(OX)\json_wiki.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\json_wiki_.c" + +"$(OX)\json_wiki_.c" : "$(SRCDIR)\json_wiki.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\leaf$O" : "$(OX)\leaf_.c" "$(OX)\leaf.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\leaf_.c" + +"$(OX)\leaf_.c" : "$(SRCDIR)\leaf.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\loadctrl$O" : "$(OX)\loadctrl_.c" "$(OX)\loadctrl.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\loadctrl_.c" + +"$(OX)\loadctrl_.c" : "$(SRCDIR)\loadctrl.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\login$O" : "$(OX)\login_.c" "$(OX)\login.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\login_.c" + +"$(OX)\login_.c" : "$(SRCDIR)\login.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\lookslike$O" : "$(OX)\lookslike_.c" "$(OX)\lookslike.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\lookslike_.c" + +"$(OX)\lookslike_.c" : "$(SRCDIR)\lookslike.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\main$O" : "$(OX)\main_.c" "$(OX)\main.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\main_.c" + +"$(OX)\main_.c" : "$(SRCDIR)\main.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\manifest$O" : "$(OX)\manifest_.c" "$(OX)\manifest.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\manifest_.c" + +"$(OX)\manifest_.c" : "$(SRCDIR)\manifest.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\markdown$O" : "$(OX)\markdown_.c" "$(OX)\markdown.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\markdown_.c" + +"$(OX)\markdown_.c" : "$(SRCDIR)\markdown.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\markdown_html$O" : "$(OX)\markdown_html_.c" "$(OX)\markdown_html.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\markdown_html_.c" + +"$(OX)\markdown_html_.c" : "$(SRCDIR)\markdown_html.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\md5$O" : "$(OX)\md5_.c" "$(OX)\md5.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\md5_.c" + +"$(OX)\md5_.c" : "$(SRCDIR)\md5.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\merge$O" : "$(OX)\merge_.c" "$(OX)\merge.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\merge_.c" + +"$(OX)\merge_.c" : "$(SRCDIR)\merge.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\merge3$O" : "$(OX)\merge3_.c" "$(OX)\merge3.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\merge3_.c" + +"$(OX)\merge3_.c" : "$(SRCDIR)\merge3.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\moderate$O" : "$(OX)\moderate_.c" "$(OX)\moderate.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\moderate_.c" + +"$(OX)\moderate_.c" : "$(SRCDIR)\moderate.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\name$O" : "$(OX)\name_.c" "$(OX)\name.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\name_.c" + +"$(OX)\name_.c" : "$(SRCDIR)\name.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\path$O" : "$(OX)\path_.c" "$(OX)\path.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\path_.c" + +"$(OX)\path_.c" : "$(SRCDIR)\path.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\piechart$O" : "$(OX)\piechart_.c" "$(OX)\piechart.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\piechart_.c" + +"$(OX)\piechart_.c" : "$(SRCDIR)\piechart.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\pivot$O" : "$(OX)\pivot_.c" "$(OX)\pivot.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\pivot_.c" + +"$(OX)\pivot_.c" : "$(SRCDIR)\pivot.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\popen$O" : "$(OX)\popen_.c" "$(OX)\popen.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\popen_.c" + +"$(OX)\popen_.c" : "$(SRCDIR)\popen.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\pqueue$O" : "$(OX)\pqueue_.c" "$(OX)\pqueue.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\pqueue_.c" + +"$(OX)\pqueue_.c" : "$(SRCDIR)\pqueue.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\printf$O" : "$(OX)\printf_.c" "$(OX)\printf.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\printf_.c" + +"$(OX)\printf_.c" : "$(SRCDIR)\printf.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\publish$O" : "$(OX)\publish_.c" "$(OX)\publish.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\publish_.c" + +"$(OX)\publish_.c" : "$(SRCDIR)\publish.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\purge$O" : "$(OX)\purge_.c" "$(OX)\purge.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\purge_.c" + +"$(OX)\purge_.c" : "$(SRCDIR)\purge.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\rebuild$O" : "$(OX)\rebuild_.c" "$(OX)\rebuild.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\rebuild_.c" + +"$(OX)\rebuild_.c" : "$(SRCDIR)\rebuild.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\regexp$O" : "$(OX)\regexp_.c" "$(OX)\regexp.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\regexp_.c" + +"$(OX)\regexp_.c" : "$(SRCDIR)\regexp.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\repolist$O" : "$(OX)\repolist_.c" "$(OX)\repolist.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\repolist_.c" + +"$(OX)\repolist_.c" : "$(SRCDIR)\repolist.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\report$O" : "$(OX)\report_.c" "$(OX)\report.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\report_.c" + +"$(OX)\report_.c" : "$(SRCDIR)\report.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\rss$O" : "$(OX)\rss_.c" "$(OX)\rss.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\rss_.c" + +"$(OX)\rss_.c" : "$(SRCDIR)\rss.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\schema$O" : "$(OX)\schema_.c" "$(OX)\schema.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\schema_.c" + +"$(OX)\schema_.c" : "$(SRCDIR)\schema.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\search$O" : "$(OX)\search_.c" "$(OX)\search.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\search_.c" + +"$(OX)\search_.c" : "$(SRCDIR)\search.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\security_audit$O" : "$(OX)\security_audit_.c" "$(OX)\security_audit.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\security_audit_.c" + +"$(OX)\security_audit_.c" : "$(SRCDIR)\security_audit.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\setup$O" : "$(OX)\setup_.c" "$(OX)\setup.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\setup_.c" + +"$(OX)\setup_.c" : "$(SRCDIR)\setup.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\setupuser$O" : "$(OX)\setupuser_.c" "$(OX)\setupuser.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\setupuser_.c" + +"$(OX)\setupuser_.c" : "$(SRCDIR)\setupuser.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\sha1$O" : "$(OX)\sha1_.c" "$(OX)\sha1.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\sha1_.c" + +"$(OX)\sha1_.c" : "$(SRCDIR)\sha1.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\sha1hard$O" : "$(OX)\sha1hard_.c" "$(OX)\sha1hard.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\sha1hard_.c" + +"$(OX)\sha1hard_.c" : "$(SRCDIR)\sha1hard.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\sha3$O" : "$(OX)\sha3_.c" "$(OX)\sha3.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\sha3_.c" + +"$(OX)\sha3_.c" : "$(SRCDIR)\sha3.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\shun$O" : "$(OX)\shun_.c" "$(OX)\shun.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\shun_.c" + +"$(OX)\shun_.c" : "$(SRCDIR)\shun.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\sitemap$O" : "$(OX)\sitemap_.c" "$(OX)\sitemap.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\sitemap_.c" + +"$(OX)\sitemap_.c" : "$(SRCDIR)\sitemap.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\skins$O" : "$(OX)\skins_.c" "$(OX)\skins.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\skins_.c" + +"$(OX)\skins_.c" : "$(SRCDIR)\skins.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\smtp$O" : "$(OX)\smtp_.c" "$(OX)\smtp.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\smtp_.c" + +"$(OX)\smtp_.c" : "$(SRCDIR)\smtp.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\sqlcmd$O" : "$(OX)\sqlcmd_.c" "$(OX)\sqlcmd.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\sqlcmd_.c" + +"$(OX)\sqlcmd_.c" : "$(SRCDIR)\sqlcmd.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\stash$O" : "$(OX)\stash_.c" "$(OX)\stash.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\stash_.c" + +"$(OX)\stash_.c" : "$(SRCDIR)\stash.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\stat$O" : "$(OX)\stat_.c" "$(OX)\stat.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\stat_.c" + +"$(OX)\stat_.c" : "$(SRCDIR)\stat.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\statrep$O" : "$(OX)\statrep_.c" "$(OX)\statrep.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\statrep_.c" + +"$(OX)\statrep_.c" : "$(SRCDIR)\statrep.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\style$O" : "$(OX)\style_.c" "$(OX)\style.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\style_.c" + +"$(OX)\style_.c" : "$(SRCDIR)\style.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\sync$O" : "$(OX)\sync_.c" "$(OX)\sync.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\sync_.c" + +"$(OX)\sync_.c" : "$(SRCDIR)\sync.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\tag$O" : "$(OX)\tag_.c" "$(OX)\tag.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\tag_.c" + +"$(OX)\tag_.c" : "$(SRCDIR)\tag.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\tar$O" : "$(OX)\tar_.c" "$(OX)\tar.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\tar_.c" + +"$(OX)\tar_.c" : "$(SRCDIR)\tar.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\terminal$O" : "$(OX)\terminal_.c" "$(OX)\terminal.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\terminal_.c" + +"$(OX)\terminal_.c" : "$(SRCDIR)\terminal.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\th_main$O" : "$(OX)\th_main_.c" "$(OX)\th_main.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\th_main_.c" + +"$(OX)\th_main_.c" : "$(SRCDIR)\th_main.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\timeline$O" : "$(OX)\timeline_.c" "$(OX)\timeline.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\timeline_.c" + +"$(OX)\timeline_.c" : "$(SRCDIR)\timeline.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\tkt$O" : "$(OX)\tkt_.c" "$(OX)\tkt.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\tkt_.c" + +"$(OX)\tkt_.c" : "$(SRCDIR)\tkt.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\tktsetup$O" : "$(OX)\tktsetup_.c" "$(OX)\tktsetup.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\tktsetup_.c" + +"$(OX)\tktsetup_.c" : "$(SRCDIR)\tktsetup.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\undo$O" : "$(OX)\undo_.c" "$(OX)\undo.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\undo_.c" + +"$(OX)\undo_.c" : "$(SRCDIR)\undo.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\unicode$O" : "$(OX)\unicode_.c" "$(OX)\unicode.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\unicode_.c" + +"$(OX)\unicode_.c" : "$(SRCDIR)\unicode.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\unversioned$O" : "$(OX)\unversioned_.c" "$(OX)\unversioned.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\unversioned_.c" + +"$(OX)\unversioned_.c" : "$(SRCDIR)\unversioned.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\update$O" : "$(OX)\update_.c" "$(OX)\update.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\update_.c" + +"$(OX)\update_.c" : "$(SRCDIR)\update.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\url$O" : "$(OX)\url_.c" "$(OX)\url.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\url_.c" + +"$(OX)\url_.c" : "$(SRCDIR)\url.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\user$O" : "$(OX)\user_.c" "$(OX)\user.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\user_.c" + +"$(OX)\user_.c" : "$(SRCDIR)\user.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\utf8$O" : "$(OX)\utf8_.c" "$(OX)\utf8.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\utf8_.c" + +"$(OX)\utf8_.c" : "$(SRCDIR)\utf8.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\util$O" : "$(OX)\util_.c" "$(OX)\util.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\util_.c" + +"$(OX)\util_.c" : "$(SRCDIR)\util.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\verify$O" : "$(OX)\verify_.c" "$(OX)\verify.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\verify_.c" + +"$(OX)\verify_.c" : "$(SRCDIR)\verify.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\vfile$O" : "$(OX)\vfile_.c" "$(OX)\vfile.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\vfile_.c" + +"$(OX)\vfile_.c" : "$(SRCDIR)\vfile.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\webmail$O" : "$(OX)\webmail_.c" "$(OX)\webmail.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\webmail_.c" + +"$(OX)\webmail_.c" : "$(SRCDIR)\webmail.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\wiki$O" : "$(OX)\wiki_.c" "$(OX)\wiki.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\wiki_.c" + +"$(OX)\wiki_.c" : "$(SRCDIR)\wiki.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\wikiformat$O" : "$(OX)\wikiformat_.c" "$(OX)\wikiformat.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\wikiformat_.c" + +"$(OX)\wikiformat_.c" : "$(SRCDIR)\wikiformat.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\winfile$O" : "$(OX)\winfile_.c" "$(OX)\winfile.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\winfile_.c" + +"$(OX)\winfile_.c" : "$(SRCDIR)\winfile.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\winhttp$O" : "$(OX)\winhttp_.c" "$(OX)\winhttp.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\winhttp_.c" + +"$(OX)\winhttp_.c" : "$(SRCDIR)\winhttp.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\wysiwyg$O" : "$(OX)\wysiwyg_.c" "$(OX)\wysiwyg.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\wysiwyg_.c" + +"$(OX)\wysiwyg_.c" : "$(SRCDIR)\wysiwyg.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\xfer$O" : "$(OX)\xfer_.c" "$(OX)\xfer.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\xfer_.c" + +"$(OX)\xfer_.c" : "$(SRCDIR)\xfer.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\xfersetup$O" : "$(OX)\xfersetup_.c" "$(OX)\xfersetup.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\xfersetup_.c" + +"$(OX)\xfersetup_.c" : "$(SRCDIR)\xfersetup.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\zip$O" : "$(OX)\zip_.c" "$(OX)\zip.h" + $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\zip_.c" + +"$(OX)\zip_.c" : "$(SRCDIR)\zip.c" + "$(OBJDIR)\translate$E" $** > $@ + +"$(OX)\fossil.res" : "$(B)\win\fossil.rc" + $(RCC) /fo $@ $** + +"$(OX)\headers": "$(OBJDIR)\makeheaders$E" "$(OX)\page_index.h" "$(OX)\builtin_data.h" "$(OX)\VERSION.h" + "$(OBJDIR)\makeheaders$E" "$(OX)\add_.c":"$(OX)\add.h" \ + "$(OX)\ajax_.c":"$(OX)\ajax.h" \ + "$(OX)\alerts_.c":"$(OX)\alerts.h" \ + "$(OX)\allrepo_.c":"$(OX)\allrepo.h" \ + "$(OX)\attach_.c":"$(OX)\attach.h" \ + "$(OX)\backlink_.c":"$(OX)\backlink.h" \ + "$(OX)\backoffice_.c":"$(OX)\backoffice.h" \ + "$(OX)\bag_.c":"$(OX)\bag.h" \ + "$(OX)\bisect_.c":"$(OX)\bisect.h" \ + "$(OX)\blob_.c":"$(OX)\blob.h" \ + "$(OX)\branch_.c":"$(OX)\branch.h" \ + "$(OX)\browse_.c":"$(OX)\browse.h" \ + "$(OX)\builtin_.c":"$(OX)\builtin.h" \ + "$(OX)\bundle_.c":"$(OX)\bundle.h" \ + "$(OX)\cache_.c":"$(OX)\cache.h" \ + "$(OX)\capabilities_.c":"$(OX)\capabilities.h" \ + "$(OX)\captcha_.c":"$(OX)\captcha.h" \ + "$(OX)\cgi_.c":"$(OX)\cgi.h" \ + "$(OX)\checkin_.c":"$(OX)\checkin.h" \ + "$(OX)\checkout_.c":"$(OX)\checkout.h" \ + "$(OX)\clearsign_.c":"$(OX)\clearsign.h" \ + "$(OX)\clone_.c":"$(OX)\clone.h" \ + "$(OX)\comformat_.c":"$(OX)\comformat.h" \ + "$(OX)\configure_.c":"$(OX)\configure.h" \ + "$(OX)\content_.c":"$(OX)\content.h" \ + "$(OX)\cookies_.c":"$(OX)\cookies.h" \ + "$(OX)\db_.c":"$(OX)\db.h" \ + "$(OX)\delta_.c":"$(OX)\delta.h" \ + "$(OX)\deltacmd_.c":"$(OX)\deltacmd.h" \ + "$(OX)\deltafunc_.c":"$(OX)\deltafunc.h" \ + "$(OX)\descendants_.c":"$(OX)\descendants.h" \ + "$(OX)\diff_.c":"$(OX)\diff.h" \ + "$(OX)\diffcmd_.c":"$(OX)\diffcmd.h" \ + "$(OX)\dispatch_.c":"$(OX)\dispatch.h" \ + "$(OX)\doc_.c":"$(OX)\doc.h" \ + "$(OX)\encode_.c":"$(OX)\encode.h" \ + "$(OX)\etag_.c":"$(OX)\etag.h" \ + "$(OX)\event_.c":"$(OX)\event.h" \ + "$(OX)\export_.c":"$(OX)\export.h" \ + "$(OX)\extcgi_.c":"$(OX)\extcgi.h" \ + "$(OX)\file_.c":"$(OX)\file.h" \ + "$(OX)\fileedit_.c":"$(OX)\fileedit.h" \ + "$(OX)\finfo_.c":"$(OX)\finfo.h" \ + "$(OX)\foci_.c":"$(OX)\foci.h" \ + "$(OX)\forum_.c":"$(OX)\forum.h" \ + "$(OX)\fshell_.c":"$(OX)\fshell.h" \ + "$(OX)\fusefs_.c":"$(OX)\fusefs.h" \ + "$(OX)\fuzz_.c":"$(OX)\fuzz.h" \ + "$(OX)\glob_.c":"$(OX)\glob.h" \ + "$(OX)\graph_.c":"$(OX)\graph.h" \ + "$(OX)\gzip_.c":"$(OX)\gzip.h" \ + "$(OX)\hname_.c":"$(OX)\hname.h" \ + "$(OX)\http_.c":"$(OX)\http.h" \ + "$(OX)\http_socket_.c":"$(OX)\http_socket.h" \ + "$(OX)\http_ssl_.c":"$(OX)\http_ssl.h" \ + "$(OX)\http_transport_.c":"$(OX)\http_transport.h" \ + "$(OX)\import_.c":"$(OX)\import.h" \ + "$(OX)\info_.c":"$(OX)\info.h" \ + "$(OX)\json_.c":"$(OX)\json.h" \ + "$(OX)\json_artifact_.c":"$(OX)\json_artifact.h" \ + "$(OX)\json_branch_.c":"$(OX)\json_branch.h" \ + "$(OX)\json_config_.c":"$(OX)\json_config.h" \ + "$(OX)\json_diff_.c":"$(OX)\json_diff.h" \ + "$(OX)\json_dir_.c":"$(OX)\json_dir.h" \ + "$(OX)\json_finfo_.c":"$(OX)\json_finfo.h" \ + "$(OX)\json_login_.c":"$(OX)\json_login.h" \ + "$(OX)\json_query_.c":"$(OX)\json_query.h" \ + "$(OX)\json_report_.c":"$(OX)\json_report.h" \ + "$(OX)\json_status_.c":"$(OX)\json_status.h" \ + "$(OX)\json_tag_.c":"$(OX)\json_tag.h" \ + "$(OX)\json_timeline_.c":"$(OX)\json_timeline.h" \ + "$(OX)\json_user_.c":"$(OX)\json_user.h" \ + "$(OX)\json_wiki_.c":"$(OX)\json_wiki.h" \ + "$(OX)\leaf_.c":"$(OX)\leaf.h" \ + "$(OX)\loadctrl_.c":"$(OX)\loadctrl.h" \ + "$(OX)\login_.c":"$(OX)\login.h" \ + "$(OX)\lookslike_.c":"$(OX)\lookslike.h" \ + "$(OX)\main_.c":"$(OX)\main.h" \ + "$(OX)\manifest_.c":"$(OX)\manifest.h" \ + "$(OX)\markdown_.c":"$(OX)\markdown.h" \ + "$(OX)\markdown_html_.c":"$(OX)\markdown_html.h" \ + "$(OX)\md5_.c":"$(OX)\md5.h" \ + "$(OX)\merge_.c":"$(OX)\merge.h" \ + "$(OX)\merge3_.c":"$(OX)\merge3.h" \ + "$(OX)\moderate_.c":"$(OX)\moderate.h" \ + "$(OX)\name_.c":"$(OX)\name.h" \ + "$(OX)\path_.c":"$(OX)\path.h" \ + "$(OX)\piechart_.c":"$(OX)\piechart.h" \ + "$(OX)\pivot_.c":"$(OX)\pivot.h" \ + "$(OX)\popen_.c":"$(OX)\popen.h" \ + "$(OX)\pqueue_.c":"$(OX)\pqueue.h" \ + "$(OX)\printf_.c":"$(OX)\printf.h" \ + "$(OX)\publish_.c":"$(OX)\publish.h" \ + "$(OX)\purge_.c":"$(OX)\purge.h" \ + "$(OX)\rebuild_.c":"$(OX)\rebuild.h" \ + "$(OX)\regexp_.c":"$(OX)\regexp.h" \ + "$(OX)\repolist_.c":"$(OX)\repolist.h" \ + "$(OX)\report_.c":"$(OX)\report.h" \ + "$(OX)\rss_.c":"$(OX)\rss.h" \ + "$(OX)\schema_.c":"$(OX)\schema.h" \ + "$(OX)\search_.c":"$(OX)\search.h" \ + "$(OX)\security_audit_.c":"$(OX)\security_audit.h" \ + "$(OX)\setup_.c":"$(OX)\setup.h" \ + "$(OX)\setupuser_.c":"$(OX)\setupuser.h" \ + "$(OX)\sha1_.c":"$(OX)\sha1.h" \ + "$(OX)\sha1hard_.c":"$(OX)\sha1hard.h" \ + "$(OX)\sha3_.c":"$(OX)\sha3.h" \ + "$(OX)\shun_.c":"$(OX)\shun.h" \ + "$(OX)\sitemap_.c":"$(OX)\sitemap.h" \ + "$(OX)\skins_.c":"$(OX)\skins.h" \ + "$(OX)\smtp_.c":"$(OX)\smtp.h" \ + "$(OX)\sqlcmd_.c":"$(OX)\sqlcmd.h" \ + "$(OX)\stash_.c":"$(OX)\stash.h" \ + "$(OX)\stat_.c":"$(OX)\stat.h" \ + "$(OX)\statrep_.c":"$(OX)\statrep.h" \ + "$(OX)\style_.c":"$(OX)\style.h" \ + "$(OX)\sync_.c":"$(OX)\sync.h" \ + "$(OX)\tag_.c":"$(OX)\tag.h" \ + "$(OX)\tar_.c":"$(OX)\tar.h" \ + "$(OX)\terminal_.c":"$(OX)\terminal.h" \ + "$(OX)\th_main_.c":"$(OX)\th_main.h" \ + "$(OX)\timeline_.c":"$(OX)\timeline.h" \ + "$(OX)\tkt_.c":"$(OX)\tkt.h" \ + "$(OX)\tktsetup_.c":"$(OX)\tktsetup.h" \ + "$(OX)\undo_.c":"$(OX)\undo.h" \ + "$(OX)\unicode_.c":"$(OX)\unicode.h" \ + "$(OX)\unversioned_.c":"$(OX)\unversioned.h" \ + "$(OX)\update_.c":"$(OX)\update.h" \ + "$(OX)\url_.c":"$(OX)\url.h" \ + "$(OX)\user_.c":"$(OX)\user.h" \ + "$(OX)\utf8_.c":"$(OX)\utf8.h" \ + "$(OX)\util_.c":"$(OX)\util.h" \ + "$(OX)\verify_.c":"$(OX)\verify.h" \ + "$(OX)\vfile_.c":"$(OX)\vfile.h" \ + "$(OX)\webmail_.c":"$(OX)\webmail.h" \ + "$(OX)\wiki_.c":"$(OX)\wiki.h" \ + "$(OX)\wikiformat_.c":"$(OX)\wikiformat.h" \ + "$(OX)\winfile_.c":"$(OX)\winfile.h" \ + "$(OX)\winhttp_.c":"$(OX)\winhttp.h" \ + "$(OX)\wysiwyg_.c":"$(OX)\wysiwyg.h" \ + "$(OX)\xfer_.c":"$(OX)\xfer.h" \ + "$(OX)\xfersetup_.c":"$(OX)\xfersetup.h" \ + "$(OX)\zip_.c":"$(OX)\zip.h" \ + "$(SRCDIR)\sqlite3.h" \ + "$(SRCDIR)\th.h" \ + "$(OX)\VERSION.h" \ + "$(SRCDIR)\cson_amalgamation.h" + @copy /Y nul: $@ Index: win/buildmsvc.bat ================================================================== --- win/buildmsvc.bat +++ win/buildmsvc.bat @@ -183,29 +183,55 @@ %_VECHO% VcInstallDir = '%VCINSTALLDIR%' REM REM NOTE: Attempt to create the build output directory, if necessary. REM -IF NOT EXIST "%ROOT%\msvcbld" ( - %__ECHO% MKDIR "%ROOT%\msvcbld" +IF DEFINED BUILDDIR ( + IF DEFINED BUILDSUFFIX ( + CALL :fn_FindVarInVar BUILDSUFFIX BUILDDIR + + IF ERRORLEVEL 1 ( + REM + REM NOTE: The build suffix is already present, do nothing. + REM + ) ELSE ( + REM + REM NOTE: The build suffix is not present, add it now. + REM + SET BUILDDIR=%BUILDDIR%%BUILDSUFFIX% + ) + + CALL :fn_ResetErrorLevel + ) +) ELSE ( + SET BUILDDIR=%ROOT%\msvcbld%BUILDSUFFIX% +) + +%_VECHO% BuildSuffix = '%BUILDSUFFIX%' +%_VECHO% BuildDir = '%BUILDDIR%' + +IF NOT EXIST "%BUILDDIR%" ( + %__ECHO% MKDIR "%BUILDDIR%" IF ERRORLEVEL 1 ( - ECHO Could not make directory "%ROOT%\msvcbld". + ECHO Could not make directory "%BUILDDIR%". GOTO errors ) ) REM REM NOTE: Attempt to change to the created build output directory so that -REM the generated files will be placed there. +REM the generated files will be placed there, if needed. REM -%__ECHO2% PUSHD "%ROOT%\msvcbld" +%__ECHO2% PUSHD "%BUILDDIR%" IF ERRORLEVEL 1 ( - ECHO Could not change to directory "%ROOT%\msvcbld". + ECHO Could not change to directory "%BUILDDIR%". GOTO errors ) + +SET NEED_POPD=1 REM REM NOTE: If requested, setup the build environment to refer to the Windows REM SDK v7.1A, which is required if the binaries are being built with REM Visual Studio 201x and need to work on Windows XP. @@ -216,30 +242,38 @@ ) %_VECHO% Path = '%PATH%' %_VECHO% Include = '%INCLUDE%' %_VECHO% Lib = '%LIB%' +%_VECHO% Tools = '%TOOLS%' +%_VECHO% Root = '%ROOT%' %_VECHO% NmakeArgs = '%NMAKE_ARGS%' REM REM NOTE: Attempt to execute NMAKE for the Fossil MSVC makefile, passing REM anything extra from our command line along (e.g. extra options). +REM Also, pass the base directory of the Fossil source tree as this +REM allows an out-of-source-tree build. REM -%__ECHO% nmake /f "%TOOLS%\Makefile.msc" %NMAKE_ARGS% %* +%__ECHO% nmake /f "%TOOLS%\Makefile.msc" B="%ROOT%" %NMAKE_ARGS% %* IF ERRORLEVEL 1 ( GOTO errors ) REM -REM NOTE: Attempt to restore the previously saved directory. +REM NOTE: Attempt to restore the previously saved directory, if needed. REM -%__ECHO2% POPD +IF DEFINED NEED_POPD ( + %__ECHO2% POPD + + IF ERRORLEVEL 1 ( + ECHO Could not restore directory. + GOTO errors + ) -IF ERRORLEVEL 1 ( - ECHO Could not restore directory. - GOTO errors + CALL :fn_UnsetVariable NEED_POPD ) GOTO no_errors :fn_UseV110Sdk71A @@ -249,18 +283,36 @@ :set_v110Sdk71A_x86 SET PFILES_SDK71A=%ProgramFiles% :set_v110Sdk71A_done SET PATH=%PFILES_SDK71A%\Microsoft SDKs\Windows\7.1A\Bin;%PATH% SET INCLUDE=%PFILES_SDK71A%\Microsoft SDKs\Windows\7.1A\Include;%INCLUDE% - IF "%PLATFORM%" == "x64" ( - SET LIB=%PFILES_SDK71A%\Microsoft SDKs\Windows\7.1A\Lib\x64;%LIB% - ) ELSE ( - SET LIB=%PFILES_SDK71A%\Microsoft SDKs\Windows\7.1A\Lib;%LIB% - ) + IF "%PLATFORM%" == "x64" GOTO set_v110Sdk71A_lib_x64 + SET LIB=%PFILES_SDK71A%\Microsoft SDKs\Windows\7.1A\Lib;%LIB% + GOTO set_v110Sdk71A_lib_done + :set_v110Sdk71A_lib_x64 + SET LIB=%PFILES_SDK71A%\Microsoft SDKs\Windows\7.1A\Lib\x64;%LIB% + :set_v110Sdk71A_lib_done CALL :fn_UnsetVariable PFILES_SDK71A SET NMAKE_ARGS=%NMAKE_ARGS% FOSSIL_ENABLE_WINXP=1 GOTO :EOF + +:fn_FindVarInVar + IF NOT DEFINED %1 GOTO :EOF + IF NOT DEFINED %2 GOTO :EOF + SETLOCAL + CALL :fn_UnsetVariable VALUE + SET __ECHO_CMD=ECHO %%%2%% ^^^| FIND /I "%%%1%%" + FOR /F "delims=" %%V IN ('%__ECHO_CMD%') DO ( + SET VALUE=%%V + ) + IF DEFINED VALUE ( + CALL :fn_SetErrorLevel + ) ELSE ( + CALL :fn_ResetErrorLevel + ) + ENDLOCAL + GOTO :EOF :fn_UnsetVariable SETLOCAL SET VALUE=%1 IF DEFINED VALUE ( Index: win/fossil.rc ================================================================== --- win/fossil.rc +++ win/fossil.rc @@ -103,13 +103,13 @@ VALUE "LegalCopyright", "Copyright " MANIFEST_YEAR " by D. Richard Hipp. All rights reserved.\0" VALUE "OriginalFilename", "fossil.exe\0" VALUE "CompilerName", COMPILER_NAME "\0" VALUE "SQLiteVersion", "SQLite " SQLITE_VERSION " " SQLITE_SOURCE_ID "\0" #if defined(FOSSIL_DYNAMIC_BUILD) - VALUE "DynamicBuild", "yes\0" + VALUE "DynamicBuild", "Yes\0" #else - VALUE "DynamicBuild", "no\0" + VALUE "DynamicBuild", "No\0" #endif #if defined(FOSSIL_ENABLE_MINIZ) VALUE "MinizVersion", "miniz " MZ_VERSION "\0" #else VALUE "ZlibVersion", "zlib " ZLIB_VERSION "\0" @@ -161,16 +161,36 @@ #endif /* defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS) */ #endif /* defined(FOSSIL_ENABLE_TCL) */ #if defined(FOSSIL_ENABLE_JSON) VALUE "JsonEnabled", "Yes, cson " FOSSIL_JSON_API_VERSION "\0" #endif /* defined(FOSSIL_ENABLE_JSON) */ +#if defined(USE_MMAN_H) + VALUE "UseMmanEnabled", "Yes\0" +#else + VALUE "UseMmanEnabled", "No\0" +#endif /* defined(USE_MMAN_H) */ #if defined(USE_SEE) VALUE "UseSeeEnabled", "Yes\0" #else VALUE "UseSeeEnabled", "No\0" #endif /* defined(USE_SEE) */ VALUE "MarkdownEnabled", "Yes\0" +#if defined(FOSSIL_DEBUG) + VALUE "Debug", "Yes\0" +#else + VALUE "Debug", "No\0" +#endif /* defined(FOSSIL_DEBUG) */ +#if defined(FOSSIL_OMIT_DELTA_CKSUM_TEST) + VALUE "OmitDeltaCksumTest", "Yes\0" +#else + VALUE "OmitDeltaCksumTest", "No\0" +#endif /* defined(FOSSIL_OMIT_DELTA_CKSUM_TEST) */ +#if defined(FOSSIL_ALLOW_OUT_OF_ORDER_DATES) + VALUE "AllowOutOfOrderDates", "Yes\0" +#else + VALUE "AllowOutOfOrderDates", "No\0" +#endif /* defined(FOSSIL_ALLOW_OUT_OF_ORDER_DATES) */ END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 0x4b0 Index: win/include/dirent.h ================================================================== --- win/include/dirent.h +++ win/include/dirent.h @@ -1,8 +1,8 @@ /* * Dirent interface for Microsoft Visual Studio - * Version 1.21 + * Version 1.23.1 * * Copyright (C) 2006-2012 Toni Ronkko * This file is part of dirent. Dirent may be freely distributed * under the MIT license. For all details and documentation, see * https://github.com/tronkko/dirent @@ -9,25 +9,20 @@ */ #ifndef DIRENT_H #define DIRENT_H /* - * Define architecture flags so we don't need to include windows.h. - * Avoiding windows.h makes it simpler to use windows sockets in conjunction - * with dirent.h. + * Include windows.h without Windows Sockets 1.1 to prevent conflicts with + * Windows Sockets 2.0. */ -#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86) -# define _X86_ +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN #endif -#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64) -#define _AMD64_ -#endif +#include #include #include -#include -#include #include #include #include #include #include @@ -201,15 +196,15 @@ #endif #if !defined(S_ISBLK) # define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) #endif -/* Return the exact length of d_namlen without zero terminator */ +/* Return the exact length of the file name without zero terminator */ #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) -/* Return number of bytes needed to store d_namlen */ -#define _D_ALLOC_NAMLEN(p) (PATH_MAX) +/* Return the maximum size of a file name */ +#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) #ifdef __cplusplus extern "C" { #endif @@ -217,10 +212,13 @@ /* Wide-character version */ struct _wdirent { /* Always zero */ long d_ino; + + /* File position within stream */ + long d_off; /* Structure size */ unsigned short d_reclen; /* Length of name without \0 */ @@ -228,11 +226,11 @@ /* File type */ int d_type; /* File name */ - wchar_t d_name[PATH_MAX]; + wchar_t d_name[PATH_MAX+1]; }; typedef struct _wdirent _wdirent; struct _WDIR { /* Current directory entry */ @@ -250,29 +248,17 @@ /* Initial directory name */ wchar_t *patt; }; typedef struct _WDIR _WDIR; -static _WDIR *_wopendir (const wchar_t *dirname); -static struct _wdirent *_wreaddir (_WDIR *dirp); -static int _wclosedir (_WDIR *dirp); -static void _wrewinddir (_WDIR* dirp); - - -/* For compatibility with Symbian */ -#define wdirent _wdirent -#define WDIR _WDIR -#define wopendir _wopendir -#define wreaddir _wreaddir -#define wclosedir _wclosedir -#define wrewinddir _wrewinddir - - -/* Multi-byte character versions */ +/* Multi-byte character version */ struct dirent { /* Always zero */ long d_ino; + + /* File position within stream */ + long d_off; /* Structure size */ unsigned short d_reclen; /* Length of name without \0 */ @@ -280,24 +266,55 @@ /* File type */ int d_type; /* File name */ - char d_name[PATH_MAX]; + char d_name[PATH_MAX+1]; }; typedef struct dirent dirent; struct DIR { struct dirent ent; struct _WDIR *wdirp; }; typedef struct DIR DIR; + +/* Dirent functions */ static DIR *opendir (const char *dirname); +static _WDIR *_wopendir (const wchar_t *dirname); + static struct dirent *readdir (DIR *dirp); +static struct _wdirent *_wreaddir (_WDIR *dirp); + +static int readdir_r( + DIR *dirp, struct dirent *entry, struct dirent **result); +static int _wreaddir_r( + _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result); + static int closedir (DIR *dirp); +static int _wclosedir (_WDIR *dirp); + static void rewinddir (DIR* dirp); +static void _wrewinddir (_WDIR* dirp); + +static int scandir (const char *dirname, struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)); + +static int alphasort (const struct dirent **a, const struct dirent **b); + +static int versionsort (const struct dirent **a, const struct dirent **b); + + +/* For compatibility with Symbian */ +#define wdirent _wdirent +#define WDIR _WDIR +#define wopendir _wopendir +#define wreaddir _wreaddir +#define wclosedir _wclosedir +#define wrewinddir _wrewinddir /* Internal utility functions */ static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); @@ -315,10 +332,11 @@ size_t sizeInBytes, const wchar_t *wcstr, size_t count); static void dirent_set_errno (int error); + /* * Open directory stream DIRNAME for read and return a pointer to the * internal working area that is used to retrieve individual directory * entries. @@ -344,23 +362,38 @@ /* Reset _WDIR structure */ dirp->handle = INVALID_HANDLE_VALUE; dirp->patt = NULL; dirp->cached = 0; - /* Compute the length of full path plus zero terminator */ - n = GetFullPathNameW (dirname, 0, NULL, NULL); + /* Compute the length of full path plus zero terminator + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + n = wcslen(dirname); +# else + n = GetFullPathNameW (dirname, 0, NULL, NULL); +# endif /* Allocate room for absolute directory name and search pattern */ dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); if (dirp->patt) { /* * Convert relative directory name to an absolute one. This * allows rewinddir() to function correctly even when current * working directory is changed between opendir() and rewinddir(). + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. */ - n = GetFullPathNameW (dirname, n, dirp->patt, NULL); +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + wcsncpy_s(dirp->patt, n+1, dirname, n); +# else + n = GetFullPathNameW (dirname, n, dirp->patt, NULL); +# endif if (n > 0) { wchar_t *p; /* Append search pattern \* to the directory name */ p = dirp->patt + n; @@ -415,68 +448,92 @@ return dirp; } /* - * Read next directory entry. The directory entry is returned in dirent - * structure in the d_name field. Individual directory entries returned by - * this function include regular files, sub-directories, pseudo-directories - * "." and ".." as well as volume labels, hidden files and system files. + * Read next directory entry. + * + * Returns pointer to static directory entry which may be overwritten by + * subsequent calls to _wreaddir(). */ static struct _wdirent* _wreaddir( _WDIR *dirp) { + struct _wdirent *entry; + + /* + * Read directory entry to buffer. We can safely ignore the return value + * as entry will be set to NULL in case of error. + */ + (void) _wreaddir_r (dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry. + * + * Returns zero on success. If end of directory stream is reached, then sets + * result to NULL and returns zero. + */ +static int +_wreaddir_r( + _WDIR *dirp, + struct _wdirent *entry, + struct _wdirent **result) +{ WIN32_FIND_DATAW *datap; - struct _wdirent *entp; /* Read next directory entry */ datap = dirent_next (dirp); if (datap) { size_t n; DWORD attr; - - /* Pointer to directory entry to return */ - entp = &dirp->ent; - /* + /* * Copy file name as wide-character string. If the file name is too * long to fit in to the destination buffer, then truncate file name * to PATH_MAX characters and zero-terminate the buffer. */ n = 0; - while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) { - entp->d_name[n] = datap->cFileName[n]; + while (n < PATH_MAX && datap->cFileName[n] != 0) { + entry->d_name[n] = datap->cFileName[n]; n++; } - dirp->ent.d_name[n] = 0; + entry->d_name[n] = 0; /* Length of file name excluding zero terminator */ - entp->d_namlen = n; + entry->d_namlen = n; /* File type */ attr = datap->dwFileAttributes; if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { - entp->d_type = DT_CHR; + entry->d_type = DT_CHR; } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { - entp->d_type = DT_DIR; + entry->d_type = DT_DIR; } else { - entp->d_type = DT_REG; + entry->d_type = DT_REG; } /* Reset dummy fields */ - entp->d_ino = 0; - entp->d_reclen = sizeof (struct _wdirent); + entry->d_ino = 0; + entry->d_off = 0; + entry->d_reclen = sizeof (struct _wdirent); + + /* Set result address */ + *result = entry; } else { - /* Last directory entry read */ - entp = NULL; + /* Return NULL to indicate end of directory */ + *result = NULL; } - return entp; + return /*OK*/0; } /* * Close directory stream opened by opendir() function. This invalidates the * DIR structure as well as any directory entry read previously by @@ -504,13 +561,15 @@ /* Release directory structure */ free (dirp); ok = /*success*/0; } else { + /* Invalid directory stream */ dirent_set_errno (EBADF); ok = /*failure*/-1; + } return ok; } /* @@ -538,11 +597,13 @@ _WDIR *dirp) { WIN32_FIND_DATAW *datap; /* Open directory and retrieve the first entry */ - dirp->handle = FindFirstFileW (dirp->patt, &dirp->data); + dirp->handle = FindFirstFileExW( + dirp->patt, FindExInfoStandard, &dirp->data, + FindExSearchNameMatch, NULL, 0); if (dirp->handle != INVALID_HANDLE_VALUE) { /* a directory entry is now waiting in memory */ datap = &dirp->data; dirp->cached = 1; @@ -555,11 +616,15 @@ } return datap; } -/* Get next directory entry (internal) */ +/* + * Get next directory entry (internal). + * + * Returns + */ static WIN32_FIND_DATAW* dirent_next( _WDIR *dirp) { WIN32_FIND_DATAW *p; @@ -576,11 +641,11 @@ /* Get the next directory entry from stream */ if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { /* Got a file */ p = &dirp->data; } else { - /* The very last entry has been processed or an error occured */ + /* The very last entry has been processed or an error occurred */ FindClose (dirp->handle); dirp->handle = INVALID_HANDLE_VALUE; p = NULL; } @@ -592,11 +657,11 @@ } return p; } -/* +/* * Open directory stream using plain old C-string. */ static DIR* opendir( const char *dirname) @@ -611,15 +676,16 @@ } /* Allocate memory for DIR structure */ dirp = (DIR*) malloc (sizeof (struct DIR)); if (dirp) { - wchar_t wname[PATH_MAX]; + wchar_t wname[PATH_MAX + 1]; size_t n; /* Convert directory name to wide-character string */ - error = dirent_mbstowcs_s (&n, wname, PATH_MAX, dirname, PATH_MAX); + error = dirent_mbstowcs_s( + &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1); if (!error) { /* Open directory stream using wide-character name */ dirp->wdirp = _wopendir (wname); if (dirp->wdirp) { @@ -629,11 +695,11 @@ /* Failed to open directory stream */ error = 1; } } else { - /* + /* * Cannot convert file name to wide-character string. This * occurs if the string contains invalid multi-byte sequences or * the output buffer is too small to contain the resulting * string. */ @@ -654,39 +720,52 @@ return dirp; } /* * Read next directory entry. - * - * When working with text consoles, please note that file names returned by - * readdir() are represented in the default ANSI code page while any output to - * console is typically formatted on another code page. Thus, non-ASCII - * characters in file names will not usually display correctly on console. The - * problem can be fixed in two ways: (1) change the character set of console - * to 1252 using chcp utility and use Lucida Console font, or (2) use - * _cprintf function when writing to console. The _cprinf() will re-encode - * ANSI strings to the console code page so many non-ASCII characters will - * display correcly. */ static struct dirent* readdir( - DIR *dirp) + DIR *dirp) +{ + struct dirent *entry; + + /* + * Read directory entry to buffer. We can safely ignore the return value + * as entry will be set to NULL in case of error. + */ + (void) readdir_r (dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry into called-allocated buffer. + * + * Returns zero on success. If the end of directory stream is reached, then + * sets result to NULL and returns zero. + */ +static int +readdir_r( + DIR *dirp, + struct dirent *entry, + struct dirent **result) { WIN32_FIND_DATAW *datap; - struct dirent *entp; /* Read next directory entry */ datap = dirent_next (dirp->wdirp); if (datap) { size_t n; int error; /* Attempt to convert file name to multi-byte string */ error = dirent_wcstombs_s( - &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX); + &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1); - /* + /* * If the file name cannot be represented by a multi-byte string, * then attempt to use old 8+3 file name. This allows traditional * Unix-code to access some file names despite of unicode * characters, although file names may seem unfamiliar to the user. * @@ -694,67 +773,72 @@ * name unless the file system provides one. At least * VirtualBox shared folders fail to do this. */ if (error && datap->cAlternateFileName[0] != '\0') { error = dirent_wcstombs_s( - &n, dirp->ent.d_name, PATH_MAX, - datap->cAlternateFileName, PATH_MAX); + &n, entry->d_name, PATH_MAX + 1, + datap->cAlternateFileName, PATH_MAX + 1); } if (!error) { DWORD attr; - /* Initialize directory entry for return */ - entp = &dirp->ent; - /* Length of file name excluding zero terminator */ - entp->d_namlen = n - 1; + entry->d_namlen = n - 1; /* File attributes */ attr = datap->dwFileAttributes; if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { - entp->d_type = DT_CHR; + entry->d_type = DT_CHR; } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { - entp->d_type = DT_DIR; + entry->d_type = DT_DIR; } else { - entp->d_type = DT_REG; + entry->d_type = DT_REG; } /* Reset dummy fields */ - entp->d_ino = 0; - entp->d_reclen = sizeof (struct dirent); + entry->d_ino = 0; + entry->d_off = 0; + entry->d_reclen = sizeof (struct dirent); } else { - /* + + /* * Cannot convert file name to multi-byte string so construct - * an errornous directory entry and return that. Note that + * an erroneous directory entry and return that. Note that * we cannot return NULL as that would stop the processing * of directory entries completely. */ - entp = &dirp->ent; - entp->d_name[0] = '?'; - entp->d_name[1] = '\0'; - entp->d_namlen = 1; - entp->d_type = DT_UNKNOWN; - entp->d_ino = 0; - entp->d_reclen = 0; - } + entry->d_name[0] = '?'; + entry->d_name[1] = '\0'; + entry->d_namlen = 1; + entry->d_type = DT_UNKNOWN; + entry->d_ino = 0; + entry->d_off = -1; + entry->d_reclen = 0; + + } + + /* Return pointer to directory entry */ + *result = entry; } else { + /* No more directory entries */ - entp = NULL; + *result = NULL; + } - return entp; + return /*OK*/0; } /* * Close directory stream. */ static int closedir( - DIR *dirp) + DIR *dirp) { int ok; if (dirp) { /* Close wide-character directory stream */ @@ -777,15 +861,174 @@ /* * Rewind directory stream to beginning. */ static void rewinddir( - DIR* dirp) + DIR* dirp) { /* Rewind wide-character string directory stream */ _wrewinddir (dirp->wdirp); } + +/* + * Scan directory for entries. + */ +static int +scandir( + const char *dirname, + struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)) +{ + struct dirent **files = NULL; + size_t size = 0; + size_t allocated = 0; + const size_t init_size = 1; + DIR *dir = NULL; + struct dirent *entry; + struct dirent *tmp = NULL; + size_t i; + int result = 0; + + /* Open directory stream */ + dir = opendir (dirname); + if (dir) { + + /* Read directory entries to memory */ + while (1) { + + /* Enlarge pointer table to make room for another pointer */ + if (size >= allocated) { + void *p; + size_t num_entries; + + /* Compute number of entries in the enlarged pointer table */ + if (size < init_size) { + /* Allocate initial pointer table */ + num_entries = init_size; + } else { + /* Double the size */ + num_entries = size * 2; + } + + /* Allocate first pointer table or enlarge existing table */ + p = realloc (files, sizeof (void*) * num_entries); + if (p != NULL) { + /* Got the memory */ + files = (dirent**) p; + allocated = num_entries; + } else { + /* Out of memory */ + result = -1; + break; + } + + } + + /* Allocate room for temporary directory entry */ + if (tmp == NULL) { + tmp = (struct dirent*) malloc (sizeof (struct dirent)); + if (tmp == NULL) { + /* Cannot allocate temporary directory entry */ + result = -1; + break; + } + } + + /* Read directory entry to temporary area */ + if (readdir_r (dir, tmp, &entry) == /*OK*/0) { + + /* Did we get an entry? */ + if (entry != NULL) { + int pass; + + /* Determine whether to include the entry in result */ + if (filter) { + /* Let the filter function decide */ + pass = filter (tmp); + } else { + /* No filter function, include everything */ + pass = 1; + } + + if (pass) { + /* Store the temporary entry to pointer table */ + files[size++] = tmp; + tmp = NULL; + + /* Keep up with the number of files */ + result++; + } + + } else { + + /* + * End of directory stream reached => sort entries and + * exit. + */ + qsort (files, size, sizeof (void*), + (int (*) (const void*, const void*)) compare); + break; + + } + + } else { + /* Error reading directory entry */ + result = /*Error*/ -1; + break; + } + + } + + } else { + /* Cannot open directory */ + result = /*Error*/ -1; + } + + /* Release temporary directory entry */ + if (tmp) { + free (tmp); + } + + /* Release allocated memory on error */ + if (result < 0) { + for (i = 0; i < size; i++) { + free (files[i]); + } + free (files); + files = NULL; + } + + /* Close directory stream */ + if (dir) { + closedir (dir); + } + + /* Pass pointer table to caller */ + if (namelist) { + *namelist = files; + } + return result; +} + +/* Alphabetical sorting */ +static int +alphasort( + const struct dirent **a, const struct dirent **b) +{ + return strcoll ((*a)->d_name, (*b)->d_name); +} + +/* Sort versions */ +static int +versionsort( + const struct dirent **a, const struct dirent **b) +{ + /* FIXME: implement strverscmp and use that */ + return alphasort (a, b); +} + /* Convert multi-byte string to wide character string */ static int dirent_mbstowcs_s( size_t *pReturnValue, @@ -816,11 +1059,11 @@ n = sizeInWords - 1; } wcstr[n] = 0; } - /* Length of resuting multi-byte string WITH zero terminator */ + /* Length of resulting multi-byte string WITH zero terminator */ if (pReturnValue) { *pReturnValue = n + 1; } /* Success */ @@ -869,11 +1112,11 @@ n = sizeInBytes - 1; } mbstr[n] = '\0'; } - /* Lenght of resulting multi-bytes string WITH zero-terminator */ + /* Length of resulting multi-bytes string WITH zero-terminator */ if (pReturnValue) { *pReturnValue = n + 1; } /* Success */ Index: win/include/unistd.h ================================================================== --- win/include/unistd.h +++ win/include/unistd.h @@ -22,18 +22,18 @@ #ifndef X_OK #define X_OK 1 #endif /* not X_OK */ +#ifndef W_OK +#define W_OK 2 +#endif /* not W_OK */ + #ifndef R_OK -#define R_OK 2 +#define R_OK 4 #endif /* not R_OK */ -#ifndef W_OK -#define W_OK 4 -#endif /* not W_OK */ - #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) Index: www/aboutcgi.wiki ================================================================== --- www/aboutcgi.wiki +++ www/aboutcgi.wiki @@ -2,11 +2,11 @@

    Introduction

    CGI or "Common Gateway Interface" is a venerable yet reliable technique for generating dynamic web content. This article gives a quick background on how CGI works and describes how Fossil can act as a CGI service.

    This is a "how it works" guide. If you just want to set up Fossil -as a CGI server, see the [./server.wiki | Fossil Server Setup] page. +as a CGI server, see the [./server/ | Fossil Server Setup] page.

    A Quick Review Of CGI

    An HTTP request is a block of text that is sent by a client application (usually a web browser) and arrives at the web server over a network @@ -66,11 +66,11 @@

    In addition to setting various CGI environment variables, if the HTTP request contains POST content, then the web server relays the POST content to standard input of the CGI script.

    -In summary, the task of the +In summary, the task of the CGI script is to read the various CGI environment variables and the POST content on standard input (if any), figure out an appropriate reply, then write that reply on standard output. The web server will read the output from the CGI script, reformat it into an appropriate HTTP reply, and relay the result back to the @@ -89,31 +89,31 @@ like the following:

     #!/usr/bin/fossil
     repository: /home/www/repos/project.fossil
     
    -The first line of the script is a +The first line of the script is a "[https://en.wikipedia.org/wiki/Shebang_%28Unix%29|shebang]" that tells the operating system what program to use as the interpreter for this script. On unix, when you execute a script that starts with a shebang, the operating system runs the program identified by the -shebang with a single argument that is the full pathname of the script +shebang with a single argument that is the full pathname of the script itself. In our example, the interpreter is Fossil, and the argument might be something like "/var/www/cgi-bin/one/two" (depending on how your particular web server is configured).

    The Fossil program that is run as the script interpreter is the same Fossil that runs when you type ordinary Fossil commands like "fossil sync" or "fossil commit". But in this case, as soon as it launches, the Fossil program -recognizes that the GATEWAY_INTERFACE environment variable is +recognizes that the GATEWAY_INTERFACE environment variable is set to "CGI/1.0" and it therefore knows that it is being used as CGI rather than as an ordinary command-line tool, and behaves accordingly.

    When Fossil recognizes that it is being run as CGI, it opens and reads -the file identified by its sole argument (the file named by +the file identified by its sole argument (the file named by argv[1]). In our example, the second line of that file tells Fossil the location of the repository it will be serving. Fossil then starts looking at the CGI environment variables to figure out what web page is being requested, generates that one web page, then exits. @@ -130,11 +130,11 @@

    1. [https://www.fossil-scm.org/fossil/info/c14ecc43]
    2. [https://www.fossil-scm.org/fossil/info?name=c14ecc43]
    In both cases, the CGI script is called "/fossil". For case (A), -the PATH_INFO variable will be "info/c14ecc43" and so the +the PATH_INFO variable will be "info/c14ecc43" and so the "[/help?cmd=/info|/info]" webpage will be generated and the suffix of PATH_INFO will be converted into the "name" query parameter, which identifies the artifact about which information is requested. In case (B), the PATH_INFO is just "info", but the same "name" query parameter is set explicitly by the URL itself. @@ -141,11 +141,11 @@

    Serving Multiple Fossil Repositories From One CGI Script

    The previous example showed how to serve a single Fossil repository using a single CGI script. -On a website that wants to server multiple repositories, one could +On a website that wants to serve multiple repositories, one could simply create multiple CGI scripts, one script for each repository. But it is also possible to serve multiple Fossil repositories from a single CGI script.

    If the CGI script for Fossil contains a "directory:" line instead of @@ -164,11 +164,11 @@

    http://example.com/cgis/example2/subdir/three/timeline
    Here is what happens:
      -
    1. The input URI on the HTTP request is +
    2. The input URI on the HTTP request is /cgis/example2/subdir/three/timeline
    3. The web server searches prefixes of the input URI until it finds the "cgis/example2" script. The web server then sets PATH_INFO to the "subdir/three/timeline" suffix and invokes the "cgis/example2" script. @@ -175,15 +175,23 @@
    4. Fossil runs and sees the "directory:" line pointing to "/home/www/repos". Fossil then starts pulling terms off the front of the PATH_INFO looking for a repository. It first looks at "/home/www/resps/subdir.fossil" but there is no such repository. So then it looks at "/home/www/repos/subdir/three.fossil" and finds - a repository. The PATH_INFO is shortened by removing + a repository. The PATH_INFO is shortened by removing "subdir/three/" leaving it at just "timeline".
    5. Fossil looks at the rest of PATH_INFO to see that the webpage requested is "timeline".
    +
    +

    Additional CGI Script Options

    +
    +

    +The CGI script can have additional options used to fine-tune +Fossil's behavior. See the [./cgi.wiki|CGI script documentation] +for details. +

    Additional Observations

    1. Fossil does not distinguish between the various HTTP methods (GET, PUT, @@ -201,14 +209,18 @@ and has a value.

    2. The "[/help?cmd=ui|fossil ui]" and "[/help?cmd=server|fossil server]" commands are implemented using a simple built-in web server that accepts incoming HTTP requests, translates each request into a CGI invocation, then creates a -separate child Fossil process to handle each request. In other words, CGI +separate child Fossil process to handle each request. In other words, CGI is used internally to implement "fossil ui/server".

      SCGI is processed using the same built-in web server, just modified to parse SCGI requests instead of HTTP requests. Each SCGI request is -converted into CGI, then Fossil creates a separate child Fossil +converted into CGI, then Fossil creates a separate child Fossil process to handle each CGI request. +

    3. +Fossil is itself often launched using CGI. But Fossil can also then +turn around and launch [./serverext.wiki|sub-CGI scripts to implement +extensions].

    ADDED www/aboutdownload.wiki Index: www/aboutdownload.wiki ================================================================== --- /dev/null +++ www/aboutdownload.wiki @@ -0,0 +1,98 @@ +How The Fossil Download Page Works +

    How The Download Page Works

    + +

    1.0 Overview

    + +The [/uv/download.html|Download] page for the Fossil self-hosting +repository is implemented using [./unvers.wiki|unversioned files]. +The "download.html" screen itself, and the various build products +are all stored as unversioned content. The download.html page +uses XMLHttpRequest() to retrieve the [/help?cmd=/juvlist|/juvlist] webpage +for a list of all unversioned files. Javascript in the +[/uv/download.js?mimetype=text/plain|download.js] file (which is +sourced by "download.html") then figures out which unversioned files are +build products and paints appropriate icons on the displayed +download page. + +When a new version is generated, the developers use the +[/help?cmd=uv|fossil uv edit] command to make minor changes +to the "[/uv/download.js?mimetype=text/plain|download.js]" +file so that it knows about the +new version number. Then the developers run +the [/help?cmd=uv|fossil uv add] command for each +build product. Finally, the +[/help?cmd=uv|fossil uv sync] command is run to push all +the content up to servers. All +[./selfhost.wiki|three self-hosting repositories] for Fossil +are updated automatically. + +

    2.0 Details

    + +The current text of the "download.html" and "download.js" files can +be seen at: + + * [/uv/download.html?mimetype=text/plain] + * [/uv/download.js?mimetype=text/plain] + +Notice how the hyperlinks above use the "mimetype=text/plain" +query parameter in order to display the file as plain text +instead of the usual HTML or Javascript. + +The default mimetype for "download.html" is +text/html. But because the entire page is enclosed within + + <div class='fossil-doc' data-title='Download Page'>...</div> + +Fossil knows to add its standard header and footer information to the +document, making it look just like any other page. See +"[./embeddeddoc.wiki|embedded documentation]" for further details on +how <div class='fossil-doc'> this works. + +With each new release, the "releases" variable in the javascript on +the [/uv/download.js?mimetype=text/plain|download.js] page is +edited (using "[/help?cmd=uv|fossil uv edit download.js]") to add +details of the release. + +When the JavaScript in the "download.js" file runs, it requests +a listing of all unversioned content using the /juvlist URL. +([/juvlist|sample /juvlist output]). The content of the download page is +constructed by matching unversioned files against regular expressions +in the "releases" variable. + +Build products need to be constructed on different machines. The precompiled +binary for Linux is compiled on Linux, the precompiled binary for Windows +is compiled on Windows10, and so forth. After a new release is tagged, +the release manager goes around to each of the target platforms, checks +out the release and compiles it, then runs +[/help?cmd=uv|fossil uv add] for the build product followed by +[/help?cmd=uv|fossil uv sync] to push the new build product to the +[./selfhost.wiki|various servers]. This process is repeated for +each build product. + +When older builds are retired from the download page, the +[/uv/download.js?mimetype=text/plain|download.js] page is again +edited to remove the corresponding entry from the "release" variable +and the edit is synced using +[/help?cmd=uv|fossil uv sync]. This causes the build products to +disappear from the download page immediately. But those build products +are still taking up space in the unversioned content table of the +server repository. To purge the obsolete build products, one or +more [/help?cmd=uv|fossil uv rm] commands are run, followed by +another [/help?cmd=uv|fossil uv sync]. It is important to purge +obsolete build products since they take up a lot of space. +At [/repo-tabsize] you can see that the unversioned table takes up +a substantial fraction of the repository. + +

    3.0 Security

    + +Only users with the [/setup_ulist_notes|"y" permission] are allowed +to push unversioned content up to the servers. Having the ability +to push check-ins (the [/setup_ulist_notes|"i" permission]) is not +sufficient. + +On the Fossil project there are 67 people (as of 2017-03-24) who have +check-in privileges. But only 3 core developers +can push unversioned content and thus +change the build products on the download page. Minimizing the number +of people who can change the build products helps to ensure that +rogue binaries do not slip onto the download page unnoticed. Index: www/adding_code.wiki ================================================================== --- www/adding_code.wiki +++ www/adding_code.wiki @@ -1,11 +1,17 @@ Adding Features To Fossil

    1.0 Introduction

    -This article provides a brief overview of how to write new code that extends -or enhances Fossil. +This article provides a brief overview of how to write new C-code code that +extends or enhances the core Fossil binary. + +New features can be added to a Fossil server using +[./serverext.wiki|external CGI programs], +but that is not what this article is about. +This article focuses on how to make changes +to Fossil itself.

    2.0 Programming Language

    Fossil is written in C-89. There are specific [./style.wiki | style guidelines] that are required for any new code that will be accepted into the Fossil core. @@ -22,11 +28,11 @@ 2. The makeheaders preprocessor generates all the ".h" files automatically. Fossil programmers write ".c" files only and let the makeheaders preprocessor create the ".h" files. - 3. The translate preprocessor converts source code lines that + 3. The translate preprocessor converts source code lines that begin with "@" into string literals, or into print statements that generate web page output, depending on context. The [./makefile.wiki|Makefile] for Fossil takes care of running these preprocessors with all the right arguments and in the right order. So it is @@ -39,13 +45,13 @@

    3.0 Adding New Source Code Files

    New source code files are added in the "src/" subdirectory of the Fossil source tree. Suppose one wants to add a new source code file named "xyzzy.c". The first step is to add this file to the various makefiles. -Do so by editing the file src/makemake.tcl and adding "xyzzy" (without +Do so by editing the file src/makemake.tcl and adding "xyzzy" (without the final ".c") to the list of source modules at the top of that script. -Save the result and then run the makemake.tcl script using a TCL +Save the result and then run the makemake.tcl script using a TCL interpreter. The command to run the makemake.tcl script is: tclsh makemake.tcl The working directory must be src/ when the command above is run. @@ -60,20 +66,20 @@
    /* ** Copyright boilerplate goes here. ***************************************************** -** High-level description of what this module goes +** High-level description of what this module goes ** here. */ #include "config.h" #include "xyzzy.h" #if INTERFACE /* Exported object (structure) definitions or #defines ** go here */ -#endif /* INTEFACE */ +#endif /* INTERFACE */ /* New code goes here */
    Note in particular the #include "xyzzy.h" line near the top. @@ -83,11 +89,11 @@ exceptions to this rule. Don't worry about those exceptions. The files you write will require this #include line.) The "#if INTERFACE ... #endif" section is optional and is only needed if there are structure definitions or typedefs or macros that need to -be used by other source code files. The makeheaders preprocessor +be used by other source code files. The makeheaders preprocessor uses definitions in the INTERFACE section to help it generate header files. See [../src/makeheaders.html | makeheaders.html] for additional information. After creating a template file such as shown above, and after updating @@ -96,10 +102,11 @@ It is recommended that you try this. Be sure to [/help/add|fossil add] your new source file to the self-hosting Fossil repository and then [/help/commit|commit] your changes! +

    4.0 Creating A New Command

    By "commands" we mean the keywords that follow "fossil" when invoking Fossil from the command-line. So, for example, in @@ -161,10 +168,11 @@ the working check-out. Study implementations of existing commands to get an idea of how things are done. You can easily find the implementations of existing commands by searching for "COMMAND: name" in the files of the "src/" directory. +

    5.0 Creating A New Web Page

    As with commands, new webpages can be added simply by inserting a function that generates the webpage together with a special header comment. A template follows: @@ -211,5 +219,6 @@

    6.0 See Also

    * [./makefile.wiki|The Fossil Build Process] * [./tech_overview.wiki|A Technical Overview Of Fossil] * [./contribute.wiki|Contributing To The Fossil Project] + * [./serverext.wiki|Adding CGI Extensions To A Fossil Server] ADDED www/alerts.md Index: www/alerts.md ================================================================== --- /dev/null +++ www/alerts.md @@ -0,0 +1,746 @@ +# Email Alerts + +## Overview + +Beginning with version 2.7, Fossil can send email messages to +subscribers to alert them to changes in the repository: + + * New [checkins](/help?cmd=ci) + * [Ticket](./tickets.wiki) changes + * [Wiki](./wikitheory.wiki) page changes + * New and edited [forum](./forum.wiki) posts + * Announcements + +Subscribers can elect to receive emails as soon as these events happen, +or they can receive a daily digest of the events instead. + +Email alerts are sent by a [Fossil server](./server/), which must be +[set up](#quick) by the Fossil administrator to send email. + +Email alerts do not currently work if you are only using Fossil from the +command line. + +A bit of terminology: Fossil uses the terms "email alerts" and +"notifications" interchangeably. We stick to the former term in this +document except when referring to parts of the Fossil UI still using the +latter term. + + +## Setup Prerequisites + +Much of this document describes how to set up Fossil's email alert +system. To follow this guide, you will need a Fossil UI browser window +open to the [Admin → Notification](/setup_notification) Fossil UI screen +on the Fossil server that will be sending these email alerts, logged +in as a user with [**Admin** capability](./caps/ref.html#a). It is not possible to work on a +clone of the server's repository and push the configuration changes up +to that repo as an Admin user, [on purpose](#backup). + +**Important:** Do not confuse that screen with Admin → Email-Server, +which sets up a different subsystem within Fossil. That feature is +related to this document's topic, but it is currently incomplete, so we +do not cover it at this time. + + +You will also need a CLI window open with its working directory changed +to a checkout directory of the Fossil repository you are setting up to +send email. If you don't `cd` to such a checkout directory first, +you'll need to add `-R /path/to/repo.fossil` to each `fossil` command +below to tell Fossil which repository you mean it to apply the command +to. + +There are other prerequisites for email service, but since they vary +depending on the configuration you choose, we'll cover these inline +below. + + + +## Quick Email Service Setup + +If you've already got a working Postfix, Exim, or Sendmail server on the +machine running your Fossil instance(s), and you aren't using Fossil's +`chroot` feature to wall Fossil off from the rest of the machine, it's +fairly simple to set up email alerts. + +(Otherwise, skip [ahead](#advanced) to the sections on advanced email +service setup.) + +This is our "quick setup" option even though setting up an SMTP mail +server is not trivial, because there are many other reasons to have such +a server set up already: internal project email service, `cron` +notifications, server status monitoring notifications... + +With that out of the way, the Fossil-specific steps are easy: + +1. Go to [Admin → Notification](/setup_notification) and fill out all + of the **Required** fields: + + * **Canonical server URL** — Use the suggested URL + + * **"From" email address** — `forum-bounces@example.com` is + traditional, but suit yourself + + * **Repository nickname** — See the suggested examples on the web page. + +2. Set "Email Send Method" to "Pipe to a command" + +3. Set the "Administrator email address" to a suitable valid email + address on that machine. It could be the same value you used for + the "From" address above, or it could be a different value like + `admin@example.com`. + +Save your changes. + +At the command line, say + + $ fossil set email-send-command + +If that gives a blank value instead of `sendmail -ti`, say + + $ fossil set email-send-command "sendmail -ti" + +to force the setting. That works around a [known +bug](https://fossil-scm.org/forum/forumpost/840b676410) which may be +squished by the time you read this. + +If you're running Postfix or Exim, you might think that command is +wrong, since you aren't running Sendmail. These mail servers provide a +`sendmail` command for compatibility with software like Fossil that has +no good reason to care exactly which SMTP server implementation is +running at a given site. There may be other SMTP servers that also +provide a compatible `sendmail` command, in which case they may work +with Fossil using the same steps as above. + + +If you reload the Admin → Notification page, the Status section at the +top should show: + + Outgoing Email: Piped to command "sendmail -ti" + Pending Alerts: 0 normal, 0 digest + Subscribers: 0 active, 0 total + +Before you move on to the next section, you might like to read up on +[some subtleties](#pipe) with the "pipe to a command" method that we did +not cover above. + + + +## Usage and Testing + +Now that email service from Fossil is set up, you can test it and begin +using it. + + + +### Subscribing to Alerts + +In the Status output above, we saw that there are no subscribers, so the +next step is to add the first one. + +Go to the `/subscribe` page on your Fossil instance to sign up for email +alerts. At the very least, you will need to sign up for "Forum Posts" +and "Announcements" to complete the testing steps below. + +If you're logged in with a Fossil repository user account and put the +same user name and email address into this forum as you used for your +user information under Admin → Users, Fossil will simply tie your alert +preferences to your login record, and the email address in your user's +Contact Info field will be considered already-verified. Otherwise, +Fossil will create an alert-only record, and you will have to verify the +email address before Fossil will send alerts to it. + +This shows a key aspect of the way Fossil's email alerts system works, +by the way: a user can be signed up for email alerts without having a +full-fledged Fossil user account. Only when both user names are the same +are the two records tied together under the hood. For more on this, see +[Users vs Subscribers below](#uvs). + +If you are seeing the following complaint from Fossil: + +
    + Use a different login with greater privilege than FOO to access + /subscribe +
    + +...then the repository's administrator forgot to give the +[**EmailAlert** capability][cap7] +to that user or to a user category that the user is a member of. + +After a subscriber signs up for alerts for the first time, a single +verification email is sent to that subscriber's given email address. +The new subscriber must click a link in that email in order to activate +the subscription. + +Subscription verification emails are only sent once. This is a defense +against malicious robots that try to harass innocent Internet users by +having subscription pages send multiple verification emails. If the +initial subscription verification does not go through correctly, an +administrator must [intervene](#admin) to reset the subscription. + +Every subscriber-only email address has a [long random hexadecimal +security code](#scode) that serves in place of a password. All email +alerts contain a link in their footer back to the Fossil server, +incorporating this security code, which allows the subscriber to adjust +their subscription options. If a user doesn't have any of those emails, +they can request a link via email by visiting the `/alerts` or +`/unsubscribe` page on the repository. + +Those with Fossil repository logins can adjust their email alert +settings by visiting the `/alerts` page on the repository. With the +default skin, you can get there by clicking the "Logout" link in the +upper right corner of any Fossil UI page then clicking the "Email +Alerts" link. That link is also available via the Sitemap (`/sitemap`) +and via the default skin's hamburger menu (☰). + +[cap7]: ./caps/ref.html#7 + + + +### Unsubscribing + +To unsubscribe from alerts, visit the `/alerts` page on the repository, +click the "Unsubscribe" button, then check the "Unsubscribe" checkbox to +verify your action and press the "Unsubscribe" button a second time. + +This interlock is intended to prevent accidental unsubscription. + + + +### Test Email Service + +The easiest way to test email sending from Fossil is via the "[Send +Announcement](/announce)" link at the top of the "Email Notification +Setup" page. Put your email address in the "To:" line and a test +message below, then press "Send Message" to verify that outgoing email +is working. + +Another method is from the command line: + + $ fossil alerts test-message you@example.com --body README.md --subject Test + +That should send you an email with "Test" in the subject line and the +contents of your project's `README.md` file in the body. + +That command assumes that your project contains a "readme" file, but of +course it does, because you have followed the [Programming Style Guide +Checklist][cl], right? Right. + +[cl]: https://sendgrid.com/blog/programming-style-guide-checklist/ + + + +### User Capabilities + +Once email alerts are working, you may need to [adjust the default user +capabilities](./caps/) to give "[Email Alerts][cap7]" capability to any +[user category](./caps/#ucat) or [individual user](./caps/#ucap) that +needs to use the subscription setup pages, `/subscribe` and `/alerts`. +[**Admin**][capa] and [**Setup**][caps] users always have this +capability. + +To allow any passer-by on the Internet to subscribe, give the "Email +Alerts" capability to the "nobody" user category. To require that a +person solve a simple CAPTCHA first, give that capability to the +"anonymous" user category instead. + +[capa]: ./caps/ref.html#a +[caps]: ./caps/ref.html#s + + + +### First Post + +I suggest taking the time to compose a suitable introductory message +especially for your project's forum, one which a new user would find +helpful. + +Wait a few seconds, and you should receive an email alert with the +post's subject and body text in the email. + + + +### Troubleshooting + +If email alerts aren't working, there are several useful commands you +can give to figure out why. + +(Be sure to [`cd` into a repo checkout directory](#cd) first!) + + $ fossil alerts status + +This should give much the same information as you saw [above](#status). +One difference is that, since you've created a forum post, the +`pending-alerts` value should only be zero if you did in fact get the +requested email alert. If it's zero, check your mailer's spam folder. If +it's nonzero, continue with these troubleshooting steps. + + $ fossil backoffice + +That forces Fossil to run its ["back office" process](./backoffice.md). +Its only purpose at the time of this writing is to push out alert +emails, but it might do other things later. Sometimes it can get stuck +and needs to be kicked. For that reason, you might want to set up a +crontab entry to make sure it runs occasionally. + + $ fossil alerts send + +This should also kick off the backoffice processing, if there are any +pending alerts to send out. + + $ fossil alert pending + +Show any pending alerts. The number of lines output here should equal +the [status output above](#status). + + $ fossil test-add-alerts f5900 + $ fossil alert send + +Manually create an email alert and push it out immediately. + +The `f` in the first command's final parameter means you're scheduling a +"forum" alert. The integer is the ID of a forum post, which you can find +by visiting `/timeline?showid` on your Fossil instance. + +The second command above is necessary because the `test-add-alerts` +command doesn't kick off a backoffice run. + + $ fossil ale send + +This only does the same thing as the final command above, rather than +send you an ale, as you might be hoping. Sorry. + + + +## Advanced Email Setups + +Fossil offers several methods of sending email: + + 1. Pipe the email message text into a command. + 2. Store email messages as entries in a SQLite database. + 3. Store email messages as individual files in a directory. + 4. Send emails to an SMTP relay. + 5. Send emails directly to the recipients via SMTP. + +This wide range of options allows Fossil to talk to pretty much any +SMTP setup. + +The first four options let Fossil delegate email handling to an existing +[MTA][mta] so that Fossil does not need to implement the [roughly two +dozen][mprotos] separate [RFCs][rfcs] required in order to properly +support SMTP email in this complex world we've built. As well, this +design choice means you do not need to do duplicate configuration, such +as to point Fossil at your server's TLS certificate in order to support +users behind mail servers that require STARTTLS encryption. + +[mprotos]: http://sqlite.1065341.n5.nabble.com/Many-ML-emails-going-to-GMail-s-SPAM-tp98685p98722.html +[rfcs]: https://en.wikipedia.org/wiki/Request_for_Comments + + + +### Method 1: Pipe to a Command + +This is our ["quick setup" option](#quick) above, but there are some +details we ignored which we'll cover now. + +Fossil pipes the email message in [RFC 822 format][rfc822] to the +standard input of the command you gave as the "Email Send Method", +defaulting to `sendmail -ti`. This constitutes a protocol between Fossil +and the SMTP [message transfer agent (MTA)][mta]. Any other MTA which +speaks the same protocol can be used in place of the most common +options: Sendmail, Exim, and Postfix. + +The `-t` option tells the command to expect the list of email recipients +in a `To` header in the RFC 822 message presented on its standard input. +Without this option, the `sendmail` command expects to receive the +recipient list on the command line, but that's not possible with the +current design of this email sending method. Therefore, if you're +attempting to use a less common MTA which cannot parse the recipient +list from the `To` header in the email message, you might need to look +for a different MTA. + +The `-i` option is only needed for MTAs that take a dot/period at the +beginning of a line of standard input text as "end of message." Fossil +doesn't attempt to escape such dots, so if the line wrapping happens to +occur such that a dot or period in an alert message is at the beginning +of a line, you'll get a truncated email message without this option. +Statistically, this will happen about once every 70 or so messages, so +it is important to give this option if your MTA treats leading dots on a +line this way. + + +We believe the [`msmtp`][msmtp] SMTP client is compatible with this +protocol if you give it the `-t` option. To our knowledge, this remains +untested, but if it works, this would be a useful option on a server +hosting a Fossil repository which doesn't otherwise require a separate +SMTP server for other purposes. + +It is probably also possible to configure [`procmail`][pmdoc] to work +with this protocol. If you know how to do it, a patch to this document +or a how-to on [the Fossil forum][ff] would be appreciated. + +[ff]: https://fossil-scm.org/forum/ +[msmtp]: https://marlam.de/msmtp/ +[mta]: https://en.wikipedia.org/wiki/Message_transfer_agent +[pmdoc]: http://pm-doc.sourceforge.net/doc/ +[rfc822]: https://www.w3.org/Protocols/rfc822/ + + + +### Method 2: Store in a Database + +The self-hosting Fossil repository at +currently uses this method rather than [the pipe method](#pipe) because +it is running inside of a restrictive [chroot jail][cj] which is unable +to hand off messages to the local MTA directly. + +When you configure a Fossil server this way, it adds outgoing email +messages to a SQLite database file. A separate daemon process can then +extract those messages for further disposition. + +Fossil includes a copy of [the daemon](/file/tools/email-sender.tcl) +used on `fossil-scm.org`: it is just a short Tcl script that +continuously monitors this database for new messages and hands any that +it finds off to a local MTA using the same [pipe to MTA protocol](#pipe) +as above. + +In this way, outbound email alerts escape the chroot jail without +requiring that we insert a separate MTA configuration inside that jail. +We only need to arrange that the same SQLite DB file be visible both +inside and outside the chroot jail, which we do by naming the database +file in the "Store Emails In This Database" setting under Admin → +Notification. The Tcl script has this path hard-coded as +`/home/www/fossil/emailqueue.db`, but you will probably need to adjust +that for your local purposes. + +This method may work with other similar technologies besides `chroot`: +Docker containers, LXC containers, BSD jails, Solaris zones, etc. + +With suitable file share mappings, this method may even work with +virtual machine or distributed computing setups where the MTA and Fossil +servers are not on the same machine, though beware the [risk of DB +corruption][rdbc] if used with a file sharing technology that doesn't +use proper file locking. + +You can start this Tcl script as a daemon automatically on most Unix and +Unix-like systems by adding the following line to the `/etc/rc.local` +file of the server that hosts the repository sending email alerts: + + /usr/bin/tclsh /home/www/fossil/email-sender.tcl & + +[cj]: https://en.wikipedia.org/wiki/Chroot +[rdbc]: https://www.sqlite.org/howtocorrupt.html#_filesystems_with_broken_or_missing_lock_implementations + + + +### Method 3: Store in a Directory + +This method is functionally very similar to [the DB method](#db), +differing only in that messages are written to a directory in the +filesystem. You should therefore read that section and make the minor +adjustments required by the storage method. + +This method may work over a file sharing mechanism that doesn't do file +locking properly, as long as the reading process is somehow restricted +from reading a message file as it's being written. + +It might be useful in testing and debugging to temporarily switch to +this method, since you can easily read the generated email messages +without needing to involve [an MTA][mta]. + + + +### Method 4: SMTP Relay + +In this configuration, the Fossil server contacts an open SMTP relay and +sends the messages to it. This method is only appropriate when: + +1. You have a local MTA that doesn't accept [the pipe + protocol](#pipe). + +2. The MTA is willing to accept anonymous submissions, since Fossil + currently has no way to authenticate itself to the MTA. This is [an + unsafe configuration][omr] in most cases, but some SMTP servers make + an exception for connections coming from a `localhost` or LAN + address, choosing to accept such submissions as inherently safe. + +If you have a local MTA meeting criterion #1 but not #2, we'd suggest +using a more powerful SMTP client such as [msmtp](#msmtp) along with one +of the other methods above. + +[omr]: https://en.wikipedia.org/wiki/Open_mail_relay + + + +### Method 5: Direct SMTP Send + +As of Fossil 2.7, the code to support this method is incomplete, so you +cannot currently select it as an option in Admin → Notification. + + + +## Users vs Subscribers + +Fossil makes a distinction between "users" and "subscribers". A user is +someone with a username and password: that is, someone who can log into +the Fossil repository. A subscriber is someone who receives email +alerts. Users can also be subscribers and subscribers can be users, but +that does not have to be the case. It is possible to be a user without +being a subscriber and to be a subscriber without being a user. + +In the repository database file, users are tracked with the `user` table +and subscribers are tracked via the `subscriber` table. + + + +## Administrator Activities + +The "[List Subscribers](/subscribers)" button at the top of the Admin → +Notification screen gives a list of subscribers, which gives a Fossil +server administrator a lot of power over those subscriptions. + +Clicking an email address in this subscriber list opens the same +`/alerts` page that the user can see for their own subscription, but +with more information and functionality than normal users get: + +* Subscription creation and modification timestamps. + +* The IP address the user had when they last made a change via either + `/subscribe` or `/alert`. + +* The user's login name, if they are not [a mere subscriber](#uvs). A + Fossil Admin user is allowed to modify this, either to tie a + subscription-only record to an existing Fossil user account or to + break that tie. + +* The "Do not call" checkbox allows a Fossil Admin user to mark a given + email address so that Fossil never sends email to that address. This + is distinct from unsubscribing that email address because it prevents + Fossil from accepting a new subscription for that address. + +* The Verified checkbox is initially unchecked for subscriber-only + email addresses until the user clicks the link in the verification + email. This checkbox lets the Fossil Admin user manually verify the + user, such as in the case where the verification email message got + lost. Unchecking this box does not cause another verification email + to be sent. + +This screen also allows a Fossil Admin user to perform other activities +on behalf of a subscriber which they could do themselves, such as to +[unsubscribe](#unsub) them. + + + +## Cloning, Syncing, and Backups + +The Admin → Notification settings are not replicated using clone or +sync, and it is not possible to push such settings from one repository +to another. In a network of peer repositories, you only want one +repository sending email alerts. If you were to replicate the email +alert settings to a separate repository, then subscribers would get +multiple alerts for each event, which would be bad. + +However, the subscriber list can be synced for backup purposes. Use the +[`fossil config pull subscriber`](/help?cmd=configuration) command to +pull the latest subscriber list from a server into a backup repository. + +The `push`, `export`, and `import` commands all work similarly. + + + +## Controlling the Email Alert System + +This section collects the list of Fossil UI pages and CLI commands that +control the email alert system, some of which have not been mentioned so +far: + +Commands: + + * The [`alerts`](/help?cmd=alerts) command + * The [`test-alert`](/help?cmd=test-alert) command + * The [`test-add-alerts`](/help?cmd=test-add-alerts) command + +Web pages available to users and subscribers: + + * The [`/subscribe`](/help?cmd=/subscribe) page + * The [`/alerts`](/help?cmd=/alerts) page + * The [`/unsubscribe`](/help?cmd=/unsubscribe) page + * The [`/contact_admin`](/help?cmd=/contact_admin) page + +Administrator-only web pages: + + * The [`/setup_notification`](/help?cmd=/setup_notification) page + * The [`/subscribers`](/help?cmd=/subscribers) page + + + +## Design of Email Alerts + +This section describes the low-level design of the email alert system in +Fossil. This expands on the high-level administration focused material +above with minimal repetition. + +This section assumes expert-level systems knowledge. If the material +above sufficed for your purposes, feel free to skip this section, which +runs to the end of this document. + + + +### Data Design + +There are three new tables in the repository database, starting with +Fossil 2.7. These tables are not created in new repositories by +default. The tables only come into existence as needed when email +alerts are configured and used. + + + * SUBSCRIBER → + The subscriber table records the email address for people who + want to receive email notifications. Each subscriber has a + `subscriberCode` which is a random 32-byte blob that uniquely + identifies the subscriber. There are also fields to indicate + what kinds of notifications the subscriber wishes to receive, + whether or not the email address of the subscriber has been + verified, etc. + + * PENDING\_ALERT → + The PENDING\_ALERT table contains records that define events + about which alert emails might need to be sent. + A pending\_alert always refers to an entry in the + EVENT table. The EVENT table is part of the standard schema + and records timeline entries. In other words, there is one + row in the EVENT table for each possible timeline entry. The + PENDING\_ALERT table refers to EVENT table entries for which + we might need to send alert emails. + + * EMAIL\_BOUNCE → + This table is intended to record email bounce history so that + subscribers with excessive bounces can be turned off. That + logic has not yet been implemented so the EMAIL\_BOUNCE table + is currently unused. + +As pointed out above, ["subscribers" are distinct from "users"](#uvs). +The SUBSCRIBER.SUNAME field is the optional linkage between users and +subscribers. + + + +### The "stdout" Method + +The [list of mail sending methods](#advanced) above left out an +internal-only method called "stdout" which simply writes the text of the +email message on standard output. The "stdout" method is used for +testing and debugging. If you need something similar and can't modify +your local Fossil instance to use this method, you might temporarily +switch to [the "dir" method](#dir) instead. + + + +### Message Format + +The email messages generated by Fossil have a [well-formed +header][rfc822]. The downstream processing is expected to extract the +"To:", "From:", "Subject:" and whatever other attributes it needs from +the email header text. + +These emails use the `text/plain` MIME type with the UTF-8 character +set. We currently use a transfer encoding of `quoted-printable`, but +there is commented-out code in Fossil to switch to `base64` encoding, +which Fossil used in the early days leading up to the 2.7 release. + +If you switch Fossil back to `base64` mode, you may want to build a +utility program that ships in the Fossil source tree named +["tools/decode-email.c"](/file/tools/decode-email.c) which can decode +these messages into a human-readable format. + + + +### Dealing with Inbound Email + +Inbound email messages — for example, bounces from failed alert emails — +should be relayed to the `fossil email inbound` command. That command +is currently a no-op place-holder. At some point, we will need to +design and write a bounce-message processing system for Fossil. + + + +### Passwords vs Subscriber Codes + +When anonymous passers-by on the Internet sign up for email alerts, +their email address must first be verified. An email message is sent to +the address supplied inviting the user to click on a link. The link +includes a pseudorandom 128-bit blob encoded as 32 hexadecimal digits, +which serves in place of a password for that email address. (This is +stored in the database as `subscriber.subscriberCode`.) If anyone visits +the link, the email address is verified. + +Knowledge of the `subscriberCode` is sufficient to control a +subscription. + +Because this code is included in plain text in email alert messages, it +is not as secure as a separate password, but it has several virtues: + +* It is easier for the average subscriber to deal with in that they + don't have to come up with yet another password and store it safely. + +* If the `subscriberCode` is stolen, the worst that can happen is that + the thief can change that email address's subscription settings. + Contrast a password which may be shared with other services, which + then compromises those other services. + +* No PII other than the subscriber's email address is available to an + attacker with the `subscriberCode`. Nor can knowledge of the + `subscriberCode` lead to a email flood or other annoyance attack, as + far as I can see. + +If the `subscriberCodes` for a Fossil repository are ever compromised, +new ones can be generated as follows: + + UPDATE subscriber SET subscriberCode=randomblob(32); + +Since this then affects all new email alerts going out from Fossil, your +end users may never even realize that they're getting new codes, as long +as they don't click on the URLs in the footer of old alert messages. + +With that in mind, a Fossil server administrator could choose to +randomize the `subscriberCodes` periodically, such as just before the +daily digest emails are sent out each day. + +**Important:** All of the above is distinct from the passwords for users +with a Fossil repository login. Such users also have subscriber codes, +but those codes can only be used to modify the user's email alert +settings. That code cannot allow a user to log into the user's Fossil +repository account. + + + +### Internal Processing Flow + +Almost all of the email alert code is found in the +[`src/alerts.c`](/file/src/alerts.c) source file. + +When email alerts are enabled, a trigger is created in the schema +(`email_trigger1`) that adds a new entry to the `PENDING_ALERT` table +every time a row is added to the `EVENT` table. During a +`fossil rebuild`, the `EVENT` table is rebuilt from scratch; since we do not +want users to get alerts for every historical check-in, the trigger is +disabled during `rebuild`. + +Email alerts are sent out by the `alert_send_alerts()` function, which +is normally called automatically due to the `email-autoexec` setting, +which defaults to enabled. If that setting is disabled or if the user +simply wants to force email alerts to be sent immediately, they can give +a `fossil alert send` command, such as via a `cron` script. Each time +this function is called, the alert messages are moved further down the +chain, so you cannot cause duplicate alerts by calling it too often. + +Digests are handled by recording the time of the last digest in the +`email-last-digest` setting, and only sending a new digest if the +current time is one day or later after the last digest. + +Individual emails are sent to each subscriber. I (drh) ran tests and +found that I could send about 1200 emails/second, which is fast enough +that I do not need to resort to trying to notify multiple subscribers +with a single email. Because each subscriber gets a separate email, the +system can include information in the email that is unique to the +subscriber, such as a link to the page to edit their subscription. That +link includes the `subscriberCode`. Index: www/antibot.wiki ================================================================== --- www/antibot.wiki +++ www/antibot.wiki @@ -1,53 +1,50 @@ Defense Against Spiders The website presented by a Fossil server has many hyperlinks. Even a modest project can have millions of pages in its -tree, and many of those pages (for example diffs and annotations -and ZIP archive of older check-ins) can be expensive to compute. +tree, and many of those pages (for example diffs and annotations +and ZIP archives of older check-ins) can be expensive to compute. If a spider or bot tries to walk a website implemented by Fossil, it can present a crippling bandwidth and CPU load. The website presented by a Fossil server is intended to be used -interactively by humans, not walked by spiders. This article +interactively by humans, not walked by spiders. This article describes the techniques used by Fossil to try to welcome human users while keeping out spiders. -

    The "hyperlink" user capability

    +

    The Hyperlink User Capability

    Every Fossil web session has a "user". For random passers-by on the internet (and for spiders) that user is "nobody". The "anonymous" user is also available for humans who do not wish to identify themselves. The difference is that "anonymous" requires a login (using a password supplied via -a CAPTCHA) whereas "nobody" does not require a login. -The site administrator can also create logins with +a CAPTCHA) whereas "nobody" does not require a login. +The site administrator can also create logins with passwords for specific individuals. -The "h" or "hyperlink" capability is a permission that can be granted -to users that enables the display of hyperlinks. Most of the hyperlinks -generated by Fossil are suppressed if this capability is missing. So -one simple defense against spiders is to disable the "h" permission for -the "nobody" user. This means that users must log in (perhaps as -"anonymous") before they can see any of the hyperlinks. Spiders do not -normally attempt to log into websites and will therefore -not see most of the hyperlinks and will not try to walk the millions of -historical check-ins and diffs available on a Fossil-generated website. - -If the "h" capability is missing from user "nobody" but is present for -user "anonymous", then a message automatically appears at the top of each -page inviting the user to log in as anonymous in order to activate hyperlinks. - -Removing the "h" capability from user "nobody" is an effective means -of preventing spiders from walking a Fossil-generated website. But -it can also be annoying to humans, since it requires them to log in. -Hence, Fossil provides other techniques for blocking spiders which +Users without the [./caps/ref.html#h | Hyperlink] capability +do not see most Fossil-generated hyperlinks. This is +a simple defense against spiders, since [./caps/#ucat | the "nobody" +user category] does not have this capability by default. +Users must log in (perhaps as +"anonymous") before they can see any of the hyperlinks. A spider +that cannot log into your Fossil repository will be unable to walk +its historical check-ins, create diffs between versions, pull zip +archives, etc. by visiting links, because they aren't there. + +A text message appears at the top of each page in this situation to +invite humans to log in as anonymous in order to activate hyperlinks. + +Because this required login step is annoying to some, +Fossil provides other techniques for blocking spiders which are less cumbersome to humans. -

    Automatic hyperlinks based on UserAgent

    +

    Automatic Hyperlinks Based on UserAgent

    Fossil has the ability to selectively enable hyperlinks for users -that lack the "h" capability based on their UserAgent string in the +that lack the Hyperlink capability based on their UserAgent string in the HTTP request header and on the browsers ability to run Javascript. The UserAgent string is a text identifier that is included in the header of most HTTP requests that identifies the specific maker and version of the browser (or spider) that generated the request. Typical UserAgent @@ -62,14 +59,14 @@ The first two UserAgent strings above identify Firefox 19 and Internet Explorer 8.0, both running on Windows NT. The third example is the spider used by Google to index the internet. The fourth example is the "wget" utility running on OpenBSD. -Thus the first two UserAgent strings above identify the requestor -as human whereas the second two identify the requestor as a spider. +Thus the first two UserAgent strings above identify the requester +as human whereas the second two identify the requester as a spider. Note that the UserAgent string is completely under the control -of the requestor and so a malicious spider can forge a UserAgent +of the requester and so a malicious spider can forge a UserAgent string that makes it look like a human. But most spiders truly seem to desire to "play nicely" on the internet and are quite open about the fact that they are a spider. And so the UserAgent string provides a good first-guess about whether or not a request originates from a human or a spider. @@ -76,72 +73,76 @@ In Fossil, under the Admin/Access menu, there is a setting entitled "Enable hyperlinks for "nobody" based on User-Agent and Javascript". If this setting is enabled, and if the UserAgent string looks like a human and not a spider, then Fossil will enable hyperlinks even if -the "h" capability is omitted from the user permissions. This setting +the Hyperlink capability is omitted from the user permissions. This setting gives humans easy access to the hyperlinks while preventing spiders from walking the millions of pages on a typical Fossil site. But the hyperlinks are not enabled directly with the setting above. Instead, the HTML code that is generated contains anchor tags ("<a>") -without "href=" attributes. Then, javascript code is added to the +without "href=" attributes. Then, JavaScript code is added to the end of the page that goes back and fills in the "href=" attributes of the anchor tags with the hyperlink targets, thus enabling the hyperlinks. -This extra step of using javascript to enable the hyperlink targets +This extra step of using JavaScript to enable the hyperlink targets is a security measure against spiders that forge a human-looking -UserAgent string. Most spiders do not bother to run javascript and +UserAgent string. Most spiders do not bother to run JavaScript and so to the spider the empty anchor tag will be useless. But all modern -web browsers implement javascript, so hyperlinks will appears +web browsers implement JavaScript, so hyperlinks will show up normally for human users. -

    Further defenses

    +

    Further Defenses

    -Recently (as of this writing, in the spring of 2013) the Fossil server +Recently (as of this writing, in the spring of 2013) the Fossil server on the SQLite website ([http://www.sqlite.org/src/]) has been hit repeatedly -by Chinese spiders that use forged UserAgent strings to make them look -like normal web browsers and which interpret javascript. We do not +by Chinese spiders that use forged UserAgent strings to make them look +like normal web browsers and which interpret JavaScript. We do not believe these attacks to be nefarious since SQLite is public domain and the attackers could obtain all information they ever wanted to -know about SQLite simply by cloning the repository. Instead, we +know about SQLite simply by cloning the repository. Instead, we believe these "attacks" are coming from "script kiddies". But regardless of whether or not malice is involved, these attacks do present an unnecessary load on the server which reduces the responsiveness of the SQLite website for well-behaved and socially responsible users. For this reason, additional defenses against spiders have been put in place. -On the Admin/Access page of Fossil, just below the +On the Admin/Access page of Fossil, just below the "Enable hyperlinks for "nobody" based on User-Agent and Javascript" -setting, there are now two additional subsettings that can be optionally +setting, there are now two additional sub-settings that can be optionally enabled to control hyperlinks. -The first subsetting waits to run the -javascript that sets the "href=" attributes on anchor tags until after +The first sub-setting waits to run the +JavaScript that sets the "href=" attributes on anchor tags until after at least one "mouseover" event has been detected on the <body> element of the page. The thinking here is that spiders will not be simulating mouse motion and so no mouseover events will ever occur and hence the hyperlinks will never become enabled for spiders. -The second new subsetting is a delay (in milliseconds) before setting +The second new sub-setting is a delay (in milliseconds) before setting the "href=" attributes on anchor tags. The default value for this delay is 10 milliseconds. The idea here is that a spider will try to render the page immediately, and will not wait for delayed scripts to be run, thus will never enable the hyperlinks. -These two subsettings can be used separately or together. If used together, +These two sub-settings can be used separately or together. If used together, then the delay timer does not start until after the first mouse movement is detected. -

    The ongoing struggle

    +See also [./loadmgmt.md|Managing Server Load] for a description +of how expensive pages can be disabled when the server is under heavy +load. + +

    The Ongoing Struggle

    Fossil currently does a very good job of providing easy access to humans while keeping out troublesome robots and spiders. However, spiders and bots continue to grow more sophisticated, requiring ever more advanced defenses. This "arms race" is unlikely to ever end. The developers of Fossil will continue to try improve the spider defenses of Fossil so -check back from time to time for the latest releases and updates. +check back from time to time for the latest releases and updates. Readers of this page who have suggestions on how to improve the spider defenses in Fossil are invited to submit your ideas to the Fossil Users -mailing list: -[mailto:fossil-users@lists.fossil-scm.org | fossil-users@lists.fossil-scm.org]. +forum: +[https://fossil-scm.org/forum]. ADDED www/backoffice.md Index: www/backoffice.md ================================================================== --- /dev/null +++ www/backoffice.md @@ -0,0 +1,189 @@ +Backoffice +========== + +This is technical documentation about the internal workings of Fossil. +Ordinary Fossil users do not need to know about anything covered by this +document. The information here is intended for people who want to enhance +or extend the Fossil code, or who just want a deeper understanding of +the internal workings of Fossil. + +What Is The Backoffice +---------------------- + +The backoffice is a mechanism used by a +[Fossil server](./server/) to do low-priority +background work that is not directly related to the user interface. Here +are some examples of the kinds of work that backoffice performs: + + 1. Sending email alerts and notifications + 2. Sending out daily digests of email notifications + 3. Other background email handling chores + 4. Automatic syncing of peer repositories + 5. Repository maintenance and optimization + +(As of 2018-08-07, only items 1 and 2 have actually been implemented.) +The idea is that the backoffice handles behind-the-scenes work that does +not have tight latency requirements. + +When Backoffice Runs +-------------------- + +A backoffice process is usually launched automatically by a webpage +request. After each webpage is generated, Fossil checks to see if any +backoffice work needs to be done. If there is work to do, and no other +process is already assigned to do the work, then a new backoffice process +is started to do the work. + +This happens for every webpage, regardless of how that webpage is launched, +and regardless of the purpose of the webpage. This also happens on the +server for "[fossil sync](/help?cmd=sync)" and +[fossil clone](/help?cmd=clone)" commands which are implemented as +web requests - albeit requests that the human user never sees. +Web requests can arrive at the Fossil server via direct TCP/IP (for example +when Fossil is started using commands like "[fossil server](/help?cmd=server)") +or via [CGI](./server/any/cgi.md) or +[SCGI](./server/any/scgi.md) or via SSH. +A backoffice process might be started regardless of the origin of the +request. + +The backoffice is not a daemon. Each backoffice process runs for a short +while and then exits. This helps keep Fossil easy to manage, since there +are no daemons to start and stop. To upgrade Fossil to a new version, +you simply replace the older "fossil" executable with the newer one, and +the backoffice processes will (within a minute or so) start using the new +one. (Upgrading the executable on Windows is more complicated, since on +Windows it is not possible to replace an executable file that is in active +use. But Windows users probably already know this.) + +The backoffice is serialized and rate limited. No more than a single +backoffice process will be running at once, and backoffice runs will not +occur more frequently than once every 60 seconds. + +If a Fossil server is idle, then no backoffice processes will be running. +That means there are no extra processes sitting around taking up memory +and process table slots for seldom accessed repositories. +The backoffice is an on-demand system. +A busy repository will usually have a backoffice +running at all times. But an infrequently accessed repository will only have +backoffice processes running for a minute or two following the most recent +access. + +Manually Running The Backoffice +------------------------------- + +The automatic backoffice runs are sufficient for most installations. +However, the daily digest of email notifications is handled by the +backoffice. If a Fossil server can sometimes go more than a day without +being accessed, then the automatic backoffice will never run, and the +daily digest might not go out until somebody does visit a webpage. +If this is a problem, an administrator can set up a cron job to +periodically run: + +> fossil backoffice _REPOSITORY_ + +That command will cause backoffice processing to occur immediately. +Note that this is almost never necessary for an internet-facing +Fossil repository, since most repositories will get multiple accesses +per day from random robots, which will be sufficient to kick off the +daily digest emails. And even for a private server, if there is very +little traffic, then the daily digests are probably a no-op anyhow +and won't be missed. + +How Backoffice Is Implemented +----------------------------- + +The backoffice is implemented by the "backoffice.c" source file. + +Serialization and rate limiting is handled by a single entry in the +repository database CONFIG table named "backoffice". This entry is +called "the lease". The value of the lease +is a text string representing four integers, which +are respectively: + + 1. The process id of the "current" backoffice process + 2. The lease expiration time of the current backoffice process + 3. The process id of the "next" backoffice process + 4. The lease expiration time for the next backoffice process + +Times are expressed in seconds since 1970. A process id of zero means +"no process". Sometimes the process id will be non-zero even if there +is no corresponding process. Fossil knows how to figure out whether or +not a process still exists. + +You can print out a decoded copy of the current backoffice lease using +this command: + +> fossil test-backoffice-lease -R _REPOSITORY_ + +If a system has been idle for a long time, then there will be no +backoffice processes. (Either the process id entries in the lease +will be zero, or there will exist no process associated with the +process id.) When a new web request comes in, the system +sees that no backoffice process is active and so it kicks off a separate +process to run backoffice. + +The new backoffice process becomes the "current" process. It sets a +lease expiration time for itself to be 60 seconds in the future. +Then it does the backoffice processing and exits. Note that usually +the backoffice process will exit long before its lease expires. That +is ok. The lease is there to limit the rate at which backoffice processes +run. + +If a new backoffice process starts up and sees that the "current" lease has +yet to expire, the new process makes itself the "next" backoffice process +and sets its expiration time to be 60 seconds past the expiration time of +the "current" backoffice process. The "next" process then puts itself to +sleep until the "current" lease expires. After the "current" +lease expires and the "current" process has itself exited, then +the "next" process promotes itself to the new "current" process. It +sets the current lease expiration to be 60 seconds in the future, runs +whatever backoffice work is needed, then exits. + +If a new backoffice process starts up and finds that there is already +a "current" lease and a "next" process, it exits without doing anything. +This should happen only rarely, since the lease information is checked +prior to spawning the backoffice process, so a conflict will only happen +in a race. + +Because the "backoffice" entry of the CONFIG table is in the repository +database, access to the lease is serialized. The lease prevents more +than one backoffice process from running at a time. It prevents +backoffice processes from running more frequently than once every 60 seconds. +And, it guarantees (assuming processes are not killed out-of-band) that +every web request will be followed within 60 seconds by a backoffice +run. + +Debugging The Backoffice +------------------------ + +The backoffice should "just work". It should not require administrator +attention. However, if you suspect that something is not working right, +there are some debugging aids. + +We have already mentioned the command that shows the backoffice lease +for a repository: + +> fossil test-backoffice-lease -R _REPOSITORY_ + +Running that command every few seconds should show what is going on with +backoffice processing in a particular repository. + +There are also settings that control backoffice behavior. The +"backoffice-nodelay" setting prevents the "next" process from taking a +lease and sleeping. If "backoffice-nodelay" is set, that causes all +backoffice processes to exit either immediately or after doing whatever +backoffice works needs to be done. If something is going wrong and +backoffice leases are causing delays in webpage processing, then setting +"backoffice-nodelay" to true can work around the problem until the bug +can be fixed. The "backoffice-logfile" setting is the name of a log +file onto which is appended a short message everything a backoffice +process actually starts to do the backoffice work. This log file can +be used to verify that backoffice really is running, if there is any +doubt. The "backoffice-disable" setting prevents automatic backoffice +processing, if true. Use this to completely disable backoffice processing +that occurs automatically after each HTTP request. The "backoffice-disable" +setting does not affect the operation of the manual +"fossil backoffice" command. +Most installations should leave "backoffice-nodelay" and "backoffice-disable" +set to their default values of off and +leave "backoffice-logfile" unset or set to an empty string. Index: www/blame.wiki ================================================================== --- www/blame.wiki +++ www/blame.wiki @@ -18,16 +18,16 @@
  • Locate the check-in that contains the file that is to be annotated. Call this check-in C0.
  • Find all direct ancestors of C0. A direct ancestor is the closure of the primary parent of C0. Merged in branches are not part of the direct ancestors of C0. -
  • Prune the list of ancestors of C0 so that it contains only +
  • Prune the list of ancestors of C0 so that it contains only check-in in which the file to be annotated was modified.
  • Load the complete text of the file to be annotated from check-in C0. Call this version of the file F0.
  • Parse F0 into lines. Mark each line as "unchanged". -
  • For each ancestor of C0 on the pruned list (call the ancestor CX), +
  • For each ancestor of C0 on the pruned list (call the ancestor CX), beginning with the most recent ancestor and moving toward the oldest ancestor, do the following steps:
    1. Load the text for the file to be annotated as it existed in check-in CX. @@ -44,19 +44,19 @@

      3.0 Discussion and Notes

      The time-consuming part of this algorithm is step 6b - computing the diff from all historical versions of the file to the version of the file under analysis. For a large file that has many historical changes, this -can take several seconds. For this reason, the default +can take several seconds. For this reason, the default [/help?cmd=/annotate|/annotate] webpage only shows those lines that where changed by the 20 most recent modifications to the file. This allows the loop on step 6 to terminate after only 19 diffs instead of the hundreds or thousands of diffs that might be required for a frequently modified file. As currently implemented (as of 2015-12-12) the annotate algorithm does not -follow files across name changes. File name change information is +follow files across name changes. File name change information is available in the database, and so the algorithm could be enhanced to follow files across name changes by modifications to step 3. Step 2 is interesting in that it is [/artifact/6cb824a0417?ln=196-201 | implemented] using a [https://www.sqlite.org/lang_with.html#recursivecte|recursive common table expression]. ADDED www/blockchain.md Index: www/blockchain.md ================================================================== --- /dev/null +++ www/blockchain.md @@ -0,0 +1,32 @@ +# Fossil As Blockchain + +Fossil is a version control system built around blockchain. + +Wikipedia defines "blockchain" as + +> + "a growing list of records, called blocks, which are linked using + cryptography. Each block contains a cryptographic hash of the previous + block, a timestamp, and transaction data..." [(1)][] + + +By that definition, Fossil is clearly an implementation of blockchain. +The blocks are ["manifests" artifacts](./fileformat.wiki#manifest). +Each manifest has a SHA1 or SHA3 hash of its parent or parents, +a timestamp, and other transactional data. The repository grows by +adding new manifests onto the list. + +Some people have come to associate blockchain with cryptocurrency, however, +and since Fossil has nothing to do with cryptocurrency, the claim that +Fossil is built around blockchain is met with skepticism. The key thing +to note here is that cryptocurrency implementations like BitCoin are +built around blockchain, but they are not synonymous with blockchain. +Blockchain is a much broader concept. Blockchain is a mechanism for +constructing a distributed ledger of transactions. +Yes, you can use a distributed +ledger to implement a cryptocurrency, but you can also use a distributed +ledger to implement a version control system, and probably many other kinds +of applications as well. Blockchain is a much broader idea than +cryptocurrency. + +[(1)]: https://en.wikipedia.org/wiki/Blockchain DELETED www/branch01.gif Index: www/branch01.gif ================================================================== --- www/branch01.gif +++ /dev/null cannot compute difference between binary files ADDED www/branch01.graphml Index: www/branch01.graphml ================================================================== --- /dev/null +++ www/branch01.graphml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + 2 + + + + + + + + + + + 3 + + + + + + + + + + + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADDED www/branch01.svg Index: www/branch01.svg ================================================================== --- /dev/null +++ www/branch01.svg @@ -0,0 +1,228 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + 1 + + + + + + + 2 + + + + + + + 3 + + + + + + + 4 + + + + + + + + + DELETED www/branch02.gif Index: www/branch02.gif ================================================================== --- www/branch02.gif +++ /dev/null cannot compute difference between binary files ADDED www/branch02.graphml Index: www/branch02.graphml ================================================================== --- /dev/null +++ www/branch02.graphml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + 2 + + + + + + + + + + + 3 + + + + + + + + + + + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADDED www/branch02.svg Index: www/branch02.svg ================================================================== --- /dev/null +++ www/branch02.svg @@ -0,0 +1,247 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + 2 + + + + + + + 3 + + + + + + + 4 + + + + + + + + + DELETED www/branch03.gif Index: www/branch03.gif ================================================================== --- www/branch03.gif +++ /dev/null cannot compute difference between binary files ADDED www/branch03.graphml Index: www/branch03.graphml ================================================================== --- /dev/null +++ www/branch03.graphml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + 2 + + + + + + + + + + + 3 + + + + + + + + + + + 4 + + + + + + + + + + + 5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADDED www/branch03.svg Index: www/branch03.svg ================================================================== --- /dev/null +++ www/branch03.svg @@ -0,0 +1,303 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + 2 + + + + + + + 3 + + + + + + + 4 + + + + + + + 5 + + + + + + + + + + + + + DELETED www/branch04.gif Index: www/branch04.gif ================================================================== --- www/branch04.gif +++ /dev/null cannot compute difference between binary files ADDED www/branch04.graphml Index: www/branch04.graphml ================================================================== --- /dev/null +++ www/branch04.graphml @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + test + + + + + + + + + + + 1 + + + + + + + + + + + 2 + + + + + + + + + + + 3 + + + + + + + + + + + 4 + + + + + + + + + + + 5 + + + + + + + + + + + 7 + + + + + + + + + + + 8 + + + + + + + + + + + 10 + + + + + + + + + + + 6 + + + + + + + + + + + 9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADDED www/branch04.svg Index: www/branch04.svg ================================================================== --- /dev/null +++ www/branch04.svg @@ -0,0 +1,569 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + test + + + + + + + 1 + + + + + + + 2 + + + + + + + 3 + + + + + + + 4 + + + + + + + 5 + + + + + + + 7 + + + + + + + 8 + + + + + + + 10 + + + + + + + 6 + + + + + + + 9 + + + + + + + + + + + + + + + + + + + + + + + + + DELETED www/branch05.gif Index: www/branch05.gif ================================================================== --- www/branch05.gif +++ /dev/null cannot compute difference between binary files ADDED www/branch05.graphml Index: www/branch05.graphml ================================================================== --- /dev/null +++ www/branch05.graphml @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + test + + + + + + + + + + + 1 + + + + + + + + + + + 2 + + + + + + + + + + + 3 + + + + + + + + + + + 4 + + + + + + + + + + + 5 + + + + + + + + + + + 7 + + + + + + + + + + + 8 + + + + + + + + + + + 10 + + + + + + + + + + + 6 + + + + + + + + + + + 9 + + + + + + + + + + + branch=trunk +sym-trunk + + + + + + + + + + + branch=test +sym-test +bgcolor=blue +cancel=sym-trunk + + + + + + + + + + + sym-release-1.0 +closed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADDED www/branch05.svg Index: www/branch05.svg ================================================================== --- /dev/null +++ www/branch05.svg @@ -0,0 +1,730 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + test + + + + + + + 1 + + + + + + + 2 + + + + + + + 3 + + + + + + + 4 + + + + + + + 5 + + + + + + + 7 + + + + + + + 8 + + + + + + + 10 + + + + + + + 6 + + + + + + + 9 + + + + + + + branch=trunk + sym-trunk + + + + + + + branch=test + sym-test + bgcolor=blue + cancel=sym-trunk + + + + + + + sym-release-1.0 + closed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADDED www/branch06.graphml Index: www/branch06.graphml ================================================================== --- /dev/null +++ www/branch06.graphml @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + + + + + + + + + Varying User Views of Fossil Repository + Alan + Betty + Charlie + Darlene + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + 3 + + + + + + + + + + + future + + + + + + + + + + + 2 + + + + + + + + + + + 4 + + + + + + + + + + + 1 + + + + + + + + + + + 3 + + + + + + + + + + + future + + + + + + + + + + + 2 + + + + + + + + + + + 4 + + + + + + + + + + + 5 + + + + + + + + + + + 6 + + + + + + + + + + + 1 + + + + + + + + + + + 3 + + + + + + + + + + + future + + + + + + + + + + + 2 + + + + + + + + + + + 2 + + + + + + + + + + + 5 + + + + + + + + + + + 1 + + + + + + + + + + + future + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fork! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + goes offline + + + + + + + + + + + + + + + + + + + + + back online, +pushes 5, +pulls 3 & 4 + + + + + + + + + ADDED www/branch06.svg Index: www/branch06.svg ================================================================== --- /dev/null +++ www/branch06.svg @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Varying User Views of Fossil Repository + + + Alan + + + Betty + + + Charlie + + + Darlene + + + + + + + 1 + + + + + + + 3 + + + + + + + future + + + + + + + 2 + + + + + + + 4 + + + + + + + 1 + + + + + + + 3 + + + + + + + future + + + + + + + 2 + + + + + + + 4 + + + + + + + 5 + + + + + + + 6 + + + + + + + 1 + + + + + + + 3 + + + + + + + future + + + + + + + 2 + + + + + + + 2 + + + + + + + 5 + + + + + + + 1 + + + + + + + future + + + + + + + + + + + + + + + + + + + + + + + fork! + + + + + + + goes offline + + + + + back online, + pushes 5, + pulls 3 & 4 + + + Index: www/branching.wiki ================================================================== --- www/branching.wiki +++ www/branching.wiki @@ -1,35 +1,34 @@ Branching, Forking, Merging, and Tagging

      Background

      In a simple and perfect world, the development of a project would proceed -linearly, as shown in figure 1. +linearly, as shown in Figure 1.
      -
      +
      Figure 1
      Each circle represents a check-in. For the sake of clarity, the check-ins are given small consecutive numbers. In a real system, of course, the -check-in numbers would be 40-character SHA1 hashes since it is not possible +check-in numbers would be long hexadecimal hashes since it is not possible to allocate collision-free sequential numbers in a distributed system. But as sequential numbers are easier to read, we will substitute them for -the 40-character SHA1 hashes in this document. +the long hashes in this document. -The arrows in figure 1 show the evolution of a project. The initial +The arrows in Figure 1 show the evolution of a project. The initial check-in is 1. Check-in 2 is derived from 1. In other words, check-in 2 was created by making edits to check-in 1 and then committing those edits. We say that 2 is a child of 1 and that 1 is a parent of 2. Check-in 3 is derived from check-in 2, making 3 a child of 2. We say that 3 is a descendant of both 1 and 2 and that 1 and 2 are both ancestors of 3. - -

      DAGs

      +

      DAGs

      The graph of check-ins is a [http://en.wikipedia.org/wiki/Directed_acyclic_graph | directed acyclic graph] commonly shortened to DAG. Check-in 1 is the root of the DAG since it has no ancestors. Check-in 4 is a leaf of the DAG since @@ -36,105 +35,135 @@ it has no descendants. (We will give a more precise definition later of "leaf.") Alas, reality often interferes with the simple linear development of a project. Suppose two programmers make independent modifications to check-in 2. -After both changes are committed, the check-in graph looks like figure 2: +After both changes are committed, the check-in graph looks like Figure 2:
      -
      +
      Figure 2
      -The graph in figure 2 has two leaves: check-ins 3 and 4. Check-in 2 has +The graph in Figure 2 has two leaves: check-ins 3 and 4. Check-in 2 has two children, check-ins 3 and 4. We call this state a fork. Fossil tries to prevent forks. Suppose two programmers named Alice and Bob are each editing check-in 2 separately. Alice finishes her edits first and commits her changes, resulting in check-in 3. Later, when Bob -attempts to commit his changes, fossil verifies that check-in 2 is still +attempts to commit his changes, Fossil verifies that check-in 2 is still a leaf. Fossil sees that check-in 3 has occurred and aborts Bob's commit attempt with a message "would fork." This allows Bob to do a "fossil update" which pulls in Alice's changes, merging them into his own changes. After merging, Bob commits check-in 4 as a child of check-in 3. -The result is a linear graph as shown in figure 1. This is how CVS -works. This is also how fossil works in [./concepts.wiki#workflow | +The result is a linear graph as shown in Figure 1. This is how CVS +works. This is also how Fossil works in [./concepts.wiki#workflow | "autosync"] mode. But perhaps Bob is off-network when he does his commit, so he has no way of knowing that Alice has already committed her changes. Or, it could be that Bob has turned off "autosync" mode in Fossil. Or, maybe Bob just doesn't want to merge in Alice's changes before he has saved his own, so he forces the commit to occur using the "--allow-fork" -option to the fossil commit command. For any of these reasons, +option to the fossil commit command. For any of these reasons, two commits against check-in 2 have occurred and now the DAG has two leaves. So which version of the project is the "latest" in the sense of having the most features and the most bug fixes? When there is more than -one leaf in the graph, you don't really know. So we like to have -graphs with a single leaf. +one leaf in the graph, you don't really know, so we like to have +check-in graphs with a single leaf. -To resolve this situation, Alice can use the fossil merge command -to merge in Bob's changes in her local copy of check-in 3. Then she -can commit the results as check-in 5. This results in a DAG as shown -in figure 3. +Fossil resolves such problems using the check-in time on the leaves to +decide which leaf to use as the parent of new leaves. When a branch is +forked as in Figure 2, Fossil will choose check-in 4 as the parent for a +later check-in 5, but only if it has sync'd that check-in down +into the local repository. If autosync is disabled or the user is +off-network when that fifth check-in occurs, so that check-in 3 is the +latest on that branch at the time within that clone of the repository, +Fossil will make check-in 3 the parent of check-in 5! + +Fossil also uses a forked branch's leaf check-in timestamps when +checking out that branch: it gives you the fork with the latest +check-in, which in turn selects which parent your next check-in will be +a child of. This situation means development on that branch can fork +into two independent lines of development, based solely on which branch +tip is newer at the time the next user starts his work on it. Because +of this, we strongly recommend that you do not intentionally create +forks on long-lived shared working branches with "--allow-fork". (Prime +example: trunk.) + +Let us return to Figure 2. To resolve such situations before they can +become a real problem, Alice can use the fossil merge command to +merge Bob's changes into her local copy of check-in 3. Then she can +commit the results as check-in 5. This results in a DAG as shown in +Figure 3.
      -
      +
      Figure 3
      Check-in 5 is a child of check-in 3 because it was created by editing check-in 3. But check-in 5 also inherits the changes from check-in 4 by virtue of the merge. So we say that check-in 5 is a merge child of check-in 4 and that it is a direct child of check-in 3. -The graph is now back to a single leaf (check-in 5). +The graph is now back to a single leaf, check-in 5. -We have already seen that if fossil is in autosync mode then Bob would +We have already seen that if Fossil is in autosync mode then Bob would have been warned about the potential fork the first time he tried to commit check-in 4. If Bob had updated his local check-out to merge in Alice's check-in 3 changes, then committed, then the fork would have never occurred. The resulting graph would have been linear, as shown -in figure 1. Really the graph of figure 1 is a subset of figure 3. -Hold your hand over the check-in 4 circle of figure 3 and then figure -3 looks exactly like figure 1 (except that the leaf has a different check-in -number, but that is just a notational difference - the two check-ins have -exactly the same content). In other words, figure 3 is really a superset -of figure 1. The check-in 4 of figure 3 captures additional state which -is omitted from figure 1. Check-in 4 of figure 3 holds a copy -of Bob's local checkout before he merged in Alice's changes. That snapshot -of Bob's changes, which is independent of Alice's changes, is omitted from figure 1. -Some people say that the approach taken in figure 3 is better because it -preserves this extra intermediate state. Others say that the approach -taken in figure 1 is better because it is much easier to visualize a -linear line of development and because the merging happens automatically -instead of as a separate manual step. We will not take sides in that -debate. We will simply point out that fossil enables you to do it either way. - -

      Forking Versus Branching

      +in Figure 1. + +Realize that the graph of Figure 1 is a subset of Figure 3. Hold your +hand over the check-in 4 circle of Figure 3 and then Figure 3 looks +exactly like Figure 1, except that the leaf has a different check-in +number, but that is just a notational difference — the two check-ins +have exactly the same content. In other words, Figure 3 is really a +superset of Figure 1. The check-in 4 of Figure 3 captures additional +state which is omitted from Figure 1. Check-in 4 of Figure 3 holds a +copy of Bob's local checkout before he merged in Alice's changes. That +snapshot of Bob's changes, which is independent of Alice's changes, is +omitted from Figure 1. Some people say that the approach taken in +Figure 3 is better because it preserves this extra intermediate state. +Others say that the approach taken in Figure 1 is better because it is +much easier to visualize a linear line of development and because the +merging happens automatically instead of as a separate manual step. We +will not take sides in that debate. We will simply point out that +Fossil enables you to do it either way. + +

      The Alternative to Forking: Branching

      Having more than one leaf in the check-in DAG is called a "fork." This is usually undesirable and either avoided entirely, -as in figure 1, or else quickly resolved as shown in figure 3. +as in Figure 1, or else quickly resolved as shown in Figure 3. But sometimes, one does want to have multiple leaves. For example, a project might have one leaf that is the latest version of the project under development and another leaf that is the latest version that has been tested. When multiple leaves are desirable, we call this branching -instead of forking. +instead of forking: + +
      +Key Distinction: A branch is a named, intentional fork. +
      + +Forks may be intentional, but most of the time, they're accidental. + Figure 4 shows an example of a project where there are two branches, one for development work and another for testing.
      -
      +
      Figure 4
      -The hypothetical scenario of figure 4 is this: The project starts and +The hypothetical scenario of Figure 4 is this: The project starts and progresses to a point where (at check-in 2) it is ready to enter testing for its first release. In a real project, of course, there might be hundreds or thousands of check-ins before a project reaches this point, but for simplicity of presentation we will say that the project is ready after check-in 2. @@ -147,35 +176,160 @@ the bug fixes implemented by the testing team. So periodically, the changes in the test branch are merged into the dev branch. This is shown by the dashed merge arrows between check-ins 6 and 7 and between check-ins 9 and 10. -In both figures 2 and 4, check-in 2 has two children. In figure 2, +In both Figures 2 and 4, check-in 2 has two children. In Figure 2, we call this a "fork." In diagram 4, we call it a "branch." What is -the difference? As far as the internal fossil data structures are +the difference? As far as the internal Fossil data structures are concerned, there is no difference. The distinction is in the intent. -In figure 2, the fact that check-in 2 has multiple children is an -accident that stems from concurrent development. In figure 4, giving +In Figure 2, the fact that check-in 2 has multiple children is an +accident that stems from concurrent development. In Figure 4, giving check-in 2 multiple children is a deliberate act. So, to a good approximation, we define forking to be by accident and branching to be by intent. Apart from that, they are the same. - -

      Tags And Properties

      +Fossil offers two primary ways to create named, intentional forks, +a.k.a. branches. First: + +
      +    $ fossil commit --branch my-new-branch-name
      +
      + +This is the method we recommend for most cases: it creates a branch as +part of a checkin using the version in the current checkout directory +as its basis. (This is normally the tip of the current branch, though +it doesn't have to be. You can create a branch from an ancestor checkin +on a branch as well.) After making this branch-creating +checkin, your local working directory is switched to that branch, so +that further checkins occur on that branch as well, as children of the +tip checkin on that branch. + +The second, more complicated option is: + +
      +    $ fossil branch new my-new-branch-name trunk
      +    $ fossil update my-new-branch-name
      +    $ fossil commit
      +
      + +Not only is this three commands instead of one, the first of which is +longer than the entire simpler command above, you must give the second command +before creating any checkins, because until you do, your local working +directory remains on the same branch it was on at the time you issued +the command, so that the commit would otherwise put the new material on +the original branch instead of the new one. + +In addition to those problems, the second method is a violation of the +[https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it|YAGNI +Principle]. We recommend that you wait until you actually need the +branch and create it using the first command above. + +(Keep in mind that trunk is just another branch in Fossil. It is simply +the default branch name for the first checkin and every checkin made as +one of its direct descendants. It is special only in that it is Fossil's +default when it has no better idea of which branch you mean.) + + +

      Justifications For Forking

      + +The primary cases where forking is justified over branching are all when +it is done purely in software in order to avoid losing information: + +
        +
      1. By Fossil itself when two users check in children to the same + leaf of a branch, as in Figure 2. If the fork occurs because + autosync is disabled on one or both of the repositories or because + the user doing the check-in has no network connection at the moment + of the commit, Fossil has no way of knowing that it is creating a + fork until the two repositories are later synchronized.

      2. + +
      3. By Fossil when the cloning hierarchy is more + than 2 levels deep. +

        + [./sync.wiki|Fossil's synchronization protocol] is a two-party + negotiation; syncs don't automatically propagate up the clone tree + beyond that. Because of that, if you have a master repository and + Alice clones it, then Bobby clones from Alice's repository, a + check-in by Bobby that autosyncs with Alice's repo will not + also autosync with the master repo. The master doesn't get a copy of + Bobby's checkin until Alice separately syncs with the master. + If Carol cloned from the master repo and checks something in that + creates a fork relative to Bobby's check-in, the master repo won't + know about that fork until Alice syncs her repo with the master. + Even then, realize that Carol still won't know about the fork until + she subsequently syncs with the master repo. +

        + One way to deal with this is to just accept it as a fact of using a + [https://en.wikipedia.org/wiki/Distributed_version_control|Distributed + Version Control System] like Fossil. +

        + Another option, which we recommend you consider carefully, is to + make it a local policy that checkins be made only against the master + repo or one of its immediate child clones so that the autosync + algorithm can do its job most effectively; any clones deeper than + that should be treated as read-only and thus get a copy of the new + state of the world only once these central repos have negotiated + that new state. This policy avoids a class of inadvertent fork you + might not need to tolerate. Since [#bad-fork|forks on long-lived + shared working branches can end up dividing a team's development + effort], a team may easily justify this restriction on distributed + cloning.

      4. + +
      5. You've automated Fossil (e.g. with a shell script) and + forking is a possibility, so you write fossil commit + --allow-fork commands to prevent Fossil from refusing the + check-in because it would create a fork. It's better to write such + a script to detect this condition and cope with it (e.g. fossil + update) but if the alternative is losing information, you may + feel justified in creating forks that an interactive user must later + clean up with fossil merge commands.

      6. +
      + +That leaves only one case where we can recommend use of "--allow-fork" +by interactive users: when you're working on +a personal branch so that creating a dual-tipped branch isn't going to +cause any other user an inconvenience or risk forking the development. +Only one developer is involved, and the fork may be short-lived, so +there is no risk of [#bad-fork|inadvertently forking the overall development effort]. +This is a good alternative to branching when you just need to +temporarily fork the branch's development. It avoids cluttering the +global branch namespace with short-lived temporary named branches. + +There's a common generalization of that case: you're a solo developer, +so that the problems with branching vs forking simply don't matter. In +that case, feel free to use "--allow-fork" as much as you like. + + +

      Fixing Forks

      + +If your local checkout is on a forked branch, you can usually fix a fork +automatically with: + +
      +    $ fossil merge
      +
      + +Normally you need to pass arguments to fossil merge to tell it +what you want to merge into the current basis view of the repository, +but without arguments, the command seeks out and fixes forks. + + +

      Tags And Properties

      -Tags and properties are used in fossil to help express the intent, and +Tags and properties are used in Fossil to help express the intent, and thus to distinguish between forks and branches. Figure 5 shows the -same scenario as figure 4 but with tags and properties added: +same scenario as Figure 4 but with tags and properties added:
      -
      +
      Figure 5
      A tag is a name that is attached to a check-in. A -property is a name/value pair. Internally, fossil implements +property is a name/value pair. Internally, Fossil implements tags as properties with a NULL value. So, tags and properties really are much the same thing, and henceforth we will use the word "tag" to mean either a tag or a property. A tag can be a one-time tag, a propagating tag or a cancellation tag. @@ -188,16 +342,16 @@ is attached to a single check-in in order to either override a one-time tag that was previously placed on that same check-in, or to block tag propagation from an ancestor. The initial check-in of every repository has two propagating tags. In -figure 5, that initial check-in is check-in 1. The branch tag +Figure 5, that initial check-in is check-in 1. The branch tag tells (by its value) what branch the check-in is a member of. The default branch is called "trunk." All tags that begin with "sym-" are symbolic name tags. When a symbolic name tag is attached to a check-in, that allows you to refer to that check-in by its symbolic -name rather than by its 40-character SHA1 hash name. When a symbolic name +name rather than by its hexadecimal hash name. When a symbolic name tag propagates (as does the sym-trunk tag) then referring to that name is the same as referring to the most recent check-in with that name. Thus the two tags on check-in 1 cause all descendants to be in the "trunk" branch and to have the symbolic name "trunk." @@ -226,10 +380,156 @@ not make a graphical distinction between one-time and propagating tags.) The sym-release-1.0 tag means that check-in 9 can be referred to using the more meaningful name "release-1.0." The closed tag means that check-in 9 is a "closed leaf." A closed leaf is a leaf that should never have direct children. + +

      How Can Forks Divide Development Effort?

      + +[#dist-clone|Above], we stated that forks carry a risk that development +effort on a branch can be divided among the forks. It might not be +immediately obvious why this is so. To see it, consider this swim lane +diagram: + + +
      +
      +Figure 6 +
      + +This is a happy, cooperating team. That is an important restriction on +our example, because you must understand that this sort of problem can +arise without any malice, selfishness, or willful ignorance in sight. +All users on this diagram start out with the same view of the +repository, cloned from the same master repo, and all of them are +working toward their shared vision of a unified future. + +All users, except possibly Alan, start out with the same two initial +checkins in their local working clones, 1 & 2. It might be that Alan +starts out with only check-in 1 in his local clone, but we'll deal with +that detail later. + +It doesn't matter which branch this happy team is working on, only that +our example makes the most sense if you think of it as a long-lived shared +working branch like trunk. Each user makes +only one check-in, shaded light gray in the diagram. + +

      Step 1: Alan

      + +Alan sets the stage for this problem by creating a +fork from check-in 1 as check-in 3. How and why Alan did this doesn't +affect what happens next, though we will walk through the possible cases +and attempt to assign blame [#post-mortem|in the post mortem]. +For now, you can assume that Alan did this out of unavoidable ignorance. + +

      Step 2: Betty

      + +Because Betty's local clone is autosyncing with +the same upstream repository as Alan's clone, there are a number of ways +she can end up seeing Alan's check-in 3 as the latest on that branch: + +
        +
      1. The working check-out directory she's using at the moment was + on a different branch at the time Alan made check-in 3, so Fossil + sees that as the tip at the time she switches her working directory + to that branch with a fossil update $BRANCH command. (There is an + implicit autosync in that command, if the option was enabled at the + time of the update.)

      2. + +
      3. The same thing, only in a fresh checkout directory with a + fossil open $REPO $BRANCH command.

      4. + +
      5. Alan makes his check-in 3 while Betty has check-in 1 or 2 as + the tip in her local clone, but because she's working with an + autosync'd connection to the same upstream repository as Alan, on + attempting what will become check-in 4, she gets the "would fork" + message from fossil ci, so she dutifully updates her clone + and tries again, moving her work to be a child of the new tip, + check-in 3. (If she doesn't update, she creates a second + fork, which simply complicates matters beyond what we need here for + our illustration.)

      6. +
      + +For our purposes here, it doesn't really matter which one happened. All +that matters is that Alan's check-in 3 becomes the parent of Betty's +check-in 4 because it was the newest tip of the working branch at the +time Betty does her check-in. + +

      Step 3: Charlie

      + +Meanwhile, Charlie went offline after syncing +his repo with check-in 2 as the latest on that branch. When he checks +his changes in, it is as a child of 2, not of 4, because Charlie doesn't +know about check-ins 3 & 4 yet. He does this at an absolute wall clock +time after Alan and Betty made their check-ins, so when Charlie +comes back online and pushes his check-in 5 to the master repository and +learns about check-ins 3 and 4 during Fossil sync, Charlie inadvertently +revives the other side of the fork. + +

      Step 4: Darlene

      + +Darlene sees all of this, because she joins in +on the work on this branch after Alan, Betty, and Charlie made their +check-ins and pushed them to the master repository. She's taking one of +the same three steps as we [#bf-betty|outlined for Betty above]. +Regardless of her path to this view, it happens after Charlie pushed his +check-in 5 to the master repo, so Darlene sees that as the latest on the +branch, causing her work to be saved as a child of check-in 5, not of +check-in 4, as it would if Charlie didn't come back online and sync +before Darlene started work on that branch. + +

      Post Mortem

      + +The end result of all of this is that even though everyone makes only one check-in +and no one disables autosync without genuine need, +half of the check-ins end up on one side of the fork and half on +the other. + +A future user — his mother calls him Edward, but please call him Eddie — +can then join in on the work on this branch and end up on either side of +the fork. If Eddie joins in with the state of the repository as drawn +above, he'll end up on the top side of the fork, because check-in 6 is +the latest, but if Alan or Betty makes a seventh check-in to that branch +first, it will be as a child of check-in 4 since that's the version in +their local check-out directories. Since that check-in 7 will then be the latest, +Eddie will end up on the bottom side of the fork instead. + +In all of this, realize that neither side of the fork is obviously +"correct." Every participant was doing the right thing by their own +lights at the time they made their lone check-in. + +Who, then, is to blame? + +We can only blame the consequences of creating the fork on Alan if he +did so on purpose, as by passing "--allow-fork" when creating a check-in +on a shared working branch. Alan might have created it inadvertently by +going offline while check-in 1 was the tip of the branch in his local +clone, so that by the time he made his check-in 3, check-in 2 had +arrived at the shared parent repository from someone else. (Francine?) +When Alan rejoins the network and does an autosync, he learns about +check-in 2. Since his #3 is already checked into his local clone because +autosync was off or blocked, the sync creates an unavoidable fork. We +can't blame either Alan or Francine here: they were both doing the right +thing given their imperfect view of the state of the global situation. + +The same is true of Betty, Charlie, and Darlene. None of them tried to +create a fork, and none of them chose a side in this fork to participate +in. They just took Fossil's default and assumed it was correct. + +The only blame I can assign here is on any of these users who believed +forks couldn't happen before this did occur, and I blame them only for +their avoidable ignorance. (You, dear reader, have been ejected from +that category by reading this very document.) Any time someone can work +without getting full coordination from every other clone of the repo, +forks are possible. Given enough time, they're all but inevitable. This +is a general property of DVCSes, not just of Fossil. + +This sort of consequence is why forks on shared working branches are +bad, which is why [./concepts.wiki#workflow|Fossil tries so hard to avoid them], why it warns you +about it when they do occur, and why it makes it relatively [#fix|quick and +painless to fix them] when they do occur. +

      Review Of Terminology

      Branch
      @@ -250,22 +550,51 @@

      A branch point occurs when a check-in has two or more direct (non-merge) children in different branches. A branch point is similar to a fork, except that the children are in different branches.

      -Check-in 4 of figure 3 is not a leaf because it has a child (check-in 5) -in the same branch. Check-in 9 of figure 5 also has a child (check-in 10) +Check-in 4 of Figure 3 is not a leaf because it has a child (check-in 5) +in the same branch. Check-in 9 of Figure 5 also has a child (check-in 10) but that child is in a different branch, so check-in 9 is a leaf. Because of the closed tag on check-in 9, it is a closed leaf. -Check-in 2 of figure 3 is considered a "fork" -because it has two children in the same branch. Check-in 2 of figure 5 +Check-in 2 of Figure 3 is considered a "fork" +because it has two children in the same branch. Check-in 2 of Figure 5 also has two children, but each child is in a different branch, hence in -figure 5, check-in 2 is considered a "branch point." +Figure 5, check-in 2 is considered a "branch point."

      Differences With Other DVCSes

      + +

      Single DAG

      Fossil keeps all check-ins on a single DAG. Branches are identified with tags. This means that check-ins can be freely moved between branches simply by altering their tags. Most other DVCSes maintain a separate DAG for each branch. + +

      Branch Names Need Not Be Unique

      + +Fossil does not require that branch names be unique, as in some VCSes, +most notably Git. Just as with unnamed branches (which we call forks) +Fossil resolves such ambiguities using the timestamps on the latest +checkin in each branch. If you have two branches named "foo" and you say +fossil up foo, you get the tip of the "foo" branch with the most +recent checkin. + +This fact is helpful because it means you can reuse branch names, which +is especially useful with utility branches. There are several of these +in the SQLite and Fossil repositories: "broken-build," "declined," +"mistake," etc. As you might guess from these names, such branch names +are used in renaming the tip of one branch to shunt it off away from the +mainline of that branch due to some human error. (See fossil +amend and the Fossil UI checkin amendment features.) This is a +workaround for Fossil's [./shunning.wiki|normal inability to forget +history]: we usually don't want to actually remove history, but +would like to sometimes set some of it aside under a new label. + +Because some VCSes can't cope with duplicate branch names, Fossil +collapses such names down on export using the same time stamp based +arbitration logic, so that only the branch with the newest checkin gets +the branch name in the export. + +All of the above is true of tags in general, not just branches. Index: www/bugtheory.wiki ================================================================== --- www/bugtheory.wiki +++ www/bugtheory.wiki @@ -27,11 +27,11 @@ Recall that a fossil repository consists of an unordered collection of artifacts. (See the file format document for details.) Some artifacts have a special format, and among those are Ticket Change Artifacts. -One or more ticket change artifacts are associated with each +One or more ticket change artifacts are associated with each ticket. A ticket is created by a ticket change artifact. Each subsequent modification of the ticket is a separate artifact. The "push", "pull", and "sync" algorithms share ticket change artifacts between repositories in the same way as every other artifact. In fact, Index: www/build.wiki ================================================================== --- www/build.wiki +++ www/build.wiki @@ -1,16 +1,14 @@ Compiling and Installing Fossil

      0.0 Using A Pre-compiled Binary

      -

      Released versions of fossil come with -pre-compiled binaries and -a source archive for that release. You can thus skip the following if you -want to run or build a release version of fossil. Just download -the appropriate package from the downloads page +

      [/uv/download.html|Pre-compiled binaries] are available for recent +releases. Just download +the appropriate executable for your platform and put it on your $PATH. -To uninstall, simply delete the binary. +To uninstall, simply delete the executable. To upgrade from an older release, just overwrite the older binary with the newer one.

      0.1 Executive Summary

      @@ -29,20 +27,17 @@

      Fossil is self-hosting, so you can obtain a ZIP archive or tarball containing a snapshot of the latest version directly from Fossil's own fossil repository. Additionally, source archives of released versions of -fossil are available from the downloads page. +fossil are available from the [/uv/download.html|downloads page]. To obtain a development version of fossil, follow these steps:

        -
      1. Point your web browser to - -http://www.fossil-scm.org/.

      2. +
      3. Point your web browser to [https://www.fossil-scm.org/]

      4. -
      5. Click on the -Timeline +

      6. Click on the [/timeline|Timeline] link at the top of the page.

      7. Select a version of of Fossil you want to download. The latest version on the trunk branch is usually a good choice. Click on its link.

      8. @@ -78,17 +73,42 @@
        1. Unpack the ZIP or tarball you downloaded then cd into the directory created.

        2. +
        3. (Optional, Debian-compatible Linux only) +Make sure you have all the necessary tools and libraries at hand by running: +sudo apt install tcl-dev tk libssl-dev. +
        4. (Optional, Unix only) Run ./configure to construct a makefile.
          1. -If you do not have the OpenSSL library installed on your system, then -add --with-openssl=none to omit the https functionality. +The build system for Fossil on Unix-like systems assumes that the +OpenSSL development and runtime files are available on your system, +because unprotected repositories are trivial to attack otherwise. +Indeed, some public Fossil repositories — including Fossil's own — today +run in an HTTPS-only mode, so that you can't even do an anonymous clone +from them without using the TLS features added to Fossil by OpenSSL. To +weaken that stance could allow a +[https://en.wikipedia.org/wiki/Man-in-the-middle_attack|man in the +middle attack], such as one that substitutes malicious code into your +Fossil repository clone.

            + +

            You can force the Fossil build system to avoid searching for, building +against, and linking to the OpenSSL library by passing +--with-openssl=none to the configure script.

            + +

            If you do not have the OpenSSL development libraries on your system, +we recommend that you install them, typically via your OS's package +manager. The Fossil build system goes to a lot of effort to seek these +out wherever they may be found, so that is typically all you need to +do.

            + +

            For more advanced use cases, see the [./ssl.wiki#openssl-bin|OpenSSL +discussion in the "TLS and Fossil" document].

          2. To build a statically linked binary (suitable for use inside a chroot jail) add the --static option. @@ -113,11 +133,11 @@ want to make minor edits to Makefile.classic to configure the build for your system.

          3. MinGW 3.x (not 4.x) / MinGW-w64 → Use the MinGW makefile: "make -f win/Makefile.mingw". On a Windows box you will need either -Cygwin or Msys as build environment. On Cygwin, Linux or Darwin you may want +Cygwin or MSYS as build environment. On Cygwin, Linux or Darwin you may want to make minor edits to win/Makefile.mingw to configure the cross-compile environment. To enable the native [./th1.md#tclEval | Tcl integration feature], use a command line like the following (all on one line): @@ -141,11 +161,11 @@ the optional OpenSSL support, first download the official source code for OpenSSL and extract it to an appropriately named "openssl-X.Y.ZA" subdirectory within the local [/tree?ci=trunk&name=compat | compat] directory (e.g. -"compat/openssl-1.0.2j"), then make sure that some recent +"compat/openssl-1.1.1g"), then make sure that some recent Perl binaries are installed locally, and finally run one of the following commands:

             nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
             
            @@ -170,11 +190,11 @@

          3.0 Installing

            -
          1. +
          2. The finished binary is named "fossil" (or "fossil.exe" on Windows). Put this binary in a directory that is somewhere on your PATH environment variable. It does not matter where.

            @@ -209,5 +229,139 @@ TCC += -DWITHOUT_ICONV TCC += -Dsocketlen_t=int TCC += -DSQLITE_MAX_MMAP_SIZE=0 + +

            5.0 Building a Static Binary on Linux using Docker

            + +Building a static binary on Linux is not as straightforward as it +could be because the GNU C library requires that certain components be +dynamically loadable. That can be worked around by building against a +different C library, which is simplest to do by way of a container +environment like [https://www.docker.com/ | Docker]. + +The following instructions for building fossil using Docker +were adapted from [https://fossil-scm.org/forum/forumpost/5dd2d61e5f | forumpost/5dd2d61e5f]. +These instructions assume that docker is installed and that the user running +these instructions has permission to do so (i.e., they are root or +are a member of the docker group). + +First, create a file named Dockerfile with the following contents: + +
            
            +FROM    alpine:edge
            +RUN     apk update                                                                                      \
            +        && apk upgrade                                                                                  \
            +                                                                                                        \
            +        && apk add --no-cache                                                                           \
            +        curl gcc make tcl                                                                               \
            +        musl-dev                                                                                        \
            +        openssl-dev zlib-dev                                                                            \
            +        openssl-libs-static zlib-static                                                                 \
            +                                                                                                        \
            +        && curl                                                                                         \
            +        "https://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=trunk"    \
            +        -o fossil-src.tar.gz                                                                            \
            +                                                                                                        \
            +        && tar xf fossil-src.tar.gz                                                                     \
            +        && cd fossil-src                                                                                \
            +                                                                                                        \
            +        && ./configure                                                                                  \
            +        --static                                                                                        \
            +        --disable-fusefs                                                                                \
            +        --with-th1-docs                                                                                 \
            +        --with-th1-hooks                                                                                \
            +                                                                                                        \
            +        && make
            +
            + +Be sure to modify the configure flags, if desired. e.g., add --json +for JSON support. + +From the directory containing that file, build it with docker: + +
            # docker build -t fossil_static .
            + +If you get permissions errors when running that as a non-root user, +be sure to add the user to the docker group before trying +again. + +That creates a docker image and builds a static fossil binary inside +it. That step will take several minutes or more, depending on the +speed of the build environment. + +Next, create a docker container to host the image we just created: + +
            # docker create --name fossil fossil_static
            + +Then copy the fossil binary from that container: + +
            # docker cp fossil:/fossil-src/fossil fossil
            + +The resulting binary will be huge because it is built with +debug info. To strip that information, reducing the size greatly: + +
            # strip fossil
            + +To delete the Docker container and image (if desired), run: + +
            # docker container rm fossil
            +# docker image ls
            +
            + +Note the IDs of the images named fossil_static and alpine, then: + +
            docker image rm THE_FOSSIL_ID THE_ALPINE_ID
            + + +

            6.0 Building on/for Android

            + +

            6.1 Cross-compiling from Linux

            + +The following instructions for building Fossil for Andoid, +without requiring a rooted OS, are adapted from +[https://fossil-scm.org/forum/forumpost/e0e9de4a7e | forumpost/e0e9de4a7e]. + +On the development machine, from the fossil source tree: + +
            export CC=$NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi21-clang
            +./configure --with-openssl=none
            +make
            +
            + + +On the Android device, enable the USB debugging option from +Developer menu in Device Options. Connect the device to the development +system with USB. If it's configured and connected properly, +the device should show up in the output of adb devices: + +
            sudo adb devices
            +
            + +Copy the resulting fossil binary onto the device... + +
            sudo adb push fossil /data/local/tmp
            +
            + +And run it from an adb shell: + +
            sudo adb shell
            +> cd /data/local/tmp
            +# Fossil requires a HOME directory to work with:
            +> export HOME=$PWD
            +> export PATH=$PWD:$PATH
            +> fossil version
            +This is fossil version 2.11 [e5653a4ceb] 2020-03-26 18:54:02 UTC
            +
            + +The output might, or might not, include warnings such as: + +
            WARNING: linker: ./fossil: unused DT entry: type 0x6ffffef5 arg 0x1464
            +WARNING: linker: ./fossil: unused DT entry: type 0x6ffffffe arg 0x1ba8
            +WARNING: linker: ./fossil: unused DT entry: type 0x6fffffff arg 0x2
            +
            + +The source of such warnings is not 100% certain. +Some information about these (reportedly harmless) warnings can +be found +[https://stackoverflow.com/a/41900551 | on this StackOverflow post]. ADDED www/caps/admin-v-setup.md Index: www/caps/admin-v-setup.md ================================================================== --- /dev/null +++ www/caps/admin-v-setup.md @@ -0,0 +1,459 @@ +# Differences Between Setup and Admin User + +This document explains the distinction between [Setup users][caps] and +[Admin users][capa]. For other information about use types, see: + +* [Administering User Capabilities](./) +* [How Moderation Works](../forum.wiki#moderation) +* [Users vs Subscribers](../alerts.md#uvs) +* [Defense Against Spiders](../antibot.wiki) + + +## Philosophical Core + +The Setup user "owns" the Fossil repository and may delegate a subset of +that power to one or more Admin users. + +The Setup user can grant Admin capability and take it away, but Admin +users cannot grant themselves Setup capability, either directly via the +Admin → Users UI page or via any indirect means. (If you discover +indirect means to elevate Admin privilege to Setup, it's a bug, so +please [report it][forum]!) + +It is common for the Setup user to have administrative control over the +host system running the Fossil repository, whereas it makes no sense for +Admin users to have that ability. If an Admin-only user had `root` +access on a Linux box running the Fossil instance they are an Admin on, +they could elevate their capability to Setup in several ways. (The +`fossil user` command, the `fossil sql` command, editing the repository +DB file directly, etc.) Therefore, if you wish to grant someone +Setup-like capability on a Fossil repository but you're unwilling to +give them a login on the host system, you probably want to grant +them Admin capability instead. + +Admin power is delegated from Setup. When a Setup user grants Admin +capability, it is an expression of trust in that user's judgement. + +Admin-only users must not fight against the policies of the Setup user. +Such a rift would be just cause for the Setup user to strip the Admin +user's capabilities. This may then create a fork in the project’s +development effort as the ex-Admin takes their clone and stands it up +elsewhere, so they may become that fork’s Setup user. + +A useful rule of thumb here is that Admin users should only change +things that the Setup user has not changed from the stock configuration. +In this way, an Admin-only user can avoid overriding the Setup user's +choices. + +You can also look at the role of Admin from the other direction, up +through the [user power hierarchy][ucap] rather than down from Setup. An +Admin user is usually a “super-developer” role, given full control over +the repository’s managed content: versioned artifacts in [the block +chain][bc], [unversioned content][uv], forum posts, wiki articles, +tickets, etc. + +We’ll explore these distinctions in the rest of this document. + +[bc]: ../blockchain.md +[ucap]: ./index.md#ucap +[uv]: ../unvers.wiki + + +## No Granularity + +Fossil doesn’t make any distinction between these two user types beyond +this binary choice: Setup or Admin. + +A few features of Fossil are broken down so that only part of the +feature is accessible to Admin, with the rest left only to Setup users, +but for the most part each feature affected by this distinction is +either Admin + Setup or Setup-only. + +We could add more capability letters to break down individual +sub-features, but we’d run out of ASCII alphanumerics pretty quickly, +and we might even run out of ASCII punctuation and symbols. Then would +we need to shift to Unicode? + +Consider the Admin → Settings page, which is currently restricted to +Setup users only: you might imagine breaking this up into several +subsets so that some settings can be changed by Admin users. Is that a +good idea? Maybe, but it should be done only after due consideration. It +would definitely be wrong to assign a user capability bit to *each* +setting on that page. + +Now consider the opposite sort of case, Admin → Skins. Fossil grants +Admin users full access to this page so that the Admins can maintain and +extend the skin as the repository evolves, not so Admins can switch the +entire skin to another without consulting with the Setup user first. How +would Fossil decide, using user capabilities only, which skin changes +the Admin user is allowed to do, and which must be left to Setup? Do we +assign a separate capability letter to each step in `/setup_skin`? Do we +assign one more each to the five sections of a skin? (Header, Footer, +CSS, JavaScript, and Details.) It quickly becomes unmanageable. + + + +## Capability Groups + +We can break up the set of powers the Admin user capability grants into +several groups, then defend each group as a coherent whole. + + +### Security + +While establishing the Fossil repository's security policy is a task for +the Setup user, *maintaining* that policy is something that Fossil +allows a Setup user to delegate to trustworthy users via the Admin user +capability: + +* **Manage users**: The only thing an Admin-only user cannot do on the + Admin → Users page is grant Setup capability, either to themselves + or to other users. The intent is that Admin users be able to take + some of the load of routine user management tasks off the shoulders + of the Setup user: delete accounts created by spammers, fix email + alert subscriptions, reset passwords, etc. + +* **Security audit**: The Admin → Security-Audit page runs several + tests on the Fossil repository's configuration, then reports + potential problems it found and offers canned solutions. Those + canned solutions do not do anything that an Admin-user could not do + via other means, so this page offers the Admin-only user no more + power than they otherwise had. For example, this page's "Take it + Private" feature can also be done manually via Admin → Users. This + page is a convenience, not a grant of new power to the Admin-only + user. + +* **Logging**: Admin-only users get to see the various + Fossil logs in case they need to use them to understand a problem + they're empowered to solve. An obvious example is a spam attack: the + Admin might want to find the user's last-used IP, see if they cloned + the repository, see if they attempted to brute-force an existing + login before self-registering, etc. + +Some security-conscious people might be bothered by the fact that +Admin-only users have these abilities. Think of a large IT organization: +if the CIO hires a [tiger team][tt] to test the company's internal IT +defenses, the line grunts fix the reported problems, not the CIO. + + +### Administrivia + +It is perfectly fine for a Fossil repository to only have Setup users, +no Admin users. The smaller the repository, the more likely the +repository has no Admin-only users. If the Setup user neither needs nor +wants to grant Admin power to others, there is no requirement in Fossil +to do so. [Setup capability is a pure superset of Admin capability.][sia] + +As the number of users on a Fossil repository grows, the value in +delegating administrivia also grows, because the Setup user typically +has other time sinks they consider more important. + +Admin users can take over the following routine tasks on behalf of the +Setup user: + +* **Shunning**: After user management, this is one of the greatest + powers of an Admin-only user. Fossil grants access to the Admin → + Shunned page to Admin users rather than reserve it to Setup users + because one of the primary purposes of [the Fossil shunning + system][shun] is to clean up after a spammer, and that's + exactly the sort of administrivia we wish to delegate to Admin users. + + Coupled with the Rebuild button on the same page, an Admin user has + the power to delete the repository's entire + [blockchain][bc]! This makes this feature a pretty good + razor in deciding whether to grant someone Admin capability: do you + trust that user to shun Fossil artifacts responsibly? + + Realize that shunning is cooperative in Fossil. As long as there are + surviving repository clones, an Admin-only user who deletes the + whole blockchain has merely caused a nuisance. An Admin-only user + cannot permanently destroy the repository unless the Setup user has + been so silly as to have no up-to-date clones. + +* **Moderation**: According to the power hierarchy laid out at the top + of this article, Admins are greater than Moderators, so control over + what Moderators can do clearly belongs to both Admins and to the + Setup user(s). + +* **Status**: Although the Fossil `/stat` page is visible to every + user with Read capability, there are several additional things this + page gives access to when a user also has the Admin capability: + + *

            [Email alerts][ale] and [backoffice](../backoffice.md) + status. Admin-only users cannot modify the email alerts setup, + but they can see some details about its configuration and + current status.

            + + *

            The `/urllist` page, which is a read-only page showing the + ways the repository can be accessed and how it has been accessed + in the past. Logically, this is an extension to logging, + [covered above](#log).

            + + *

            The Fossil repository SQL schema. This is not particularly + sensitive information, since you get more or less the same + information when you clone the repository. It's restricted to + Admin because it's primarily useful in debugging SQL errors, + which happen most often when Fossil itself is in flux and the + schema isn't being automatically updated correctly. That puts + this squarely into the "administrivia" category.

            + + *

            Web cache status, environment, and logging: more + administrivia meant to help the Admin debug problems.

            + +* **Configure search** + +[ale]: ../alerts.md +[shun]: ../shunning.wiki + + +### Cosmetics + +While the Setup user is responsible for setting up the initial "look" of +a Fossil repository, the Setup user entrusts Admin users with +*maintaining* that look. An Admin-only user therefore has the following +special abilities: + +* Modify the repository skin + +* Create and modify URL aliases + +* Manage the "ad units" feature, if enabled. + +* Adjust the `/timeline` display preferences. + +* Change the "logo" element displayed by some skins. + +These capabilities allow an Admin-only user to affect the branding and +possibly even the back-end finances of a project. This is why we began +this document with a philosophical discussion: if you cannot entrust a +user with these powers, you should not grant that user Admin capability. + + +## Clones and Backups + +Keep in mind that Fossil is a *distributed* version control system, +which means that a user known to Fossil might have Setup capability on +one repository but be a mere "user" on one of its clones. The most +common case is that when you clone a repository, even anonymously, you +gain Setup power over the local clone. + +The distinctions above therefore are intransitive: they apply only +within a single repository instance. + +The exception to this is when the clone is done as a Setup user, since +this also copies the `user` table on the initial clone. A user with +Setup capability can subsequently say [`fossil conf pull all`][fcp] to +update that table and everything else not normally synchronized between +Fossil repositories. In this way, a Setup user can create multiple +interchangeable clones. This is useful not only to guard against rogue +Admin-only users, it is a useful element of a load balancing and +failover system. + + +## The All-Powerful Setup User + +Setup users get [every user capability](./ref.html) of Fossil except for +[two exceptionally dangerous capabilities](#dcap), which they can later +grant to themselves or to others. + +In addition, Setup users can use every feature of the Fossil UI. If Fossil can do a +thing, a Setup user on that repo can make Fossil do it. + +Setup users can do many things that Admin users cannot: + +* Use all of the Admin UI features +* See record IDs (RIDs) on screens that show them +* See the MIME type of attachments on [`/ainfo` pages](/help?cmd=/ainfo) +* See a remote repo’s HTTP [cache status](/help?cmd=/cachestat) + and [pull cache entries](/help?cmd=/cacheget) +* Edit a Setup user’s account! + +The “Admin” feature of Fossil UI is so-named because Admin users can use +about half of its functions, but only Setup can use these pages: + +* **Access**: This page falls under the [Security](#security) + category above, but like Configuration, it's generally something set + up once and never touched, so only Setup users should change it. + +* **Configuration**: This page nominally falls + under [Cosmetics](#cosmetics) above, but it's such a core part of the Fossil + configuration — something every Setup user is expected to fully + specify on initial repository setup — that we have trouble + justifying any case where an Admin-only user would have good cause + to modify any of it. This page is generally set up once and then + never touched again. + +* **Email-Server**: This is an experimental SMTP server feature which + is currently unused in Fossil. Should we get it working, it will + likely remain Setup-only, since it will likely be used as a + replacement for the platform’s default SMTP server, a powerful + position for a piece of software to take. + +* **Login-Group**: [Login groups][lg] allow one Fossil repository to + delegate user access to another. Since an Admin-only user on one + repo might not have such access to another repo on the same host + system, this must be a Setup-only task. + +* **Notification**: This is the main UI for setting up integration + with a platform’s SMTP service, for use in sending out [email + notifications][ale]. Because this screen can set commands to execute + on the host, and because finishing the configuration requires a + login on the Fossil host system, it is not appropriate to give Admin + users access to it. + +* **Settings**: The [repository settings][rs] available via Admin → + Settings have too wide a range of power to allow modification by + Admin-only users: + + *

            Harmless: Admin-only users on a repository may well + have checkin rights on the repository, so the fact that + versionable settings like `crlf-glob` can also be set at the + repository level seems like a thing we might want to allow + Admin-only users the ability to change. Since Fossil currently + has no way to allow only some settings to be changed by + Admin-only users and some not, we can't just show these harmless + settings to Admin-only users.

            + + *

            Low-Risk: The admin-log setting controls + whether the Fossil admin log is generated. Since we've already decided that Admin-only users can see + this log, it seems fine that the Admin users can choose whether + this log gets generated in the first place.

            + +

            There's a small risk that a rogue Admin user could disable + the log before doing something evil that the log would capture, + so ideally, we'd want to restrict changing this setting from 1 + to 0 to Setup only while allowing Admin-only users to change it + from 0 to 1. Fossil doesn't currently allow that.

            + + *

            Risky: The https-login setting falls under + the "Security" section above, but it should probably never be + adjusted by Admin-only users. Sites that want it on will never + want it to be disabled without a very good reason.

            + +

            There is also an inverse risk: if the site has a front-end + HTTPS proxy that uses HTTP to communicate over localhost to + Fossil, enabling this setting will create an infinite redirect + loop! (Ask me how I know.)

            + + *

            Dangerous: The email-send-command setting + could allow a rogue Admin to run arbitrary commands on the host + system, unless it's prevented via some kind of host-specific + restriction. (chroot, jails, SELinux, VMs, etc.) Since it makes + no sense to trust Admin-only users with root level + access on the host system, we almost certainly don't want to + allow them to change such settings.

            + +* **SQL**: The Admin → SQL feature allows the Setup user to enter raw + SQL queries against the Fossil repository via Fossil UI. This not + only allows arbitrary ability to modify the repository blockchain + and its backing data tables, it can probably also be used to damage + the host such as via `PRAGMA temp_store = FILE`. + +* **Tickets**: This section allows input of aribtrary TH1 code that + runs on the server, affecting the way the Fossil ticketing system + works. The justification in the **TH1** section below therefore + applies. + +* **TH1**: The [TH1 language][TH1] is quite restricted relative to the + Tcl language it descends from, so this author does not believe there + is a way to damage the Fossil repository or its host via the Admin → + TH1 feature, which allows execution of arbitrary TH1 code within the + repository's execution context. Nevertheless, interpreters are a + well-known source of security problems, so it seems best to restrict + this feature to Setup-only users as long as we lack a good reason + for Admin-only users to have access to it. + +* **Transfers**: This is for setting up TH1 hooks on various actions, + so the justification in the **TH1** section above applies. + +* **Wiki**: These are mainly cosmetic and usability settings. We might + open this up to Admin users in the future. + +Just remember, [user caps affect Fossil’s web interfaces only][webo]. A +user is a Setup user by default on their local clone of a repo, and +Fossil’s ability to protect itself against malicious (or even simply +incorrect) pushes is limited. Someone with clone and push capability on +your repo could clone it, modify their local repo, and then push the +changes back to your repo. Be careful who you give that combination of +capabilities to! + +When you run [`fossil ui`][fui], you are the Setup user on that repo +through that UI instance, regardless of the capability set defined in +the repo’s user table. This is true even if you cloned a remote repo +where you do not have Setup caps. This is why `ui` always binds to +`localhost` without needing the `--localhost` flag: in this mode, anyone +who can connect to that repo’s web UI has full power over that repo. + + +## Dangerous Capabilities Initially Denied to Everyone + +There are two capabilities that Fossil doesn’t grant by default to Setup +or Admin users automatically. They are exceptionally dangerous, so +Fossil makes these users grant themselves (or others) these capabilities +deliberately, hopefully after careful consideration. + + +### Write Unversioned + +Fossil currently doesn’t distinguish the sub-operations of [`fossil +uv`](/help?cmd=uv); they’re all covered by [**WrUnver**][capy] (“y”) +capability. Since some of these operations are unconditionally +destructive due to the nature of unversioned content, and since this +goes against Fossil’s philosophy of immutable history, nobody gets cap +“y” on a Fossil repo by default, not even the Setup or Admin users. A +Setup or Admin user must grant cap “y” to someone — not necessarily +themselves! — before modifications to remote +unversioned content are possible. + +Operations on unversioned content made without this capability affect +your local clone only. In this way, your local unversioned file table +can have different content from that in its parent repo. This state of +affairs will continue until your user either gets cap “y” and syncs that +content with its parent or you say `fossil uv revert` to make your local +unversioned content table match that of its parent repo. + + +### Private Branch Push + +For private branches to remain private, they must never be accidentally +pushed to a public repository. It can be [difficult to impossible][shun] +to recover from such a mistake, so nobody gets [**Private**][capx] (“x”) +capability on a Fossil repo by default, not even Admin or Setup users. + +There are two common uses for private branches. + +One use is part of a local social contract allowing individual +developers to work on some things in private until they’re ready to push +them up to the parent repository. This goes against [a core tenet][fdp] +of Fossil’s design philosophy, but Fossil allows it, so some development +organizations do this. If yours is one of these, you might give cap “x” +to the “developer” category. + +The other use is in development organizations that follow the Fossil +philosophy, where you do not work in private unless you absolutely must. +You may have a public-facing project — let’s call it “SQLite” for the +sake of argument — but then someone comes along and commissions a custom +modification to your project which they wish to keep proprietary. You +do your work on a private branch, which you absolutely must never push +to the public repo, because that would be illegal. (Breach of contract, +copyright violation on a work-for-hire agreement, etc.) If you are using +Fossil in this way, we recommend that you give “x” capability to a +special developer account only, if at all, to minimize the chance of an +accidental push. + + +[capa]: ./ref.html#a +[caps]: ./ref.html#s +[capx]: ./ref.html#x +[capy]: ./ref.html#y + +[fcp]: https://fossil-scm.org/fossil/help?cmd=configuration +[fdp]: ../fossil-v-git.wiki#devorg +[forum]: https://fossil-scm.org/forum/ +[fui]: /help?cmd=ui +[lg]: ./login-groups.md +[rs]: https://www.fossil-scm.org/index.html/doc/trunk/www/settings.wiki +[sia]: https://fossil-scm.org/fossil/artifact?udc=1&ln=1259-1260&name=0fda31b6683c206a +[snoy]: https://fossil-scm.org/forum/forumpost/00e1c4ecff +[tt]: https://en.wikipedia.org/wiki/Tiger_team#Security ADDED www/caps/impl.md Index: www/caps/impl.md ================================================================== --- /dev/null +++ www/caps/impl.md @@ -0,0 +1,111 @@ +# Implementation Details of User Capabilities + +## Capability Letter Choices + +We [assigned][ref] user capability characters using only lowercase ASCII +letters at first, so those are the most important within Fossil: they +control the functions most core to Fossil’s operation. Once we used up +most of the lowercase letters, we started using uppercase, and then +during the development of the [forum feature][for] we assigned most of +the decimal numerals. All of the lowercase ASCII letters are now +assigned. Eventually, we might have to start using ASCII +punctuation and symbols. We expect to run out of reasons to define new caps before +we’re forced to switch to Unicode, though the possibilities for [mnemonic][mn] +assignments with emoji are intriguing. 😉 + +The existing caps are usually mnemonic, especially among the +earliest and therefore most central assignments, made when we still had +lots of letters to choose from. There is still hope for good future +mnemonic assignments among the uppercase letters, which are mostly still +unused. + + +## Why Not Bitfields? + +Some may question the use of ASCII character strings for [capability +sets][ucap] instead of bitfields, which are more efficient, both in +terms of storage and processing time. + +Fossil handles these character strings in one of two ways. For most HTTP +hits, Fossil [expands][sexp] the string into a [`struct` full of +flags][sff] so that later code can just do simple Boolean tests. In a +minority of cases, where Fossil only needs to check for the presence of +a single flag, it just does a [`strchr()` call][sc] on the string +instead. + +Both methods are slower than bit testing in a bitfield, but keep the +execution context in mind: at the front end of an HTTP request handler, +where the nanosecond differences in such implementation details are +completely swamped by the millisecond scale ping time of that repo’s +network connection, followed by the required I/O to satisfy the request. +Either method is plenty fast in that context. + +In exchange for this immeasurable cost per hit, we get human-readable +capability sets. + + +## Why Doesn’t Fossil Filter “Bad” Artifacts on Sync? + +Fossil is more trusting about the content it receives from a remote +clone during sync than you might expect. Common manifestations of this +design choice are: + +1. A user may be able to impersonate other users. This can be + [accidental](./index.md#defuser) as well as purposeful. + +2. If your local system clock is out-of-sync with absolute time, + artifacts committed to that repo will appear with the “wrong” time + when sync’d. If the time sync error is big enough, it can make + check-ins appear to go back in time and other bad effects. + +3. You can purposely overwrite good timestamps with bad ones and push + those changes up to the remote with no interference, even though + Fossil tries to make that a Setup-only operation. + +All of this falls out of two of Fossil’s design choices: sync is +all-or-nothing, and [the Fossil block chain][bc] is immutable. Fossil +would have to violate one or both of these principles to filter such +problems out of incoming syncs. + +We have considered auto-[shunning][shun] “bad” content on sync, but this +is [difficult][asd] due to [the design of the sync protocol][dsp]. This +is not an impossible set of circumstances, but implementing a robust +filter on this input path would be roughly as difficult as writing a +basic [inter-frame video codec][ifvc]: do-able, but still a lot of +work. Patches to do this will be thoughtfully considered. + +We can’t simply change content as it arrives. Such manipulations would +change the artifact manifests, which would change the hashes, which +would require rewriting all parts of the block chain from that point out +to the tips of those branches. The local Fossil repo must then go +through the same process as the remote one on subsequent syncs in order +to build up a sync sequence that the remote can understand. Even if +you’re willing to accept all of that, this would break all references to +the old artifact IDs in forum posts, wiki articles, check-in comments, +tickets, etc. + +The bottom line here is that [**Clone**](./ref.html#g) and +[**Write**](./ref.html#i) are a potent combination of user capabilities. +Be careful who you give that pair to! + + +----- + +*[Back to Administering User Capabilities](./)* + + +
            + +[asd]: https://fossil-scm.org/forum/forumpost/ce4a3b5f3e +[bc]: ../blockchain.md +[dsp]: https://fossil-scm.org/fossil/doc/trunk/www/sync.wiki +[for]: ./forum.wiki +[ifvc]: https://en.wikipedia.org/wiki/Inter_frame +[mn]: https://en.wikipedia.org/wiki/Mnemonic +[ref]: ./ref.html +[sexp]: http://fossil-scm.org/fossil/artifact?udc=1&ln=1223-1298&name=889d6724 +[sff]: http://fossil-scm.org/fossil/artifact?udc=1&ln=80-117&name=52d2860f +[sc]: https://en.cppreference.com/w/c/string/byte/strchr +[shun]: ../shunning.wiki +[ucap]: ./index.md#ucap ADDED www/caps/index.md Index: www/caps/index.md ================================================================== --- /dev/null +++ www/caps/index.md @@ -0,0 +1,374 @@ +# Administering User Capabilities + +Fossil includes a powerful [role-based access control system][rbac] +which affects which users have which capabilities within a given +[served][svr] Fossil repository. We call this the capability system, or +“caps” for short. + +Fossil stores a user’s caps as an unordered string of ASCII characters, +one capability per, [currently](./impl.md#choices) limited to +[alphanumerics][an]. Caps are case-sensitive: “**A**” and “**a**” are +different user capabilities. + +This is a complex topic, so some sub-topics have their own documents: + +1. [Login Groups][lg] +2. [Implementation Details](./impl.md) +3. [User Capability Reference](./ref.html) + +[an]: https://en.wikipedia.org/wiki/Alphanumeric +[avs]: ./admin-v-setup.md +[lg]: ./login-groups.md +[rbac]: https://en.wikipedia.org/wiki/Role-based_access_control + + +## User Categories + +Before we explain individual user capabilities and their proper +administration, we want to talk about an oft-overlooked and +misunderstood feature of Fossil: user categories. + +Fossil defines four user categories. Two of these apply based on the +user’s login status: **nobody** and **anonymous**. The other two act +like Unix or LDAP user groups: **reader** and **developer**. Because we +use the word “group” for [another purpose][lg] in Fossil, we will +avoid using it that way again in this document. The correct term in +Fossil is “category.” + +Fossil user categories give you a way to define capability sets for four +hard-coded situations within the Fossil C source code. Logically +speaking: + +> *(developer* ∨ *reader)* ≥ *anonymous* ≥ *nobody* + +When a user visits a [served Fossil repository][svr] via its web UI, +they initially get the capabilities of the “nobody” user category. This +category would be better named “everybody” because it applies whether +you’re logged in or not. + +When a user logs in as “anonymous” via [`/login`](/help?name=/login) they +get all of the “nobody” category’s caps plus those assigned to the +“anonymous” user category. It would be better named “user” because it +affects all logged-in users, not just those logged in via Fossil’s +anonymous user feature. + +When a user with either the “reader” ([**u**][u]) or “developer” +([**v**][v]) capability letter logs in, they get their [individual user +caps](#ucap) plus those assigned to this special user category. They +also get those assigned to the “anonymous” and “nobody” categories. + +Because “developer” users do not automatically inherit “reader” caps, +it is standard practice to give both letters to your “developer” users: +**uv**. You could instead just assign cap **u** to the “developer” +category. + +Fossil shows how these capabilities apply hierarchically in the user +editing screen (Admin → Users → name) with the `[N]` `[A]` `[D]` `[R]` +tags next to each capability check box. If a user gets a capability from +one of the user categories already assigned to it, there is no value in +redundantly assigning that same cap to the user explicitly. For example, +with the default **ei** cap set for the “developer” category, the cap +set **ve** is redundant because **v** grants **ei**, which includes +**e**. + +We suggest that you lean heavily on these fixed user categories when +setting up new users. Ideally, your users will group neatly into one of +the predefined categories, but if not, you might be able to shoehorn +them into our fixed scheme. For example, the administrator of a +wiki-only Fossil repo for non-developers could treat the “developer” +user category as if it were called “author,” and a forum-only repo could +treat the same category as if it were called “member.” + +There is currently no way to define custom user categories. + +[svr]: ../server/ + + +## Individual User Capabilities + +When one or more users need to be different from the basic capabilities +defined in user categories, you can assign caps to individual users. You +may want to have the [cap reference][ref] open when doing such work. + +It is useful at this time to expand on the logical +expression [above](#cat), which covered only the four fixed user categories. +When we bring the individual user capabilities into it, the complete +expression of the way Fossil implements user power becomes: + +> *setup* ≥ *admin* ≥ *moderator* ≥ *(developer* ∨ *reader)* ≥ *[subscriber]* ≥ *anonymous* ≥ *nobody* + +The two additions at the top are clear: [setup is all-powerful][apsu], +and since admin users have [all capabilities][ref] except for Setup +capability, they are [subordinate only to the setup user(s)][avsp]. + +The moderator insertion could go anywhere from where it’s shown now down +to above the “anonymous” level, depending on what other caps you give to +your moderators. Also, there is not just one type of moderator: Fossil +has [wiki][l], [ticket][q], and [forum][5] moderators, each +independent of the others. Usually your moderators are fairly +high-status users, with developer capabilities or higher, but Fossil +does allow the creation of low-status moderators. + +The placement of “subscriber” in that hierarchy is for the +sort of subscriber who has registered an account on the repository +purely to [receive email alerts and announcements][7]. Users with +additional caps can also be subscribers, but not all users *are* in fact +subscribers, which is why we show it in square brackets. (See [Users vs +Subscribers](../alerts.md#uvs).) + +[apsu]: ./admin-v-setup.md#apsu +[avsp]: ./admin-v-setup.md#philosophy + + +## New Repository Defaults + +Fossil creates one user account in new repos, which is named after your +OS user name [by default](#defuser). + +Fossil gives the initial repository user the [all-powerful Setup +capability][apsu]. + +Users who visit a [served repository][svr] without logging in get the +“nobody” user category’s caps which default to +**[g][g][j][j][o][o][r][r][z][z]**: clone the repo, read the wiki, +check-out files via the web UI, view tickets, and pull version archives. +This default is suited to random passers-by on a typical FOSS project’s +public web site and its code repository. + +Users who [prove they are not a bot][bot] by logging in — even if only +as “anonymous” — get the “nobody” capability set plus +**[h][h][m][m][n][n][c][c]**: see internal hyperlinks, append to +existing wiki articles, file new tickets, and comment on existing +tickets. We chose these additional capabilities as those we don’t want +bots to have, but which a typical small FOSS project would be happy to +give anonymous humans visiting the project site. + +The “reader” user category is typically assigned to users who want to be +identified within the repository but who primarily have a passive role +in the project. The default capability set on a Fossil repo adds +**[k][k][p][p][t][t][w][w]** caps to those granted by “nobody” and +“anonymous”. This category is not well-named, because the default caps +are all about modifying repository content: edit existing wiki pages, +change one’s own password, create new ticket report formats, and modify +existing tickets. This category would be better named “participant”. + +Those in the “developer” category get the “nobody” and “anonymous” cap +sets plus **[e][e][i][i]**: view +sensitive user material and check in changes. + +[bot]: ../antibot.wiki + + +## Consequences of Taking a Repository Private + +When you click Admin → Security-Audit → “Take it private,” one of the +things it does is set the user capabilities for the “nobody” and +“anonymous” user categories to blank, so that users who haven’t logged +in can’t even see your project’s home page, and the option to log in as +“anonymous” isn’t even offered. Until you log in with a user name, all +you see is the repository’s skin and those few UI elements that work +without any user capability checks at all, such as the “Login” link. + +Beware: Fossil does not reassign the capabilities these users had to +other users or to the “reader” or “developer” user category! All users +except those with Setup capability will lose all capabilities they +inherited from “nobody” and “anonymous” categories. Setup is the [lone +exception][apsu]. + +If you will have non-Setup users in your private repo, you should parcel +out some subset of the capability set the “nobody” and “anonymous” +categories had to other categories or to individual users first. + + +## Reading vs. Cloning + +Fossil has two capabilities that are often confused: +[**Read**](./ref.html#o) and [**Clone**](./ref.html#g). + +The **Read** capability has nothing to do with reading data from a local +repository, because [caps affect Fossil’s web interfaces +only](#webonly). Once you’ve cloned a remote repository to your local +machine, you can do any reading you want on that repository irrespective +of whether your local user within that repo has Read capability. +The repo clone is completely under your user’s power at that point, +affected only by OS file permissions and such. If you need to prevent +that, you want to deny **Clone** capability instead. + +Withholding the **Read** capability has a different effect: it +prevents a web client from viewing [embedded +documentation][edoc], using [the file +browser](/help?name=/dir), and pulling file content via the +[`/artifact`](/help?name=/artifact), [`/file`](/help?name=/file), and +[`/raw`](/help?name=/raw) URLs. +It is is common to withhold **Read** capability from low-status visitors +on private or semi-private repos to prevent them from pulling individual +elements of the repo over the web one at a time, as someone may do when +denied the bulk **Clone** capability. + +[edoc]: ../embeddeddoc.wiki + + +## Default User Name + +By default, Fossil assumes your OS user account name is the same as the +one you use in any Fossil repository. It is the [default for a new +repository](#new), though you can override this with [the `--admin-user` +option][auo]. Fossil has other ways of overriding this in other contexts +such as the `name@` syntax in clone URLs. + +It’s simplest to stick with the default; a mismatch can cause problems. +For example, if you clone someone else’s repo anonymously, turn off +autosync, and make check-ins to that repository, they will be assigned +to your OS user name by default. If you later get a login on the remote +repository under a different name and sync your repo with it, your +earlier “private” check-ins will get synced to the remote under your OS +user name! + +When such problems occur, you can amend the check-in to hide the +incorrect name from Fossil reports, but the original values remain in +the repository [forever][shun]. It is [difficult enough][fos] to fix +such problems automatically during sync that we are unlikely to ever do +so. + +[auo]: /help?name=new +[fos]: ./impl.md#filter +[shun]: ../shunning.wiki + + + +## Cloning the User Table + +When cloning over HTTP, the initial user table in the local clone is set +to its “[new state:](#new)” only one user with Setup capability, named +after either your OS user account, per the default above, or after the +user given in the clone URL. + +There is one exception: if you clone as a named Setup user, you get a +complete copy of the user information. This restriction keeps the user +table private except for the only user allowed to make absolutely +complete clones of a remote repo, such as for failover or backup +purposes. Every other user’s clone is missing this and a few other +items, either for information security or PII privacy reasons. + +When cloning with file system paths, `file://` URLs, or over SSH, you +get a complete clone, including the parent repo’s complete user table. + +All of the above applies to [login groups][lg] as well. + + +## Caps Affect Web Interfaces Only + +User caps only affect Fossil’s [UI pages][wp], remote operations over +`http[s]://` URLs, and [the JSON API][japi]. + +User caps *do not* affect operations done on a local repo opened via a +`file://` URL or a file system path. This should strike you as sensible: +only local file permissions matter when operating on a local SQLite DB +file. The same is true when working on a clone done over such a path, +except that there are then two sets of file system permission checks: +once to modify the working check-out’s repo clone DB file, then again on +[sync][sync] with the parent DB file. The Fossil capability checks are +effectively defeated because your user has [**Setup**][s] capability on +both sides of the sync. + +What may surprise you is that user caps *also do not affect SSH!* When +you make a change to such a repository, the change first goes to the +local clone, where file system permissions are all that matter, but then +upon sync, the situation is effectively the same as when the parent repo +is on the local file system. If you can log into the remote system over +SSH and that user has the necessary file system permissions on that +remote repo DB file, it is the same situation as for `file://` URLs. + +All Fossil syncs are done over HTTP, even for `file://` and `ssh://` +URLs: + +* For `ssh://` URLs, Fossil pipes the HTTP conversation through a + local SSH client to a remote instance of Fossil running the + [`test-http`](/help?name=test-http) command to recieve the tunneled + HTTP connection without cap checks. The SSH client defaults to “`ssh + -e none -T`” on most platforms, except on Windows where it defaults + to “`plink -ssh -T`”. You can override this with [the `ssh-command` + setting](/help?name=ssh-command). + +* For `file://` URLs, the “sending” Fossil instance writes its side of + the HTTP conversation out to a temporary file in the same directory + as the local repo clone and then calls itself on the “receiving” + repository to read that same HTTP transcript file back in to apply + those changes to that repository. Presumably Fossil doesn’t do this + with a pipe to ease portability to Windows. + +Because both mechanisms work on local repos, the checks for capabilities +like [**Read**][o] and [**Write**][i] within the HTTP conversation for +such URLs can never return “false,” because you are the [**Setup**][s] +user on both sides of the conversation. Such checks only have a useful +effect when done over an `http[s]://` URL. + + +## Public Pages + +In Admin → Access, there is an option for giving a list of [globs][glob] +to name URLs which get treated as if the visitor had [the default cap +set](#defcap). For example, you could take the [**Read**][o] capability +away from the “nobody” user category, who has it by default, to prevent +users without logins from pulling down your repository contents one +artifact at a time, yet give those users the ability to read the project +documentation by setting the glob to match your [embedded +documentation][edoc]’s URL root. + + +## Default User Capability Set + +In Admin → Access, you can define a default user capability set, which +is used as: + +1. the default caps for users newly created by an Admin or Setup user +2. the default caps for self-registered users, an option in that same UI +3. the effective caps for URIs considered [public pages](#pubpg) + +This defaults to [**Reader**][u]. + + + +
            + +[ref]: ./ref.html + +[a]: ./ref.html#a +[b]: ./ref.html#b +[c]: ./ref.html#c +[d]: ./ref.html#d +[e]: ./ref.html#e +[f]: ./ref.html#f +[g]: ./ref.html#g +[h]: ./ref.html#h +[i]: ./ref.html#i +[j]: ./ref.html#j +[k]: ./ref.html#k +[l]: ./ref.html#l +[m]: ./ref.html#m +[n]: ./ref.html#n +[o]: ./ref.html#o +[p]: ./ref.html#p +[q]: ./ref.html#q +[r]: ./ref.html#r +[s]: ./ref.html#s +[t]: ./ref.html#t +[u]: ./ref.html#u +[v]: ./ref.html#v +[w]: ./ref.html#w +[x]: ./ref.html#x +[y]: ./ref.html#y +[z]: ./ref.html#z + +[2]: ./ref.html#2 +[3]: ./ref.html#3 +[4]: ./ref.html#4 +[5]: ./ref.html#5 +[6]: ./ref.html#6 +[7]: ./ref.html#7 + +[glob]: https://en.wikipedia.org/wiki/Glob_(programming) +[japi]: https://docs.google.com/document/d/1fXViveNhDbiXgCuE7QDXQOKeFzf2qNUkBEgiUvoqFN4/view#heading=h.6k0k5plm18p1 +[sp]: ../sync.wiki +[sync]: /help?name=sync +[wp]: /help#webpages ADDED www/caps/login-groups.md Index: www/caps/login-groups.md ================================================================== --- /dev/null +++ www/caps/login-groups.md @@ -0,0 +1,32 @@ +# Login Groups + +The Admin → Login-Groups UI feature and its corresponding [`login-group` +command][lg] solve a common problem with Fossil: you’ve created multiple +repositories that some set of users all need access to, those users all +have the same access level on all of these shared repositories, and you +don’t want to redundantly configure the user set for each repository. + +This feature ties changes to the “`user`” table in one repo to that in +one or more other repos. With this configured, you get a new choice on +the user edit screen, offering to make changes specific to the one +repository only or to apply it to all others in the login group as well. + +A user can log into one repo in a login group only if that user has an +entry in that repo’s user table. That is, setting up a login group +doesn’t automatically transfer all user accounts from the joined repo to +the joining repo. Only when a user exists by name in both repos will +that user be able to share credentials across the repos. + +Login groups can have names, allowing one “master” repo to host multiple +subsets of its users to other repos. + +Trust in login groups is transitive within a single server. If repo C +joined repo B and repo B joined A, changes in C’s user table affect both +A and B, if you tell Fossil that the change applies to all repos in the +login group. + +[lg]: /help?cmd=login-group + +----- + +*[Back to Administering User Capabilities](./)* ADDED www/caps/ref.html Index: www/caps/ref.html ================================================================== --- /dev/null +++ www/caps/ref.html @@ -0,0 +1,420 @@ +
            + + + +

            Here we document each currently-defined user capability character in +more detail than the brief summary on the “key” page in the Fossil user editor. Each +row gives the capability letter used in the Fossil user editor followed +by the C code’s name for that cap within the FossilUserPerms +object, so you can use this reference both from the UI down and from the +C code up.

            + +

            The mnemonics +given here vary from obviously-correct to post facto +rationalizations to the outright fanciful. To some extent, this is unavoidable.

            + + +

            Reference

            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
            ?NameDescription
            aAdmin + Admin users have all of the capabilities below except for + setup, Private, and WrUnver. + See Admin vs. Setup for a more + nuanced discussion. Mnemonic: administrate. +
            bAttach + Add attachments to wiki articles or tickets. Mnemonics: bind, + button, bond, or bolt. +
            cApndTkt + Append comments to existing tickets. Mnemonic: comment. +
            dn/a + Legacy capability letter from Fossil's forebear CVSTrac, which has no useful + meaning in Fossil due to its durable blockchain nature. This + letter was assigned by default to Developer in repos created with + Fossil 2.10 or earlier, but it has no effect in current or past + versions of Fossil; we recommend that you remove it in case we + ever reuse this letter for another purpose. See this + post for details. +
            eRdAddr + View personal + identifying information (PII) about other users such as email + addresses. Mnemonics: show email addresses; or + Europe, home of GDPR. +
            fNewWiki + Create new wiki articles. Mnemonic: fast, English + translation of the Hawaiian word wiki. +
            gClone + Clone the repository. Note that this is distinct from check-out capability, o. Mnemonic: + get. +
            hHyperlink + Get hyperlinks in generated HTML which link you to other parts of + the repository. This capability exists so we can deny it to the + “nobody” category, to prevent bots from + wandering around aimlessly in the site’s hyperlink web, chewing up server resources to little + good purpose. Mnemonic: hyperlink. +
            iWrite + Check changes into the repository. Note that a lack of this + capability does not prevent you from checking changes into your + local clone, only from syncing those changes up to the parent + repo, and then only over HTTP. + Granting this capability also grants o (Read) Mnemonics: + input, check in changes. +
            jRdWiki + View wiki articles. Mnemonic: injest page content. (All + right, you critics, you do better, then.) +
            kWrWiki + Edit wiki articles. Granting this capability also grants RdWiki and ApndWiki, + but it does not grant NewWiki! + Mnemonic: kontribute. +
            lModWiki + Moderate wiki article appends. Appends do not get + saved permanently to the receiving repo’s block chain until Setup or someone with this cap approves it. + Mnemonic: allow. +
            mApndWiki + Append content to existing wiki articles. Mnemonic: amend + wiki +
            nNewTkt + File new tickets. Mnemonic: new ticket. +
            oRead + Read repository content from a remote Fossil instance over + HTTP. See Reading vs. + Cloning. Mnemonic: check out remote repo contents. +
            pPassword + Change one’s own password. Mnemonic: password. +
            qModTkt + Moderate tickets: delete comments appended to tickets. Mnemonic: + quash noise commentary. +
            rRdTkt + View existing tickets. Mnemonic: read tickets. +
            sSetup + The all-powerful Setup user. + Mnemonics: setup or superuser. +
            tTktFmt + Create new ticket report formats. Note that although this allows + the user to provide SQL code to be run in the server’s context, + and this capability is given to the untrusted “anonymous” user + category by default, this is a safe capability to give to users + because it is internally restricted to read-only queries on the + tickets table only. (This restriction is done with a SQLite + authorization hook, not by any method so weak as SQL text + filtering.) Mnemonic: new ticket report. +
            un/a + Inherit all capabilities of the “reader” user category; does not + have a dedicated flag internally within Fossil. Mnemonic: + user +
            vn/a + Inherit all capabilities of the “developer” user category; does + not have a dedicated flag internally within Fossil. Mnemonic: + developer. +
            wWrTkt + Edit existing tickets. Granting this capability also grants RdTkt, ApndTkt, and + NewTkt. Mnemonic: write to ticket. +
            xPrivate + Push or pull private branches. + Mnemonic: exclusivity; “x” connotes unknown material in + many Western languages due to its traditional + use in mathematics. +
            yWrUnver + Push unversioned content. Mnemonic: + yield, sense + 4: “hand over.” +
            zZip + Pull archives of particular repository versions via /zip, /tarball, and /sqlar URLs. This is an + expensive capability to grant, because creating such archives can + put a large load on a Fossil server which + you may then need to manage. + Mnemonic: zip file download. +
            2RdForum + Read forum posts by other users. + Mnemonic: from thee 2 me. +
            3WrForum + Create new forum threads, reply to threads created by others, and + edit one’s own posts. New posts are held for moderation and do + not appear in repo clones or syncs. Granting this capability also + grants RdForum. Mnemonic: post for + 3 audiences: me, the mods, and the Man. +
            4WrTForum + Extends WrForum, bypassing the moderation + and sync restrictions. Mnemonic: post 4 immediate release. +
            5ModForum + Moderate forum posts. + Granting this capability also grants WrTForum and RdForum, + so a user with this cap never has to moderate their own posts. + Mnemonic: “May I have 5 seconds of your time, honored + Gatekeeper?” +
            6AdminForum + Users with this capability see a checkbox on unmoderated forum + posts labeled “Trust user X so that future posts by user X do not + require moderation.” Checking that box and then clicking the + moderator-only “Approve” button on that post grants WrTForum capability to that post’s author. + There is currently no UI for a user with this cap to + revoke trust from a user once it is granted; only Admin and Setup can + currently revoke granted caps. Granting this capability also + grants ModForum and those it in turn + grants. Mnemonic: “I’m 6 [sick] of hitting Approve on your + posts!” +
            7EmailAlert + User can sign up for email alerts. + Mnemonic: Seven can + wait, I’ve got email to read now. +
            AAnnounce + Send email announcements to users signed up to + receive them. Mnemonic: announce. +
            DDebug + Enable debugging features. Mnemonic: debug. +
            + +
            + + ADDED www/cgi.wiki Index: www/cgi.wiki ================================================================== --- /dev/null +++ www/cgi.wiki @@ -0,0 +1,145 @@ +CGI Script Configuration Options + +

            Summary

            + +It is not necessary to have a central server in order to use Fossil. +But a central server can help a project run more smoothly by giving developers +a common point of rendezvous for syncing, and by providing a web-based +portal where developers and non-developers alike can learn about the +project and its current state. + +Setting up a server using Fossil is easy. +A [./server/|separate document] talks about all of the many different methods for +setting up a Fossil server, one of which is [./server/any/cgi.md | as a CGI +script]. CGI is the technique that the three +[./selfhost.wiki|self-hosting Fossil repositories] all use. + +Setting up a Fossil server using CGI is mostly about writing a short +script (usually just 2 lines line) in the cgi-bin folder of an ordinary +web-server. But there are a lot of extra options that can be added +to this script, to customize the configuration. This article describes +those options. + +

            CGI Script Options

            + +The CGI script used to launch a Fossil server will usually look something +like this: + +
            +#!/usr/bin/fossil +repository: /home/www/fossils/myproject.fossil +
            + +Of course, pathnames will likely be different. The first line (the "shebang") +always gives the name of the Fossil executable. Subsequent lines are of +the form "property: argument ...". +The remainder of this document describes the available properties and +their arguments. + +
            +

            repository: PATH

            + +This property defines the Fossil repository that the server will use. +Every Fossil CGI requires either this property or the +[#directory|directory:] property (but not both). +Many Fossil repository sets have this one property and no other. + +

            directory: PATH

            + +The PATH is the name of a directory that contains one or more Fossil +repository files having the suffix ".fossil". If this property is used +instead of [#repository|repository:], then the Fossil server is +able to serve all of the repositories in the directory. The specific +repository used is selected by a prefix on the PATH_INFO. + + +

            errorlog: FILENAME

            + +This setting causes the server to log any errors in FILENAME. +It is ok for multiple Fossil CGIs to share the same error log. + +Setting up an error log for Fossil servers is not required, but it +is recommended. + +

            notfound: URL

            + +If the [#directory|directory:] option is used and if the PATH_INFO +of the HTTP request does not correspond to any Fossil repository, then +the request redirects to URL. + +

            repolist

            + +This is a Boolean property. +If it is present, and if the [#directory:|directory:] option is used, +and if the PATH_INFO string is empty, then Fossil will show a list +of available Fossil repositories. + +The "skin" of the reply is determined by the first +repository in the list that has a non-zero +[/help?cmd=repolist-skin|repolist-skin] setting. +If no repository has such a non-zero repolist-skin setting, then +the repository list is generic HTML without any decoration. + +

            extroot: PATH

            + +This property defines the DOCUMENT_ROOT for the +[./serverext.wiki|CGI Server Extensions]. If this property +is present, then CGI Server Extensions are enabled. When this +property is omitted, CGI Server Extensions are disabled. + +A cascade of CGI invocations can occur here. Fossil itself is +started as CGI, then Fossil can turn around and invoke a sub-CGI +extension. The sub-CGI extension outputs reply text, when Fossil +then (optionally) augments with its own header and footer and returns +to the original requestor. The property controls the DOCUMENT_ROOT +of the sub-CGI. + +

            timeout: N

            + +This property changes the timeout on each CGI request to N seconds. +If N is zero, then there is no timeout. If this property is omitted, +then the default timeout is 300 seconds (5 minutes). + +

            localauth

            + +This is a Boolean property. +If it is present, [./caps/ref.html#s | setup capability] +is granted to any HTTP request that +comes in over a loopback interface, such as 127.0.0.1. +If the PATH_INFO string is empty, Fossil will show a list +of available Fossil repositories. + +

            skin: NAME

            + +If NAME is the name of one of the built-in skins supported by Fossil, +then this option causes Fossil to display using that built-in skin, +and to ignore any custom skin that might be configured in the repository +itself. + +So, if you wanted to set up a server for a single Fossil project, but +also give users the option to use several of the different built-in +skins, you could create multiple CGI scripts, each with a different +"skin:" property, but all pointing to the same repository:. +Then users can select which skin to use by using the appropriate CGI. + +

            files: GLOBLIST

            + +The GLOBLIST argument is a comma-separate list of "globs" that specify +filenames. In [#directory|directory: mode], if the PATH_INFO +does not identify any Fossil repository, but it does refer some other +file in the directory, and that filename matches one of the glob patterns +in the GLOBLIST, then the file is returned as static content. + +

            setenv: NAME VALUE

            + +This parameter causes additional environment variable NAME to have VALUE. +This parameter can be repeated as many times as necessary. + +

            HOME: PATH

            + +This parameter is a short-hand for "setenv HOME PATH". + +

            cgi-debug: FILE

            + +Cause CGI-related debugging information to be appended in FILE. Use +this to help debug CGI problems. Index: www/changes.wiki ================================================================== --- www/changes.wiki +++ www/changes.wiki @@ -1,23 +1,560 @@ Change Log -

            Changes for Version 1.36 (2016-00-00)

            + +

            Changes for Version 2.12 (pending)

            + + * Security fix in the "fossil git export" command. New "safety-nets" + added to prevent future problems. + * Enhancements to the graph display for cases when there are + many merges into a single check-in. + [/info/2d75e87b760c0a9?diff=0|Example] + * The markdown-to-html translator can prevent unsafe HTML + (for example: <script>) on user pages like forum and + tickets and wiki, at the administrators option. On by + default. + [https://www.fossil-scm.org/forum/forumpost/3714e6568f|Example]. + * Enhance the [/help?cmd=revert|fossil revert] command so that it + is able to revert all files beneath a directory. + * Added --reset flag to the "[/help?cmd=add|fossil add]", + "[/help?cmd=rm|fossil rm]", and + "[/help?cmd=addremove|fossil addremove]" commands. + * Editing forum posts now applies delta compression to the edits. + * Added the [/help?cmd=/fileedit|/fileedit page], which allows + editing of text files online. Requires explicit activation by + a setup user. + * Update the built-in SQLite so that the + "[/help?cmd=sql|fossil sql]" command supports new output + modes ".mode box" and ".mode json". + * Delta compression now applied to forum edits. + + +

            Changes for Version 2.11 (2020-05-25)

            + + * Support [/md_rules|Markdown] in the default ticket configuration. + * Timestamp strings in [./checkin_names.wiki|object names] + can now omit punctation. So, for example, "202004181942" and + "2020-04-18 19:42" mean the same thing. + * Enhance backlink processing so that it works with Markdown-formatted + tickets and so that it works for wiki pages. + Ticket [a3572c6a5b47cd5a]. +
            • "[/help?cmd=rebuild|fossil rebuild]" is needed to + take full advantage of this fix. Fossil will continue + to work without the rebuild, but the new backlinks will be missing.
            + * The algorithm for finding the + [./tech_overview.wiki#configloc|location of the configuration database] + is enhanced to be XDG-compliant. + * Add a hide/show feature to + [./wikitheory.wiki#assocwiki|associated wiki] display on + check-in and branch information pages. + * Enhance the "[/help?cmd=info|fossil info]" command so that it + works with no arguments even if not within an open check-out. + * Many improvements to the forum and especially email notification + of forum posts, in response to community feedback after switching + SQLite support from a mailing list over to the forum. + * Minimum length of a self-registered user ID increased from 3 to 6 + characters. + * When the "vfx" query parameter is used on the + "[/help?cmd=/timeline|/timeline]" page, it causes the complete + text of forum posts to be displayed. + * Rework the "[/help?cmd=grep|fossil grep]" command to be more useful. + * Expose the [/help?cmd=redirect-to-https|redirect-to-https] + setting to the [/help?cmd=settings|settings] command. + * Improve support for CGI on IIS web servers. + * The [./serverext.wiki|/ext page] can now render index files, + in the same way as the embedded docs. + * Most commands now support the Unix-conventional "--" + flag to treat all following arguments as filenames + instead of flags. + * Added the [/help?cmd=mimetypes|mimetypes config setting] + (versionable) to enable mimetype overrides and custom definitions. + * Add an option on the /Admin/Timeline setup page to set a default + timeline style other than "Modern". + * In [./embeddeddoc.wiki|embedded documentation], hyperlink URLs + of the form "/doc/$CURRENT/..." the "$CURRENT" text is translated + into the check-in hash for the document currently being viewed. + * Added the [/help?cmd=/phantoms|/phantoms] webpage that shows all + phantom artifacts. + * Enhancements to phantom processing to try to reduce + bandwidth-using chatter about phantoms on the sync protocol. + * Security: Fossil now assumes that the schema of every + database it opens has been tampered with by an adversary and takes + extra precautions to ensure that such tampering is harmless. + * Security: Fossil now puts the Content-Security-Policy in the + HTTP reply header, in addition to also leaving it in the + HTML <head> section, so that it is always available, even + if a custom skin overrides the HTML <head> and omits + the CSP in the process. + * Output of the [/help?cmd=diff|fossil diff -y] command automatically + adjusts according to the terminal width. + * The Content-Security-Policy is now set using the + [/help?cmd=default-csp|default-csp setting]. + * Merge conflicts caused via the [/help?cmd=merge|merge] and + [/help?cmd=update|update] commands no longer leave temporary + files behind unless the new --keep-merge-files flag + is used. + * The [/help?cmd=/artifact_stats|/artifact_stats page] is now accessible + to all users if the new "artifact_stats_enable" setting is turned + on. There is a new checkbox under the /Admin/Access menu to turn + that capability on and off. + * Add the [/help?cmd=tls-config|fossil tls-config] command for viewing + the TLS configuration and the list of SSL Cert exceptions. + * Captchas all include a button to read the captcha using an audio + file, so that they can be completed by the visually impaired. + * Stop using the IP address as part of the login cookie. + * Bug fix: fix the SSL cert validation logic so that if an exception + is allowed for particular site, the exception expires as soon as the + cert changes values. + * Bug fix: the FTS search into for forum posts is now kept up-to-date + correctly. + * Bug fix: the "fossil git export" command is now working on Windows + * Bug fix: display Technote items on the timeline correctly + * Bug fix: fix the capability summary matrix of the Security Audit + page so that it does not add "anonymous" capabilities to the + "nobody" user. + * Update internal Unicode character tables, used in regular expression + handling, from version 12.1 to 13. + * Many documentation enhancements. + * Many minor enhancements to existing features. + + +

            Changes for Version 2.10 (2019-10-04)

            + + * Added support for [./serverext.wiki|CGI-based Server Extensions]. + * Added the [/help?cmd=repolist-skin|repolist-skin] setting used to + add style to repository list pages. + * Enhance the hierarchical display of Forum threads to do less + indentation and to provide links back to the previous message + in the thread. Provide sequential numbers for all messages in + a forum thread. + * Add support for fenced code blocks and improved hyperlink + processing to the [/md_rules|markdown formatter]. + * Add support for hyperlinks to wiki pages in the + [/md_rules|markdown formatter]. + * Enhance the [/help?cmd=/stat|/stat] page so that it gives the + option to show a breakdown of forum posts. + * The special check-in name "merge-in:BRANCH" means the source of + the most recent merge-in from the parent branch of BRANCH. + * Add hyperlinks to branch-diffs on the /info page and from + timelines of a branch. + * Add graphical context on the [/help?cmd=/vdiff|/vdiff] page. + * Uppercase query parameters, POST parameters, and cookie names are + converted to all lowercase and entered into the parameter set, + instead of being discarded. + * Change the default [./hashpolicy.wiki|hash policy] to SHA3. + * Timeout [./server/any/cgi.md|CGI requests] after 300 seconds, or + some other value set by the + [./cgi.wiki#timeout|"timeout:" property] in the CGI script. + * The check-in lock interval is reduced from 24 hours to 60 seconds, + though the interval is now configurable using a setting. + An additional check for conflicts is added after interactive + check-in comment entry, to compensate for the reduced lock interval. + * Performance optimizations. + * Many documentation improvements. + + +

            Changes for Version 2.9 (2019-07-13)

            + + * Added the [/help?cmd=git|fossil git export] command and instructions + for [./mirrortogithub.md|creating a GitHub mirror of a Fossil project]. + * Improved handling of relative hyperlinks on the + [/help?cmd=/artifact|/artifact] pages for wiki. For example, + hyperlinks and the lizard <img> now work correctly + for both [/artifact/2ff24ab0887cf522] and + [/doc/0d7ac90d575004c2415/www/index.wiki]. + * Enhancements to the timeline graph layout, to show more information + with less clutter. + * Added tool-tips to the /timeline graph. On by default but can be + disabled by setting the "Tooltip dwell time" to 0 in the timeline + configuration. + * Copy buttons added to various check-in hash and branch name links. + * Double-clicking on a /timeline graph node now jumps to the /info page + for the check-in. So, repurpose the timestamp hyperlink to show all + activity around that check-in in time. + * Added the [/help?cmd=touch|fossil touch] command, and the --setmtime + option on the [/help?cmd=open|fossil open] and + [/help?cmd=update|fossil update] commands. + * Many documentation enhancements. + * For the "[/help?cmd=update|fossil update]" and + "[/help?cmd=checkout|fossil checkout]" commands, if a + managed file is removed because it is no longer part of the target + check-in and the directory containing the file is empty after the + file is removed and the directory is not the current working + directory and is not on the [/help?cmd=empty-dirs|empty-dirs] + list, then also remove the directory. + * Update internal Unicode character tables, used in regular expression + handling, from version 11.0 to 12.1. + * In "[/help?cmd=regexp|fossil regexp]", "[/help?cmd=grep|fossil grep]" + and the TH1 "regexp" command, the -nocase option now removes multiple + diacritics from the same character (derived from SQLite's + remove_diacritics=2) + * Added the [/help?cmd=/secureraw|/secureraw] page that requires the + complete SHA1 or SHA3 hash, not just a prefix, before it will deliver + content. + * Accept purely numeric ISO8601 date/time strings as long as they + do not conflict with a hash. Example: "20190510134217" instead of + "2019-05-10 13:42:17". This helps keep URLs shorter and less + complicated + * Support both "1)" and "1." for numbered lists in markdown, as + commonmark does. + * The sync and clone HTTP requests omit the extra /xfer path element + from the end of the request URI. All servers since 2010 know that + the HTTP request is for a sync or clone from the mimetype so the + extra path element is not needed. + * If an automatic sync gets a permanent redirect request, then update + the saved remote URL to the new address. + * Temporary filenames (for example used for external "diff" commands) + try to preserve the suffix of the original file. + * Added the [/help?cmd=/thisdayinhistory|/thisdayinhistory] web page. + * Enhanced parsing of [/help?cmd=/timeline|/timeline] query parameters + "ymd=", "ym=", and "yw=". All arguments are option (in which case they + default to the current time) and all accept ISO8601 date/times without + punctuation. + * Automatically disapprove pending moderation requests for a user when + that user is deleted. This helps in dealing with spam-bots. + * Improvements to the "Capability Summary" section in the + [/help?cmd=/secaudit0|Security Audit] web-page. + * Use new "ci-lock" and "ci-lock-failed" pragmas in the + [./sync.wiki|sync protocol] to try to prevent accident forks + caused by concurrent commits when operating in auto-sync mode. + * Fix a bug ([https://www.fossil-scm.org/forum/forumpost/c51b9a1169|details]) + that can cause repository databases to be overwritten with debugging + output, thus corrupting the repository. This is only a factor when + CGI debugging is enabled, and even then is a rare occurrence, but it is + obviously an important fix. + + +

            Changes for Version 2.8 (2019-02-20)

            + + * Show cherry-pick merges as dotted lines on the timeline graph. + → The "fossil rebuild" command must be run to create and + populate the new "cherrypick" table in the repository in order + for this feature to operate. + * Add the ability to associate branches, check-ins, and tags with + specially-named Wiki pages. This gives the ability to better + document branches and tags, and provide more documentation on + check-ins beyond the check-in comment. The associated Wiki is + automatically displayed on /info pages for check-ins, and on + /timeline?r=BRANCH and /timeline?t=TAG pages for branches and + tags. This feature is on by default, but can be disabled in on + the Admin/Wiki page. + * Enhance the repository list page (shown for example by + "fossil all ui") so that it shows the name and last check-in + time for each project. The implementation of the repository + list page is now broken out into a separate source file (repolist.c). + * Allow users with Forum Supervisor permission ('6') to add Forum + Write Trusted permission ('4') to users as they are approving a + forum post by that user. + * When running a bisect, report the number of check-ins still in + the search range and the estimated number of bisect steps remaining. + Do this at each step of the bisect. + * Provide a permanent link to a bisect timeline using the bid= query + parameter. + * Make the chronological forum display feature available to all users, + and make it the default format on mobile devices. + * Break out Wiki setup into a separate /setup_wiki page, accessible + on the standard menus through Admin/Wiki. + * Add "Next" and "Previous" buttons on the /wdiff page, allowing + the user to step through the versions of a wiki page. + * Improve the display of the /whistory page. + * Omit the "HH:MM" timestamps on timeline graphs on narrow-screen + devices, to improve horizontal space uses. This helps make Fossil + more mobile-friendly. + * Enhance /wcontent to show a sortable list of Wiki pages together + with the number of revisions and the most recent change time for + each page. + * Hyperlinks to Wiki pages on the /timeline go to the specific + version of the Wiki page named in the timeline, not to the latest + version. + * Enhancements to the "amend", "tag", and "reparent" commands, including + adding options --override-date, --override-user, and --dry-run. + * Add the global --comment-format command-line option and the + comment-format setting to control the display of the command-line + timeline. + * Change the "fossil reparent" command so that it only works from + within an active checkout. + * On the /setup_ucap_list, show administrators how many users have + each capability. The counts are a hyperlink to the /setup_ulist + page showing the subset of users that have that capability. + * Provide the ability to redirect all HTTP pages to HTTPS. Formerly + one could cause this to occur for the /login page only. That option + still exists, but the redirect can now also be done for all pages. + * "Compress" the built-in javascript by omitting comments and + leading and trailing whitespace. + * Detect when the repository used by a checkout is swapped out for + a clone that uses different RID values, and make appropriate adjustments + to the checkout database to avoid any problems. + * Add the backoffice-disable setting to completely disable the + backoffice feature. + * Update the built-in SQLite to version 3.27.1. + * Various other small enhancements to webpages and documentation. + + + +

            Changes for Version 2.7 (2018-09-22)

            + + * Add the [./alerts.md|email alerts] feature for commits, ticket + changes, wiki changes, forum posts, and announcements. This is + still a work in progress. It is functional, but it is not as easy to + setup and use as it ought to be. + * Add the [./forum.wiki|discussion forum] feature. + * Add new user capabilities letters needed to support alerts and forum. + Formerly, user capabilities were letters from [a-z], but with the + enhancements, the supply of lower case letters was exhausted. + User capabilities are now letters in [a-zA-Z0-9]. + * The built-in skins are now responsive, providing better layout on + small screens, including mobile devices. + * The default skin now includes a hamburger menu that is generated + by the [/sitemap] page. + * All of the built-in skins now use a + [https://en.wikipedia.org/wiki/Content_Security_Policy|Content Security Policy (CSP)] + to help prevent cross-site injection and forgery attacks. There are no known + vulnerabilities in Fossil. The added CSP does not fix anything; it merely adds + another layer of defense. + * The [/sitemap] and other list pages show as multiple columns if + the viewing window is wide enough. + * There is an optional "js" file for each skin that can be used to + hold javascript. This file can be loaded by reference or can be + included in the header or footer. + * Add the [./backoffice.md|backoffice]. + * Update internal Unicode character tables, used in regular expression + handling, from version 10.0 to 11.0. + * Improvements to the "Security Audit" administration page + * Add the [/help?cmd=branch|fossil branch current] command. + * Add the [./grep.md|grep] command. + * Update the built-in SQLite to version 3.25.1. + * Some code and interfaces are in place to support sending and + receiving email directly via SMTP, but this feature is not yet + complete or ready for production use. + * The `mv-rm-files` setting is now compiled into Fossil in the + default Fossil configuration; no longer must you say + ./configure --with-legacy-mv-rm to make it available. The + setting remains disabled by default, however, so you must still say + fossil set mv-rm-files 1 to enable it on each repository + where you want hard mv/rm behavior. + + +

            Changes for Version 2.6 (2018-05-04)

            + + * Fix a bug that was causing crashes while trying to clone the TCL + repository. This fix is the main reason for the current release. + * Added the new "Classic" timeline viewing mode. "Classic" is the + same as "Verbose" in the previous release. The "Verbose" mode is + now like "Compact" except the extra check-in details are shown by + default. + * Add support for ETags:, Last-Modified:, and If-Modified-Since: + cache control mechanisms. + * Enhance the [/help?cmd=/tarball|/tarball], + [/help?cmd=/zip|/zip], and + [/help?cmd=/sqlar|/sqlar] pages so that the checkin + name to be downloaded can be expressed as part of the URI, + and without the need for query parameters. + * On the [/help?cmd=/timeline|/timeline] webpage, add the days=N + query parameter and enhance the ymd=DATE and yw=DATE query parameters + to accept 'now' as an argument to show the latest day or week. + * In the web page that comes up in response to the + [/help?cmd=all|fossil all ui] command, show the last modification + time for each repository, and allow click-to-sort on the modification + time column. + * In the tarball cache replacement algorithm, give extra weight to + tarballs that have been accessed more than once. + * Additional defenses against web-based attacks. There have not been + any known vulnerabilities. We are just being paranoid. + * Update the built-in SQLite to an alpha version of 3.24.0. + + +

            Changes for Version 2.5 (2018-02-07)

            + + * Numerous enhancements to the look and feel of the web interface. + Especially: Added separate "Modern", "Compact", "Verbose", and + "Columnar" view options on timelines. + * Common display settings (such as the "view" option and the number + of rows in a timeline) are held in a cookie and thus persist + across multiple pages. + * Rework the skin editing process so that changes are implemented + on one of nine /draft pages, evaluated, then merged back to the + default. + * Added the [https://fossil-scm.org/skins/ardoise/timeline|Ardoise] + skin. + * Fix the "fossil server" command on Unix to be much more responsive + to multiple simultaneous web requests. + * Use the IPv6 stack for the "fossil ui" and "fossil server" + commands on Windows. + * Support for [https://sqlite.org/sqlar|SQL Archives] as a download + option. + * Fossil now automatically generates the + <html><head>...</head><body> + at the beginning of each web page if the configurable header + lacks a <body> tag. + * Added the /artifact_stats page, currently accessible only by + the administrator. + * Upgrade to the latest versions of SQLite and OpenSSL. + * Improved key bindings on the Tk diff screen generated by + "fossil diff --tk". + * Begin factoring out in-line javascript into separately loaded + script files. This is a step along the + road toward supporting a strict Content Security Policy. More work + is to be done. + * Initial infrastructure is in place to make use of the pledge() + system call in OpenBSD. More work is to be done. + + +

            Changes for Version 2.4 (2017-11-03)

            + + * New feature: URL Aliases. URL Aliases allow an administrator + to define their own URLs on the web interface that are rewritten to + built-in URLs with specific parameters. Create and configure URL Aliases + using the /Setup/URL_Aliases menu option in the web interface. + * Add tech-note search capability. + * Add the -r|--revision and -o|--origin options to the + [/help?cmd=annotate|annotate] command. + * Add the origin= query parameter to the [/help?cmd=/annotate|/annotate] + webpage. + * The [/help?cmd=annotate|fossil annotate] command and the + [/help?cmd=/annotate|/annotate] web page go backwards in time as far + as can be computed in 30 milliseconds by default, rather than stopping + after 20 steps. The new limit= query parameter or the --limit command-line + option can be used to alter this timeout. + * Provide separate [/help#settings|on-line help screens for each setting]. + * Back out support for the --no-dir-symlinks option + * Remove support from the legacy configuration sync protocol. The only + way now to do a configuration push or pull is to use the new protocol that + was added in 2011. + * Add the from= and to= query parameters to [/help?cmd=/fdiff|/fdiff] + in order to get a diff of two files in the same check-in. + * Fix the "ssh://" protocol to prevent an attack whereby the attacker convinces + a victim to run a "clone" with a dodgy URL and thereby gains access to their + system. + * Provide a checkbox that will temporarily disable all ad-units. + * Improvements to the [/help?cmd=/stat|/stat] page + * Various new hyperlinks to the [/help?cmd=/bloblist|/bloblist] + and [/help?cmd=/bigbloblist|/bigbloblist] pages. + * Correct the [/help?cmd=/doc|/doc] page to support read-only repositories. + * Correct [/help?cmd=/zip|/zip], [/help?cmd=/tarball|/tarball], + [/help?cmd=zip|zip], and [/help?cmd=tarball|tarball] pages and commands to + honor the versioned manifest setting when outside of an open checkout + directory. + * The admin-log and access-log settings are now on by default for + new repositories. + * Update the built-in SQLite to version 3.21.0. + + +

            Changes for Version 2.3 (2017-07-21)

            + + * Update the built-in SQLite to version 3.20.0 (beta). + * Update internal Unicode character tables, used in regular expression + handling, from version 9.0 to 10.0. + * Show the last-sync-URL on the [/help?cmd=/urllist|/urllist] page. + * Added the "Event Summary" activity report. + [/reports?type=ci&view=lastchng|example] + * Added the "Security Audit" page, available to administrators only + * Added the Last Login time to the user list page, for administrators only + * Added the --numstat option to the [/help?cmd=diff|fossil diff] command + * Limit the size of the heap and stack on unix systems, as a proactive + defense against the + [https://www.qualys.com/2017/06/19/stack-clash/stack-clash.txt|Stack Clash] + attack. + * Fix "database locked" warnings caused by "PRAGMA optimize". + * Fix a potential XSS vulnerability on the + [/help?cmd=/help|/help] webpage. + * Documentation updates + + +

            Changes for Version 2.2 (2017-04-11)

            + + * GIT comment tags are now handled by Fossil during import/export. + * Show the content of README files on directory listings. + ([/file/skins|example]) + * Support for Basic Authentication if enabled (default off). + * Show the hash algorithms used on the + [/help?cmd=/rcvfromlist|/rcvfromlist] page. + * The [/help?cmd=/tarball|/tarball] and [/help?cmd=/zip|/zip] pages + now use the the r= query parameter + to select which check-in to deliver. The uuid= query parameter + is still accepted for backwards compatibility. + * Update the built-in SQLite to version 3.18.0. + * Run "[https://www.sqlite.org/pragma.html#pragma_optimize|PRAGMA optimize]" + on the database connection as it is closing. + + +

            Changes for Version 2.1 (2017-03-10)

            + + * Add support for [./hashpolicy.wiki|hash policies] that control which + of the Hardened-SHA1 or SHA3-256 algorithms is used to name new + artifacts. + * Add the "gshow" and "gcat" subcommands to [/help?cmd=stash|fossil stash]. + * Add the [/help?cmd=/juvlist|/juvlist] web page and use it to construct + the [/uv/download.html|Download Page] of the Fossil self-hosting website + using Ajax. + + +

            Changes for Version 2.0 (2017-03-03)

            + + * Use the + [https://github.com/cr-marcstevens/sha1collisiondetection|hardened SHA1] + implemenation by Marc Stevens and Dan Shumow. + * Add the ability to read and understand + [./fileformat.wiki#names|artifact names] that are based on SHA3-256 + rather than SHA1, but do not actually generate any such names. + * Added the [/help?cmd=sha3sum|sha3sum] command. + * Update the built-in SQLite to version 3.17.0. + + +

            Changes for Version 1.37 (2017-01-16)

            + + * Add checkbox widgets to various web pages. See [/technote/8d18bf27e9| + this technote] for more information. To get the checkboxes to look as + intended, you must update the CSS in your repository and all clones. + * Add the [/help/all|fossil all ui] command + * Add the [/help?cmd=/file|/file] webpage + * Enhance the [/help?cmd=/brlist|/brlist] webpage to make use of branch colors. + * Add support for the ms=EXACT|LIKE|GLOB|REGEXP query parameter on the + [/help?cmd=/timeline|/timeline] webpage, with associated form widgets. + * Enhance the [/help/changes|changes] and [/help/status|status] commands + with many new filter options so that specific kinds of changes can be + found without having to pipe through grep or sed. + * Enhanced the [/help/sqlite3|fossil sql] command so that it opens the + [./tech_overview.wiki#localdb|checkout database] and the + [./tech_overview.wiki#configdb|configuration database] in addition to the + respository database. + * TH1 enhancements: +
            • Add [unversioned content] command.
            • +
            • Add [unversioned list] command.
            • +
            • Add project_description variable.
            • +
            + * Rename crnl-glob [/help/settings|setting] to crlf-glob, but keep + crnl-glob as a compatibility alias. + * Added the --command option to the [/help/diff|diff] command. + * Fix a C99-ism that prevents the 1.36 release from building with MSVC. + * Fix [/help?cmd=ticket|ticket set] when using the "+" prefix with fields + from the "ticketchng" table. + * Remove the "fusefs" command from builds that do not have the underlying + support enabled. + * Fixes for incremental git import/export. + * Minor security enhancements to + [./encryptedrepos.wiki|encrypted repositories]. + * Update the built-in SQLite to version 3.16.2. + * Update the built-in Zlib to version 1.2.11. + + + +

            Changes for Version 1.36 (2016-10-24)

            * Add support for [./unvers.wiki|unversioned content], the [/help?cmd=unversioned|fossil unversioned] command and the [/help?cmd=/uv|/uv] and [/uvlist] web pages. * The [/uv/download.html|download page] is moved into [./unvers.wiki|unversioned content] so that the self-hosting Fossil websites no longer uses any external content. * Added the "Search" button to the graphical diff generated by the --tk option on the [/help?cmd=diff|diff] command. - * Added the "--checkin VERSION" option to the + * Added the "--checkin VERSION" option to the [/help?cmd=diff|diff] command. * Various performance enhancements to the [/help?cmd=diff|diff] command. * Update internal Unicode character tables, used in regular expression handling, from version 8.0 to 9.0. - * Update the built-in SQLite to version 3.15 (beta). Fossil now requires + * Update the built-in SQLite to version 3.15. Fossil now requires the SQLITE_DBCONFIG_MAINDBNAME interface of SQLite which is only available in SQLite version 3.15 and later and so Fossil will not work with earlier SQLite versions. * Fix [https://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg23618.html|multi-line timeline bug] * Enhance the [/help?cmd=purge|fossil purge] command. @@ -28,10 +565,11 @@ able to pull from their parent but not push. * Added the -nocomplain option to the TH1 "query" command. * Added support for the chng=GLOBLIST query parameter on the [/help?cmd=/timeline|/timeline] webpage. +

            Changes for Version 1.35 (2016-06-14)

            * Enable symlinks by default on all non-Windows platforms. * Enhance the [/md_rules|Markdown formatting] so that hyperlinks that begin with "/" are relative to the root of the Fossil repository. @@ -71,10 +609,11 @@ names in place of getpass() to read passwords and passphrases * Option --baseurl now works on Windows. * Numerious documentation improvements. * Update the built-in SQLite to version 3.13.0. +

            Changes for Version 1.34 (2015-11-02)

            * Make the [/help?cmd=clean|fossil clean] command undoable for files less than 10MiB. * Update internal Unicode character tables, used in regular expression @@ -106,10 +645,11 @@ * Change the mimetype for ".n" and ".man" files to text/plain. * Display improvements in the [/help?cmd=bisect|fossil bisect chart] command. * Updated the built-in SQLite to version 3.9.1 and activated JSON1 and FTS5 support (both currently unused within Fossil). +

            Changes for Version 1.33 (2015-05-23)

            * Improved fork detection on [/help?cmd=update|fossil update], [/help?cmd=status|fossil status] and related commands. * Change the default skin to what used to be called "San Francisco Modern". * Add the [/repo-tabsize] web page @@ -155,10 +695,11 @@ field for direct entry of the user name to each applicable report. * Create parent directories of [/help?cmd=settings|empty-dirs] if they don't already exist. * Inhibit timeline links to wiki pages that have been deleted. +

            Changes for Version 1.32 (2015-03-14)

            * When creating a new repository using [/help?cmd=init|fossil init], ensure that the new repository is fully compatible with historical versions of Fossil by having a valid manifest as RID 1. * Anti-aliased rendering of arrowheads on timeline graphs. @@ -171,10 +712,11 @@ * Enhance the "ln=" query parameter on artifact displays to accept multiple ranges, separate by spaces (or "+" when URL-encoded). * Added [/help?cmd=forget|fossil forget] as an alias for [/help?cmd=rm|fossil rm]. +

            Changes For Version 1.31 (2015-02-23)

            * Change the auxiliary schema by adding columns MLINK.ISAUX and MLINK.PMID columns to the schema, to support better drawing of file change graphs. A [/help?cmd=rebuild|fossil rebuild] is recommended but is not required. so that the new graph drawing logic can work effectively. @@ -222,10 +764,11 @@ * Allow the user of Common Table Expressions in the SQL that defaults ticket reports. * Break out the components (css, footer, and header) for the various built-in skins into separate files in the source tree. +

            Changes For Version 1.30 (2015-01-19)

            * Added the [/help?cmd=bundle|fossil bundle] command. * Added the [/help?cmd=purge|fossil purge] command. * Added the [/help?cmd=publish|fossil publish] command. * Added the [/help?cmd=unpublished|fossil unpublished] command. @@ -292,10 +835,11 @@ the correctness of printf-style formatting strings. * Fix CVE-2014-3566, also known as the POODLE SSL 3.0 vulnerability. * Numerous documentation fixes and improvements. * Other obscure and minor bug fixes - see the timeline for details. +

            Changes For Version 1.29 (2014-06-12)

            * Add the ability to display content, diffs and annotations for UTF16 text files in the web interface. * Add the "SaveAs..." and "Invert" buttons to the graphical diff display that results Index: www/checkin_names.wiki ================================================================== --- www/checkin_names.wiki +++ www/checkin_names.wiki @@ -1,25 +1,25 @@ Check-in Names
            -

            Executive Summary

            -

            A check-in can be identified using any of the following -names: +

            Quick Reference

              -
            • SHA1 hash prefix -
            • Tag or branchname +
            • Hash prefix +
            • Branch name +
            • Tag name
            • Timestamp: YYYY-MM-DD HH:MM:SS
            • tag-name : timestamp
            • root : branchname +
            • merge-in : branchname
            • Special names:
              • tip
              • current
              • next
              • previous or prev -
              • ckout for embedded docs +
              • ckout (embedded docs only)
            Many Fossil [/help|commands] and [./webui.wiki | web-interface] URLs accept @@ -42,36 +42,36 @@ determines which version of the documentation to display. Fossil provides a variety of ways to specify a check-in. This document describes the various methods. -

            Canonical Check-in Name

            +

            Canonical Check-in Name

            -The canonical name of a check-in is the SHA1 hash of its -[./fileformat.wiki#manifest | manifest] expressed as a 40-character +The canonical name of a check-in is the hash of its +[./fileformat.wiki#manifest | manifest] expressed as a 40-or-more character lowercase hexadecimal number. For example:
             fossil info e5a734a19a9826973e1d073b49dc2a16aa2308f9
             
            -The full 40-character SHA1 hash is unwieldy to remember and type, though, +The full 40+ character hash is unwieldy to remember and type, though, so Fossil also accepts a unique prefix of the hash, using any combination of upper and lower case letters, as long as the prefix is at least 4 -characters long. Hence the following commands all +characters long. Hence the following commands all accomplish the same thing as the above:
             fossil info e5a734a19a9
             fossil info E5a734A
             fossil info e5a7
             
            -Many web-interface screens identify check-ins by 10- or 16-character +Many web-interface screens identify check-ins by 10- or 16-character prefix of canonical name. -

            Tags And Branch Names

            +

            Tags And Branch Names

            Using a tag or branch name where a check-in name is expected causes Fossil to choose the most recent check-in with that tag or branch name. So, for example, as of this writing the most recent check-in that is tagged with "release" is [d0753799e44]. @@ -100,10 +100,11 @@ Note that unlike other command DVCSes, a "branch" in Fossil is not anything special; it is simply a sequence of check-ins that share a common tag. So the same mechanism that resolves tag names also resolves branch names. + Note also that there can (in theory) be an ambiguity between tag names and canonical names. Suppose, for example, you had a check-in with the canonical name deed28aa99a835f01fa06d5b4a41ecc2121bf419 and you also happened to have tagged a different check-in with "deed2". If you use the "deed2" name, does it choose the canonical name or the tag @@ -112,15 +113,15 @@
            fossil info tag:deed2
            -The "tag:deed2" name will refer to the most recent check-in +The "tag:deed2" name will refer to the most recent check-in tagged with "deed2" not to the check-in whose canonical name begins with "deed2". -

            Whole Branches

            +

            Whole Branches

            Usually when a branch name is specified, it means the latest check-in on that branch. But for some commands (ex: [/help/purge|purge]) a branch name on the argument means the earliest connected check-in on the branch. This seems confusing when being explained here, but it works out to be intuitive @@ -137,38 +138,52 @@ tag, just as it always does. But if that tag is a branch name, it then walks back down the branch looking for the first check-in of that branch. Again, this behavior only occurs on a few commands where it make sense. -

            Timestamps

            +

            Timestamps

            A timestamp in one of the formats shown below means the most recent check-in that occurs no later than the timestamp given: - * YYYY-MM-DD - * YYYY-MM-DD HH:MM - * YYYY-MM-DD HH:MM:SS - * YYYY-MM-DD HH:MM:SS.SSS + 1. YYYY-MM-DD + 2. YYYY-MM-DD HH:MM + 3. YYYY-MM-DD HH:MM:SS + 4. YYYY-MM-DD HH:MM:SS.SSS + 5. YYYYMMDD + 6. YYYYMMDDHHMM + 7. YYYYMMDDHHMMSS -The space between the day and the year can optionally be +In the second through the fourth forms, +the space between the day and the year can optionally be replaced by an uppercase T and the entire timestamp can optionally be followed by "z" or "Z". In the fourth form with fractional seconds, any number of digits may follow the decimal point, though due to precision limits only the first three -digits will be significant. +digits will be significant. The final three pure-digit forms +without punctuation are only valid if the number they encode is +not also the prefix of an artifact hash. In its default configuration, Fossil interprets and displays all dates in Universal Coordinated Time (UTC). This tends to work the best for distributed projects where participants are scattered around the globe. But there is an option on the Admin/Timeline page of the web-interface to -switch to local time. The "Z" suffix on an timestamp check-in +switch to local time. The "Z" suffix on a timestamp check-in name is meaningless if Fossil is in the default mode of using UTC for everything, but if Fossil has been switched to local time mode, then the -"Z" suffix means to interpret that particular timestamp using +"Z" suffix means to interpret that particular timestamp using UTC instead of local time. -For an example of how timestamps are useful, +You may prefix a timestamp with the string “date:”, in which case +processing stops immediately, whether the string is parsed correctly and +refers to anything within the repository or not. The prefix is therefore +useful when the date could be misinterpreted as a tag. For example, a +repo could have release tags like “2020-04-01”, the date the release was +cut, but you could force Fossil to interpret that string as a date +rather than as a tag by passing “date:2020-04-01”. + +For an example of how timestamps are useful, consider the homepage for the Fossil website itself:
            http://www.fossil-scm.org/fossil/doc/trunk/www/index.wiki
            @@ -179,11 +194,11 @@
            http://www.fossil-scm.org/fossil/doc/2009-01-01/www/index.wiki
            -

            Tag And Timestamp

            +

            Tag And Timestamp

            A check-in name can also take the form of a tag or branch name followed by a colon and then a timestamp. The combination means to take the most recent check-in with the given tag or branch which is not more recent than the timestamp. So, for example: @@ -191,14 +206,14 @@
            fossil update trunk:2010-07-01T14:30
            Would cause Fossil to update the working check-out to be the most recent -check-in on the trunk that is not more recent that 14:30 (UTC) on +check-in on the trunk that is not more recent that 14:30 (UTC) on July 1, 2010. -

            Root Of A Branch

            +

            Root Of A Branch

            A branch name that begins with the "root:" prefix refers to the last check-in in the parent branch prior to the beginning of the branch. Such a label is useful, for example, in computing all diffs for a single branch. The following example will show all changes in the hypothetical @@ -206,29 +221,48 @@
            fossil diff --from root:xyzzy --to xyzzy
            + +A branch name that begins with the "merge-in:" prefix refers not +to the root of the branch, but to the most recent merge-in for that branch +from its parent. The most recent merge-in is the version to diff the branch +against in order to see all changes in just the branch itself, omitting +any changes that have already been merged in from the parent branch. + -

            Special Tags

            +

            Special Tags

            The tag "tip" means the most recent check-in. The "tip" tag is roughly equivalent to the timestamp tag "5000-01-01". -If the command is being run from a working check-out (not against a bare -repository) then a few extra tags apply. The "current" tag means the -current check-out. The "next" tag means the youngest child of the -current check-out. And the "previous" or "prev" tag means the primary -(non-merge) parent of the current check-out. - -For embedded documentation, the tag "ckout" means the version as present in -the local source tree on disk, provided that the web server is started using -"fossil ui" or "fossil server" from within the source tree. This tag can be -used to preview local changes to documentation before committing them. It does -not apply to CLI commands. - -

            Additional Examples

            +This special name works anywhere you can pass a "NAME", such as in in +/info URLs: + +
            +http://localhost:8080/info/tip
            +
            + +There are several other special names, but they only work from within a +check-out directory because they are relative to the current checked-out +version: + + * "current": the current checked-out version + * "next": the youngest child of the current checked-out version + * "previous" or "prev": the primary (non-merge) parent of "current" + +Therefore, you can use these names in a fossil info command, +but not in an /info URL, for example. + +For embedded documentation URLs only, there is one more special name, +"ckout". See [./embeddeddoc.wiki#ckout | its coverage elsewhere] for +more details. You cannot currently use "ckout" anywhere other than in +/doc URLs. + + +

            Additional Examples

            To view the changes in the most recent check-in prior to the version currently checked out:
            @@ -239,5 +273,23 @@
             Then to see everything that has changed on the trunk since the last release:
             
             
             fossil diff --from release --to trunk
             
            + + +

            Resolution Order

            + +Fossil currently resolves name strings to artifact hashes in the +following order: + + # Exact matches on [#special | the special names] + # [#timestamps | Timestamps], with preference to ISO8601 forms + # [#tagpfx | tag:TAGNAME] + # [#root | root:BRANCH] + # [#merge-in | merge-in:BRANCH] + # [#tag-ts | TAG:timestamp] + # Full artifact hash or hash prefix. + # Any other type of symbolic name that Fossil extracts from + blockchain artifacts. + +
            Index: www/childprojects.wiki ================================================================== --- www/childprojects.wiki +++ www/childprojects.wiki @@ -37,21 +37,21 @@ VALUES('project-code',lower(hex(randomblob(20)))); INSERT INTO config(name,value) VALUES('project-name','CHILD-PROJECT-NAME');
            -Modify the CHILD-PROJECT-NAME in the last statement to be the name of +Modify the CHILD-PROJECT-NAME in the last statement to be the name of the child project, of course. The repository is now a separate project, independent from its parent. Clone the new project to the developers as needed. The child project and the parent project will not normally be able to sync with one another, since they are now separate projects with distinct project codes. However, if the -"--from-parent-project" command-line option is provided to the -"[/help?cmd=pull|fossil pull]" command in the child, and the URL of +"--from-parent-project" command-line option is provided to the +"[/help?cmd=pull|fossil pull]" command in the child, and the URL of parent repository is also provided on the command-line, then updates to the parent project that occurred after the child was created will be added to the child repository. Thus, by periodically doing a pull --from-parent-project, the child project is able to stay up to date with all the latest changes in the parent. ADDED www/chroot.md Index: www/chroot.md ================================================================== --- /dev/null +++ www/chroot.md @@ -0,0 +1,42 @@ +# The Server Chroot Jail + +If you run Fossil as root in any mode that [serves data on the +network][srv], and you're running it on Unix or a compatible OS, Fossil +will drop itself into a [`chroot(2)` jail][cj] shortly after starting +up, once it's done everything that requires root access. Most commonly, +you run Fossil as root to allow it to bind to TCP port 80 for HTTP +service, since normal users are restricted to ports 1024 and up on OSes +where this behavior occurs. + +Fossil uses the owner of the Fossil repository file as its new user +ID when dropping root privileges. + +When this happens, Fossil needs to have all of its dependencies inside +the chroot jail in order to continue work. There are several things you +typically need in order to make things work properly: + +* the repository file(s) + +* `/dev/null` — create it with `mknod(8)` inside the jail directory + ([Linux example][mnl], [OpenBSD example][obsd]) + +* `/dev/urandom` — ditto + +* `/proc` — you might need to mount this virtual filesystem inside the + jail on Linux systems that make use of [Fossil’s server load + shedding feature][fls] + +* any shared libraries your `fossil` binary is linked to, unless you + [configured Fossil with `--static`][bld] to avoid it + +Fossil does all of this in order to protect the host OS. You can make it +bypass the jail part of this by passing --nojail to fossil server, +but you cannot make it skip the dropping of root privileges, on purpose. + + +[bld]: https://www.fossil-scm.org/fossil/doc/trunk/www/build.wiki +[cj]: https://en.wikipedia.org/wiki/Chroot +[fls]: ./loadmgmt.md +[mnl]: https://fossil-scm.org/forum/forumpost/90caff30cb +[srv]: ./server/ +[obsd]: ./server/openbsd/httpd.md#chroot DELETED www/cmd_.wiki-template Index: www/cmd_.wiki-template ================================================================== --- www/cmd_.wiki-template +++ /dev/null @@ -1,22 +0,0 @@ -

            foo

            - -The foo command is informational, it doesn't do anything to -a checked-out project, but it tells you something about it. - -The foo command < to> | bar. - -The flibenglookners that the foo command | bar. - -Typing fossil foo will gonkulate any flibenglookners, but baz. - -What we going to exemplify. - -Example. - -Raison d'etre. - -Compare foo to this here other thingy. - -See also: [./cmd_bar.wiki | fossil bar], -[./cmd_baz.wiki | fossil baz], -[./reference.wiki | Reference] ADDED www/collisions.ipynb Index: www/collisions.ipynb ================================================================== --- /dev/null +++ www/collisions.ipynb @@ -0,0 +1,139 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*Pull in the packages we need:*" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "require(stats)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Parameters\n", + "\n", + "* **cpd** - Checkins per day. Defaults to 20.\n", + "\n", + "* **days** - Number of days to simulate. Defaults to 10000, or roughly\n", + " 40 working years.\n", + "\n", + "* **winSz** - Size of the commit window as a fraction of `workSec`. Defaults\n", + " to 0.01%, which is roughly 3 seconds for the default 8-hour work day, a\n", + " a long-ish commit time for Fossil.\n", + "\n", + "* **workSec** - Seconds in working day, defaulting to 8 hours. This value\n", + " only affects the reporting output, not the results of the underlying\n", + " simulation. It's a scaling parameter to humanize the results.\n", + " \n", + "* **spread** - Adjustment factor in computing the standard deviation for our \n", + " normally-distributed random numbers. The default gives \"nice\" distributions,\n", + " spread over the working day with a low chance of generating values outside\n", + " the working day.\n", + " \n", + " The smaller this value gets (<4), the more spread out the checkins, and\n", + " so the lower the chance of collisions. You might want to decrease it a bit\n", + " to simulate early and late workers.\n", + " \n", + " As you increase this value (>4) you're simulating a work environment\n", + " where people tend to check their work in closer and closer to mid-day,\n", + " which increases the chance of collision." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "collisions <- function(\n", + " cpd = 20,\n", + " days = 10000,\n", + " winSz = 0.01 / 100,\n", + " workSec = 8 * 60 * 60,\n", + " spread = 4)\n", + "{\n", + " cat(\"Running simulation...\\n\")\n", + "\n", + " day = 0\n", + " collisions = 0\n", + " winSec = workSec * winSz\n", + " mean = workSec / 2\n", + " sd = workSec / spread\n", + "\n", + " while (day < days) {\n", + " # Create the commit time vector as random values in a normal\n", + " # distribution.\n", + " times = sort(rnorm(cpd, mean, sd))\n", + "\n", + " # Are there any pairs in the time vector that are within the\n", + " # passed window size? If so, that's a Fossil checkin collision.\n", + " i = 1\n", + " while (i < cpd) {\n", + " if (abs(times[i] - times[i + 1]) < winSec) {\n", + " collisions = collisions + 1\n", + " }\n", + " i = i + 1\n", + " }\n", + " \n", + " day = day + 1\n", + " }\n", + " \n", + " cat(\"Found\", collisions, \"collisions in\", days, (workSec / 3600),\n", + " \"hour working days with\", winSec, \"second windows.\\n\")\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*Run the following cell, possibly changing parameters documented above:*" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running simulation...\n", + "Found 422 collisions in 10000 8 hour working days with 2.88 second windows.\n" + ] + } + ], + "source": [ + "collisions()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "R", + "language": "R", + "name": "ir" + }, + "language_info": { + "codemirror_mode": "r", + "file_extension": ".r", + "mimetype": "text/x-r-source", + "name": "R", + "pygments_lexer": "r", + "version": "3.3.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} Index: www/concepts.wiki ================================================================== --- www/concepts.wiki +++ www/concepts.wiki @@ -80,22 +80,25 @@ Communication between repositories is via HTTP. Remote repositories are identified by URL. You can also point a web browser at a repository and get human-readable status, history, and tracking information about the project. -

            2.1 Identification Of Artifacts

            - -A particular version of a particular file is called an "artifact". -Each artifact has a universally unique name which is the -SHA1 hash of the content -of that file expressed as 40 characters of lower-case hexadecimal. Such -a hash is referred to as the Artifact Identifier or Artifact ID -for the artifact. The SHA1 algorithm is created with the purpose of -providing a highly forgery-resistant identifier for a file. Given any -file it is simple to find the artifact ID for that file. But given a -artifact ID it is computationally intractable to generate a file that will -have that Artifact ID. +

            2.1 Identification Of Artifacts

            + +A particular version of a particular file is called an "artifact". Each +artifact has a universally unique name which is the SHA1 or SHA3-256 hash of the +content of that file expressed as either 40 or 64 characters of +lower-case hexadecimal. (See the [./hashpolicy.wiki|hash policy +document] for information on which algorithm is used, when.) Such a hash +is referred to as the Artifact ID. These hash algorithms were created +with Fossil's purpose in mind: to provide a highly forgery-resistant +identifier for a blob of data, such as a file. Given any file, it is +simple to find the artifact ID for that file. But given an artifact ID, +it is computationally intractable to generate a file that will have that +same artifact ID. Artifact IDs look something like this:
            6089f0b563a9db0a6d90682fe47fd7161ff867c8
            @@ -131,11 +134,11 @@

            2.2 Manifests

            Associated with every check-in is a special file called the [./fileformat.wiki#manifest| "manifest"]. The manifest is a listing of all other files in -that source tree. The manifest contains the (complete) artifact ID +that source tree. The manifest contains the (complete) artifact ID of the file and the name of the file as it appears on disk, and thus serves as a mapping from artifact ID to disk name. The artifact ID of the manifest is the identifier for the entire check-in. When you look at a "timeline" of changes in Fossil, the ID associated with each check-in or commit is really just the artifact ID of the @@ -147,11 +150,11 @@ manifest file to be materialized to disk, if desired. Both Fossil itself, and SQLite cause the manifest file to be materialized to disk so that the makefiles for these project can read the manifest and embed version information in generated binaries. -

            Fossil automatically generates a manifest whenever you "commit" +

            Fossil automatically generates a manifest whenever you "commit" a new check-in. So this is not something that you, the developer, need to worry with. The format of a manifest is intentionally designed to be simple to parse, so that if you want to read and interpret a manifest, either by hand or with a script, that is easy to do. But you will probably never @@ -187,24 +190,24 @@ Fossil is software. The implementation of Fossil is in the form of a single executable named "fossil" (or "fossil.exe" on Windows). To install Fossil on your system, all you have to do is obtain a copy of this one executable file (either by downloading a -pre-compiled version +pre-compiled version or [./build.wiki | compiling it yourself]) and then putting that file somewhere on your PATH. Fossil is completely self-contained. It is not necessary to install any other software in order to use Fossil. You do not need -CVS, gzip, diff, rsync, Python, Perl, Tcl, Java, apache, PostgreSQL, MySQL, +CVS, gzip, diff, rsync, Python, Perl, Tcl, Java, Apache, PostgreSQL, MySQL, SQLite, patch, or any similar software on your system in order to use Fossil effectively. You will want to have some kind of text editor for entering check-in comments. Fossil will use whatever text editor is identified by your VISUAL environment variable. Fossil will also use GPG to clearsign your manifests if you happen to have it installed, but Fossil will skip that step if GPG missing from your system. -You can optionally set up Fossil to use external "diff" programs, +You can optionally set up Fossil to use external "diff" programs, though Fossil has an excellent built-in "diff" algorithm that works fine for most people. If you happen to have Tcl/Tk installed on your system, Fossil will use it to generate a graphical "diff" display when you use the --tk option to the "diff" command, but this too is entirely optional. @@ -211,11 +214,11 @@ To uninstall Fossil, simply delete the executable. To upgrade an older version of Fossil to a newer version, just -replace the old executable with the new one. You might need to +replace the old executable with the new one. You might need to run "fossil all rebuild" to restructure your repositories after an upgrade. Running "all rebuild" never hurts, so when upgrading it is a good policy to run it even if it is not strictly necessary. To use Fossil, simply type the name of the executable in your @@ -231,11 +234,11 @@ token after the name of the Fossil executable, as shown above.

            4.0 Workflow

            - + Fossil has two modes of operation: "autosync" and "manual-merge" Autosync mode is reminiscent of CVS or SVN in that it automatically keeps your changes in synchronization with your co-workers through @@ -255,11 +258,11 @@ fossil settings
            By default, Fossil runs with autosync mode turned on. The authors finds that projects run more smoothly in autosync mode since -autosync helps to prevent pointless forking and merge and helps keeps +autosync helps to prevent pointless forking and merging and helps keeps all collaborators working on exactly the same code rather than on their own personal forks of the code. In the author's view, manual-merge mode should be reserved for disconnected operation.

            4.1 Autosync Workflow

            @@ -266,11 +269,11 @@
            1. Establish a local repository using either the new command to start a new project, or the clone command to make a clone -of a repository for an existing project. +of a repository for an existing project.
            2. Establish one or more source trees using the open command with the name of the repository file as its @@ -279,11 +282,11 @@
            3. The open command in the previous step populates your local source tree with a copy of the latest check-in. Usually this is what you want. In the rare cases where it is not, use the update command to -switch to a different check-in. +switch to a different check-in. Use the timeline or leaves commands to identify alternative check-ins to switch to.
            4. @@ -302,17 +305,17 @@ you cloned from or whatever server you most recently synced with.
            5. When your coworkers make their own changes, you can merge those changes -into your local local source tree using the update command. +into your local local source tree using the update command. In autosync mode, update will first go back to the server you cloned from or with which you most recently synced, and pull down all recent changes into your local repository. Then it will merge recent changes into your local source tree. If you do an update and find that it messes something up in your source tree (perhaps a co-worker -checked in incompatible changes) you can use the undo command +checked in incompatible changes) you can use the undo command to back out the changes.
            6. Repeat all of the above until you have generated great software. @@ -420,11 +423,11 @@
            7. Inetd or Stunnel. Configure programs like inetd, xinetd, or stunnel to hand off HTTP requests directly to the [/help?cmd=http|fossil http] command.

            -See the [./server.wiki | How To Configure A Fossil Server] document +See the [./server/ | How To Configure A Fossil Server] document for details.

            6.0 Review Of Key Concepts

              Index: www/contribute.wiki ================================================================== --- www/contribute.wiki +++ www/contribute.wiki @@ -10,11 +10,11 @@ [./copyright-release.pdf | Contributor Agreement (PDF)] (or [./copyright-release.html | as HTML]) on file for you. We require this in order to maintain clear title to the Fossil code and prevent the introduction of code with incompatible licenses or other entanglements that might cause legal problems for Fossil users. Many larger companies -and other lawyer-rich organizations require this as a precondition to using +and other lawyer-rich organizations require this as a precondition to using Fossil. If you do not wish to submit a Contributor Agreement, we would still welcome your suggestions and example code, but we will not use your code directly - we will be forced to re-implement your changes from scratch which @@ -21,14 +21,14 @@ might take longer.

              2.0 Submitting Patches

              Suggested changes or bug fixes can be submitted by creating a patch -against the current source tree. Email patches to -drh@sqlite.org. Be sure to +against the current source tree. Email patches to +drh@sqlite.org. Be sure to describe in detail what the patch does and which version of Fossil -it is written against. +it is written against. A contributor agreement is not strictly necessary to submit a patch. However, without a contributor agreement on file, your patch will be used for reference only - it will not be applied to the code. This may delay acceptance of your patch. @@ -53,23 +53,23 @@ Fossil Architect (Richard Hipp) will merge changes onto the trunk.

              Contributors are required to following the [./checkin.wiki | pre-checkin checklist] prior to every check-in to the Fossil self-hosting repository. This checklist is short and succinct -and should only require a few seconds to follow. Contributors +and should only require a few seconds to follow. Contributors should print out a copy of the pre-checkin checklist and keep -it on a notecard beside their workstations, for quick reference. +it on a note card beside their workstations, for quick reference. Contributors should review the [./style.wiki | Coding Style Guidelines] and mimic the coding style used through the rest of the Fossil source code. Your code should blend in. A third-party reader should be unable to distinguish your -code from any other code in the source corpus. +code from any other code in the source corpus.

              4.0 Testing

              -Fossil has the beginnings of a +Fossil has the beginnings of a [../test/release-checklist.wiki | release checklist] but this is an area that needs further work. (Your contributions here are welcomed!) Contributors with check-in privileges are expected to run the release checklist on any major changes they contribute, and if appropriate expand the checklist and/or the automated test scripts to cover their additions. ADDED www/css-tricks.md Index: www/css-tricks.md ================================================================== --- /dev/null +++ www/css-tricks.md @@ -0,0 +1,74 @@ +# Fossil CSS Tips and Tricks + +Many aspects of Fossil's appearance can be customized by +[customizing the site skin](customskin.md). This document +details certain specific CSS tweaks which users have asked +about via the forums. + +This is a "living document" - please feel free to suggest +additions via [the Fossil forum](https://fossil-scm.org/forum/). + +This document is *not* an introduction to CSS - the web is +full of tutorials on that topic. It covers only the specifics +of customizing certain CSS-based behaviors in a Fossil UI. That said... + +## Is it Really `!important`? + +By and large, CSS's `!important` qualifier is not needed when +customzing Fossil's CSS. On occasion, however, particular styles may +be set directly on DOM elements when Fossil generates its HTML, and +such cases require the use of `!important` to override them. + + + +# Main UI CSS + +## Number of Columns in `/dir` View + +The width of columns on the [`/dir` page](/dir) is calculated +dynamically as the page is generated, to attempt to fit the widest +name in a given directory. The number of columns is determined +automatically by CSS. To modify the number of columns and/or the entry width: + +```css +div.columns { + columns: WIDTH COLUMN_COUNT !important; + /* Examples: + columns: 20ex 3 !important + columns: auto auto !important + */ +} +/* The default rule uses div.columns, but it can also be selected using: */ +div.columns.files { ... } +``` + +The `!important` qualifier is required here because the style values are dynamically +calculated and applied when the HTML is emitted. + +The file list itself can be further customized via: + +```css +div.columns > ul { + ... +} +ul.browser { + ... +} +``` + + + +# Forum-specific CSS + +## Limiting Display Length of Long Posts + +Excessively long posts can make scrolling through threads problematic, +especially on mobile devices. The amount of a post which is visible can +be configured using: + +```css +div.forumPostBody { + max-height: 25em; /* change to the preferred maximum effective height */ + overflow: auto; /* tells the browser to add scrollbars as needed */ +} +``` Index: www/custom_ticket.wiki ================================================================== --- www/custom_ticket.wiki +++ www/custom_ticket.wiki @@ -65,11 +65,11 @@ </tr> <th1>enable_output 1</th1> This bit of code will get rid of the "email" field entry for logged-in users. Since we know the user's information, we don't have to ask for it. NOTE: it -might be good to automatically scoop up the user's email and put it here. +might be good to automatically scoop up the user's email and put it here.

              Modify the 'view ticket' page

              @@ -83,11 +83,11 @@ <td align="right">Opened by:</td><td bgcolor="#d0d0d0"> $<opened_by> </td> This will add a row which displays these two fields, in the event the user has -"edit" capability. +ticket "edit" capability.

              Modify the 'edit ticket' page

              Index: www/customskin.md ================================================================== --- www/customskin.md +++ www/customskin.md @@ -1,75 +1,40 @@ -Theming -======= - -Every HTML page generated by Fossil has the following basic structure: - - -

              - - - -
              Header
              -Fossil-Generated Content
              Footer
              - -The header and footer control the "look" of Fossil pages. Those -two sections can be customized separately for each repository to -develop a new theme. - -The header will normally look something like this: - - - ... - - ... top banner and menu bar ... -
              - -And the footer will look something like this: - -
              - ... bottom material ... - - - -The <head> element in the header will normally reference the -/style.css CSS file that Fossil stores internally. (The $stylesheet_url -TH1 variable, described below, is useful for accomplishing this.) - -The middle "content" section comprised the bulk of most pages and -contains the actual Fossil-generated data -that the user is interested in seeing. The text of this content -section is not normally configurable. The content text can be styled -using CSS, but it otherwise fixed. Hence it is the header and footer -and the CSS that determine the look of a repository. -We call the bundle of built-in CSS, header, and footer a "skin". - -Built-in Skins --------------- - -Fossil comes with several built-in skins. The sources to these built-ins can -be found in the Fossil source tree under the skins/ folder. The skins/ +# Skinning the Fossil Web Interface + +The Fossil web interface comes with a pre-configured look and feel. The default +look and feel works fine in many situations. However, you may want to change +the look and feel (the "skin") of Fossil to better suite your own individual tastes. +This document provides background information to aid you in that task. + +## Built-in Skins + +Fossil comes with multiple built-in skins. If the default skin does not +suite your tastes, perhaps one of the other built-in skins will work better. +If nothing else, the built-in skins can serve as examples or baselines that +you can use to develop your own custom skin. + +The sources to these built-ins can +be found in the Fossil source tree under the skins/ folder. The +[skins/](/dir?ci=trunk&name=skins) folder contains a separate subfolder for each built-in skin, with each -subfolders holding four files, "css.txt", "details.txt", -"footer.txt", and "header.txt", -that describe the CSS, rendering options, -footer, and header for that skin, respectively. - -The skin of a repository can be changed to any of the built-in skins using -the web interface by going to the /setup_skin web page (requires Admin -privileges) and clicking the appropriate button. Or, the --skin command -line option can be used for the -[fossil ui](../../../help?cmd=ui) or -[fossil server](../../../help?cmd=server) commands to force that particular -instance of Fossil to use the specified built-in skin. - -Sharing Skins -------------- +subfolders holding at least these five files: + + * css.txt + * details.txt + * footer.txt + * header.txt + * js.txt + +Try out the built-in skins by using the --skin option on the +[fossil ui](/help?cmd=ui) or [fossil server](/help?cmd=server) commands. + +## Sharing Skins The skin of a repository is not part of the versioned state and does not "push" or "pull" like checked-in files. The skin is local to the repository. However, skins can be shared between repositories using -the [fossil config](../../../help?cmd=configuration) command. +the [fossil config](/help?cmd=configuration) command. The "fossil config push skin" command will send the local skin to a remote repository and the "fossil config pull skin" command will import a skin from a remote repository. The "fossil config export skin FILENAME" will export the skin for a repository into a file FILENAME. This file can then be imported into a different repository using the @@ -85,69 +50,301 @@ automatically change the skin when looking backwards in time, but it will provide an historical record of what the skin used to be and allow the historical look of the repositories to be recreated if necessary. -When cloning a repository, the skin of new repository is initialized to +When cloning a repository, the skin of the new repository is initialized to the skin of the repository from which it was cloned. -Header And Footer Processing ----------------------------- +# Structure Of A Fossil Web Page + +Every HTML page generated by Fossil has the same basic structure: + +
              + + + + + +
              +Fossil-Generated HTML Header
              Content Header
              +Fossil-Generated Content
              Content Footer
              +Fossil-Generated HTML Footer
              + +The green parts are generated by Fossil. The blue parts are things that +you, the administrator, get to modify in order to customize the skin. + +Fossil *usually* (but not always - [see below](#override)) +generates the initial HTML Header section of a page. The +generated HTML Header will look something like this: + + + + + + + .... + + + + +In most cases, it is best to leave the Fossil-generated HTML Header alone. +The configurable part of the skin begins with the Content Header section which +should followign the following template: + +
              + ... top banner and menu bar ... +
              + +Note that `
              ` and `
              ` tags must be included in the +Content Header text of the skin. In other words, you the administrator need +to supply that text as part of your skin customization. + +The Fossil-generated Content section immediately follows the Content Header. +The Content section will looks like this: + +
              + ... Fossil-generated content here ... +
              + +After the Content is the custom Content Footer section which should +following this template: + + + + +As with the Content Header, the template elements of the Content Footer +should appear exactly as they are shown. + +Finally, Fossil always adds its own footer (unless overridden) +to close out the generated HTML: + + + + +## Overriding the HTML Header and Footer + +Notice that the ``, ``, and opening `` +elements at the beginning of the document, +and the closing `` and `` elements at the end are automatically +generated by Fossil. This is recommended. + +However, for maximum design flexibility, Fossil allows those elements to be +supplied as part of the configurable Content Header and Content Footer. +If the Content Header contains the text "``, +``, and `` text itself, and the Fossil-generated header and +footer will be blank. + +When overriding the HTML Header in this way, you will probably want to use some +of the [TH1 variables documented below](#vars) such as `$stylesheet_url` +to avoid hand-writing code that Fossil can generate for you. + +# Designing, Debugging, and Installing A Custom Skin + +It is possible to develop a new skin from scratch. But a better and easier +approach is to use one of the existing built-in skins as a baseline and +make incremental modifications, testing after each step, to obtain the +desired result. + +The skin is controlled by five files: + +
              +
              css.txt
              + +

              The css.txt file is the text of the CSS for Fossil. +Fossil might add additional CSS elements after the +the css.txt file, if it sees that the css.txt omits some +CSS components that Fossil needs. But for the most part, +the content of the css.txt is the CSS for the page.

              + +
              details.txt
              + +

              The details.txt file is short list of settings that control +the look and feel, mostly of the timeline. The default +details.txt file looks like this: + +

              +timeline-arrowheads:        1
              +timeline-circle-nodes:      1
              +timeline-color-graph-lines: 1
              +white-foreground:           0
              +
              + +The first three setings in details.txt control the appearance +of certain aspects of the timeline graph. The number on the +right is a boolean - "1" to activate the feature and "0" to +disable it. The "white-foreground:" setting should be set to +"1" if the page color has light-color text on a darker background, +and "0" if the page has dark text on a light-colored background.
              + +
              footer.txt and header.txt
              + +

              The footer.txt and header.txt files contain the Content Footer +and Content Header respectively. Of these, the Content Header is +the most important, as it contains the markup used to generate +the banner and menu bar for each page. + +

              Both the footer.txt and header.txt file are +[processed using TH1](#headfoot) prior to being output as +part of the overall web page.

              + +
              js.txt
              + +

              The js.txt file is intended to be javascript. The complete +text of this javascript is typically inserted into the Content Footer +by this part of the "footer.txt" file: + +

              +<script nonce="$nonce">
              +  <th1>styleScript</th1>
              +</script>
              +
              + +

              The js.txt file was originally intended to insert javascript +that controls the hamburger menu. +The footer.txt file probably should contain lines like the +above, even if js.txt is empty.

              +
              + +Developing a new skin is simply a matter of creating appropriate +versions of these five control files. + +### Skin Development Using The Web Interface + +Users with admin privileges can use the Admin/Skin configuration page +on the web interface to develop a new skin. The development of a new +skin occurs without disrupting the existing skin. So you can work on +a new skin for a Fossil instance while the existing skin is still in +active use. + +The new skin is a "draft" skin. You initialize one of 9 draft skins +to either the current skin or to one of the built-in skins. Then +use forms to edit the 5 control files described above. The new +skin can be tested after each edit. Finally, once the new skin is +working as desired, the draft skin is "published" and becomes the +new live skin that most users see. + +### Skin Development Using A Local Text Editor + +An alternative approach is to copy the five control files for your +baseline skin into a temporary working directory (here called +"./newskin") and then launch the [fossil ui](/help?cmd=ui) command +with the "--skin ./newskin" option. If the argument to the --skin +option contains a "/" character, then the five control files are +read out of the directory named. You can then edit the control +files in the ./newskin folder using you favorite text editor, and +press "Reload" on your browser to see the effects. + +## Header and Footer Processing -The header.txt and footer.txt files of a scan are merely the HTML text -of the header and footer. Except, before being prepended and appended to -the content, the header and footer text are run through a +The `header.txt` and `footer.txt` control files of a skin are the HTML text +of the Contnet Header and Content Footer, except that before being inserted +into the output stream, the text is run through a [TH1 interpreter](./th1.md) that might adjust the text as follows: - * All text within <th1>...</th1> is elided from the - output and that text is instead run as a TH1 script. That TH1 + * All text within <th1>...</th1> is omitted from the + output and is instead run as a TH1 script. That TH1 script has the opportunity to insert new text in place of itself, or to inhibit or enable the output of subsequent text. - * Text for the form "$NAME" or "$<NAME>" is replace with + * Text of the form "$NAME" or "$<NAME>" is replaced with the value of the TH1 variable NAME. -For example, the following is the first few lines of a typical -header file: - - - - - $<project_name>: $<title> - - - - -After variables are substituted by TH1, the final header text -delivered to the web browser might look something like this: - - - - - Fossil: Timeline - - - +For example, first few lines of a typical Content Header will look +like this: + +
              +

              $

              $/div> + +After variables are substituted by TH1, that will look more like this: + + <div class="header"> + <div class="title"><h1>Project Name</h1>Page Title</div> + +As you can see, two TH1 variable substitutions were done. The same TH1 interpreter is used for both the header and the footer and for all scripts contained within them both. Hence, any global TH1 variables that are set by the header are available to the footer. -TH1 Variables -------------- +## <a name="menu"></a>Customizing the ≡ Hamburger Menu + +The menu bar of the default skin has an entry to open a drop-down menu with +additional navigation links, represented by the ≡ button (hence the name +"hamburger menu"). The Javascript logic to open and close the hamburger menu +when the button is clicked is contained in the optional Javascript part (js.txt) +of the default skin. Out of the box, the drop-down menu shows the [Site +Map](../../../sitemap), loaded by an AJAX request prior to the first display. + +The ≡ button for the hamburger menu is added to the menu bar by the following +TH1 command in the default skin header.txt, right before the menu bar links: + + html "<a id='hbbtn' href='#'>☰</a>" + +The hamburger button can be repositioned between the other menu links (but the +drop-down menu is always left-aligned with the menu bar), or it can be removed +by deleting the above statement (the Javascript logic detects this case and +remains idle, so it's not necessary to modify the default skin js.txt). + +The following empty element at the bottom of the default skin header.txt serves +as the panel to hold the drop-down menu elements: + + <div id='hbdrop'></div> + +Out of the box, the contents of the panel is populated with the [Site +Map](../../../sitemap), but only if the panel does not already contain any HTML +elements (that is, not just comments, plain text or non-presentational white +space). So the hamburger menu can be customized by replacing the empty `<div +id='hbdrop'></div>` element with a menu structure knitted according to the +following template: + + <div id="hbdrop" data-anim-ms="400"> + <ul class="columns" style="column-width: 20em; column-count: auto"> + <!-- NEW GROUP WITH HEADING LINK --> + <li> + <a href="$home$index_page">Link: Home</a> + <ul> + <li><a href="$home/timeline">Link: Timeline</a></li> + <li><a href="$home/dir?ci=tip">Link: File List</a></li> + </ul> + </li> + <!-- NEW GROUP WITH HEADING TEXT --> + <li> + Heading Text + <ul> + <li><a href="$home/doc/trunk/www/customskin.md">Link: Theming</a></li> + <li><a href="$home/doc/trunk/www/th1.md">Link: TH1 Scripts</a></li> + </ul> + </li> + <!-- NEXT GROUP GOES HERE --> + </ul> + </div> + +The custom `data-anim-ms` attribute can be added to the panel element to direct +the Javascript logic to override the default menu animation duration of 400 ms. +A faster animation duration of 80-200 ms may be preferred for smaller menus. The +animation is disabled by setting the attribute to `"0"`. + + +## <a name="vars"></a>TH1 Variables Before expanding the TH1 within the header and footer, Fossil first initializes a number of TH1 variables to values that depend on -respository settings and the specific page being generated. +repository settings and the specific page being generated. * **project_name** - The project_name variable is filled with the name of the project as configured under the Admin/Configuration menu. + + * **project_description** - The project_description variable is + filled with the description of the project as configured under + the Admin/Configuration menu. * **title** - The title variable holds the title of the page being generated. The title variable is special in that it is deleted after @@ -170,14 +367,22 @@ * **current_page** - The name of the page currently being processed, without the leading "/" and without query parameters. Examples: "timeline", "doc/trunk/README.txt", "wiki". * **csrf_token** - A token used to prevent cross-site request forgery. + + * **default_csp** - [Fossil’s default CSP](./defcsp.md) unless + [overridden by custom TH1 code](./defcsp.md#th1). Useful within + the skin for inserting the CSP into a `<meta>` tag within [a + custom `<head>` element](#headfoot). + + * **nonce** - The value of the cryptographic nonce for the request + being processed. * **release_version** - The release version of Fossil. Ex: "1.31" - * **manifest_version** - A prefix on the SHA1 check-in hash of the + * **manifest_version** - A prefix on the check-in hash of the specific version of fossil that is running. Ex: "\[47bb6432a1\]" * **manifest_date** - The date of the source-code check-in for the version of fossil that is running. @@ -199,12 +404,12 @@ All of the above are variables in the sense that either the header or the footer is free to change or erase them. But they should probably be treated as constants. New predefined values are likely to be added in future releases of Fossil. -Suggested Skin Customization Procedure --------------------------------------- + +## <a name="procedure"></a>Suggested Skin Customization Procedure Developers are free, of course, to develop new skins using any method they want, but the following is a technique that has worked well in the past and can serve as a starting point for future work: @@ -233,9 +438,9 @@ 4. Copy/paste the resulting css.txt, details.txt, header.txt, and footer.txt files into the CSS, details, header, and footer configuration screens under the Admin/Skins menu. -See Also --------- + +## See Also * [Customizing the Timeline Graph](customgraph.md) ADDED www/defcsp.md Index: www/defcsp.md ================================================================== --- /dev/null +++ www/defcsp.md @@ -0,0 +1,389 @@ +# The Default Content Security Policy (CSP) + +When Fossil’s web interface generates an HTML page, it normally includes +a [Content Security Policy][csp] (CSP) in the `<head>`. The CSP defines +a “white list” to tell the browser what types of content (HTML, images, +CSS, JavaScript...) the document may reference and the sources the +browser is allowed to pull and interpret such content from. The aim is to prevent +certain classes of [cross-site scripting][xss] (XSS) and code injection +attacks. The browser will not pull content types disallowed by the CSP; +the CSP also adds restrictions on the types of inline content the +browser is allowed to interpret. + +Fossil has built-in server-side content filtering logic. For example, it +purposely breaks `<script>` tags when it finds them in Markdown and +Fossil Wiki documents. (But not in [HTML-formatted embedded +docs][hfed]!) We also back that with multiple levels of analysis and +checks to find and fix content security problems: compile-time static +analysis, run-time dynamic analysis, and manual code inspection. Fossil +is open source software, so it benefits from the “[many +eyeballs][llaw],” limited by the size of its developer community. + +However, there is a practical limit to the power of server-side +filtering and code quality practices. + +First, there is an endless battle between those looking for clever paths +around such barriers and those erecting the barriers. The developers of +Fossil are committed to holding up our end of that fight, but this is, +to some extent, a reactive posture. It is cold comfort if Fossil’s +developers react quickly to a report of code injection — as we do! — if +the bad guys learn of it and start exploiting it first. + +Second, Fossil has purposefully powerful features that are inherently +difficult to police from the server side: HTML tags [in wiki](/wiki_rules) +and [in Markdown](/md_rules) docs, [TH1 docs](./th1.md), the Admin → +Wiki → “Use HTML as wiki markup language” mode, etc. + +Fossil’s strong default CSP adds client-side filtering as a backstop for +all of this. + +Fossil site administrators can [modify the default CSP](#override), perhaps +to add trusted external sources for auxiliary content. But for maximum +safety, site developers are encouraged to work within the restrictions +imposed by the default CSP and avoid the temptation to relax the CSP +unless they fully understand the security implications of what they are +doing. + +[llaw]: https://en.wikipedia.org/wiki/Linus%27s_Law + + +## The Default Restrictions + +The Fossil default CSP declares the following content restrictions: + + +### <a name="base"></a> default-src 'self' data: + +This policy means mixed-origin content isn’t allowed, so you can’t refer +to resources on other web domains. Browsers will ignore a link like the +one in the following Markdown under our default CSP: + + ![fancy 3D Fossil logotype](https://i.imgur.com/HalpMgt.png) + +If you look in the browser’s developer console, you should see a CSP +error when attempting to render such a page. + +The default policy does allow inline `data:` URIs, which means you could +[data-encode][de] your image content and put it inline within the +document: + + ![small inline image](data:image/gif;base64,R0lGODlh...) + +That method is best used for fairly small resources. Large `data:` URIs +are hard to read and edit. There are secondary problems as well: if you +put a large image into a Fossil forum post this way, anyone subscribed +to email alerts will get a copy of the raw URI text, which can amount to +pages and pages of [ugly Base64-encoded text][b64]. + +For inline images within [embedded documentation][ed], it suffices to +store the referred-to files in the repo and then refer to them using +repo-relative URLs: + + ![large inline image](./inlineimage.jpg) + +This avoids bloating the doc text with `data:` URI blobs: + +There are many other cases, [covered below](#serving). + +[b64]: https://en.wikipedia.org/wiki/Base64 +[svr]: ./server/ + + +### <a name="style"></a> style-src 'self' 'unsafe-inline' + +This policy allows CSS information to come from separate files hosted +under the Fossil repo server’s Internet domain. It also allows inline CSS +`<style>` tags within the document text. + +The `'unsafe-inline'` declaration allows CSS within individual HTML +elements: + + <p style="margin-left: 4em">Indented text.</p> + +As the "`unsafe-`" prefix on the name implies, the `'unsafe-inline'` +feature is suboptimal for security. However, there are +a few places in the Fossil-generated HTML that benefit from this +flexibility and the work-arounds are verbose and difficult to maintain. +Futhermore, the harm that can be done with style injections is far +less than the harm possible with injected javascript. And so the +`'unsafe-inline'` compromise is accepted for now, though it might +go away in some future release of Fossil. + +### <a name="script"></a> script-src 'self' 'nonce-%s' + +This policy disables in-line JavaScript and only allows `<script>` +elements if the `<script>` includes a `nonce` attribute that matches the +one declared by the CSP. That nonce is a large random number, unique for +each HTTP page generated by Fossil, so an attacker cannot guess the +value, so the browser will ignore an attacker’s injected JavaScript. + +That nonce can only come from one of three sources, all of which should +be protected at the system administration level on the Fossil server: + +* **Fossil server C code:** All code paths in Fossil that emit + `<script>` elements include the `nonce` attribute. There are several + cases, such as the “JavaScript” section of a [custom skin][cs]. + That text is currently inserted into each HTML page generated by + Fossil,¹ which means it needs to include a `nonce` attribute to + allow it to run under this default CSP. We consider JavaScript + emitted via these paths to be safe because it’s audited by the + Fossil developers. We assume that you got your Fossil server’s code + from a trustworthy source and that an attacker cannot replace your + Fossil server binary. + +* **TH1 code:** The Fossil TH1 interpreter pre-defines the + [`$nonce` variable](./th1.md#nonce) for use in [custom skins][cs]. For + example, some of the stock skins that ship with Fossil include a + wall clock feature up in the corner that updates once a minute. + These paths are safe in the default Fossil configuration because + only the [all-powerful Setup user][su] can write TH1 code that + executes in the server’s running context. + + There is, however, [a default-disabled path](#xss) to beware of, + covered in the next section. + +* **[CGI server extensions][ext]:** Fossil exports the nonce to the + CGI in the `FOSSIL_NONCE` environment variable, which it can then + use in `<script>` elements it generates. Because these extensions + can only be installed by the Fossil server’s system administrator, + this path is also considered safe. + +[ext]: ./serverext.wiki +[su]: ./caps/admin-v-setup.md#apsu + + +#### <a name="xss"></a>Cross-Site Scripting via Ordinary User Capabilities + +We’re so restrictive about how we treat JavaScript because it can lead +to difficult-to-avoid scripting attacks. If we used the same CSP for +`<script>` tags [as for `<style>` tags](#style), anyone with check-in +rights on your repository could add a JavaScript file to your repository +and then refer to it from other content added to the site. Since +JavaScript code can access any data from any URI served under its same +Internet domain, and many Fossil users host multiple Fossil repositories +under a single Internet domain, such a CSP would only be safe if all of +those repositories are trusted equally. + +Consider [the Chisel hosting service](http://chiselapp.com/), which +offers free Fossil repository hosting to anyone on the Internet, all +served under the same `http://chiselapp.com/user/$NAME/$REPO` URL +scheme. Any one of those hundreds of repositories could trick you into +visiting their repository home page, set to [an HTML-formatted embedded +doc page][hfed] via Admin → Configuration → Index Page, with this +content: + + <script src="/doc/trunk/bad.js"></script> + +That script can then do anything allowed in JavaScript to *any other* +Chisel repository your browser can access.The possibilities for mischief +are *vast*. For just one example, if you have login cookies on four +different Chisel repositories, your attacker could harvest the login +cookies for all of them through this path if we allowed Fossil to serve +JavaScript files under the same CSP policy as we do for CSS files. + +This is why the default configuration of Fossil has no way for [embedded +docs][ed], [wiki articles][wiki], [tickets][tkt], [forum posts][fp], or +[tech notes][tn] to automatically insert a nonce into the page content. +This is all user-provided content, which could link to user-provided +JavaScript via check-in rights, effectively giving all such users a +capability that is usually reserved to the repository’s administrator. + +The default-disabled [TH1 documents feature][edtf] is the only known +path around this restriction. If you are serving a Fossil repository +that has any user you do not implicitly trust to a level that you would +willingly run any JavaScript code they’ve provided, blind, you **must +not** give the `--with-th1-docs` option when configuring Fossil, because +that allows substitution of the [pre-defined `$nonce` TH1 +variable](./th1.md#nonce) into [HTML-formatted embedded docs][hfed]: + + <script src="/doc/trunk/bad.js" nonce="$nonce"></script> + +Even with this feature enabled, you cannot put `<script>` tags into +Fossil Wiki or Markdown-formatted content, because our HTML generators +for those formats purposely strip or disable such tags in the output. +Therefore, if you trust those users with check-in rights to provide +JavaScript but not those allowed to file tickets, append to wiki +articles, etc., you might justify enabling TH1 docs on your repository, +since the only way to create or modify HTML-formatted embedded docs is +through check-ins. + +[ed]: ./embeddeddoc.wiki +[edtf]: ./embeddeddoc.wiki#th1 +[hfed]: ./embeddeddoc.wiki#html + + +## <a name="serving"></a>Serving Files Within the Limits + +There are several ways to serve files within the above restrictions, +avoiding the need to [override the default CSP](#override). In +decreasing order of simplicity and preference: + +1. Within [embedded documentation][ed] (only!) you can refer to files + stored in the repo using document-relative file URLs: + + ![inline image](./inlineimage.jpg) + +2. Relative file URLs don’t work from [wiki articles][wiki], + [tickets][tkt], [forum posts][fp], or [tech notes][tn], but you can + still refer to them inside the repo with [`/doc`][du] or + [`/raw`][ru] URLs: + + ![inline image](/doc/trunk/images/inlineimage.jpg) + <img src="/raw/logo.png" style="float: right; margin-left: 2em"> + +3. Store the files as [unversioned content][uv], referred to using + [`/uv`][uu] URLs instead: + + ![logo](/uv/logo.png) + +4. Use the [optional CGI server extensions feature](./serverext.wiki) + to serve such content via `/ext` URLs. + +5. Put Fossil behind a [front-end proxy server][svr] as a virtual + subdirectory within the site, so that our default CSP’s “self” rules + match static file routes on that same site. For instance, your repo + might be at `https://example.com/code`, allowing documentes in that + repo to refer to: + + * images as `/image/foo.png` + * JavaScript files as `/js/bar.js` + * CSS style sheets as `/style/qux.css` + + Although those files are all outside the Fossil repo at `/code`, + keep in mind that it is the browser’s notion of “self” that matters + here, not Fossil’s. All resources come from the same Internet + domain, so the browser cannot distinguish Fossil-provided content + from static content served directly by the proxy server. + + This method opens up many other potential benefits, such as [TLS + encryption](./tls-nginx.md), high-performance tuning via custom HTTP + headers, integration with other web technologies like PHP, etc. + +You might wonder why we rank in-repo content as most preferred above. It +is because the first two options are the only ones that cause such +resources to be included in an initial clone or in subsequent repo +syncs. The methods further down the list have a number of undesirable +properties: + +1. Relative links to out-of-repo files break in `fossil ui` when run on + a clone. + +2. Absolute links back to the public repo instance solve that: + + ![inline image](https://example.com/images/logo.png) + + ...but using them breaks some types of failover and load-balancing + schemes, because it creates a [single point of failure][spof]. + +3. Absolute links fail when one’s purpose in using a clone is to + recover from the loss of a project web site by standing that clone + up [as a server][svr] elsewhere. You probably forgot to copy such + external resources in the backup copies, so that when the main repo + site disappears, so do those files. + +Unversioned content is in the middle of the first list above — between +fully-external content and fully in-repo content — because it isn’t +included in a clone unless you give the `--unversioned` flag. If you +then want updates to the unversioned content to be included in syncs, +you have to give the same flag to [a `sync` command](/help?cmd=sync). +There is no equivalent with other commands such as `up` and `pull`, so +you must then remember to give `fossil uv` commands when necessary to +pull new unversioned content down. + +Thus our recommendation that you refer to in-repo resources exclusively. + +[du]: /help?cmd=/doc +[fp]: ./forum.wiki +[ru]: /help?cmd=/raw +[spof]: https://en.wikipedia.org/wiki/Single_point_of_failure +[tkt]: ./tickets.wiki +[tn]: ./event.wiki +[uu]: /help?cmd=/uv +[uv]: ./unvers.wiki +[wiki]: ./wikitheory.wiki + + +## <a name="override"></a>Overriding the Default CSP + +If you wish to relax the default CSP’s restrictions or to tighten them +further, there are two ways to accomplish that: + + +### <a name="th1"></a>TH1 Setup Hook + +The stock CSP text is hard-coded in the Fossil C source code, but it’s +only used to set the default value of one of [the TH1 skinning +variables](./customskin.md#vars), `$default_csp`. That means you can +override the default CSP by giving this variable a value before Fossil +sees that it’s undefined and uses this default. + +The best place to do that is from the [`th1-setup` +script](./th1-hooks.md), which runs before TH1 processing happens during +skin processing: + + $ fossil set th1-setup "set default_csp {default-src 'self'}" + +This is the cleanest method, allowing you to set a custom CSP without +recompiling Fossil or providing a hand-written `<head>` section in the +Header section of a custom skin. + +You can’t remove the CSP entirely with this method, but you can get the +same effect by telling the browser there are no content restrictions: + + $ fossil set th1-setup 'set default_csp {default-src *}' + + +### <a name="header"></a>Custom Skin Header + +Fossil only inserts a CSP into the HTML pages it generates when the +[skin’s Header section](./customskin.md#headfoot) doesn’t contain a +`<head>` tag. None of the stock skins include a `<head>` tag,² so if you +haven’t [created a custom skin][cs], you should be getting Fossil’s +default CSP. + +We say “should” because long-time Fossil users may be hanging onto a +legacy behavior from before Fossil 2.5, when Fossil added this automatic +`<head>` insertion feature. Repositories created before that release +where the admin either defined a custom skin *or chose one of the stock +skins* (!) will effectively override this automatic HTML `<head>` +insertion feature because the skins from before that time did include +these elements. Unless the admin for such a repository updated the skin +to track this switch to automatic `<head>` insertion, the default CSP +added to the generated header text in Fossil 2.7 is probably being +overridden by the skin. + +If you want the protection of the default CSP in your custom skin, the +simplest method is to leave the `<html><head>...` elements out of the +skin’s Header section, starting it with the `<div class="head">` element +instead as described in the custom skinning guide. Alternately, you can +[make use of `$default_csp`](#th1). + +This then tells you one way to override Fossil’s default CSP: provide +your own HTML header in a custom skin. + +A useful combination is to entirely override the default CSP in the skin +but then provide a new CSP [in the front-end proxy layer][svr] +using any of the many reverse proxy servers that can define custom HTTP +headers. + + +------------ + + +**Asides and Digressions:** + +1. Fossil might someday switch to serving the “JavaScript” section of a + custom skin as a virtual text file, allowing it to be cached by the + browser, reducing page load times. + +2. The stock Bootstrap skin does actually include a `<head>` tag, but + from Fossil 2.7 through Fossil 2.9, it just repeated the same CSP + text that Fossil’s C code inserts into the HTML header for all other + stock skins. With Fossil 2.10, the stock Bootstrap skin uses + `$default_csp` instead, so you can [override it as above](#th1). + + +[cs]: ./customskin.md +[csp]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP +[de]: https://dopiaza.org/tools/datauri/index.php +[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting Index: www/delta_encoder_algorithm.wiki ================================================================== --- www/delta_encoder_algorithm.wiki +++ www/delta_encoder_algorithm.wiki @@ -153,11 +153,11 @@ byte forward. The "base" is left unchanged in that case.</p> <p>The processing loop stops at one of two conditions: <ol> <li>The encoder decided to move the window forward, but the end of the -window reached the end of the "target". +window reached the end of the "target". </li> <li>After the emission of instructions the new "base" location is within NHASH bytes of end of the "target", i.e. there are no more than at most NHASH bytes left. </li> Index: www/delta_format.wiki ================================================================== --- www/delta_format.wiki +++ www/delta_format.wiki @@ -1,42 +1,80 @@ <title>Fossil Delta Format - -

              Abstract

              +

              1.0 Overview

              Fossil achieves efficient storage and low-bandwidth synchronization through the use of delta-compression. Instead of storing -or transmitting the complete content of an artifact, fossil stores or +or transmitting the complete content of an artifact, Fossil stores or transmits only the changes relative to a related artifact.

              -

              This document describes the delta-encoding format used by fossil. +

              This document describes the delta-encoding format used by Fossil. The intended audience is developers working on either -fossil itself, or on tools compatible with -fossil.

              - -

              Note that the delta-encoding is not a fundamental element of the -state of a fossil repository. A state of a fossil repository is -defined by the uncompressed and undeltaed content of all artifacts. -The fact the artifacts -are stored on disk using this delta-encoding format is merely an -optimization. One could, in theory, create an entirely new and -compatible implementation of fossil that used a different delta-encoding -or did no delta-encoding at all. However, experience has shown that -the delta-encoding described here is both efficient to compute and -results in very small deltas, so its continued use is recommended.

              - -

              1.0 Structure

              +Fossil itself, or on tools compatible with +Fossil. Understanding of this document is not required for +ordinary users of Fossil. This document is an implementation detail.

              + +

              This document only describes the delta file format. A +[./delta_encoder_algorithm.wiki|separate document] describes one possible +algorithm for generating deltas in this format.

              + +

              1.1 Sample Software And Analysis Tools

              + +

              The core routines used to generate and apply deltas in this format +are contained in the [../src/delta.c|delta.c] source file. Interface +logic, including "test-*" commands to directly manipulate deltas are +contained in the [../src/deltacmd.c|deltacmd.c] source file. SQL functions +to create, apply, and analyze deltas are implemented by code in the +[../src/deltafunc.c|deltafunc.c] source file. + +

              The following command-line tools are available to create and apply +deltas and to test the delta logic: + + * [/help?cmd=test-delta|fossil test-delta] → Run self-tests of + the delta logic + + * [/help?cmd=test-delta-create|fossil test-delta-create X Y] → compute + a delta that converts file X into file Y. Output that delta. + + * [/help?cmd=test-delta-apply|fossil test-delta-apply X D] → apply + delta D to input file X and output the result. + + * [/help?cmd=test-delta-analyze|fossil test-delta-analyze X Y] → compute + and delta that converts file X into file Y but instead of writing the + delta to output, write performance information about the delta. + +

              When running the [/help?cmd=sqlite3|fossil sql] command to get an +interactive SQL session connected to the repository, the following +additional SQL functions are provided: + + * delta_create(X,Y) → + Compute a data that carries blob X into blob Y and return that delta + as a blob. + + * delta_apply(X,D) → + Apply delta D to input blob X return a new blob which is the result. + + + * delta_output_size(D) → + Return the size of the output that would result from applying delta D. + + * delta_parse(D) → This is a table-valued function + that returns one row for the header, for the trailer, and for each segment + in delta D. + + +

              2.0 Structure

              A delta consists of three parts, a "header", a "trailer", and a "segment-list" between them.

              Both header and trailer provide information about the target helping the decoder, and the segment-list describes how the target can be constructed from the original.

              -

              1.1 Header

              +

              2.1 Header

              The header consists of a single number followed by a newline character (ASCII 0x0a). The number is the length of the target in bytes.

              @@ -44,11 +82,11 @@

              This means that, given a delta, the decoder can compute the size of the target (and allocate any necessary memory based on that) by simply reading the first line of the delta and decoding the number found there. In other words, before it has to decode everything else.

              -

              1.2 Trailer

              +

              2.2 Trailer

              The trailer consists of a single number followed by a semicolon (ASCII 0x3b). This number is a checksum of the target and can be used by a decoder to verify that the delta applied correctly, reconstructing the @@ -61,11 +99,11 @@

              By putting this information at the end of the delta a decoder has it available immediately after the target has been reconstructed fully.

              -

              1.3 Segment-List

              +

              2.3 Segment-List

              The segment-list of a delta describes how to create the target from the original by a combination of inserting literal byte-sequences and copying ranges of bytes from the original. This is where the @@ -74,20 +112,20 @@

              The target is constructed from beginning to end, with the data generated by each instruction appended after the data of all previous instructions, with no gaps.

              -

              1.3.1 Insert Literal

              +

              2.3.1 Insert Literal

              A literal is specified by two elements, the size of the literal in bytes, and the bytes of the literal itself.

              The length is written first, followed by a colon character (ASCII 0x3a), followed by the bytes of the literal.

              -

              1.3.2 Copy Range

              +

              2.3.2 Copy Range

              A range to copy is specified by two numbers, the offset of the first byte in the original to copy, and the size of the range, in bytes. The size zero is special, its usage indicates that the range extends to the end of the original.

              @@ -94,11 +132,11 @@

              The length is written first, followed by an "at" character (ASCII 0x40), then the offset, followed by a comma (ASCII 0x2c).

              -

              2.0 Encoding of integers

              +

              3.0 Encoding of integers

              The format currently handles only 32 bit integer numbers. They are written base-64 encoded, MSB first, and without leading "0"-characters, except if they are significant (i.e. 0 => "0"). @@ -107,13 +145,13 @@

              The base-64 coding is described in RFC 3548.

              -

              3.0 Examples

              +

              4.0 Examples

              -

              3.1 Integer encoding

              +

              4.1 Integer encoding

              @@ -130,11 +168,11 @@
              Value Encoding-1101438770 2zMM3E
              -

              3.2 Delta encoding

              +

              4.2 Delta encoding

              An example of a delta using the specified encoding is:

               1Xb
              @@ -161,56 +199,56 @@
               

              The unified diff behind the above delta is

              -bluepeak:(761) ~/Projects/Tcl/Fossil/Devel/devel > diff -u ../DELTA/old ../DELTA/new 
              +bluepeak:(761) ~/Projects/Tcl/Fossil/Devel/devel > diff -u ../DELTA/old ../DELTA/new
               --- ../DELTA/old        2007-08-23 21:14:40.000000000 -0700
               +++ ../DELTA/new        2007-08-23 21:14:33.000000000 -0700
               @@ -5,7 +5,7 @@
              - 
              +
                 *  If the server does not have write permission on the database
              -     file, or on the directory containing the database file (and 
              +     file, or on the directory containing the database file (and
               -    it is thus unable to update database because it cannot create
               +    it is thus unable to update the database because it cannot create
                    a rollback journal) then it currently fails silently on a push.
                    It needs to return a helpful error.
              - 
              +
               @@ -27,8 +27,8 @@
                 *  Additional information displayed for the "vinfo" page:
              - 
              +
                     +  All leaves of this version that are not included in the
               -        descendant list.  With date, user, comment, and hyperlink.
               -        Leaves in the descendant table should be marked as such.
               +        descendant list.  With date, user, comment, and hyperlink.
               +        Leaves in the descendant table should be marked as such.
                        See the compute_leaves() function to see how to find all
                        leaves.
                     +  Add file diff links to the file change list.
               @@ -37,7 +37,7 @@
              - 
              +
                 *  The /xfer handler (for push, pull, and clone) does not do
                    delta compression.  This results in excess bandwidth usage.
               -    There are some code in xfer.c that are sketches of ideas on
               +    There are some pieces in xfer.c that are sketches of ideas on
                    how to do delta compression, but nothing has been implemented.
              - 
              +
                 *  Enhancements to the diff and tkdiff commands in the cli.
               @@ -45,7 +45,7 @@
                    single file.  Allow diffs against any two arbitrary versions,
              -     not just diffs against the current check-out.  Allow 
              +     not just diffs against the current check-out.  Allow
                    configuration options to replace tkdiff with some other
               -    visual differ of the users choice.
               +    visual differ of the users choice. Example: eskil.
              - 
              +
                 *  Ticketing interface (expand this bullet)
               
               
              -

              Notes

              +

              Notes

              • Pure text files generate a pure text delta.
              • Binary files generate a delta that may contain some binary data. Index: www/embeddeddoc.wiki ================================================================== --- www/embeddeddoc.wiki +++ www/embeddeddoc.wiki @@ -24,11 +24,11 @@ on the nature of your project.) We will call documentation that is included as files in the source tree "embedded documentation". -

                Fossil Support For Embedded Documentation

                +

                1.0 Fossil Support For Embedded Documentation

                The fossil web interface supports embedded documentation using the "/doc" page. To access embedded documentation, one points a web browser to a fossil URL of the following form: @@ -36,93 +36,183 @@ <baseurl>/doc/<version>/<filename>
              The <baseurl> is the main URL used to access the fossil web server. For example, the <baseurl> for the fossil project itself is -either http://www.fossil-scm.org/fossil or -http://www.hwaci.com/cgi-bin/fossil. -If you launch the web server using the "fossil server" command line, +[https://www.fossil-scm.org/fossil]. +If you launch the web server using the "[/help?cmd=ui|fossil ui]" command line, then the <baseurl> is usually http://localhost:8080/. -The <version> is any unique prefix of the check-in ID for -the check-in containing the documentation you want to access. -Or <version> can be the name of a -[./branching.wiki | branch] in order to show -the documentation for the latest version of that branch. -Or <version> can be one of the keywords "tip" or -"ckout". The "tip" keyword means to use the most recent -check-in. This is useful if you want to see the very latest -version of the documentation. The "ckout" keywords means to +The <version> is the +[./checkin_names.wiki|name of a check-in] +that contains the embedded document. This might be a hash prefix for +the check-in, or it might be the name of a branch or tag, or it might +be a timestamp. See the prior link +for more possibilities and examples. + +The <version> can +also be the special identifier "ckout". +The "ckout" keywords means to pull the documentation file from the local source tree on disk, not -from the any check-in. The "ckout" keyword normally -only works when you start your server using the "fossil server" -or "fossil ui" -command line and is intended to show what the documentation you are currently -editing looks like before you check it in. +from the any check-in. The "ckout" keyword +only works when you start your server using the +"[/help?cmd=server|fossil server]" or "[/help?cmd=ui|fossil ui]" +commands. The "/doc/ckout" URL is intended to show a preview of +the documentation you are currently editing but have not yet you checked in. + +The original designed purpose of the "ckout" feature is to allow the +user to preview local changes to documentation before committing the +change. This is an important facility, since unlike other document +languages like HTML, there is still a lot of variation among rendering +engines for Fossil's markup languages, Markdown and Fossil Wiki. Your +changes may look fine in your whizzy GUI Markdown editor, but what +actually matters is how Fossil will interpret your Markdown text. +Therefore, you should always preview your edits before committing them. Finally, the <filename> element of the URL is the pathname of the documentation file relative to the root of the source tree. -The mimetype (and thus the rendering) of documentation files is -determined by the file suffix. Fossil currently understands +The mimetype (and thus the rendering) of documentation files is +determined by the file suffix. Fossil currently understands [/mimetype_list|many different file suffixes], including all the popular ones such as ".css", ".gif", ".htm", ".html", ".jpg", ".jpeg", ".png", and ".txt". -Documentation files whose names end in ".wiki" use the +Documentation files whose names end in ".wiki" use the [/wiki_rules | fossil wiki markup] - a safe subset of HTML together with some wiki rules for paragraph -breaks, lists, and hyperlinks. +breaks, lists, and hyperlinks. Documentation files ending in ".md" or ".markdown" use the -[/md_rules | Markdown markup langauge]. +[/md_rules | Markdown markup language]. Documentation files ending in ".txt" are plain text. Wiki, markdown, and plain text documentation files are rendered with the standard fossil header and footer added. Most other mimetypes are delivered directly to the requesting web browser without interpretation, additions, or changes. -Files with the mimetype "text/html" (the .html or .htm suffix) are -usually rendered directly to the browser without interpretation. +

              1.1 HTML Rendering With Fossil Headers And Footers

              + +Files with the mimetype "text/html" (the .html or .htm suffix) are +usually rendered directly to the browser without interpretation. However, if the file begins with a <div> element like this: <div class='fossil-doc' data-title='Title Text'> Then the standard Fossil header and footer are added to the document prior to being displayed. The "class='fossil-doc'" attribute is required for this to occur. The "data-title='...'" attribute is optional, but if it is present the text will become the title displayed -in the Fossil header. An example of this can be seen in the text -of the [/artifact/84b4b3d041d93a?txt=1 | Index Of Fossil Documentation] -document. +in the Fossil header. An example of this can be seen in Fossil +Documentation Index www/permutedindex.html: + + * [/file/www/permutedindex.html?txt|source text for www/permutedindex.html] + * [/doc/trunk/www/permutedindex.html|www/permutedindex.html rendered as HTML] + +Beware that such HTML files render in the same browser security context +as all other embedded documentation served from Fossil; they are not +fully-independent web pages. One practical consequence of this is that +embedded <script> tags will cause a +[https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP | Content +Security Policy] error in your browser with the default CSP as served by +Fossil. See the documentation on [./customskin.md#headfoot | Header and +Footer Processing] and [./defcsp.md | The Default CSP]. + + +

              2.0 Server-Side Text Substitution

              + +Fossil can do a few types of substitution of server-side information +into the embedded document. + +

              2.1 "$ROOT" In HTML and Markdown Hyperlinks

              + +Hyperlinks in Markdown and HTML embedded documents can reference +the root of the Fossil repository using the special text "$ROOT" +at the beginning of a URL. For example, a Markdown hyperlink to +the Markdown formatting rules might be +written in the embedded document like this: + +
              +        [Markdown formatting rules]($ROOT/wiki_rules)
              +
              + +Depending on how the how the Fossil server is configured, that hyperlink +might be renderer like one of the following: + +
              +        <a href="/wiki_rules">Wiki formatting rules</a>
              +        <a href="/cgi-bin/fossil/wiki_rules">Wiki formatting rules</a>
              +
              + +So, in other words, the "$ROOT" text is converted into whatever +the "<baseurl>" is for the document. + +This substitution works for HTML and Markdown documents. +It does not work for Wiki embedded documents, since with +Wiki you can just begin a URL with "/" and it automatically knows +to prepend the $ROOT. + +

              2.2 "$CURRENT" In "/doc/" Hyperlinks

              + +Similarly, URLs of the form "/doc/$CURRENT/..." have the check-in +hash of the check-in currently being viewed substituted in place of +the "$CURRENT" text. This feature, in combination with the "$ROOT" +substitution above, allows an absolute path to be used for hyperlinks. + +For example, if an embedded document documented wanted to reference +some other document in a separate file named "www/otherdoc.md", +it could use a URL like this: + +
              +        [Other Document]($ROOT/doc/$CURRENT/www/otherdoc.md)
              +
              + +As with "$ROOT", this substitution only works for Markdown and HTML +documents. For Wiki documents, you would need to use a relative URL. + +

              2.3 TH1 Documents

              + +Fossil will substitute the value of [./th1.md | TH1 expressions] within +{ curly braces } into the output HTML if you have +configured it with the --with-th1-docs option, which is +disabled by default. + +Since TH1 is a full scripting language, this feature essential grants +the ability to execute code on the server to any with check-in +privilege for the project. +This is a security risk that needs to be carefully managed. +The feature is off by default. +Administrators should understand and carefully assess the risks +before enabling the use of TH1 within embedded documentation. + -

              Examples

              +

              3.0 Examples

              This file that you are currently reading is an example of embedded documentation. The name of this file in the fossil source tree is "www/embeddeddoc.wiki". You are perhaps looking at this file using the URL: - [http://www.fossil-scm.org/index.html/doc/trunk/www/embeddeddoc.wiki]. + [http://www.fossil-scm.org/fossil/doc/trunk/www/embeddeddoc.wiki]. -The first part of this path, the "[http://www.fossil-scm.org/index.html]", +The first part of this path, the "[http://www.fossil-scm.org/fossil]", is the base URL. You might have originally typed: [http://www.fossil-scm.org/]. The web server at the www.fossil-scm.org -site automatically redirects such links by appending "index.html". The -"index.html" file on www.fossil-scm.org is really a CGI script -(do not be mislead by the name) which runs the fossil web service in -CGI mode. The "index.html" CGI script looks like this: +site automatically redirects such links by appending "fossil". The +"fossil" file on www.fossil-scm.org is really a CGI script +which runs the fossil web service in CGI mode. +The "fossil" CGI script looks like this:
               #!/usr/bin/fossil
               repository: /fossil/fossil.fossil
               
              -This is one of four ways to set up a -fossil web server. +This is one of the many ways to set up a +Fossil server. The "/trunk/" part of the URL tells fossil to use the documentation files from the most recent trunk check-in. If you wanted to see an historical version of this document, you could substitute the name of a check-in for "/trunk/". @@ -138,18 +228,18 @@
            • YYYY-MM-DD
            • YYYY-MM-DDTHH:MM
            • YYYY-MM-DDTHH:MM:SS
            -When the symbolic name is a date and time, fossil shows the version +When the symbolic name is a date and time, fossil shows the version of the document that was most recently checked in as of the date and time specified. So, for example, to see what the fossil website looked like at the beginning of 2010, enter:
            - -http://www.fossil-scm.org/index.html/doc/2010-01-01/www/index.wiki + +http://www.fossil-scm.org/fossil/doc/2010-01-01/www/index.wiki
            The file that encodes this document is stored in the fossil source tree under the name "www/embeddeddoc.wiki" and so that name forms the Index: www/encryptedrepos.wiki ================================================================== --- www/encryptedrepos.wiki +++ www/encryptedrepos.wiki @@ -3,11 +3,11 @@ Fossil can be compiled so that it works with encrypted repositories using the [https://www.sqlite.org/see/doc/trunk/www/readme.wiki|SQLite Encryption Extension]. This technical note explains the process.

            Building An Encryption-Enabled Fossil

            -The SQLite Encryption Extension (SEE) is proprietary software and requires +The SQLite Encryption Extension (SEE) is proprietary software and requires [http://www.hwaci.com/cgi-bin/see-step1|purchasing a license].

            Assuming you have an SEE license, the first step of compiling Fossil to use SEE is to create an SEE-enabled version of the SQLite database source code. This alternative SQLite database source file should be called "sqlite3-see.c" @@ -50,11 +50,11 @@ prevents fossil from trying to remember the previous sync password.

             export FOSSIL_SECURITY_LEVEL=2
             
            A setting of 2 or greater -causes all password prompts to be preceeded by a random translation matrix similar +causes all password prompts to be preceded by a random translation matrix similar to the following:
             abcde fghij klmno pqrst uvwyz
             qresw gjymu dpcoa fhkzv inlbt
             
            Index: www/env-opts.md ================================================================== --- www/env-opts.md +++ www/env-opts.md @@ -55,10 +55,13 @@ * _16_ — Looks for the original comment text within the text being printed. Upon matching, a new line will be emitted, thus preserving more of the pre-existing formatting. + +`--comment-format NUMBER`: Alias for `--comfmtflags NUMBER`. + `--errorlog ERRLOG`: Name a file to which fossil will log panics, errors, and warnings. @@ -88,11 +91,15 @@ `--sqlstats`: (Sets `g.fSqlStats`.) Print a number of performance statistics about each SQLite database used when it is closed. `--sshtrace`: (Sets `g.fSshTrace`.) -`--ssl-identity SSLIDENTITY`: +`--ssl-identity`: The fully qualified name of the file containing the client +certificate and private key to use, in PEM format. It can be created by +concatenating the client certificate and private key files. This identity will +be presented to SSL servers to authenticate the client, in addition to the +normal password authentication. `--systemtrace`: (Sets `g.fSystemTrace`.) Trace all commands launched as sub processes. `--user LOGIN`: (Sets `g.zLogin`) Also `-U LOGIN`. Set the user name @@ -105,20 +112,22 @@ Environment Variables --------------------- - -`APPDATA`: (Windows) Location of the `~/.fossil` file. The first -environment variable found in the environment from the list -`FOSSIL_HOME`, `LOCALAPPDATA` (Windows), `APPDATA` (Windows), -`HOMEDRIVE` and `HOMEPATH` (Windows, used together), and `HOME` is -used as the location of the `~/.fossil` file. +The location of the user's account-wide [configuration database][configdb] +depends on the operating system and on the existance of various +environment variables and/or files. See the discussion of the +[configuration database location algorithm][configloc] for details. `EDITOR`: Name the editor to use for check-in and stash comments. Overridden by the local or global `editor` setting or the `VISUAL` environment variable. + +`FOSSIL_BREAK`: If set, an opportunity will be created to attach a +debugger to the Fossil process prior to any significant work being +performed. `FOSSIL_FORCE_TICKET_MODERATION`: If set, *ALL* changes for tickets will be required to go through moderation (even those performed by the local interactive user via the command line). This can be useful for local (or remote) testing of the moderation subsystem and its impact @@ -129,53 +138,55 @@ local interactive user via the command line). This can be useful for local (or remote) testing of the moderation subsystem and its impact on the contents and status of wiki pages. -`FOSSIL_HOME`: Location of the `~/.fossil` file. The first environment -variable found in the environment from the list `FOSSIL_HOME`, -`LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and -`HOMEPATH` (Windows, used together), and `HOME` is used as the -location of the `~/.fossil` file. +`FOSSIL_HOME`: Location of [configuration database][configdb]. +See the [configuration database location][configloc] description +for additional information. + +`FOSSIL_USE_SEE_TEXTKEY`: If set, treat the encryption key string for +SEE as text to be hashed into the actual encryption key. This has no +effect if Fossil was not compiled with SEE support enabled. + `FOSSIL_USER`: Name of the default user account if the checkout, local or global `default-user` setting is not present. The first environment variable found in the environment from the list `FOSSIL_USER`, `USER`, `LOGNAME`, and `USERNAME` is the user name. If none of those are set, then the default user name is "root". See the discussion of Fossil Username below for a lot more detail. + + +`FOSSIL_SECURITY_LEVEL`: If set to any of the values listed below, +additional measures for password security will be enabled (also see +[How To Use Encrypted Repositories][encryptedrepos.wiki]): + +[encryptedrepos.wiki]: /doc/trunk/www/encryptedrepos.wiki + + * _≥1_ — Do not remember passwords. + + * _≥2_ — Use a scrambled matrix for password input. + `FOSSIL_TCL_PATH`: When Tcl stubs support is configured, point to a specific file or folder containing the version of Tcl to load at run time. -`FOSSIL_TEMP`: Fallback location of the temporary directories and files -created and deleted when running the test suite. The first environment -variable found in the environment from the list `FOSSIL_TEST_TEMP`, -`FOSSIL_TEMP`, `TEMP`, and `TMP` is used. - `FOSSIL_TEST_DANGEROUS_IGNORE_OPEN_CHECKOUT`: When set to the literal value `YES_DO_IT`, the test suite will relax the constraint that some tests may not run within an open checkout. This is subject to removal in the future. -`FOSSIL_TEST_TEMP`: Primary location of the temporary directories -and files created and deleted when running the test suite. The -first environment variable found in the environment from the list -`FOSSIL_TEST_TEMP`, `FOSSIL_TEMP`, `TEMP`, and `TMP` is used. - `FOSSIL_VFS`: Name a VFS to load into SQLite. `GATEWAY_INTERFACE`: If present and the `--nocgi` option is not, assume fossil is invoked from a web server as a CGI command, and act accordingly. -`HOME`: Location of the `~/.fossil` file. The first environment -variable found in the environment from the list `FOSSIL_HOME`, -`LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and -`HOMEPATH` (Windows, used together), and `HOME` is used as the -location of the `~/.fossil` file. +`HOME`: Potential location of the [configuration database][configdb]. +See the [configuration database location][configloc] description for details. `HOMEDRIVE`, `HOMEPATH`: (Windows) Location of the `~/.fossil` file. The first environment variable found in the environment from the list `FOSSIL_HOME`, `LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and `HOMEPATH` (Windows, used together), and `HOME` is @@ -230,16 +241,10 @@ `SYSTEMROOT`: (Windows) Used to locate `notepad.exe` as a fall back comment editor. -`TEMP`: On Windows, the location of temporary files. The first -environment variable found in the environment that names an existing -directory from the list `TMP`, `TEMP`, `USERPROFILE`, the Windows -directory (usually `C:\WINDOWS`), `TEMP`, `TMP`, and the current -directory (aka `.`) is the temporary folder. - `TERM`: If the linenoise library is used (almost certainly not on Windows), it will check `TERM` to verify that the interactive terminal is not named on a short list on terminals known to not work with linenoise. Linenoise is a library that provides command history and command line editing to interactive programs, and can be used in the @@ -267,16 +272,10 @@ `TH1_TEST_USER_CAPS`: Override the default user permissions used when processing the `--set-user-caps` option for the `test-th-eval`, `test-th-render`, and `test-th-source` test commands. -`TMP`: On Windows, the location of temporary files. The first -environment variable found in the environment that names an existing -directory from the list `TMP`, `TEMP`, `USERPROFILE`, the Windows -directory (usually `C:\WINDOWS`), `TEMP`, `TMP`, and the current -directory (aka `.`) is the temporary folder. - `TMPDIR`: Names the temporary file location for SQLite. `USER`: Name of the logged in user on many Unix-like platforms. Used as the fossil user name if `FOSSIL_USER` is not specified. See @@ -284,16 +283,10 @@ `USERNAME`: Name of the logged in user on Windows platforms. Used as the fossil user name if `FOSSIL_USER` is not specified. See the discussion of Fossil Username below for a lot more detail. -`USERPROFILE`: On Windows, the location of temporary files. The first -environment variable found in the environment that names an existing -directory from the list `TMP`, `TEMP`, `USERPROFILE`, the Windows -directory (usually `C:\WINDOWS`), `TEMP`, `TMP`, and the current -directory (aka `.`) is the temporary folder. - `VISUAL`: Name the editor to use for check-in and stash comments. Overrides the `EDITOR` environment variable. Overridden by the local or global `editor` setting. @@ -392,28 +385,30 @@ first found environment variable from the list `FOSSIL_USER`, `USER`, `LOGNAME`, and `USERNAME`, is the user name. As a final fallback, if none of those are set, then the default user name is "root". -### Home Directory - -Fossil keeps some information interesting to each user in the user's -home directory. This includes the global settings and the list of -repositories and checkouts used by `fossil all`. - -The user's home directory is specified by the first environment -variable found in the environment from the list `FOSSIL_HOME`, -`LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and -`HOMEPATH` (Windows, used together), and `HOME`. - -SQLite has its own notion of the user's home directory, which is only -exposed if the interactive SQL shell is run with the "fossil -sqlite3" command. Being a separate library, SQLite uses many of the -same variables to find the home directory, but uses them in a -different order, and does not use the `FOSSIL_HOME` variable at all. - - +### Configuration Database Location + +Fossil keeps some information pertinent to each user in the user's +[configuration database file][configdb]. +The configuration database file includes the global settings +and the list of repositories and checkouts used by `fossil all`. + +The location of the configuration database file depends on the +operating system and on the existance of various environment +variables and/or files. In brief, the configuration database is +usually: + + * Traditional unix → "`$HOME/.fossil`" + * Windows → "`%LOCALAPPDATA%/_fossil`" + * [XDG-unix][xdg] → "`$HOME/.config/fossil.db`" + +[xdg]: https://www.freedesktop.org/wiki/ + +See the [configuration database location +algorithm][configloc] discussion for full information. ### SQLite VFS to use See [the SQLite documentation](http://www.sqlite.org/vfs.html) for an explanation of what a VFS actually is and what it does. @@ -422,32 +417,36 @@ can be selected with either the `--vfs VFSNAME` option or the `FOSSIL_VFS` environment variable. The `--vfs` option takes precedence. -### Temporary File Location +### Temporary File Location -Fossil places some temporary files in the current directory, notably +Fossil places some temporary files in the checkout directory. Most notably, supporting files related to merge conflicts are placed in the same folder as the merge result. -Other temporary files need a home. On Unix-like systems, the first -folder from the hard coded list `/var/tmp`, `/usr/tmp`, `/tmp`, -`/temp`, and `.` that is found to exist in the file system is used by -fossil. The SQLite library has its own code for finding a safe place for -temporary files. It checks the environment variables `SQLITE_TMPDIR` -and `TMPDIR` ahead of the hard coded list `/var/tmp`, `/usr/tmp`, -`/tmp`, and `.` for the first directory that exists. - -On Windows, fossil calls [`GetTempPath`][gtp], and also queries the -environment variables `TEMP`, and `TMP`. If none of those three places -exist, then it uses `.`. Notice that `GetTempPath` itself used `TMP`, -`TEMP`, `USERPROFILE`, and the Windows folder (named in the variable -`SystemRoot`). Since the Windows folder always exists, but in modern -versions of Windows is generally *not* writable by the logged in user, -not having `TEMP`, `TMP`, or `USERPROFILE` set is almost guaranteed to -cause trouble. +Other temporary files need a different home. The rules for choosing one are +complicated. + +Fossil-specific code uses `FOSSIL_TEMP`, `TEMP`, and `TMP`, in that +order. Fossil’s own test suite prepends `FOSSIL_TEST_TEMP` to that list. + +The underlying SQLite code uses several different path sets for its temp +files, depending on the platform type. + +On Unix-like platforms, excepting Cygwin, SQLite first checks the +environment variables `SQLITE_TMPDIR` and `TMPDIR`, in that order. If +neither is defined, it falls back to a hard-coded list of paths: +`/var/tmp`, `/usr/tmp`, and `/tmp`. If all of that fails, it uses the +current working directory. + +For Cygwin builds, SQLite instead uses the first defined variable in +this list: `SQLITE_TMPDIR`, `TMPDIR`, `TMP`, `TEMP`, and `USERPROFILE`. + +For native Windows builds, SQLite simply calls the OS’s [`GetTempPath()` +API][gtp]. See that reference page for details. [gtp]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx @@ -477,5 +476,8 @@ On Apple platforms, it assumes that `open` is the command to open an URL in the user's configured default browser. On Windows platforms, it assumes that `start` is the command to open an URL in the user's configured default browser. + +[configdb]: ./tech_overview.wiki#configdb +[configloc]: ./tech_overview.wiki#configloc Index: www/event.wiki ================================================================== --- www/event.wiki +++ www/event.wiki @@ -23,21 +23,21 @@ can be something simple like "Version 1.2.3" perhaps with a bright color background to draw attention to the entry and the wiki content can contain release notes, for example. * Blog Entries. Blog entries from developers describing the current - state of a project, or rational for various design decisions, or + state of a project, or rationale for various design decisions, or roadmaps for future development, can be entered as technotes. * Process Checkpoints. For projects that have a formal process, technotes can be used to record the completion or the initiation of various process steps. For example, a technote can be used to record the successful completion of a long-running test, perhaps with performance results and details of where the test was run and who ran it recorded in the wiki content. - * News Articles. Significant occurrences in the lifecycle of + * News Articles. Significant occurrences in the life cycle of a project can be recorded as news articles using technotes. Perhaps the domain name of the canonical website for a project changes, or new server hardware is obtained. Such happenings are appropriate for reporting as news. @@ -49,11 +49,11 @@ stay better organized and provide a better historical record of the development progress.

            Viewing Technotes

            -Because technotes are considered a special kind of wiki, +Because technotes are considered a special kind of wiki, users must have permission to read wiki in order read technotes. Enable the "j" permission under the /Setup/Users menu in order to give specific users or user classes the ability to view wiki and technotes. @@ -64,12 +64,12 @@ There is a hyperlink under the /wikihelp menu that can be used to create new technotes. And there is a submenu hyperlink on technote displays for editing existing technotes. -Users must have check-in privileges (permission "i") in order to +Users must have check-in privileges (permission "i") in order to create or edit technotes. In addition, users must have create-wiki privilege (permission "f") to create new technotes and edit-wiki privilege (permission "k") in order to edit existing technotes. Technote content may be formatted as [/wiki_rules | Fossil wiki], [/md_rules | Markdown], or a plain text. Index: www/faq.wiki ================================================================== --- www/faq.wiki +++ www/faq.wiki @@ -1,9 +1,11 @@ Fossil FAQ

            Frequently Asked Questions

            -

            Note: See also Questions and Criticisms. +

            Note: +This page is old and has not been kept up-to-date. See the +[/finfo?name=www/faq.wiki|change history of this page].

            1. What GUIs are available for fossil?
            2. What is the difference between a "branch" and a "fork"?
            3. How do I create a new branch?
            4. @@ -62,12 +64,12 @@ If you already have a fork in your check-in tree and you want to convert that fork to a branch, you can do this from the web interface. First locate the check-in that you want to be the initial check-in of your branch on the timeline and click on its link so that you are on the ci page. Then find the "edit" -link (near the "Commands:" label) and click on that. On the -"Edit Check-in" page, check the box beside "Branching:" and fill in +link (near the "Commands:" label) and click on that. On the +"Edit Check-in" page, check the box beside "Branching:" and fill in the name of your new branch to the right and press the "Apply Changes" button.
          3. (4) How do I tag a check-in?

            @@ -89,11 +91,11 @@ The CHECK-IN in the previous line can be any [./checkin_names.wiki | valid check-in name format]. You can also add (and remove) tags from a check-in using the -[./webui.wiki | web interface]. First locate the check-in that you +[./webui.wiki | web interface]. First locate the check-in that you what to tag on the timeline, then click on the link to go the detailed information page for that check-in. Then find the "edit" link (near the "Commands:" label) and click on that. There are controls on the edit page that allow new tags to be added and existing tags to be removed. @@ -100,13 +102,13 @@

            (5) How do I create a private branch that won't get pushed back to the main repository.

            -
            Use the --private command-line option on the +
            Use the --private command-line option on the commit command. The result will be a check-in which exists on -your local repository only and is never pushed to other repositories. +your local repository only and is never pushed to other repositories. All descendants of a private check-in are also private. Unless you specify something different using the --branch and/or --bgcolor options, the new private check-in will be put on a branch named "private" with an orange background color. ADDED www/fileedit-page.md Index: www/fileedit-page.md ================================================================== --- /dev/null +++ www/fileedit-page.md @@ -0,0 +1,271 @@ +# The fileedit Page + +This document describes the limitations of, caveats for, and +disclaimers for the [](/fileedit) page, which provides users with +[checkin privileges](./caps/index.md) basic editing features for files +via the web interface. + +# Important Caveats and Disclaimers + +Predictably, the ability to edit files in a repository from a web +browser halfway around the world comes with several obligatory caveats +and disclaimers... + +## `/fileedit` Does *Nothing* by Default. + +In order to "activate" it, a user with [the "setup" +permission](./caps/index.md) must set the +[fileedit-glob](/help?cmd=fileedit-glob) repository setting to a +comma- or newline-delimited list of globs representing a whitelist of +files which may be edited online. Any user with commit access may then +edit files matching one of those globs. Certain pages within the UI +get an "edit" link added to them when the current user's permissions +and the whitelist both permit editing of that file. + +## CSRF & HTTP Referrer Headers + +In order to protect against [Cross-site Request Forgery (CSRF)][csrf] +attacks, Fossil UI features which write to the database require that +the browser send the so-called [HTTP `Referer` header][referer] +(noting that the misspelling of "referrer" is a historical accident +which has long-since been standardized!). Modern browsers, by default, +include such information automatically for *interactive* actions which +lead to a request, e.g. clicking on a link back to the same +server. However, `/fileedit` uses asynchronous ["XHR"][xhr] +connections, which browsers *may* treat differently than strictly +interactive elements. + +- **Firefox**: configuration option `network.http.sendRefererHeader` + specifies whether the `Referer` header is sent. It must have a value + of 2 (which is the default) for XHR requests to get the `Referer` + header. Purely interactive Fossil features, in which users directly + activate links or forms, work with a level of 1 or higher. +- **Chrome**: apparently requires an add-on in order to change this + policy, so Chrome without such an add-on will not suppress this + header. +- **Safari**: ??? +- **Other browsers**: ??? + +If `/filepage` shows an error message saying "CSRF violation," the +problem is that the browser is not sending a `Referer` header to XHR +connections. Fossil does not offer a way to disable its CSRF +protections. + +[referer]: https://en.wikipedia.org/wiki/HTTP_referer +[csrf]: https://en.wikipedia.org/wiki/Cross-site_request_forgery +[xhr]: https://en.wikipedia.org/wiki/XMLHttpRequest + +## `/fileedit` **Works by Creating Commits** + +Thus any edits made via that page become a normal part of the +repository's blockchain. + +## `/fileedit` is *Intended* for use with Embedded Docs + +... and similar text files, and is most certainly +**not intended for editing code**. + +Editing files with unusual syntax requirements, e.g. hard tabs in +makefiles, may break them. *You Have Been Warned.* + +Similarly, though every effort is made to retain the end-of-line +style used by being-edited files, the round-trip through an HTML +textarea element may change the EOLs. The Commit section of the page +offers three different options for how to treat newlines when saving +changes. **Files with mixed EOL styles** *will be normalized to a single +EOL style* when modified using `/fileedit`. When "inheriting" the EOL +style from a previous version which has mixed styles, the first EOL +style detected in the previous version of the file is used. + +## `/fileedit` **is Not a Replacement for a Checkout** + +A full-featured checkout allows far more possibilities than this basic +online editor permits, and the feature scope of `/fileedit` is +intentionally kept small, implementing only the bare necessities +needed for performing basic edits online. It *is not, and will never +be, a replacement for a checkout.* + +It is to be expected that users will want to do "more" with this +page, and we generally encourage feature requests, but be aware that +certain types of ostensibly sensible feature requests *will be +rejected* for `/fileedit`. These include, but are not limited to: + +- Features which are already provided by other pages, e.g. +the ability to create a new named branch or add tags. +- Features which would require re-implementing significant +capabilities provided only within a checkout (e.g. merging files). +- The ability to edit/manipulate files which are in a local +checkout. (If you have a checkout, use your local editor, not +`/fileedit`.) +- Editing of non-text files, e.g. images. Use a checkout and your +preferred graphics editor. +- Support for syncing/pulling/pushing of a repository before and/or +after edits. Those features cannot be *reliably* provided via a web +interface for several reasons. + +Similarly, some *potential* features have significant downsides, +abuses, and/or implementation hurdles which make the decision of +whether or not to implement them subject to notable contributor +debate. e.g. the ability to add new files or remove/rename older +files. + + +## `/fileedit` **Stores Only Limited Local Edits While Working** + +When changes are made to a given checkin/file combination, +`/fileedit` will, if possible, store them in [`window.localStorage` +or `window.sessionStorage`][html5storage], if available, but... + +- Which storage is used is unspecified and may differ across + environments. +- If neither of those is available, the storage is transient and + will not survive a page reload. In this case, the UI issues a clear + warning in the editor tab. +- It stores only the most recent checkin/file combinations which have + been modified (exactly how many may differ - the number will be + noted somewhere in the UI). Note that changing the "executable bit" + is counted as a modification, but the checkin *comment* is *not* + and is reset after a commit. +- If its internal limit on the number of modified files is exceeded, + it silently discards the oldest edits to keep the list at its limit. + +Edits are saved whenever the editor component fires its "change" +event, which essentially means as soon as it loses input focus. Thus +to force the browser to save any pending changes, simply click +somwhere on the page outside of the editor. + +Exactly how long `localStorage` will survive, and how much it or +`sessionStorage` can hold, is environment-dependent. `sessionStorage` +will survive until the current browser tab is closed, but it survives +across reloads of the same tab. + +If `/filepage` determines that no peristent storage is available a +warning is displayed on the editor page. + +[html5storage]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API + +## The Power is Yours, but... + +> "With great power comes great responsibility." + +**Use this feature judiciously, *if at all*.** + +Now, with those warnings and caveats out of the way... + +----- + +# Tips and Tricks + +## `fossil` Global-scope JS Object + +`/fileedit` is largely implemented in JavaScript, and makes heavy use +of the global-scope `fossil` object, which provides +infrastructure-level features intended for use by Fossil UI pages. +(That said, that infrastructure was introduced with `/fileedit`, and +most pages do not use it.) + +The `fossil.page` object represents the UI's current page (on pages +which make use of this API - most do not). That object supports +listening to page-specific events so that JS code installed via +[client-side edits to the site skin's footer](customskin.md) may react +to those changes somehow. The next section describes one such use for +such events... + +## Integrating Syntax Highlighting + +Assuming a repository has integrated a 3rd-party syntax highlighting +solution, it can probably (depending on its API) be told how to +highlight `/fileedit`'s wiki/markdown-format previews. Here are +instructions for doing so with [highlightjs](https://highlightjs.org/): + +At the very bottom of the [site skin's footer](customskin.md), add a +script tag similar to the following: + +```javascript + +``` + +Note that the `nonce="$"` part is intended to be entered +literally as shown above. It will be expanded to contain the current +request's nonce value when the page is rendered. + +The first line of the script just ensures that the expected JS-level +infrastructure is loaded. It's only loaded in the `/fileedit` page and +possibly pages added or "upgraded" since `/fileedit`'s introduction. + +The part in the `if` block adds an event listener to the `/filepage` +app which gets called when the preview is refreshed. That event +contains 3 properties: + +- `previewMode`: a string describing the current preview mode: `wiki` + (which includes Fossil-native wiki and markdown), `text`, + `htmlInline`, `htmlIframe`. We should "probably" only highlight wiki + text, and thus the example above limits its work to that type of + preview. It won't work with `htmlIframe`, as that represents an + iframe element which contains a complete HTML document. +- `element`: the DOM element in which the preview is rendered. +- `mimetype`: the mimetype of the being-previewed content, as determined + by Fossil (by its file extension). + +The event listener callback shown above doesn't use the `mimetype`, +but makes used of the other two. It fishes all `code` blocks out of +the preview which explicitly have a CSS class named +`language-`something, and then asks highlightjs to highlight them. + +## Integrating a Custom Editor Widget + +*Hypothetically*, though this is currently unproven "in the wild," it +is possible to replace `/filepage`'s basic text-editing widget (a +`textarea` element) with a fancy 3rd-party editor widget by following +these instructions... + +All JavaScript code which follows is assumed to be in a script tag +similar to the one shown in the previous section: + +```javascript + +``` + +First, install proxy functions so that `fossil.page.fileContent()` +can get and set your content: + +``` +fossil.page.setFileContentMethods( + function(){ return text-form content of your widget }, + function(content){ set text-form content of your widget } +}; +``` + +Secondly, inject the custom editor widget into the UI, replacing +the default editor widget: + +```javascript +fossil.page.replaceEditorWidget(yourNewWidgetElement); +``` + +That method must be passed a DOM element and may only be called once: +it *removes itself* the first time it is called. + +That "should" be all there is to it. When `fossil.page` needs to get +the being-edited content, it will call `fossil.page.fileContent()` +with no arguments, and when it sets the content (immediately after +(re)loading a file), it will pass that content to +`fossil.page.fileContent()`. Those, in turn will trigger the installed +proxies and fire any relevant events. Index: www/fileformat.wiki ================================================================== --- www/fileformat.wiki +++ www/fileformat.wiki @@ -2,23 +2,28 @@

            Fossil File Formats

            The global state of a fossil repository is kept simple so that it can -endure in useful form for decades or centuries. +endure in useful form for decades or centuries. A fossil repository is intended to be readable, searchable, and extensible by people not yet born. The global state of a fossil repository is an unordered set of artifacts. An artifact might be a source code file, the text of a wiki page, -part of a trouble ticket, or one of several special control artifacts -used to show the relationships between other artifacts within the -project. Each artifact is normally represented on disk as a separate -file. Artifacts can be text or binary. +part of a trouble ticket, a description of a check-in including all +the files in that check-in with the check-in comment and so forth. +Artifacts are broadly grouped into two types: content artifacts and +structural artifacts. Content artifacts are the raw project source-code +files that are checked into the repository. Structural artifacts have +special formatting rules and are used to show the relationships between +other artifacts in the repository. It is possible for an artifact to +be both a structure artifact and a content artifact, though this is +rare. Artifacts can be text or binary. -In addition to the global state, +In addition to the global state, each fossil repository also contains local state. The local state consists of web-page formatting preferences, authorized users, ticket display and reporting formats, and so forth. The global state is shared in common among all repositories for the same project, whereas the local state is often @@ -27,299 +32,291 @@ with the global state. The local state is not composed of artifacts and is not intended to be enduring. This document is concerned with global state only. Local state is only mentioned here in order to distinguish it from global state. -Each artifact in the repository is named by its SHA1 hash. -No prefixes or meta information is added to an artifact before -its hash is computed. The name of an artifact in the repository -is exactly the same SHA1 hash that is computed by sha1sum -on the file as it exists in your source tree.

            - -Some artifacts have a particular format which gives them special -meaning to fossil. Fossil recognizes: + +

            1.0 Artifact Names

            + +Each artifact in the repository is named by a hash of its content. +No prefixes, suffixes, or other information is added to an artifact before +the hash is computed. The artifact name is just the (lower-case +hexadecimal) hash of the raw artifact. + +Fossil currently computes artifact names using either SHA1 or SHA3-256. It +is relatively easy to add new algorithms in the future, but there are no +plans to do so at this time. + +When referring to artifacts in using tty commands or webpage URLs, it is +sufficient to specify a unique prefix for the artifact name. If the input +prefix is not unique, Fossil will show an error. Within a structural +artifact, however, all references to other artifacts must be the complete +hash. + +Prior to Fossil version 2.0, all names were formed from the SHA1 hash of +the artifact. The key innovation in Fossil 2.0 was adding support for +alternative hash algorithms. + + +

            2.0 Structural Artifacts

            + +A structural artifact is an artifact with a particular format +that is used to define the relationships between other artifacts in the +repository. +Fossil recognizes the following kinds of structural +artifacts:
            • [#manifest | Manifests]
            • [#cluster | Clusters]
            • [#ctrl | Control Artifacts]
            • [#wikichng | Wiki Pages]
            • [#tktchng | Ticket Changes]
            • [#attachment | Attachments]
            • [#event | TechNotes]
            • +
            • [#forum | Forum Posts]
            -These seven artifact types are described in the following sections. +These eight structural artifact types are described in subsections below. -In the current implementation (as of 2009-01-25) the artifacts that +Structural artifacts are ASCII text. The artifact may be PGP clearsigned. +After removal of the PGP clearsign header and suffix (if any) a structural +artifact consists of one or more "cards" separated by a single newline +(ASCII: 0x0a) character. Each card begins with a single +character "card type". Zero or more arguments may follow +the card type. All arguments are separated from each other +and from the card-type character by a single space +character. There is no surplus white space between arguments +and no leading or trailing whitespace except for the newline +character that acts as the card separator. All cards must be in strict +lexicographical order. There may not be any duplicate cards. + +In the current implementation (as of 2017-02-27) the artifacts that make up a fossil repository are stored as delta- and zlib-compressed blobs in an SQLite database. This is an implementation detail and might change in a future release. For the purpose of this article "file format" means the format of the artifacts, not how the artifacts are stored on disk. It is the artifact format that is intended to be enduring. The specifics of how artifacts are stored on disk, though stable, is not intended to live as long as the artifact format. -All of the artifacts can be extracted from a Fossil repository using -the "fossil deconstruct" command. - -

            1.0 The Manifest

            +

            2.1 The Manifest

            -A manifest defines a check-in or version of the project -source tree. The manifest contains a list of artifacts for +A manifest defines a check-in. +A manifest contains a list of artifacts for each file in the project and the corresponding filenames, as -well as information such as parent check-ins, the name of the +well as information such as parent check-ins, the username of the programmer who created the check-in, the date and time when the check-in was created, and any check-in comments associated with the check-in. -Any artifact in the repository that follows the syntactic rules -of a manifest is a manifest. Note that a manifest can -be both a real manifest and also a content file, though this -is rare. - -A manifest is a text file. Newline characters -(ASCII 0x0a) separate the file into "cards". -Each card begins with a single -character "card type". Zero or more arguments may follow -the card type. All arguments are separated from each other -and from the card-type character by a single space -character. There is no surplus white space between arguments -and no leading or trailing whitespace except for the newline -character that acts as the card separator. - -All cards of the manifest occur in strict sorted lexicographical order. -No card may be duplicated. -The entire manifest may be PGP clear-signed, but otherwise it -may contain no additional text or data beyond what is described here. - Allowed cards in the manifest are as follows:
            B baseline-manifest
            C checkin-comment
            D time-and-date-stamp
            -F filename ?SHA1-hash? ?permissions? ?old-name?
            +F filename ?hash? ?permissions? ?old-name?
            N mimetype
            -P SHA1-hash+
            -Q (+|-)SHA1-hash ?SHA1-hash?
            +P artifact-hash+
            +Q (+|-)artifact-hash ?artifact-hash?
            R repository-checksum
            T (+|-|*)tag-name * ?value?
            U user-login
            Z manifest-checksum
            -A manifest may optionally have a single B-card. The B-card specifies +A manifest may optionally have a single B card. The B card specifies another manifest that serves as the "baseline" for this manifest. A -manifest that has a B-card is called a delta-manifest and a manifest -that omits the B-card is a baseline-manifest. The other manifest -identified by the argument of the B-card must be a baseline-manifest. +manifest that has a B card is called a delta-manifest and a manifest +that omits the B card is a baseline-manifest. The other manifest +identified by the argument of the B card must be a baseline-manifest. A baseline-manifest records the complete contents of a check-in. -A delta-manifest records only changes from its baseline. +A delta-manifest records only changes from its baseline. -A manifest must have exactly one C-card. The sole argument to -the C-card is a check-in comment that describes the check-in that +A manifest must have exactly one C card. The sole argument to +the C card is a check-in comment that describes the check-in that the manifest defines. The check-in comment is text. The following escape sequences are applied to the text: A space (ASCII 0x20) is represented as "\s" (ASCII 0x5C, 0x73). A -newline (ASCII 0x0a) is "\n" (ASCII 0x5C, x6E). A backslash +newline (ASCII 0x0a) is "\n" (ASCII 0x5C, x6E). A backslash (ASCII 0x5C) is represented as two backslashes "\\". Apart from space and newline, no other whitespace characters are allowed in the check-in comment. Nor are any unprintable characters allowed in the comment. -A manifest must have exactly one D-card. The sole argument to -the D-card is a date-time stamp in the ISO8601 format. The +A manifest must have exactly one D card. The sole argument to +the D card is a date-time stamp in the ISO8601 format. The date and time should be in coordinated universal time (UTC). The format one of:
            YYYY-MM-DDTHH:MM:SS
            YYYY-MM-DDTHH:MM:SS.SSS
            -A manifest has zero or more F-cards. Each F-card identifies a file +A manifest has zero or more F cards. Each F card identifies a file that is part of the check-in. There are one, two, three, or four arguments. The first argument is the pathname of the file in the check-in relative to the root of the project file hierarchy. No ".." or "." directories are allowed within the filename. Space characters -are escaped as in C-card comment text. Backslash characters and +are escaped as in C card comment text. Backslash characters and newlines are not allowed within filenames. The directory separator character is a forward slash (ASCII 0x2F). The second argument to the -F-card is the full 40-character lower-case hexadecimal SHA1 hash of +F card is the lower-case hexadecimal artifact hash of the content artifact. The second argument is required for baseline manifests but is optional for delta manifests. When the second -argument to the F-card is omitted, it means that the file has been +argument to the F card is omitted, it means that the file has been deleted relative to the baseline (files removed in baseline manifests -versions are not added as F-cards). The optional 3rd argument +versions are not added as F cards). The optional 3rd argument defines any special access permissions associated with the file. This can be defined as "x" to mean that the file is executable or "l" (small letter ell) to mean a symlink. All files are always readable and writable. This can be expressed by "w" permission if desired but is optional. The file format might be extended with new permission letters in the future. The optional 4th argument is the name of the same file as it existed in the parent check-in. If the name of the file is unchanged from its parent, then the 4th argument is omitted. -A manifest has zero or one N-cards. The N-card specifies the mimetype for the -text in the comment of the C-card. If the N-card is omitted, a default mimetype +A manifest has zero or one N cards. The N card specifies the mimetype for the +text in the comment of the C card. If the N card is omitted, a default mimetype is used. -A manifest has zero or one P-cards. Most manifests have one P-card. -The P-card has a varying number of arguments that +A manifest has zero or one P cards. Most manifests have one P card. +The P card has a varying number of arguments that define other manifests from which the current manifest -is derived. Each argument is a 40-character lowercase -hexadecimal SHA1 of a predecessor manifest. All arguments -to the P-card must be unique within that card. -The first argument is the SHA1 of the direct ancestor of the manifest. +is derived. Each argument is a lowercase +hexadecimal artifact hash of a predecessor manifest. All arguments +to the P card must be unique within that card. +The first argument is the artifact hash of the direct ancestor of the manifest. Other arguments define manifests with which the first was merged to yield the current manifest. Most manifests have -a P-card with a single argument. The first manifest in the -project has no ancestors and thus has no P-card or (depending -on the Fossil version) an empty P-card (no arguments). +a P card with a single argument. The first manifest in the +project has no ancestors and thus has no P card or (depending +on the Fossil version) an empty P card (no arguments). -A manifest has zero or more Q-cards. A Q-card is similar to a P-card +A manifest has zero or more Q cards. A Q card is similar to a P card in that it defines a predecessor to the current check-in. But -whereas a P-card defines the immediate ancestor or a merge -ancestor, the Q-card is used to identify a single check-in or a small +whereas a P card defines the immediate ancestor or a merge +ancestor, the Q card is used to identify a single check-in or a small range of check-ins which were cherry-picked for inclusion in or exclusion from the current manifest. The first argument of -the Q-card is the artifact ID of another manifest (the "target") -which has had its changes included or excluded in the current manifest. +the Q card is the artifact ID of another manifest (the "target") +which has had its changes included or excluded in the current manifest. The target is preceded by "+" or "-" to show inclusion or exclusion, respectively. The optional second argument to the -Q-card is another manifest artifact ID which is the "baseline" +Q card is another manifest artifact ID which is the "baseline" for the cherry-pick. If omitted, the baseline is the primary parent of the target. The changes included or excluded consist of all changes moving from -the baseline to the target. +the baseline to the target. -The Q-card was added to the interface specification on 2011-02-26. -Older versions of Fossil will reject manifests that contain Q-cards. +The Q card was added to the interface specification on 2011-02-26. +Older versions of Fossil will reject manifests that contain Q cards. -A manifest may optionally have a single R-card. The R-card has -a single argument which is the MD5 checksum of all files in +A manifest may optionally have a single R card. The R card has +a single argument which is the MD5 checksum of all files in the check-in except the manifest itself. The checksum is expressed as 32 characters of lowercase hexadecimal. The checksum is computed as follows: For each file in the check-in (except for -the manifest itself) in strict sorted lexicographical order, +the manifest itself) in strict sorted lexicographical order, take the pathname of the file relative to the root of the repository, append a single space (ASCII 0x20), the size of the file in ASCII decimal, a single newline character (ASCII 0x0A), and the complete text of the file. Compute the MD5 checksum of the result. -A manifest might contain one or more T-cards used to set +A manifest might contain one or more T cards used to set [./branching.wiki#tags | tags or properties] -on the check-in. The format of the T-card is the same as +on the check-in. The format of the T card is the same as described in Control Artifacts section below, except that the second argument is the single character "*" instead of an artifact ID. The * in place of the artifact ID indicates that the tag or property applies to the current artifact. It is not possible to encode the current artifact ID as part of an artifact, since the act of inserting the artifact ID would change the artifact ID, -hence a * is used to represent "self". T-cards are typically +hence a * is used to represent "self". T cards are typically added to manifests in order to set the branch property and a symbolic name when the check-in is intended to start a new branch. -Each manifest has a single U-card. The argument to the U-card is +Each manifest has a single U card. The argument to the U card is the login of the user who created the manifest. The login name is encoded using the same character escapes as is used for the -check-in comment argument to the C-card. +check-in comment argument to the C card. -A manifest must have a single Z-card as its last line. The argument -to the Z-card is a 32-character lowercase hexadecimal MD5 hash -of all prior lines of the manifest up to and including the newline -character that immediately precedes the "Z". The Z-card is +A manifest must have a single Z card as its last line. The argument +to the Z card is a 32-character lowercase hexadecimal MD5 hash +of all prior lines of the manifest up to and including the newline +character that immediately precedes the "Z", excluding any PGP +clear-signing prefix. The Z card is a sanity check to prove that the manifest is well-formed and consistent. A sample manifest from Fossil itself can be seen [/artifact/28987096ac | here]. -

            2.0 Clusters

            +

            2.2 Clusters

            A cluster is an artifact that declares the existence of other artifacts. -Clusters are used during repository synchronization to help +Clusters are used during repository synchronization to help reduce network traffic. As such, clusters are an optimization and may be removed from a repository without loss or damage to the underlying project code. -Clusters follow a syntax that is very similar to manifests. -A cluster is a line-oriented text file. Newline characters -(ASCII 0x0a) separate the artifact into cards. Each card begins with a single -character "card type". Zero or more arguments may follow -the card type. All arguments are separated from each other -and from the card-type character by a single space -character. There is no surplus white space between arguments -and no leading or trailing whitespace except for the newline -character that acts as the card separator. -All cards of a cluster occur in strict sorted lexicographical order. -No card may be duplicated. -The cluster may not contain additional text or data beyond -what is described here. -Unlike manifests, clusters are never PGP signed. - Allowed cards in the cluster are as follows:
            M artifact-id
            Z checksum
            -A cluster contains one or more "M" cards followed by a single "Z" -card. Each M card has a single argument which is the artifact ID of -another artifact in the repository. The Z card works exactly like -the Z card of a manifest. The argument to the Z card is the +A cluster contains one or more M cards followed by a single Z card. +Each M card has a single argument which is the artifact ID of +another artifact in the repository. The Z card works exactly like +the Z card of a manifest. The argument to the Z card is the lower-case hexadecimal representation of the MD5 checksum of all -prior cards in the cluster. The Z-card is required. +prior cards in the cluster. The Z card is required. An example cluster from Fossil can be seen [/artifact/d03dbdd73a2a8 | here]. -

            3.0 Control Artifacts

            +

            2.3 Control Artifacts

            Control artifacts are used to assign properties to other artifacts -within the repository. The basic format of a control artifact is -the same as a manifest or cluster. A control artifact is a text -file divided into cards by newline characters. Each card has a -single-character card type followed by arguments. Spaces separate -the card type and the arguments. No surplus whitespace is allowed. -All cards must occur in strict lexicographical order. - +within the repository. Allowed cards in a control artifact are as follows:
            D time-and-date-stamp
            T (+|-|*)tag-name artifact-id ?value?
            U user-name
            Z checksum
            -A control artifact must have one D card, one U card, one Z card and -one or more T cards. No other cards or other text is +A control artifact must have one D card, one U card, one Z card and +one or more T cards. No other cards or other text is allowed in a control artifact. Control artifacts might be PGP clearsigned. -The D card and the Z card of a control artifact are the same +The D card and the Z card of a control artifact are the same as in a manifest. -The T card represents a [./branching.wiki#tags | tag or property] +The T card represents a [./branching.wiki#tags | tag or property] that is applied to -some other artifact. The T card has two or three values. The -second argument is the 40 character lowercase artifact ID of the artifact +some other artifact. The T card has two or three values. The +second argument is the lowercase artifact ID of the artifact to which the tag is to be applied. The first value is the tag name. The first character of the tag is either "+", "-", or "*". The "+" means the tag should be added to the artifact. The "-" means the tag should be removed. The "*" character means the tag should be added to the artifact and all direct descendants (but not descendants through a merge) down -to but not including the first descendant that contains a +to but not including the first descendant that contains a more recent "-", "*", or "+" tag with the same name. The optional third argument is the value of the tag. A tag without a value is a Boolean. When two or more tags with the same name are applied to the @@ -331,55 +328,62 @@ for display purposes. The "user" tag overrides the name of the check-in user. The "date" tag overrides the check-in date. The "branch" tag sets the name of the branch that at check-in belongs to. Symbolic tags begin with the "sym-" prefix. -The U card is the name of the user that created the control -artifact. The Z card is the usual required artifact checksum. +The U card is the name of the user that created the control +artifact. The Z card is the usual required artifact checksum. An example control artifacts can be seen [/info/9d302ccda8 | here]. -

            4.0 Wiki Pages

            +

            2.4 Wiki Pages

            -A wiki page is an artifact with a format similar to manifests, -clusters, and control artifacts. The artifact is divided into -cards by newline characters. The format of each card is as in -manifests, clusters, and control artifacts. Wiki artifacts accept +A wiki artifact defines a single version of a +single wiki page. +Wiki artifacts accept the following card types:
            +C change-comment
            D time-and-date-stamp
            L wiki-title
            N mimetype
            P parent-artifact-id+
            U user-name
            W size \n text \n
            Z checksum
            -The D card is the date and time when the wiki page was edited. -The P card specifies the parent wiki pages, if any. The L card -gives the name of the wiki page. The optional N card specifies -the mimetype of the wiki text. If the N card is omitted, the -mimetype is assumed to be text/x-fossil-wiki. -The U card specifies the login -of the user who made this edit to the wiki page. The Z card is +The D card is the date and time when the wiki page was edited. +The P card specifies the parent wiki pages, if any. The L card +gives the name of the wiki page. The optional N card specifies +the mimetype of the wiki text. If the N card is omitted, the +mimetype is assumed to be text/x-fossil-wiki. +The U card specifies the login +of the user who made this edit to the wiki page. The Z card is the usual checksum over the entire artifact and is required. -The W card is used to specify the text of the wiki page. The -argument to the W card is an integer which is the number of bytes +The W card is used to specify the text of the wiki page. The +argument to the W card is an integer which is the number of bytes of text in the wiki page. That text follows the newline character -that terminates the W card. The wiki text is always followed by one +that terminates the W card. The wiki text is always followed by one extra newline. + +The C card on a wiki page is optional. The argument is a comment +that explains why the changes was made. The ability to have a C +card on a wiki page artifact was added on 2019-12-02 at the suggestion +of user George Krivov and is not currently used or generated by the +implementation. Older versions of Fossil will reject a wiki-page +artifact that includes a C card. An example wiki artifact can be seen [/artifact?name=7b2f5fd0e0&txt=1 | here]. -

            5.0 Ticket Changes

            +

            2.5 Ticket Changes

            A ticket-change artifact represents a change to a trouble ticket. The following cards are allowed on a ticket change artifact:
            @@ -388,47 +392,47 @@ K ticket-id
            U user-name
            Z checksum
            -The D card is the usual date and time stamp and represents the point -in time when the change was entered. The U card is the login of the -programmer who entered this change. The Z card is the required checksum over +The D card is the usual date and time stamp and represents the point +in time when the change was entered. The U card is the login of the +programmer who entered this change. The Z card is the required checksum over the entire artifact. Every ticket has a distinct ticket-id: 40-character lower-case hexadecimal number. -The ticket-id is given in the K-card. A ticket exists if it contains one or +The ticket-id is given in the K card. A ticket exists if it contains one or more changes. The first "change" to a ticket is what brings the ticket into existence. -J cards specify changes to the "value" of "fields" in the ticket. -If the value parameter of the J card is omitted, then the +J cards specify changes to the "value" of "fields" in the ticket. +If the value parameter of the J card is omitted, then the field is set to an empty string. Each fossil server has a ticket configuration which specifies the fields its understands. The ticket configuration is part of the local state for the repository and thus can vary from one repository to another. -Hence a J card might specify a field that do not exist in the -local ticket configuration. If a J card specifies a field that -is not in the local configuration, then that J card +Hence a J card might specify a field that do not exist in the +local ticket configuration. If a J card specifies a field that +is not in the local configuration, then that J card is simply ignored. -The first argument of the J card is the field name. The second +The first argument of the J card is the field name. The second value is the field value. If the field name begins with "+" then the value is appended to the prior value. Otherwise, the value -on the J card replaces any previous value of the field. +on the J card replaces any previous value of the field. The field name and value are both encoded using the character -escapes defined for the C card of a manifest. +escapes defined for the C card of a manifest. An example ticket-change artifact can be seen [/artifact/91f1ec6af053 | here]. -

            6.0 Attachments

            +

            2.6 Attachments

            An attachment artifact associates some other artifact that is the -attachment (the source artifact) with a ticket or wiki page or +attachment (the source artifact) with a ticket or wiki page or technical note to which the attachment is connected (the target artifact). The following cards are allowed on an attachment artifact:
            @@ -438,36 +442,36 @@ N mimetype
            U user-name
            Z checksum
            -The A card specifies a filename for the attachment in its first argument. -The second argument to the A card is the name of the wiki page or +The A card specifies a filename for the attachment in its first argument. +The second argument to the A card is the name of the wiki page or ticket or technical note to which the attachment is connected. The -third argument is either missing or else it is the 40-character artifact +third argument is either missing or else it is the lower-case artifact ID of the attachment itself. A missing third argument means that the attachment should be deleted. -The C card is an optional comment describing what the attachment is about. -The C card is optional, but there can only be one. +The C card is an optional comment describing what the attachment is about. +The C card is optional, but there can only be one. -A single D card is required to give the date and time when the attachment +A single D card is required to give the date and time when the attachment was applied. -There may be zero or one N cards. The N card specifies the mimetype of the -comment text provided in the C card. If the N card is omitted, the C card +There may be zero or one N cards. The N card specifies the mimetype of the +comment text provided in the C card. If the N card is omitted, the C card mimetype is taken to be text/plain. -A single U card gives the name of the user who added the attachment. -If an attachment is added anonymously, then the U card may be omitted. +A single U card gives the name of the user who added the attachment. +If an attachment is added anonymously, then the U card may be omitted. -The Z card is the usual checksum over the rest of the attachment artifact. -The Z card is required. +The Z card is the usual checksum over the rest of the attachment artifact. +The Z card is required. -

            7.0 Technical Notes

            +

            2.7 Technical Notes

            A technical note or "technote" artifact (formerly known as an "event" artifact) associates a timeline comment and a page of text (similar to a wiki page) with a point in time. Technotes can be used to record project milestones, release notes, blog entries, process @@ -484,59 +488,133 @@ U user-name
            W size \n text \n
            Z checksum
            -The C card contains text that is displayed on the timeline for the -technote. The C card is optional, but there can only be one. +The C card contains text that is displayed on the timeline for the +technote. The C card is optional, but there can only be one. -A single D card is required to give the date and time when the +A single D card is required to give the date and time when the technote artifact was created. This is different from the time at which the technote appears on the timeline. -A single E card gives the time of the technote (the point on the timeline +A single E card gives the time of the technote (the point on the timeline where the technote is displayed) and a unique identifier for the technote. When there are multiple artifacts with the same technote-id, the one with -the most recent D card is the only one used. The technote-id must be a +the most recent D card is the only one used. The technote-id must be a 40-character lower-case hexadecimal string. -The optional N card specifies the mimetype of the text of the technote -that is contained in the W card. If the N card is omitted, then the -W card text mimetype is assumed to be text/x-fossil, which is the +The optional N card specifies the mimetype of the text of the technote +that is contained in the W card. If the N card is omitted, then the +W card text mimetype is assumed to be text/x-fossil-wiki, which is the Fossil wiki format. -The optional P card specifies a prior technote with the same technote-id -from which the current technote is an edit. The P card is a hint to the +The optional P card specifies a prior technote with the same technote-id +from which the current technote is an edit. The P card is a hint to the system that it might be space efficient to store one technote as a delta of the other. -A technote might contain one or more T-cards used to set +A technote might contain one or more T cards used to set [./branching.wiki#tags | tags or properties] -on the technote. The format of the T-card is the same as +on the technote. The format of the T card is the same as described in [#ctrl | Control Artifacts] section above, except that the second argument is the single character "*" instead of an artifact ID and the name is always prefaced by "+". The * in place of the artifact ID indicates that the tag or property applies to the current artifact. It is not possible to encode the current artifact ID as part of an artifact, since the act of inserting the artifact ID would change the artifact ID, hence a * is used to represent "self". The "+" on the name means that tags can only be add and they can only be non-propagating -tags. In a technote, T cards are normally used to set the background +tags. In a technote, T cards are normally used to set the background display color for timelines. -The optional U card gives name of the user who entered the technote. +The optional U card gives name of the user who entered the technote. + +A single W card provides wiki text for the document associated with the +technote. The format of the W card is exactly the same as for a +[#wikichng | wiki artifact]. + +The Z card is the required checksum over the rest of the artifact. + + +

            2.8 Forum Posts

            + +Forum posts are intended as a mechanism for users and developers to +discuss a project. Forum posts are like messages on a mailing list. + +The following cards are allowed on an forum post artifact: + +
            +D time-and-date-stamp
            +G thread-root
            +H thread-title
            +I in-reply-to
            +N mimetype
            +P parent-artifact-id
            +U user-name
            +W size \n text \n
            +Z checksum +
            + +Every forum post must have either one I card and one G card +or one H card. +Forum posts are organized into topic threads. The initial +post for a thread (the root post) has an H card giving the title or +subject for that thread. The argument to the H card is a string +in the same format as a comment string in a C card. +All follow-up posts have an I card that +indicates which prior post in the same thread the current forum +post is replying to, and a G card specifying the root post for +the entire thread. The argument to G and I cards is the +artifact hash for the prior forum post to which the card refers. + +In theory, it is sufficient for follow-up posts to have only an +I card, since the G card value could be computed by following a +chain of I cards. However, the G card is required in order to +associate the artifact with a forum thread in the case where an +intermediate artifact in the I card chain is shunned or otherwise +becomes unreadable. + +A single D card is required to give the date and time when the +forum post was created. + +The optional N card specifies the mimetype of the text of the technote +that is contained in the W card. If the N card is omitted, then the +W card text mimetype is assumed to be text/x-fossil-wiki, which is the +Fossil wiki format. + +The optional P card specifies a prior forum post for which this +forum post is an edit. For display purposes, only the child post +is shown, though the historical post is retained as a record. +If P cards are used and there exist multiple versions of the same +forum post, then I cards for other artifacts refer to whichever +version of the post was current at the time the reply was made, +but G cards refer to the initial, unedited root post for the thread. +Thus, following the chain of I cards back to the root of the thread +may land on a different post than the one given in the G card. +However, following the chain of I cards back to the thread root, +then following P cards back to the initial version of the thread +root must give the same artifact as is provided by the G card, +otherwise the artifact containing the G card is considered invalid +and should be ignored. + +In general, P cards may contain multiple arguments, indicating a +merge. But since forum posts cannot be merged, the +P card of a forum post may only contain a single argument. + +The U card gives name of the user who entered the forum post. -A single W card provides wiki text for the document associated with the -technote. The format of the W card is exactly the same as for a +A single W card provides wiki text for the forum post. +The format of the W card is exactly the same as for a [#wikichng | wiki artifact]. -The Z card is the required checksum over the rest of the artifact. +The Z card is the required checksum over the rest of the artifact. -

            8.0 Card Summary

            +

            3.0 Card Summary

            The following table summarizes the various kinds of cards that appear on Fossil artifacts. A blank entry means that combination of card and artifact is not legal. A number or range of numbers indicates the number of times a card may (or must) appear in the corresponding artifact type. @@ -544,20 +622,21 @@ or more such cards are required. - + + @@ -564,36 +643,39 @@ + - + + - - + + + @@ -605,10 +687,11 @@ + @@ -615,18 +698,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -635,10 +753,11 @@ + @@ -645,15 +764,17 @@ + + @@ -665,10 +786,11 @@ + @@ -675,14 +797,16 @@ + + @@ -695,19 +819,21 @@ + + @@ -714,23 +840,26 @@ + - + + + @@ -739,19 +868,19 @@
            Card FormatUsed ByUsed By
            Manifest Cluster Control Wiki Ticket Attachment TechnoteForum
            A filename target ?source?          1   
            B baseline0-1*0-1             
             * = Required for delta manifests
            C comment-text 1     0-1   0-1 0-1 
            D date-time-stamp 1  1 1 1 1 1 1        1 
            F filename ?uuid? ?permissions? ?oldname? 0+            
            G thread-root       0-1
            H thread-title       0-1
            I in-reply-to       0-1
            J name ?value?         1+     
            K ticket-uuid    1     
            L wiki-title      1       
            M uuid   1+             0-1   0-1 0-10-1
            P uuid ... 0-1    0-1     0-10-1
            Q (+|-)uuid ?uuid? 0+                     
            T (+|*|-)tagname uuid ?value? 0+   1+       0+ 
            U username 1  1 1 1 0-1 0-11
            W sizeW size \n text \n       1     11
            Z md5sum1 1 1 1 1 1
            -

            9.0 Addenda

            +

            4.0 Addenda

            This section contains additional information which may be useful when implementing algorithms described above. -

            R Card Hash Calculation

            +

            4.1 R-Card Hash Calculation

            Given a manifest file named MF, the following Bash shell code -demonstrates how to compute the value of the R card in that manifest. +demonstrates how to compute the value of the R card in that manifest. This example uses manifest [28987096ac]. Lines starting with # are shell input and other lines are output. This demonstration assumes that the file versions represented by the input manifest are checked out under the current directory. @@ -779,8 +908,8 @@ Minor caveats: the above demonstration will work only when none of the filenames in the manifest are "fossilized" (encoded) because they contain spaces. In that case the shell-generated hash would differ because the stat calls will fail to find such files (which are output in encoded form here). That approach also won't work for delta manifests. Calculating -the R-card for delta manifests requires traversing both the delta and its baseline in +the R card for delta manifests requires traversing both the delta and its baseline in lexical order of the files, preferring the delta's copy if both contain a given file. Index: www/fiveminutes.wiki ================================================================== --- www/fiveminutes.wiki +++ www/fiveminutes.wiki @@ -4,73 +4,66 @@ The following document was contributed by Gilles Ganault on 2013-01-08.


            Up and running in 5 minutes as a single user

            -

            This short document explains the main basic Fossil commands for a single -user, i.e. with no additional users, with no need to synchronize with some remote +

            This short document explains the main basic Fossil commands for a single +user, i.e. with no additional users, with no need to synchronize with some remote repository, and no need for branching/forking.

            Create a new repository

            fossil new c:\test.repo

            -

            This will create the new SQLite binary file that holds the repository, i.e. -files, tickets, wiki, etc. It can be located anywhere, although it's considered -best practice to keep it outside the work directory where you will work on files +

            This will create the new SQLite binary file that holds the repository, i.e. +files, tickets, wiki, etc. It can be located anywhere, although it's considered +best practice to keep it outside the work directory where you will work on files after they've been checked out of the repository.

            Open the repository

            cd c:\temp\test.fossil

            fossil open c:\test.repo

            -

            This will check out the last revision of all the files in the repository, -if any, into the current work directory. In addition, it will create a binary +

            This will check out the last revision of all the files in the repository, +if any, into the current work directory. In addition, it will create a binary file _FOSSIL_ to keep track of changes (on non-Windows systems it is called .fslckout).

            Add new files

            fossil add .

            -

            To tell Fossil to add new files to the repository. The files aren't actually -added until you run "commit". When using ".", it tells Fossil -to add all the files in the current directory recursively, i.e. including all +

            To tell Fossil to add new files to the repository. The files aren't actually +added until you run "commit". When using ".", it tells Fossil +to add all the files in the current directory recursively, i.e. including all the files in all the subdirectories.

            Note: To tell Fossil to ignore some extensions:

            fossil settings ignore-glob "*.o,*.obj,*.exe" --global

            Remove files that haven't been committed yet

            fossil delete myfile.c

            -

            This will simply remove the item from the list of files that were previously +

            This will simply remove the item from the list of files that were previously added through "fossil add".

            Check current status

            fossil changes

            -

            This shows the list of changes that have been done and will be committed the -next time you run "fossil commit". It's a useful command to run before +

            This shows the list of changes that have been done and will be committed the +next time you run "fossil commit". It's a useful command to run before running "fossil commit" just to check that things are OK before proceeding.

            Commit changes

            -

            To actually apply the pending changes to the repository, e.g. new files marked -for addition, checked-out files that have been edited and must be checked-in, +

            To actually apply the pending changes to the repository, e.g. new files marked +for addition, checked-out files that have been edited and must be checked-in, etc.

            fossil commit -m "Added stuff"

            If no file names are provided on the command-line then all changes will be checked in, otherwise just the listed file(s) will be checked in.

            Compare two revisions of a file

            -

            If you wish to compare the last revision of a file and its checked out version +

            If you wish to compare the last revision of a file and its checked out version in your work directory:

            fossil gdiff myfile.c

            If you wish to compare two different revisions of a file in the repository:

            -

            fossil finfo myfile: Note the first hash, which is the UUID of the commit +

            fossil finfo myfile: Note the first hash, which is the hash of the commit when the file was committed

            -

            fossil gdiff --from UUID#1 --to UUID#2 myfile.c

            +

            fossil gdiff --from HASH#1 --to HASH#2 myfile.c

            Cancel changes and go back to previous revision

            fossil revert myfile.c

            Fossil does not prompt when reverting a file. It simply reminds the user about the "undo" command, just in case the revert was a mistake.

            - - -

            Close the repository

            -

            fossil close

            -

            This will simply remove the _FOSSIL_ at the root of the work directory but -will not delete the files in the work directory. From then on, any use of "fossil" -will trigger an error since there is no longer any connection.

            ADDED www/forum.wiki Index: www/forum.wiki ================================================================== --- /dev/null +++ www/forum.wiki @@ -0,0 +1,416 @@ +Fossil Forums + +

            Introduction

            + +As of Fossil 2.7, Fossil includes a built-in discussion forum feature. + +Any project complex enough to benefit from being managed by Fossil and +which has more than one user can probably also benefit from having a +discussion forum. Even if your project has a discussion forum already, +there are many benefits to using Fossil's built-in forum feature, some +of which you cannot get by using third-party alternatives: + + * Easy to Administer: Third-party discussion forum and mailing + list software tends to be difficult to install, set up, and + administer. The Fossil forum feature aims to be as close to + zero-configuration as is practical. + + * Malefactor Resistant: Because Fossil accepts forum posts + only via the web UI, it is inherently [./antibot.wiki | protected + against bots]. + + * Distributed and Tamper-Proof: Posts are stored in the Fossil + repository using the same [./fileformat.wiki | block chain technology] + that Fossil uses to store your check-ins, wiki documents, etc. + Posts sync to cloned repositories in a tamper-proof fashion. + + * Space Efficient: Because of Fossil's [./delta_format.wiki | + delta compression technology], discussions add little to the size + of a cloned repository. Ten years of the SQLite project's + discussions — averaging about 2 dozen posts per day — compress down + to [https://fossil-scm.org/forum/forumpost/9b6f3f36bdb | just + 35 MB of space] in a Fossil forum repository. + + * Built-in Full-Text Search: Fossil forums use + [https://sqlite.org/fts3.html | SQLite's powerful FTS4 engine] to + handle searches. If your project currently uses a mailing list for + discussions, this means you are no longer reliant upon third-party + mailing list archive services to provide a useful search engine for + your discussions. If you are running a private Fossil repository, + you may not even have the option of delegating this useful + service to a third-party; Fossil provides this service out of the + box. + + * One Result Per Matching Post: When you search the forum + archives via the Fossil web interface, you get only one result for + each matching post. When you search for project information via a + standard web search engine, you might get a result from the project + site's own mail archive plus one from Nabble, one from Gmane, one + from The Mail Archive... + + * Search Off-Line: Because Fossil is a [./concepts.wiki | + distributed version control system], project members can search + your forum archive while disconnected from the network where the + central Fossil instance runs. Your past discussions are potentially + just as valuable as a wiki document or checkin comment: there is no + good reason why you should have to wait to get back on the Internet + or back to the office before you can search for past posts. + + * Contribute Off-Line: Fossil forum posts work like any other + insertion into the repository, so a user can create new threads and + reply to existing ones while off-line, then sync their + contributions to the server they cloned from when back on-line. + Yes, you can post to the forum from inside a tent, miles from the + nearest WiFi router or cellular data tower. + + * Interlink with Other Fossil-Managed Artifacts: Because forum + posts are normal Fossil artifacts, you can interlink them with + other Fossil artifacts using short internal links: link to forum + threads from a [./tickets.wiki | ticket], link to a wiki document + from a forum post, etc. + + * Durable Links: Once you create a valid internal artifact + link in Fossil, it remains valid, durably. With + third-party forum software and mailing list search engines, your + links are only valid until the third-party component changes its + URL scheme or disappears from the web. + + * Role-Based Access Control: The forum uses the same + [./caps/ | capability-based access control + system] that Fossil uses to control all other repository accesses. + The Fossil forum feature simply adds [./caps/ref.html#2 | several new fine-grained + capabilities] to the existing system. + + * Enduring, Open File Format: Since Fossil has an + [./fileformat.wiki | open and well-documented file format], your + discussion archives are truly that: archives. You are no + longer dependent on the lifetime and business model of a + third-party piece of software or service. Should you choose to stop + using Fossil, you can easily extract your discussion traffic for + transfer to another system. + + * Lightweight Markup: Posts can be marked up using Fossil's + existing [/md_rules | Markdown] and [/wiki_rules | Wiki] markup + processors. No longer must you choose between two bad options: to + restrict posts to plain text only or to allow wild-west + HTML-formatted MIME email. Fossil's lightweight markup language + formatting features give you a middle path, providing your users + enough formatting power to communicate complex ideas well without + providing so much power as to risk + [https://wonko.com/post/html-escaping | security problems]. + + * Easy Email Alerts: You can configure Fossil to + [./alerts.md | send email alerts]. Forum post emails include the + complete message content for the benefit of those that prefer to + visit the forum only when they need to post something. Alerts are + optional, and each user gets the choice of immediate or daily + digest delivery. + + +

            Setting up a Fossil Forum

            + +

            Capabilities

            + +By default, no Fossil user has permission to use the forums except for +users with Setup and Admin capabilities, which get these as part of the +large package of other capabilities they get. + +For public Fossil repositories that wish to accept new users without +involving a human, go into Admin → Access and enable the "Allow +users to register themselves" setting. You may also wish to give users +in [./caps/#ucat | the anonymous user category] the +[./caps/ref.html#2 | RdForum] and +[./caps/ref.html#3 | WrForum] +capabilities: this allows people to post without creating an account +simply by solving [./antibot.wiki | a simple CAPTCHA]. + +For a private repository, you probably won't want to give the +anonymous user any forum access, but you may wish to give the +RdForum capability to users in the reader category. + +For either type of repository, you are likely to want to give at least +the [./caps/ref.html#4 | WrTForum] capability to users in the developer +category. If you did not give the RdForum capability to +anonymous above, you should give developer that +capability here if you choose to give it WrForum or +WrTForum capability. + +If you want to use the email alert feature, by default only those +users in the Setup and Admin user categories can make use of it. Grant +the [./caps/ref.html#7 | EmailAlert] capability to give others access to this feature. +Alternately, you can handle alert signups outside of Fossil, with +a Setup or Admin users manually signing users up via Admin → +Notification. You'll want to grant this capability to the +nobody user category if you want anyone to sign up without any +restrictions. Give it to anonymous instead if you want the +user to solve a simple CAPTCHA before signing up. Or, give it to +reader or developer if you want only users with Fossil +logins to have this ability. (That's assuming you give one or both of +these capabilities to every user on your Fossil repository.) + +By following this advice, you should not need to tediously add +capabilities to individual accounts except in atypical cases, such as +to grant the [./caps/ref.html#5 | ModForum] capability to an uncommonly +highly-trusted user. + + +

            Skin Setup

            + +If you create a new Fossil repository with version 2.7 or newer, its +default skin is already set up correctly for typical forum +configurations. + +If you have an existing repository, you have two choices if you want its +skin to be upgraded to support forums: + +
              +
            1. Go into Admin → Skins and switch from your current skin to + one of the stock skins. If you were on a stock skin, just switch away + from your current one to the actual stock skin, since they will be + different after the upgrade.
            2. + +
            3. If you have local customization that you do not want to throw + away, you can use the diff feature of Fossil's skin editor to show how + the skins differ.
            4. +
            + +The remainder of this section summarizes the differences you're expected +to see when taking option #2. + +The first thing is that you'll need to add something like the following +to the Header part of the skin to create the navbar link: + + + if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { + menulink /forum Forum + } + + +These rules say that any logged-in user with any [./caps/ref.html#2 | +forum-related capability] or an anonymous user RdForum or +WrForum capability will see the "Forum" navbar +link, which just takes you to /forum. + +The exact code you need here varies depending on which skin you're +using. Follow the style you see for the other navbar links. + +The new forum feature also brings many new CSS styles to the table. If +you're using the stock skin or something sufficiently close, the changes +may work with your existing skin as-is. Otherwise, you might need to +adjust some things, such as the background color used for the selected +forum post: + + + div.forumSel { + background-color: rgba(0, 0, 0, 0.05); + } + + +That overrides the default — a hard-coded light cyan — with a 95% +transparent black overlay instead, which simply darkens your skin's +normal background color underneath the selected post. That should work +with almost any background color except for very dark background colors. +For dark skins, an inverse of the above trick will work better: + + + div.forumSel { + background-color: rgba(255, 255, 255, 0.05); + } + + +That overlays the background with 5% white to lighten it slightly. + +Another new forum-related CSS style you might want to reflect into your +existing skin is: + + + div.forumPosts a:visited { + color: #6A7F94; + } + + +This changes the clicked-hyperlink color for the forum post links on the +main /forum page only, which allows your browser's history +mechanism to show which threads a user has read and which not. The link +color will change back to the normal link color — indicating "unread" — +when a reply is added to an existing thread because that changes where +the link from the /forum page points, taking you to the newest +post in the thread. + +The color given above is suitable for the stock skin. + +Beware that when changing this example, there are some +[https://hacks.mozilla.org/2010/03/privacy-related-changes-coming-to-css-vistited/ +| stringent restrictions] in modern browsers to prevent snoopy web sites +from brute-forcing your browsing history. (See the link for the method, +which explains the restrictions.) + + + + +One of the underlying assumptions of the forum feature is that you will +want to be able to search the forum archives, so the /forum +page always includes a search box. Since that depends on search being +enabled on the Fossil repository, Fossil warns that search is disabled +until you go into Admin → Search and enable the "Search Forum" +setting. + +You may want to enable some of the other Fossil search features while +you're in there. All of this does come at some CPU and I/O cost, which +is why it's disabled by default. + + +

            Single Sign-On

            + +If you choose to host your discussion forums within the same repository +as your project's other Fossil-managed content, you inherently have a +single sign-on system. Contrast third-party mailing list and forum +software where you either end up with two separate user tables and +permission sets, or you must go to significant effort to integrate the +two login systems. + +You may instead choose to host your forums in a Fossil repository +separate from your project's main Fossil repository. A good reason to do +this is that you have a public project where very few of those +participating in the forum have special capability bits for project +assets managed by Fossil, so you wish to segregate the two user sets. + +Yet, what of the users who will have logins on both repositories? Some +users will be trusted with access to the project's main Fossil +repository, and these users will probably also participate in the +project's Fossil-hosted forum. Fossil has a feature to solve this +problem: [./caps/login-groups.md | login groups]. + + +

            Email Alerts (a.k.a. Notifications)

            + +Internet email service has become rather complicated since its initial +simple and insecure implementation decades ago. Fossil's role in all of +this is rather small at the moment, but the details of the integration +are complex enough to justify [./alerts.md | a separate document]. + +(The other reason that document is separate is that Fossil's email +alerts system also gets used by features of Fossil other than the +forum.) + + +

            Accessing the Forum

            + +There are many paths to a repository's Fossil forum: + +
              +
            • + If you're using the default Fossil skin as shipped with Fossil + 2.7+ or one [#skin | updated] to support it, there + is a Forum button in the navbar which appears for users able to + access the forum. With the default skin, that button will only + appear if the user's browser window is at least + 1200 pixels wide. The + Fossil admin can adjust this limit in the skin's CSS section, down + near the bottom in the definition of the `wideonly` style. +
            • + +
            • The other stock skins have this button in them as of 2.7 as well, + without the screen width restriction, since the navbar in those skins + wraps on narrow screens more gracefully than the default skin + does.
            • + +
            • Users who set up their Fossil repository under prior versions and + who now have local skin changes they don't want to overwrite by + reverting to the stock 2.7 version of the skin they chose to start + with can easily [#skin | edit their skin] to include these links.
            • + +
            • A "Forum" link appears in the drop-down panel when you click the + default skin's hamburger menu (☰) while logged in as any user + with one or more of the [#caps | user capabilities listed above].
            • + +
            • That same link also appears on the repository's /sitemap + page, since it provides the content for the hamburger menu's + panel.
            • +
            + + +

            How Moderation Works

            + +In this section, we're going to call all of the following a "forum +update:" + + * create a new post + * reply to an existing post + * edit a post or reply + +When a person with the normal WrForum capability +updates the forum, Fossil saves the update in its block chain, but this +update is impermanent because of two other table updates made at the +same time: + +
              +
            1. Fossil saves the update artifact's ID in its private + table, preventing Fossil from sending such artifacts to any of the + repository's clones. (This is the same mechanism behind + [./private.wiki | private branches].)
            2. + +
            3. Fossil also adds a reference to that artifact in the + modreq table, which backs the moderation feature. This is + what causes Fossil to leave out the Reply button when rendering that + post's HTML in the forum's web interface.
            4. +
            + +When a moderator approves an update, Fossil deletes these table entries, +making the update [./shunning.wiki | semi-permanent]. This changes how Fossil renders the +HTML for that update. It also means the artifact will now sync to +users with [./caps/ref.html#g | Clone] capability. + +When a forum user edits a moderator-approved artifact, what actually +happens under the hood is that Fossil writes another artifact to the +repository which refers to the original version as its parent, causing +Fossil UI to present the new version instead of the original. The +original version remains in the repository, just as with historical +checkins. The parent must remain in the repository for referential +integrity purposes. + +When you "Delete" a moderator-approved post or reply through Fossil UI, +it's actually an edit with blank replacement content. The only way to +truly delete such artifacts is through [./shunning.wiki | shunning]. + +When a user with WrTForum capability +updates the forum, it happens in the same way except that Fossil skips +the private and modreq table insertions. + +When a moderator rejects an update, that artifact is unceremoniously +removed from the tip of the block chain. This is safe because Fossil +prevents replies to a reply or post awaiting moderator approval, so +referential integrity cannot be harmed. Rejecting an edit is even +safer, since the original post remains behind, so that replies continue +to refer to that original post. + + +

            Using the Moderation Feature

            + +Having described all of the work that Fossil performs under the hood on +behalf of its users, we can now give the short list of work left for the +repository's administrators and moderators: + +
              +
            1. Add the [./caps/ref.html#5 | ModForum] capability to any of + your users who should have this ability. You don't need to do this + for any user with [./caps/ref.html#s | Setup] or + [./caps/ref.html#a | Admin] capability; it's + [http://fossil-scm.org/index.html/artifact/b16221ffb736caa2?ln=1246-1257 + | already included].
            2. + +
            3. When someone updates the forum, an entry will appear in the + timeline if the type filter is set to "Forum" or "Any Type". If that + user has only the WrForum capability, any + other user with the ModForum capability + will see a conditional link appear at the top of the main forum + page: "Moderation Requests". Clicking this takes the moderator to + the /modreq page. A moderator may wish to keep the main + forum page open in a browser tab, reloading it occasionally to see + when the "Moderation Requests" link reappears.
            4. + +
            5. A moderator viewing an update pending moderation sees two + buttons at the bottom, "Approve" and "Reject" in place of the + "Delete" button that the post's creator sees. Beware that both + actions are durable and have no undo. Be careful!
            6. +
            Index: www/foss-cklist.wiki ================================================================== --- www/foss-cklist.wiki +++ www/foss-cklist.wiki @@ -89,11 +89,11 @@
          4. The project has a website.

          5. Release version numbers are in the traditional X.Y or X.Y.Z format. -

          6. Releases can be downloaded as tarball using +

          7. Releases can be downloaded as tarball using gzip or bzip2 compression.

          8. Releases unpack into a versioned top-level directory. (ex: "projectname-1.2.3/"). @@ -102,12 +102,12 @@ tarball.

          9. There are no incompatible licenses in the code.

          10. The project has not been blithely proclaimed "public domain" without -having gone through the tedious and exacting legal steps to actually put it +having gone through the tedious and exacting legal steps to actually put it in the public domain.

          11. There is an accurate change log in the code and on the website.

          12. There is documentation in the code and on the website.

          Index: www/fossil-from-msvc.wiki ================================================================== --- www/fossil-from-msvc.wiki +++ www/fossil-from-msvc.wiki @@ -11,41 +11,41 @@
        5. Tools > External Tools, where the items in this list map to "External Tool X" that we'll add to our own Fossil menu later:
          1. Rename the default "[New Tool 1]" to eg. - "Commit"   2. + "Commit"   2.
          2. Change Command to where Fossil is located eg. "c:\fossil.exe"
          3. Change Arguments to the required command, eg. - "commit -m". + "commit -m". The user will be prompted to type the comment that Commit expects
          4. -
          5. Set "Initial Directory" to point it to the work directory +
          6. Set "Initial Directory" to point it to the work directory where the source files are currently checked out by Fossil (eg. c:\Workspace). It's also possible to use system variables such as "$(ProjectDir)" instead of hard-coding the path
          7. Check "Prompt for arguments", since Commit requires typing a comment. Useless for commands like Changes that don't require arguments
          8. -
          9. Uncheck "Close on Exit", so we can see what Fossil says - before closing the DOS box. Note that "Use Output Window" - will display the output in a child window within the IDE instead of +
          10. Uncheck "Close on Exit", so we can see what Fossil says + before closing the DOS box. Note that "Use Output Window" + will display the output in a child window within the IDE instead of opening a DOS box
          11. Click on OK
        6. Tools > Customize > Commands
          1. -
          2. With "Menu bar = Menu Bar" selected, click on "Add +
          3. With "Menu bar = Menu Bar" selected, click on "Add New Menu". A new "Fossil" menu is displayed in the IDE's menu bar
          4. Click on "Modify Selection" to rename it "Fossil", and...
          5. Use the "Move Down" button to move it lower in the list
          -
        7. Still in Customize dialog: In the "Menu bar" combo, select - the new Fossil menu you just created, and Click on "Add Command...": - From Categories, select Tools, and select "External Command 1". - Click on Close. It's unfortunate that the IDE doesn't say which command +
        8. Still in Customize dialog: In the "Menu bar" combo, select + the new Fossil menu you just created, and Click on "Add Command...": + From Categories, select Tools, and select "External Command 1". + Click on Close. It's unfortunate that the IDE doesn't say which command maps to "External Command X".
        Index: www/fossil-v-git.wiki ================================================================== --- www/fossil-v-git.wiki +++ www/fossil-v-git.wiki @@ -1,197 +1,701 @@ Fossil Versus Git

        1.0 Don't Stress!

        -If you start out using one DVCS and later decide you like the other better, -you can easily [./inout.wiki | move your content]¹. - -Fossil and [http://git-scm.com | Git] are very similar in many respects, -but they also have important differences. -See the table below for -a high-level summary and the text that follows for more details. - -Keep in mind that you are reading this on a Fossil website, -so the information here -might be biased in favor of Fossil. Ask around with people who have -used both Fossil and Git for other opinions. - -¹Git does not support -wiki, tickets, or tech-notes, so those elements will not transfer when -exporting from Fossil to Git. - -

        2.0 Executive Summary:

        +The feature sets of Fossil and [http://git-scm.com | Git] overlap in +many ways. Both are +[https://en.wikipedia.org/wiki/Distributed_version_control | distributed +version control systems] which store a tree of check-in objects to a +local repository clone. In both systems, the local clone starts out as a +full copy of the remote parent. New content gets added to the local +clone and then later optionally pushed up to the remote, and changes to +the remote can be pulled down to the local clone at will. Both systems +offer diffing, patching, branching, merging, cherry-picking, bisecting, +private branches, a stash, etc. + +Fossil has inbound and outbound Git conversion features, so if you start +out using one DVCS and later decide you like the other better, you can +easily [./inout.wiki | move your version-controlled file content].¹ + +In this document, we set all of that similarity and interoperability +aside and focus on the important differences between the two, especially +those that impact the user experience. + +Keep in mind that you are reading this on a Fossil website, and though +we try to be fair, the information here +might be biased in favor of Fossil, if only because we spend most of our +time using Fossil, not Git. Ask around for second opinions from +people who have used both Fossil and Git. + + +

        2.0 Differences Between Fossil And Git

        + +Differences between Fossil and Git are summarized by the following table, +with further description in the text that follows.
        - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        GITFOSSIL
        File versioning onlyVersioning, Tickets, Wiki, and Technotes
        Ad-hoc, pile-of-files key/value databaseRelational SQL database
        Bazaar-style developmentCathedral-style development
        Designed for Linux developmentDesigned for SQLite development
        Lots of little toolsStand-alone executable
        One check-out per repositoryMany check-outs per repository
        Remembers what you should have doneRemembers what you actually did
        GPLBSD
        GITFOSSILmore
        File versioning onlyVCS, tickets, wiki, docs, notes, forum, UI, + [https://en.wikipedia.org/wiki/Role-based_access_control|RBAC]2.1 ↓
        Sprawling and inefficientSelf-contained and efficient2.2 ↓
        One-off custom pile-of-files data store[https://sqlite.org/famous.html|The most popular database in the world]2.3 ↓
        Runs natively on POSIX systems onlyNative on common desktop & server platforms2.4 ↓
        Bazaar-style developmentCathedral-style development2.5.1 ↓
        Designed for Linux kernel developmentDesigned for SQLite development2.5.2 ↓
        Many contributorsSelect contributors2.5.3 ↓
        Focus on individual branchesFocus on the entire tree of changes2.5.4 ↓
        One check-out per repositoryMany check-outs per repository2.6 ↓
        Remembers what you should have doneRemembers what you actually did2.7 ↓
        Commit firstTest first2.8 ↓
        SHA-2SHA-32.9 ↓
        -

        3.0 Discussion

        - -

        3.1 Feature Set

        +

        2.1 Featureful

        Git provides file versioning services only, whereas Fossil adds -integrated [./wikitheory.wiki | wiki], +an integrated [./wikitheory.wiki | wiki], [./bugtheory.wiki | ticketing & bug tracking], -[./embeddeddoc.wiki | embedded documentation], and -[./event.wiki | Technical notes]. -These additional capabilities are available for Git as 3rd-party and/or -user-installed add-ons, but with Fossil they are integrated into +[./embeddeddoc.wiki | embedded documentation], +[./event.wiki | technical notes], and a [./forum.wiki | web forum], +all within a single nicely-designed [./customskin.md|skinnable] web +[/help?cmd=ui|UI], +protected by [./caps/ | a fine-grained role-based +access control system]. +These additional capabilities are available for Git as 3rd-party +add-ons, but with Fossil they are integrated into the design. One way to describe Fossil is that it is -"[https://github.com/ | github]-in-a-box". +"[https://github.com/ | GitHub]-in-a-box." -If you clone Git's self-hosting repository you get just Git's source code. -If you clone Fossil's self-hosting repository, you get the entire -Fossil website - source code, documentation, ticket history, and so forth. +Fossil can do operations over all local repo clones and check-out +directories with a single command. For example, Fossil lets you say +fossil all sync on a laptop prior to taking it off the network +hosting those repos. You can sync up to all of the private repos on your +company network plus those public Internet-hosted repos you use. Whether +going out for a working lunch or on a transoceanic airplane trip, one +command gets you in sync. This works with several other Fossil +sub-commands, such as fossil all changes to get a list of files +that you forgot to commit prior to the end of your working day, across +all repos. + +Whenever Fossil is told to modify the local checkout in some destructive +way ([/help?cmd=rm|fossil rm], [/help?cmd=update|fossil update], +[/help?cmd=revert|fossil revert], etc.) Fossil remembers the prior state +and is able to return the check-out directory to that state with a +fossil undo command. You cannot undo a commit in Fossil +([#history | on purpose!]) but as long as the change remains confined to +the local check-out directory only, Fossil makes undo +[https://git-scm.com/book/en/v2/Git-Basics-Undoing-Things|easier than in +Git]. For developers who choose to self-host projects (rather than using a 3rd-party service such as GitHub) Fossil is much easier to set up, since -the stand-alone Fossil executable together with a 2-line CGI script +the stand-alone Fossil executable together with a [./server/any/cgi.md|2-line CGI script] suffice to instantiate a full-featured developer website. To accomplish the same using Git requires locating, installing, configuring, integrating, and managing a wide assortment of separate tools. Standing up a developer website using Fossil can be done in minutes, whereas doing the same using Git requires hours or days. -

        3.2 Database

        - -The baseline data structures for Fossil and Git are the same (modulo -formatting details). Both systems store check-ins as immutable -objects referencing their immediate ancestors and named by their SHA1 hash. - -The difference is that Git stores its objects as individual files -in the ".git" folder or compressed into -bespoke "pack-files", whereas Fossil stores its objects in a -relational ([https://www.sqlite.org/|SQLite]) database file. To put it -another way, Git uses an ad-hoc pile-of-files key/value database whereas -Fossil uses a proven, general-purpose SQL database. This -difference is more than an implementation detail. It -has important consequences. +Fossil is small, complete, and self-contained. If you clone +[https://github.com/git/git|Git's self-hosting repository], you get just +Git's source code. If you clone Fossil's self-hosting repository, you +get the entire Fossil website — source code, documentation, ticket +history, and so forth.² That means you get a copy of this very article +and all of its historical versions, plus the same for all of the other +public content on this site. + + +

        2.2 Efficient

        + +Git is actually a collection of many small tools, each doing one small +part of the job, which can be recombined (by experts) to perform +powerful operations. Git has a lot of complexity and many dependencies, +so that most people end up installing it via some kind of package +manager, simply because the creation of complicated binary packages is +best delegated to people skilled in their creation. Normal Git users are +not expected to build Git from source and install it themselves. + +Fossil is a single self-contained stand-alone executable which by default +depends only on common platform libraries. If your platform allows static +linking — not all do these days! — you can even get it down to +a single executable with no external dependencies at all. Most notably, +we deliver the official Windows builds of Fossil this way: the Zip file +contains only fossil.exe, a self-contained Fossil executable; +it is not a setup.exe style installer, it is the whole enchilada. + +A typical Fossil executable is about 5 MiB, not counting system +libraries it shares in common with Git such as OpenSSL and zlib, which +we can factor out of the discussion. + +These properties allow Fossil to easily run inside a minimally configured +[https://en.wikipedia.org/wiki/Chroot|chroot jail], from a Windows memory +stick, off a Raspberry Pi with a tiny SD card, etc. To install Fossil, +one merely puts the executable somewhere in the $PATH. Fossil is +[https://fossil-scm.org/fossil/doc/trunk/www/build.wiki|straightforward +to build and install], so that many Fossil users do in fact build and +install "trunk" versions to get new features between formal releases. + +Contrast a basic installation of Git, which takes up about +15 MiB on Debian 10 across 230 files, not counting the contents of +/usr/share/doc or /usr/share/locale. If you need to +deploy to any platform where you cannot count facilities like the POSIX +shell, Perl interpreter, and Tcl/Tk platform needed to fully use Git +as part of the base platform, the full footprint of a Git installation +extends to more like 45 MiB and thousands of files. This complicates +several common scenarios: Git for Windows, chrooted Git servers, +Docker images... + +Some say that Git more closely adheres to the Unix philosophy, +summarized as "many small tools, loosely joined," but we have many +examples of other successful Unix software that violates that principle +to good effect, from Apache to Python to ZFS. We can infer from that +that this is not an absolute principle of good software design. +Sometimes "many features, tightly-coupled" works better. What actually +matters is effectiveness and efficiency. We believe Fossil achieves +this. + +The above size comparisons aren't apples-to-apples anyway. We've +compared the size of Fossil with all of its [#features | many built-in +features] to a fairly minimal Git installation. You must add a lot +of third-party +software to Git to give it a Fossil-equivalent feature set. Consider +[https://about.gitlab.com/|GitLab], a third-party extension to Git +wrapping it in many features, making it roughly Fossil-equivalent, +though [https://docs.gitlab.com/ee/install/requirements.html|much more +resource hungry] and hence more costly to run than the equivalent +Fossil setup. GitLab's basic requirements are easy to accept when you're dedicating +a local rack server or blade to it, since its minimum requirements are +more or less a description of the smallest +thing you could call a "server" these days, but when you go to host that +in the cloud, you can expect to pay about 8× as much to comfortably host +GitLab as for Fossil.³ This difference is largely due to basic +technology choices: Ruby and PostgreSQL vs C and SQLite. + +The Fossil project itself is [./selfhost.wiki|hosted on a very small +VPS], and we've received many reports on the Fossil forum about people +successfully hosting Fossil service on bare-bones $5/month VPS hosts, +spare Raspberry Pi boards, and other small hosts. + + + +

        2.3 Durable

        + +The baseline data structures for Fossil and Git are the same, modulo +formatting details. Both systems manage a +[https://en.wikipedia.org/wiki/Directed_acyclic_graph | directed acyclic +graph] (DAG) of [https://en.wikipedia.org/wiki/Merkle_tree | Merkle +tree] / [./blockchain.md | block chain] structured check-in objects. +Check-ins are identified by a cryptographic hash of the check-in +comment, and each check-in refers to its parent via its hash. + +The difference is that Git stores its objects as individual files in the +.git folder or compressed into bespoke +[https://git-scm.com/book/en/v2/Git-Internals-Packfiles|pack-files], +whereas Fossil stores its objects in a [https://www.sqlite.org/|SQLite] +database file using a hybrid NoSQL/relational data model of the check-in +history. Git's data storage system is an ad-hoc pile-of-files key/value +database, whereas Fossil uses a proven, +[https://sqlite.org/testing.html|heavily-tested], general-purpose, +[https://sqlite.org/transactional.html|durable] SQL database. This +difference is more than an implementation detail. It has important +practical consequences. With Git, one can easily locate the ancestors of a particular check-in by following the pointers embedded in the check-in object, but it is difficult to go the other direction and locate the descendants of a check-in. It is so difficult, in fact, that neither native Git nor -GitHub provide this capability. With Git, if you are looking at some -historical check-in then you cannot ask -"what came next" or "what are the children of this check-in". +GitHub provide this capability short of +[http://catb.org/jargon/html/G/grovel.html|groveling] the +[https://www.git-scm.com/docs/git-log|commit log]. With Git, if you +are looking at some historical check-in then you cannot ask "What came +next?" or "What are the children of this check-in?" Fossil, on the other hand, parses essential information about check-ins -(parents, children, committers, comments, files changed, etc.) -into a relational database that can be easily -queried using concise SQL statements to find both ancestors and -descendents of a check-in. - -Leaf check-ins in Git that lack a "ref" become "detached", making them -difficult to locate and subject to garbage collection. This -"detached head" problem has caused untold grief for countless -Git users. With Fossil, all check-ins are easily located using -a variety of attributes (parents, children, committer, date, full-text -search of the check-in comment) and so detached heads are simply not possible. - -The ease with which check-ins can be located and queried in Fossil -has resulted in a huge variety of reports and status screens -([./webpage-ex.md|examples]) that show project state -in ways that help developers -maintain enhanced awareness and comprehension -and avoid errors. - -

        3.3 Cathedral vs. Bazaar

        - -Fossil and Git promote different development styles. Git promotes a -"bazaar" development style in which numerous anonymous developers make -small and sometimes haphazard contributions. Fossil -promotes a "cathedral" development model in which the project is -closely supervised by an highly engaged architect and implemented by -a clique of developers. - -Nota Bene: This is not to say that Git cannot be used for cathedral-style -development or that Fossil cannot be used for bazaar-style development. -They can be. But those modes are not their design intent nor the their -low-friction path. - -Git encourages a style in which individual developers work in relative -isolation, maintaining their -own branches and occasionally rebasing and pushing selected changes up -to the main repository. Developers using Git often have their own -private branches that nobody else ever sees. Work becomes siloed. -This is exactly what one wants when doing bazaar-style development. - -Fossil, in contrast, strives to keep all changes from all contributors -mirrored in the main repository (in separate branches) at all times. -Work in progress from one developer is readily visible to all other -developers and to the project leader, well before the code is ready -to integrate. Fossil places a lot of emphasis on reporting the state -of the project, and the changes underway by all developers, so that -all developers and especially the project leader can maintain a better -mental picture of what is happening, and better situational awareness. - -

        3.4 Linux vs. SQLite

        - -Git was specifically designed to support the development of Linux. -Fossil was specifically designed to support the development of SQLite. - -Both SQLite and Linux are important pieces of software. -SQLite is found on far more systems than Linux. (Almost every Linux -system uses SQLite, but there are many non-Linux systems such as -iPhones, PlayStations, and Windows PC that use SQLite.) On the other -hand, for those systems that do use Linux, Linux is a far more important -component. - -Linux uses a bazaar-style development model. There are thousands and -thousands of contributors, most of whom do not know each others names. -Git is designed for this scenario. - -SQLite uses cathedral-style development. 95% of the code in SQLite -comes from just three programmers, 64% from just the lead developer. -And all SQLite developers know each other well and interact daily. -Fossil is designed for this development model. - -

        3.5 Lots of little tools vs. Self-contained system

        - -Git consists of many small tools, each doing one small part of the job, -which can be recombined (by experts) to perform powerful operations. -Git has a lot of complexity and many dependencies and requires an "installer" -script or program to get it running. - -Fossil is a single self-contained stand-alone executable with hardly -any dependencies. Fossil can be (and often is) run inside a -minimally configured chroot jail. To install Fossil, -one merely puts the executable on $PATH. - -The designer of Git says that the unix philosophy is to have lots of -small tools that collaborate to get the job done. The designer of -Fossil says that the unix philosophy is "it just works". Both -individuals have written their DVCSes to reflect their own view -of the "unix philosophy". - -

        3.6 One vs. Many Check-outs per Repository

        - -A "repository" in Git is a pile-of-files in the ".git" subdirectory -of a single check-out. The check-out and the repository are inseperable. - -With Fossil, a "repository" is a single SQLite database file -that can be stored anywhere. There -can be multiple active check-outs from the same repository, perhaps -open on different branches or on different snapshots of the same branch. -Long-running tests or builds can be running in one check-out while -changes are being committed in another. - -

        3.7 What you should have done vs. What you actually did

        +(parents, children, committers, comments, files changed, etc.) into a +relational database that can easily be queried using concise SQL +statements to find both ancestors and descendants of a check-in. This is +the hybrid data model mentioned above: Fossil manages your check-in and +other data in a NoSQL block chain structured data store, but that's backed +by a set of relational lookup tables for quick indexing into that +artifact store. (See "[./theory1.wiki|Thoughts On The Design Of The +Fossil DVCS]" for more details.) + +Leaf check-ins in Git that lack a "ref" become "detached," making them +difficult to locate and subject to garbage collection. This +[http://gitfaq.org/articles/what-is-a-detached-head.html|detached head +state] problem has caused untold grief for +[https://www.google.com/search?q=git+detached+head+state | a huge number +of Git users]. With +Fossil, detached heads are simply impossible because we can always find +our way back into the block chain using one or more of the relational +indices it automatically manages for you. + +This design difference shows up in several other places within each +tool. It is why Fossil's [/help?cmd=timeline|timeline] is generally more +detailed yet more clear than those available in Git front-ends. +(Contrast [/timeline?c=6df7a853ec16865b|this Fossil timeline] with +[https://github.com/drhsqlite/fossil-mirror/commits/master?after=f720c106d297ca1f61bccb30c5c191b88a626d01+34|its +closest equivalent in GitHub].) It's why there is no inverse of the +cryptic @~ notation in Git, meaning "the parent of HEAD," which +Fossil simply calls "prev", but there is a "next" +[./checkin_names.wiki|special check-in name] in Fossil. It is why Fossil +has so many [./webpage-ex.md|built-in status reports] to help maintain +situational awareness, aid comprehension, and avoid errors. + +These differences are due, in part, to Fossil's start a year later than +Git: we were able to learn from its key design mistakes. + + +

        2.4 Portable

        + +Fossil is largely written in ISO C, almost purely conforming to the +original 1989 standard. We make very little use of +[https://en.wikipedia.org/wiki/C99|C99], and we do not knowingly make +any use of +[https://en.wikipedia.org/wiki/C11_(C_standard_revision)|C11]. Fossil +does call POSIX and Windows APIs where necessary, but it's about +as portable as you can ask given that ISO C doesn't define all of the +facilities Fossil needs to do its thing. (Network sockets, file locking, +etc.) There are certainly well-known platforms Fossil hasn't been ported +to yet, but that's most likely due to lack of interest rather than +inherent difficulties in doing the port. We believe the most stringent +limit on its portability is that it assumes at least a 32-bit CPU and +several megs of flat-addressed memory.⁴ Fossil isn't quite as +[https://www.sqlite.org/custombuild.html|portable as SQLite], but it's +close. + +Over half of the C code in Fossil is actually an embedded copy of the +current version of SQLite. Much of what is Fossil-specific after you set +SQLite itself aside is SQL code calling into SQLite. The number of lines +of SQL code in Fossil isn't large by percentage, but since SQL is such +an expressive, declarative language, it has an outsized contribution to +Fossil's user-visible functionality. + +Fossil isn't entirely C and SQL code. Its web UI [./javascript.md | +uses JavaScript where +necessary]. The server-side +UI scripting uses a custom minimal +[https://en.wikipedia.org/wiki/Tcl|Tcl] dialect called +[https://www.fossil-scm.org/xfer/doc/trunk/www/th1.md|TH1], which is +embedded into Fossil itself. Fossil's build system and test suite are +largely based on Tcl.⁵ All of this is quite portable. + +About half of Git's code is POSIX C, and about a third is POSIX shell +code. This is largely why the so-called "Git for Windows" distributions +(both [https://git-scm.com/download/win|first-party] and +[https://gitforwindows.org/|third-party]) are actually an +[http://mingw.org/wiki/msys|MSYS POSIX portability environment] bundled +with all of the Git stuff, because it would be too painful to port Git +natively to Windows. Git is a foreign citizen on Windows, speaking to it +only through a translator.⁶ + +While Fossil does lean toward POSIX norms when given a choice — LF-only +line endings are treated as first-class citizens over CR+LF, for example +— the Windows build of Fossil is truly native. + +The third-party extensions to Git tend to follow this same pattern. +[http://mingw.org/wiki/msys|GitLab isn't portable to Windows at all], +for example. For that matter, GitLab isn't even officially supported on +macOS, the BSDs, or uncommon Linuxes! We have many users who regularly +build and run Fossil on all of these systems. + + +

        2.5 Linux vs. SQLite

        + +Fossil and Git promote different development styles because each one was +specifically designed to support the creator's main software +development project: [https://en.wikipedia.org/wiki/Linus_Torvalds|Linus +Torvalds] designed Git to support development of +[https://www.kernel.org/|the Linux kernel], and +[https://en.wikipedia.org/wiki/D._Richard_Hipp|D. Richard Hipp] designed +Fossil to support the development of [https://sqlite.org/|SQLite]. +Both projects must rank high on any objective list of "most +important FOSS projects," yet these two projects are almost entirely unlike +one another, so it is natural that the DVCSes created to support these +projects also differ in many ways. + +In the following sections, we will explain how four key differences +between the Linux and SQLite software development projects dictated the +design of each DVCS's low-friction usage path. + +When deciding between these two DVCSes, you should ask yourself, "Is my +project more like Linux or more like SQLite?" + + +

        2.5.1 Development Organization

        + +Eric S. Raymond's seminal essay-turned-book +"[https://en.wikipedia.org/wiki/The_Cathedral_and_the_Bazaar|The +Cathedral and the Bazaar]" details the two major development +organization styles found in +[https://en.wikipedia.org/wiki/Free_and_open-source_software|FOSS] +projects. As it happens, Linux and SQLite fall on opposite sides of this +dichotomy. Differing development organization styles dictate a different +design and low-friction usage path in the tools created to support each +project. + +Git promotes the Linux kernel's bazaar development style, in which a +loosely-associated mass of developers contribute their work through +[https://git-scm.com/book/en/v2/Distributed-Git-Distributed-Workflows#_dictator_and_lieutenants_workflow|a +hierarchy of lieutenants] who manage and clean up these contributions +for consideration by Linus Torvalds, who has the power to cherry-pick +individual contributions into his version of the Linux kernel. Git +allows an anonymous developer to rebase and push specific locally-named +private branches, so that a Git repo clone often isn't really a clone at +all: it may have an arbitrary number of differences relative to the +repository it originally cloned from. Git encourages siloed development. +Select work in a developer's local repository may remain private +indefinitely. + +All of this is exactly what one wants when doing bazaar-style +development. + +Fossil's normal mode of operation differs on every one of these points, +with the specific designed-in goal of promoting SQLite's cathedral +development model: + +
          +
        • Personal engagement: SQLite's developers know each + other by name and work together daily on the project.

        • + +
        • Trust over hierarchy: SQLite's developers check + changes into their local repository, and these are immediately and + automatically synchronized up to the central repository; there is no + "[https://git-scm.com/book/en/v2/Distributed-Git-Distributed-Workflows#_dictator_and_lieutenants_workflow|dictator + and lieutenants]" hierarchy as with Linux kernel contributions. D. + Richard Hipp rarely overrides decisions made by those he has trusted + with commit access on his repositories. Fossil allows you to give + [./caps/admin-v-setup.md|some users] more power over what + they can do with the repository, but Fossil [./caps/index.md#ucap | + only loosely supports] the enforcement of a development organization's + social and power hierarchies. Fossil is a great fit for + [https://en.wikipedia.org/wiki/Flat_organization|flat + organizations].

        • + +
        • No easy drive-by contributions: Git + [https://www.git-scm.com/docs/git-request-pull|pull requests] offer + a low-friction path to accepting + [https://www.jonobacon.com/2012/07/25/building-strong-community-structural-integrity/|drive-by + contributions]. Fossil's closest equivalent is its unique + [/help?cmd=bundle|bundle] feature, which requires higher engagement + than firing off a PR.⁷ This difference comes directly from the + initial designed purpose for each tool: the SQLite project doesn't + accept outside contributions from previously-unknown developers, but + the Linux kernel does.

        • + +
        • No rebasing: When your local repo clone syncs changes + up to its parent, those changes are sent exactly as they were + committed locally. [#history|There is no rebasing mechanism in + Fossil, on purpose.]

        • + +
        • Sync over push: Explicit pushes are uncommon in + Fossil-based projects: the default is to rely on + [/help?cmd=autosync|autosync mode] instead, in which each commit + syncs immediately to its parent repository. This is a mode so you + can turn it off temporarily when needed, such as when working + offline. Fossil is still a truly distributed version control system; + it's just that its starting default is to assume you're rarely out + of communication with the parent repo. +

          + This is not merely a reflection of modern always-connected computing + environments. It is a conscious decision in direct support of + SQLite's cathedral development model: we don't want developers going + dark, then showing up weeks later with a massive bolus of changes + for us to integrate all at once. + [https://en.wikipedia.org/wiki/Jim_McCarthy_(author)|Jim McCarthy] + put it well in his book on software project management, + [https://www.amazon.com/dp/0735623198/|Dynamics of Software + Development]: "[https://www.youtube.com/watch?v=oY6BCHqEbyc|Beware + of a guy in a room]."

        • + +
        • Branch names sync: Unlike in Git, branch names in + Fossil are not purely local labels. They sync along with everything + else, so everyone sees the same set of branch names. Fossil's design + choice here is a direct reflection of the Linux vs. SQLite project + outlook: SQLite's developers collaborate closely on a single + coherent project, whereas Linux's developers go off on tangents and + occasionally sync changes up with each other.

        • + +
        • Private branches are rare: + [/doc/trunk/www/private.wiki|Private branches exist in Fossil], but + they're normally used to handle rare exception cases, whereas in + many Git projects, they're part of the straight-line development + process.

        • + +
        • Identical clones: Fossil's autosync system tries to + keep each local clone identical to the repository it cloned + from.

        • +
        + +Where Git encourages siloed development, Fossil fights against it. +Fossil places a lot of emphasis on synchronizing everyone's work and on +reporting on the state of the project and the work of its developers, so +that everyone — especially the project leader — can maintain a better +mental picture of what is happening, leading to better situational +awareness. + +You can think about this difference in terms of +[https://en.wikipedia.org/wiki/Feedback | feedback loop size], which we +know from the mathematics of +[https://en.wikipedia.org/wiki/Control_theory | control theory] to +directly affect the speed at which any system can safely make changes. +The larger the feedback loop, the slower the whole system must run in +order to avoid loss of control. The same concept shows up in other +contexts, such as in the [https://en.wikipedia.org/wiki/OODA_loop | OODA +loop] concept originally developed to explain the success of the US F-86 +Sabre fighter aircraft over the on-paper superior MiG-15, then later +applied in other contexts, such as business process management. +Committing your changes to private branches in order to delay a public +push to the parent repo increases the size of your collaborators' +control loops, either causing them to slow their work in order to safely +react to your work, or to overcorrect in response to each change. + +Each DVCS can be used in the opposite style, but doing so works against +their low-friction paths. + + +

        2.5.2 Scale

        + +The Linux kernel has a far bigger developer community than that of +SQLite: there are thousands and thousands of contributors to Linux, most +of whom do not know each others names. These thousands are responsible +for producing roughly 89⨉ more code than is in SQLite. (10.7 +[https://en.wikipedia.org/wiki/Source_lines_of_code|MLOC] vs. 0.12 MLOC +according to [https://dwheeler.com/sloccount/|SLOCCount].) The Linux +kernel and its development process were already uncommonly large back in +2005 when Git was designed, specifically to support the consequences of +having such a large set of developers working on such a large code base. + +95% of the code in SQLite comes from just four programmers, and 64% of +it is from the lead developer alone. The SQLite developers know each +other well and interact daily. Fossil was designed for this development +model. + +We think you should ask yourself whether you have Linus Torvalds scale +software configuration management problems or D. Richard Hipp scale +problems when choosing your DVCS. An +[https://en.wikipedia.org/wiki/Impact_wrench|automotive air impact +wrench] running at 8000 RPM driving an M8 socket-cap bolt at 16 cm/s is +not the best way to hang a picture on the living room wall. + + +

        2.5.3 Accepting Contributions

        + +As of this writing, Git has received about 4.5⨉ as many commits as +Fossil resulting in about 2.5⨉ as many lines of source code. The line +count excludes tests and in-tree third-party dependencies. It does not +exclude the default GUI for each, since it's integral for Fossil, so we +count the size of gitk in this. + +It is obvious that Git is bigger in part because of its first-mover +advantage, which resulted in a larger user community, which results in +more contributions. But is that the only reason? We believe there +are other relevant differences that also play into this which fall out +of the "Linux vs. SQLite" framing: licensing, community structure, and +how we react to +[https://www.jonobacon.com/2012/07/25/building-strong-community-structural-integrity/|drive-by +contributions]. In brief, it's harder to get a new feature into Fossil +than into Git. + +A larger feature set is not necessarily a good thing. Git's command line +interface is famously arcane. Masters of the arcane are able to do +wizardly things, but only by studying their art deeply for years. This +strikes us as a good thing only in cases where use of the tool itself is +the primary point of that user's work. + +Almost no one uses a DVCS for its own sake; very few people get paid +specifically in order to drive a DVCS. We use DVCSes as a tool to +support some other effort, so we do not necessarily want the DVCS with +the most features. We want a DVCS with easily internalized behavior so +we can thoroughly master it despite spending only a small fraction of +our working time thinking about the DVCS. We want to pick the tool up, +use it quickly, and then set it aside in order to get back to our actual +job as quickly as possible. + +Professional software developers in particular are prone to focusing on +feature set sizes when choosing tools because this is sometimes a highly +important consideration. They spend all day, every day, in their +favorite text editors, and time they spend learning all of the arcana of +their favorite programming languages is well-spent. Skills with these +tools are direct productivity drivers, which in turn directly drives how +much money a developer can make. (Or how much idle time they can afford +to take, which amounts to the same thing.) But if you are a professional +software developer, we want you to ask yourself a question: "How do I +get paid more by mastering arcane features of my DVCS?" Unless you have +a good answer to that, you probably do not want to be choosing a DVCS +based on how many arcane features it has. + +The argument is similar for other types of users: if you are a hobbyist, +how much time do you want to spend mastering your DVCS instead of on +the hobby supported by use of that DVCS? + +There is some minimal set of features required to achieve the purposes +that drive our selection of a DVCS, but there is a level beyond which +more features only slow us down while we're learning the tool, since we +must plow through documentation on features we're not likely to ever +use. When the number of features grows to the point where people of +normal motivation cannot spend the time to master them all, the tool +becomes less productive to use. + +The core developers of the Fossil project achieve a balance between feature +set size and ease of use by +carefully choosing which users to give commit bits to, then in being +choosy about which of the contributed feature branches to merge down to +trunk. We say "no" to a lot of feature proposals. + +The end result is that Fossil more closely adheres to +[https://en.wikipedia.org/wiki/Principle_of_least_astonishment|the +principle of least astonishment] than Git does. + + +

        2.5.4 Individual Branches vs. The Entire Change History

        + +Both Fossil and Git store history as a directed acyclic graph (DAG) +of changes, but Git tends to focus more on individual branches of +the DAG, whereas Fossil puts more emphasis on the entire DAG. + +For example, the default behavior in Git is to only synchronize +a single branch, whereas with Fossil the only sync option is to +sync the entire DAG. Git commands, +GitHub, and GitLab tend to show only a single branch at +a time, whereas Fossil usually shows all parallel branches at +once. Git has commands like "rebase" that help keep all relevant +changes on a single branch, whereas Fossil encourages a style of +many concurrent branches constantly springing into existence, +undergoing active development in parallel for a few days or weeks, then +merging back into the main line and disappearing. + +This difference in emphasis arises from the different purposes of +the two systems. Git focuses on individual branches, because that +is exactly what you want for a highly-distributed bazaar-style project +such as Linux. Linus Torvalds does not want to see every check-in +by every contributor to Linux, as such extreme visibility does not scale +well. But Fossil was written for the cathedral-style SQLite project +with just a handful of active committers. Seeing all +changes on all branches all at once helps keep the whole team +up-to-date with what everybody else is doing, resulting in a more +tightly focused and cohesive implementation. + + +

        2.6 One vs. Many Check-outs per Repository

        + +Because Git commingles the repository data with the initial checkout of +that repository, the default mode of operation in Git is to stick to that +single work/repo tree, even when that's a shortsighted way of working. + +Fossil doesn't work that way. A Fossil repository is a SQLite database +file which is normally stored outside the working checkout directory. You can +[/help?cmd=open | open] a Fossil repository any number of times into +any number of working directories. A common usage pattern is to have one +working directory per active working branch, so that switching branches +is done with a cd command rather than by checking out the +branches successively in a single working directory. + +Fossil does allow you to switch branches within a working checkout +directory, and this is also often done. It is simply that there is no +inherent penalty to either choice in Fossil as there is in Git. The +standard advice is to use a switch-in-place workflow in Fossil when +the disturbance from switching branches is small, and to use multiple +checkouts when you have long-lived working branches that are different +enough that switching in place is disruptive. + +You can use Git in the Fossil style, either by manually symlinking the +.git directory from one working directory to another or by use +of the [https://git-scm.com/docs/git-worktree|git-worktree] +feature. Nevertheless, Git's default tie between working directory and +repository means the standard method for working with a Git repo is to +have one working directory only. Most Git tutorials teach this style, so +it is how most people learn to use Git. Because relatively few people +use Git with multiple working directories per repository, there are +[https://duckduckgo.com/?q=git+worktree+problem | several known +problems] with that way of working, problems which don't happen in Fossil because of +the clear separation between repository and working directory. + +This distinction matters because switching branches inside a single working directory loses local context +on each switch. + +For instance, in any software project where the runnable program must be +built from source files, you invalidate build objects on each switch, +artificially increasing the time required to switch versions. Most obviously, this +affects software written in statically-compiled programming languages +such as C, Java, and Haskell, but it can even affect programs written in +dynamic languages like JavaScript. A typical +[https://en.wikipedia.org/wiki/Single-page_application | SPA] build +process involves several passes: [http://browserify.org/ | Browserify] to convert +[https://nodejs.org/ | Node] packages so they'll run in a web browser, +[https://sass-lang.com | SASS] to CSS translation, +transpilation of [https://www.typescriptlang.org | Typescript] to JavaScript, +[https://github.com/mishoo/UglifyJS | uglification], etc. +Once all that processing work is done for a given input +file in a given working directory, why re-do that work just to switch +versions? If most of the files that differ between versions don't change +very often, you can save substantial time by switching branches with +cd rather than swapping versions in-place within a working +checkout directory. + +For another example, you might have an active long-running test grinding +away in a working directory, then get a call from a customer requiring +that you switch to a stable branch to answer questions in terms of the +version that customer is running. You don't want to stop the test in +order to switch your lone working directory to the stable branch. + +Disk space is cheap. Having several working directories, each with its +own local state, makes switching versions cheap and fast. Plus, +cd is faster to type than git checkout or fossil +update. + + +

        2.7 What you should have done vs. What you actually did

        Git puts a lot of emphasis on maintaining a "clean" check-in history. Extraneous and experimental branches by individual developers often never make it into the main repository. And branches are often rebased before being pushed, to make @@ -200,116 +704,230 @@ mistakes. Fossil, in contrast, puts more emphasis on recording exactly what happened, including all of the messy errors, dead-ends, experimental branches, and so forth. One might argue that this -makes the history of a Fossil project "messy". But another point of view -is that this makes the history "accurate". In actual practice, the +makes the history of a Fossil project "messy," but another point of view +is that this makes the history "accurate." In actual practice, the superior reporting tools available in Fossil mean that the added "mess" is not a factor. -One commentator has mused that Git records history according to +Like Git, Fossil has an [/help?cmd=amend|amend command] for modifying +prior commits, but unlike in Git, this works not by replacing data in +the repository, but by adding a correction record to the repository that +affects how later Fossil operations present the corrected data. The old +information is still there in the repository, it is just overridden from +the amendment point forward. For extreme situations, Fossil adds the +[/doc/trunk/www/shunning.wiki|shunning mechanism], but it has strict +limitations that prevent global history rewrites. + +One commentator characterized Git as recording history according to the victors, whereas Fossil records history as it actually happened. -

        3.8 GPL vs. BSD

        - -Git is covered by the GPL license whereas Fossil is covered by -a two-clause BSD license. - -Consider the difference between GPL and BSD licenses: GPL is designed -to make writing easier at the expense of making reading harder. BSD is -designed to make reading easier and the expense of making writing harder. - -To a first approximation, the GPL license grants the right to read -source code to anyone who promises to give back enhancements. In other -words, the act of reading GPL source code (a prerequiste for making changes) -implies acceptance of the license which requires updates to be contributed -back under the same license. (The details are more complex, but the -foregoing captures the essence of the idea.) A big advantage of the GPL -is that anybody can contribute to the code without having to sign additional -legal documentation because they have implied their acceptance of the GPL -license by the very act of reading the source code. This means that a GPL -project can legally accept anonymous and drive-by patches. - -The BSD licenses, on the other hand, make reading much easier than the GPL, -because the reader need not surrender proprietary interest -in their own enhancements. On the flip side, BSD and similarly licensed -projects must obtain legal affidavits from authors before -new content can be added into the project. Anonymous and drive-by -patches cannot be accepted. This makes signing up new contributors for -BSD licensed projects harder. - -The licenses on the implementations of Git and Fossil only apply to the -implementations themselves, not to the projects which the systems store. -Nevertheless, one can see a more GPL-oriented world-view in Git and a -more BSD-oriented world-view in Fossil. Git encourages anonymous contributions -and siloed development, which are hallmarks of the GPL/bazaar approach to -software, whereas Fossil encourages a more tightly collaborative, -cliquish, cathedral-style approach more typical of BSD-licensed projects. - -

        4.0 Missing Features

        - -Most of the capabilities found in Git are also available in Fossil and -the other way around. For example, both systems have local check-outs, -remote repositories, push/pull/sync, bisect capabilities, and a "stash". -Both systems store project history as a directed acyclic graph (DAG) -of immutable check-in objects. - -But there are a few capabilities in one system that are missing from the -other. - -

        4.1 Features found in Fossil but missing from Git

        - - * The ability to show descendents of a check-in. - - Both Git and Fossil can easily find the ancestors of a check-in. But - only Fossil shows the descendents. (It is possible to find the - descendents of a check-in in Git using the log, but that is sufficiently - difficult that nobody ever actually does it.) - - * Wiki, Embedded documentation, Trouble-tickets, and Tech-Notes - - Git only provides versioning of source code. Fossil strives to provide - other related configuration management services as well. - - * Named branches - - Branches in Fossil have persistent names that are propagated - to collaborators via [/help?cmd=push|push] and [/help?cmd=pull|pull]. - All developers see the same name on the same branch. Git, in contrast, - uses only local branch names, so developers working on the - same project can (and frequently do) use a different name for the - same branch. - - * The [/help?cmd=all|fossil all] command - - Fossil keeps track of all repositories and check-outs and allows - operations over all of them with a single command. For example, in - Fossil is possible to request a pull of all repositories on a laptop - from their respective servers, prior to taking the laptop off network. - Or it is possible to do "fossil all status" to see if there are any - uncommitted changes that were overlooked prior to the end of the workday. - - * The [/help?cmd=ui|fossil ui] command - - Fossil supports an integrated web interface. Some of the same features - are available using third-party add-ons for Git, but they do not provide - nearly as many features and they are not nearly as convenient to use. - - -

        4.2 Features found in Git but missing from Fossil

        - - * Rebase - - Because of its emphasis on recording history exactly as it happened, - rather than as we would have liked it to happen, Fossil deliberately - does not provide a "rebase" command. One can rebase manually in Fossil, - with sufficient perserverence, but it not something that can be done with - a single command. - - * Push or pull a single branch - - The [/help?cmd=push|fossil push], [/help?cmd=pull|fossil pull], and - [/help?cmd=sync|fossil sync] commands do not provide the capability to - push or pull individual branches. Pushing and pulling in Fossil is - all or nothing. This is in keeping with Fossil's emphasis on maintaining - a complete record and on sharing everything between all developers. +We go into more detail on this topic in a separate article, +[./rebaseharm.md | Rebase Considered Harmful]. + + +

        2.8 Test Before Commit

        + +One of the things that falls out of Git's default separation of commit +from push is that there are several Git sub-commands that jump straight +to the commit step before a change could possibly be tested. Fossil, by +contrast, makes the equivalent change to the local working check-out +only, requiring a separate check-in step to commit the change. This +design difference falls naturally out of Fossil's default-enabled +autosync feature. + +The prime example in Git is rebasing: the change happens to the local +repository immediately if successful, even though you haven't tested the +change yet. It's possible to argue for such a design in a tool like Git +which doesn't automatically push the change up to its parent, because +you can still test the change before pushing local changes to the parent +repo, but in the meantime you've made a durable change to your local Git +repository's blockchain. You must do something drastic like git +reset --hard to revert that rebase if it causes a problem. If you +push your rebased local repo up to the parent without testing first, +you've now committed the error on a public branch, effectively a +violation of +[https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing +| the golden rule of rebasing]. + +Lesser examples are the Git merge, cherry-pick, and +revert commands, all of which apply work from one branch onto +another, and all of which do their work immediately without giving you +an opportunity to test the change first locally unless you give the +--no-commit option. + +Fossil cannot sensibly work that way because of its default-enabled +autosync feature. Instead of jumping straight to the commit step, Fossil +applies the proposed merge to the local working directory only, +requiring a separate check-in step before the change is committed to the +repository blockchain. This gives you a chance to test the change first, +either manually or by running your software's automatic tests. (Ideally, +both!) + +Another difference is that because Fossil requires an explicit commit +for a merge, it makes you give an explicit commit message for +each merge, whereas Git writes that commit message itself by default +unless you give the optional --edit flag to override it. + +We don't look at this difference as a workaround in Fossil for autosync, +but instead as a test-first philosophical difference. When every commit +is pushed to the parent repo by default, it encourages a working style +in which every commit is tested first. We think this is an inherently +good thing. + +Incidentally, this is a good example of Git's messy command design. +These three commands: + +
        +    $ git merge HASH 
        +    $ git cherry-pick HASH 
        +    $ git revert HASH
        +
        + +...are all the same command in Fossil: + +
        +    $ fossil merge HASH
        +    $ fossil merge --cherrypick HASH
        +    $ fossil merge --backout HASH
        +
        + +If you think about it, they're all the same function: apply work done on +one branch to another. All that changes between these commands is how +much work gets applied — just one check-in or a whole branch — and the +merge direction. This is the sort of thing we mean when we point out +that Fossil's command interface is simpler than Git's: there are fewer +concepts to keep track of in your mental model of Fossil's internal +operation. + +Fossil's implementation of the feature is also simpler to describe. The +brief online help for [/help?cmd=merge | fossil merge] is +currently 41 lines long, to which you want to add the 600 lines of +[./branching.wiki | the branching document]. The equivalent +documentation in Git is the aggregation of the man pages for the above +three commands, which is over 1000 lines, much of it mutually redundant. +(e.g. Git's --edit and --no-commit options get +described three times, each time differently.) Fossil's +documentation is not only more concise, it gives a nice split of brief +online help and full online documentation. + + +

        2.9 Hash Algorithm: SHA-3 vs SHA-2 vs SHA-1

        + +Fossil started out using 160-bit SHA-1 hashes to identify check-ins, +just as in Git. That changed in early 2017 when news of the +[https://shattered.io/|SHAttered attack] broke, demonstrating that SHA-1 +collisions were now practical to create. Two weeks later, the creator of +Fossil delivered a new release allowing a clean migration to +[https://en.wikipedia.org/wiki/SHA-3|256-bit SHA-3] with +[./hashpolicy.wiki|full backwards compatibility] to old SHA-1 based +repositories. + +In October 2019, after the last of the major binary +package repos offering Fossil upgraded to Fossil 2.x, +we switched the default hash mode so that from +Fossil 2.10 forward, the conversion to SHA-3 is fully automatic. +This not +only solves the SHAttered problem, it should prevent a reoccurrence of +similar problems for the foreseeable future. + +Meanwhile, the Git community took until August 2018 to publish +[https://git-scm.com/docs/hash-function-transition/|their first plan] +for solving the same problem by moving to SHA-256, a variant of the +[https://en.wikipedia.org/wiki/SHA-2 | older SHA-2 algorithm]. As of +this writing in February 2020, that plan hasn't been implemented, as far +as this author is aware, but there is now +[https://lwn.net/ml/git/20200113124729.3684846-1-sandals@crustytoothpaste.net/ +| a competing SHA-256 based plan] which requires complete repository +conversion from SHA-1 to SHA-256, breaking all public hashes in the +repo. One way to characterize such a massive upheaval in Git terms is a +whole-project rebase, which violates +[https://blog.axosoft.com/golden-rule-of-rebasing-in-git/ | Git's own +Golden Rule of Rebasing]. + +Regardless of the eventual implementation details, we fully expect Git +to move off SHA-1 eventually and for the changes to take years more to +percolate through the community. + +Almost three years after Fossil solved this problem, the +[https://sha-mbles.github.io/ | SHAmbles attack] was published, further +weakening the case for continuing to use SHA-1. + +The practical impact of attacks like SHAttered and SHAmbles on the +Git and Fossil blockchains isn't clear, but you want to have your repositories +moved over to a stronger hash algorithm before someone figures out how +to make use of the weaknesses in the old one. Fossil has had this covered +for years now, so that the solution is now almost universally deployed. + +
        + +

        Asides and Digressions

        + +
          +
        1. [./mirrorlimitations.md|Many + things are lost] in making a Git mirror of a Fossil repo due to + limitations of Git relative to Fossil. GitHub adds some of these + missing features to stock + Git, but because they're not part of Git proper, + [./mirrortogithub.md|exporting a Fossil repository to GitHub] will + still not include them; Fossil tickets do not become GitHub issues, + for example. + +

        2. The fossil-scm.org web site is actually hosted in + several parts, so that it is not strictly true that "everything" on + it is in the self-hosting Fossil project repo. The web forum is + hosted as [https://fossil-scm.org/forum/|a separate Fossil repo] + from the [https://fossil-scm.org/fossil/|main Fossil self-hosting + repo] for administration reasons, and the Download page content + isn't normally synchronized with a "fossil clone" command unless + you add the "-u" option. (See "[./aboutdownload.wiki|How the + Download Page Works]" for details.) There may also be some purely + static elements of the web site served via D. Richard Hipp's own + lightweight web server, + [https://sqlite.org/docsrc/doc/trunk/misc/althttpd.md|althttpd], + which is configured as a front end to Fossil running in CGI mode on + these sites. + +

        3. That estimate is based on pricing at Digital Ocean in + mid-2019: Fossil will run just fine on the smallest instance they + offer, at US $5/month, but the closest match to GitLab's minimum + requirements among Digital Ocean's offerings currently costs + $40/month. + +

        4. This means you can give up waiting for Fossil to be ported to + the PDP-11, but we remain hopeful that someone may eventually port + it to [https://en.wikipedia.org/wiki/Z/OS|z/OS]. + +

        5. "Why is there all this Tcl in and around Fossil?" you may + ask. It is because D. Richard Hipp is a long-time Tcl user and + contributor. SQLite started out as an embedded database for Tcl + specifically. ([https://sqlite.org/tclsqlite.html | [Reference]]) + When he then created Fossil to manage the development of SQLite, it + was natural for him to use Tcl-based tools for its scripting, build + system, test system, etc. It came full circle in 2011 when + [https://www.reddit.com/r/programming/comments/fwrx5/tcl_and_tk_move_away_from_cvs_to_fossil/ + | the Tcl and Tk projects moved from CVS to Fossil]. + +

        6. A minority of the pieces of the Git core software suite are + written in other languages, primarily Perl, Python, and Tcl. (e.g. + git-send-mail, git-p4, and gitk, + respectively.) Although these interpreters are quite portable, they + aren't installed by default everywhere, and on some platforms you + can't count on them at all. (Not just Windows, but also the BSDs and + many other non-Linux platforms.) This expands the dependency + footprint of Git considerably. It is why the current Git for Windows + distribution is 44.7 MiB but the current fossil.exe + zip file for Windows is 2.24 MiB. Fossil is much smaller + despite using a roughly similar amount of high-level scripting code + because its interpreters are compact and built into Fossil itself. + +

        7. Both Fossil and Git support + [https://en.wikipedia.org/wiki/Patch_(Unix)|patch(1) + files], a common way to allow drive-by contributions, but it's a + lossy contribution path for both systems. Unlike Git PRs and Fossil + bundles, patch files collapse multiple checkins together, they don't + include check-in comments, and they cannot encode changes made above + the individual file content layer: you lose branching decisions, + tag changes, file renames, and more when using patch files.

        8. +
        Index: www/fossil.eps ================================================================== --- www/fossil.eps +++ www/fossil.eps @@ -1,6 +1,6 @@ -%!PS-Adobe-3.0 EPSF-3.0 +%!PS-Adobe-3.0 EPSF-3.0 %%BoundingBox: 0 0 249 284 %%Pages: 0 %%Creator: Sun Microsystems, Inc. %%Title: none %%CreationDate: none @@ -48,82 +48,82 @@ %%EndSetup %%Page: 1 1 %%BeginPageSetup %%EndPageSetup pum -0.02835 0.02837 s +0.02835 0.02837 s 0 -10008 t /tm matrix currentmatrix def tm setmatrix --4875 -2599 t -1 1 s -0.500 c 7207 8311 m 7036 8281 6990 7727 7105 7073 ct 7221 6420 7453 5915 7625 5945 ct +-4875 -2599 t +1 1 s +0.500 c 7207 8311 m 7036 8281 6990 7727 7105 7073 ct 7221 6420 7453 5915 7625 5945 ct 7796 5975 7842 6529 7727 7183 ct 7612 7836 7379 8342 7207 8311 ct p ef -7607 10301 m 7445 10335 7221 9926 7107 9387 ct 6992 8847 7030 8382 7192 8348 ct +7607 10301 m 7445 10335 7221 9926 7107 9387 ct 6992 8847 7030 8382 7192 8348 ct 7354 8313 7578 8723 7693 9262 ct 7807 9802 7769 10267 7607 10301 ct p ef -8749 11736 m 8626 11826 8289 11574 7995 11173 ct 7701 10773 7563 10375 7686 10285 ct +8749 11736 m 8626 11826 8289 11574 7995 11173 ct 7701 10773 7563 10375 7686 10285 ct 7809 10195 8146 10446 8440 10847 ct 8734 11248 8872 11645 8749 11736 ct p ef -10691 12070 m 10668 12234 10205 12303 9658 12223 ct 9111 12143 8686 11946 8710 11782 ct +10691 12070 m 10668 12234 10205 12303 9658 12223 ct 9111 12143 8686 11946 8710 11782 ct 8734 11618 9197 11550 9744 11629 ct 10291 11709 10715 11906 10691 12070 ct p ef -10761 12053 m 10721 11951 11064 11722 11526 11541 ct 11989 11360 12396 11296 12436 11398 ct -12476 11500 12134 11729 11671 11910 ct 11208 12091 10801 12155 10761 12053 ct +10761 12053 m 10721 11951 11064 11722 11526 11541 ct 11989 11360 12396 11296 12436 11398 ct +12476 11500 12134 11729 11671 11910 ct 11208 12091 10801 12155 10761 12053 ct p ef -12410 11353 m 12365 11314 12499 11087 12709 10847 ct 12920 10607 13126 10444 13171 10483 ct -13216 10522 13082 10749 12872 10989 ct 12662 11230 12455 11392 12410 11353 ct +12410 11353 m 12365 11314 12499 11087 12709 10847 ct 12920 10607 13126 10444 13171 10483 ct +13216 10522 13082 10749 12872 10989 ct 12662 11230 12455 11392 12410 11353 ct p ef -7901 12525 m 7790 12525 7700 12212 7700 11826 ct 7700 11440 7790 11127 7901 11127 ct +7901 12525 m 7790 12525 7700 12212 7700 11826 ct 7700 11440 7790 11127 7901 11127 ct 8012 11127 8102 11440 8102 11826 ct 8102 12212 8012 12525 7901 12525 ct p ef -7826 12575 m 7765 12668 7415 12547 7044 12306 ct 6672 12064 6420 11793 6480 11700 ct +7826 12575 m 7765 12668 7415 12547 7044 12306 ct 6672 12064 6420 11793 6480 11700 ct 6541 11607 6891 11728 7262 11970 ct 7634 12211 7886 12482 7826 12575 ct p ef -6460 11694 m 6435 11723 6333 11673 6234 11584 ct 6134 11494 6073 11399 6099 11371 ct +6460 11694 m 6435 11723 6333 11673 6234 11584 ct 6134 11494 6073 11399 6099 11371 ct 6124 11343 6225 11392 6325 11482 ct 6425 11571 6485 11666 6460 11694 ct p ef -13183 10437 m 13129 10414 13185 10157 13309 9863 ct 13433 9569 13579 9350 13633 9373 ct +13183 10437 m 13129 10414 13185 10157 13309 9863 ct 13433 9569 13579 9350 13633 9373 ct 13688 9396 13632 9653 13508 9947 ct 13384 10241 13238 10460 13183 10437 ct p ef -9900 11524 m 9790 11524 9701 11211 9701 10825 ct 9701 10439 9790 10126 9900 10126 ct -10009 10126 10098 10439 10098 10825 ct 10098 11211 10009 11524 9900 11524 ct +9900 11524 m 9790 11524 9701 11211 9701 10825 ct 9701 10439 9790 10126 9900 10126 ct +10009 10126 10098 10439 10098 10825 ct 10098 11211 10009 11524 9900 11524 ct p ef -9828 11574 m 9767 11667 9417 11546 9046 11305 ct 8674 11063 8422 10792 8482 10699 ct +9828 11574 m 9767 11667 9417 11546 9046 11305 ct 8674 11063 8422 10792 8482 10699 ct 8543 10606 8893 10727 9264 10969 ct 9636 11210 9888 11481 9828 11574 ct p ef -6085 9230 m 5976 9131 6097 8819 6357 8533 ct 6616 8247 6915 8095 7024 8194 ct +6085 9230 m 5976 9131 6097 8819 6357 8533 ct 6616 8247 6915 8095 7024 8194 ct 7133 8293 7012 8605 6752 8892 ct 6493 9178 6194 9329 6085 9230 ct p ef -5910 9182 m 5805 9210 5629 8884 5516 8456 ct 5403 8027 5396 7657 5501 7629 ct +5910 9182 m 5805 9210 5629 8884 5516 8456 ct 5403 8027 5396 7657 5501 7629 ct 5605 7601 5782 7927 5895 8356 ct 6008 8784 6014 9154 5910 9182 ct p ef -8630 9345 m 8548 9270 8691 8978 8951 8692 ct 9210 8406 9487 8234 9569 8309 ct +8630 9345 m 8548 9270 8691 8978 8951 8692 ct 9210 8406 9487 8234 9569 8309 ct 9651 8383 9507 8675 9248 8961 ct 8989 9247 8712 9419 8630 9345 ct p ef -8566 9556 m 8478 9624 8188 9394 7918 9043 ct 7647 8692 7499 8352 7587 8285 ct +8566 9556 m 8478 9624 8188 9394 7918 9043 ct 7647 8692 7499 8352 7587 8285 ct 7675 8217 7965 8447 8235 8798 ct 8506 9149 8654 9489 8566 9556 ct p ef -6579 11626 m 6549 11638 6480 11543 6425 11413 ct 6371 11283 6352 11167 6382 11154 ct +6579 11626 m 6549 11638 6480 11543 6425 11413 ct 6371 11283 6352 11167 6382 11154 ct 6412 11141 6481 11237 6535 11367 ct 6590 11497 6609 11613 6579 11626 ct p ef -5952 11674 m 5959 11642 6081 11642 6223 11674 ct 6366 11707 6475 11759 6468 11791 ct +5952 11674 m 5959 11642 6081 11642 6223 11674 ct 6366 11707 6475 11759 6468 11791 ct 6461 11823 6339 11823 6197 11790 ct 6054 11758 5945 11706 5952 11674 ct p ef -5384 7615 m 5359 7644 5257 7594 5158 7505 ct 5058 7415 4997 7320 5023 7292 ct +5384 7615 m 5359 7644 5257 7594 5158 7505 ct 5058 7415 4997 7320 5023 7292 ct 5048 7264 5149 7313 5249 7403 ct 5349 7492 5409 7587 5384 7615 ct p ef -5503 7547 m 5473 7559 5404 7464 5349 7334 ct 5295 7204 5276 7088 5306 7075 ct +5503 7547 m 5473 7559 5404 7464 5349 7334 ct 5295 7204 5276 7088 5306 7075 ct 5336 7062 5405 7158 5459 7288 ct 5514 7418 5533 7534 5503 7547 ct p ef -4875 7595 m 4882 7562 5004 7563 5147 7595 ct 5289 7628 5399 7680 5392 7712 ct +4875 7595 m 4882 7562 5004 7563 5147 7595 ct 5289 7628 5399 7680 5392 7712 ct 5385 7744 5263 7744 5120 7711 ct 4977 7679 4868 7627 4875 7595 ct p ef -9764 8248 m 9739 8220 9798 8125 9898 8036 ct 9997 7946 10097 7897 10123 7925 ct +9764 8248 m 9739 8220 9798 8125 9898 8036 ct 9997 7946 10097 7897 10123 7925 ct 10148 7952 10088 8047 9989 8137 ct 9890 8226 9789 8276 9764 8248 ct p ef -9641 8179 m 9611 8167 9631 8051 9685 7920 ct 9740 7790 9809 7694 9839 7707 ct +9641 8179 m 9611 8167 9631 8051 9685 7920 ct 9740 7790 9809 7694 9839 7707 ct 9869 7720 9850 7836 9795 7966 ct 9741 8097 9672 8192 9641 8179 ct p ef -10269 8227 m 10276 8259 10167 8311 10024 8343 ct 9882 8375 9760 8375 9753 8343 ct +10269 8227 m 10276 8259 10167 8311 10024 8343 ct 9882 8375 9760 8375 9753 8343 ct 9746 8311 9856 8259 9998 8227 ct 10141 8195 10262 8195 10269 8227 ct p ef -9749 10085 m 9724 10113 9623 10064 9523 9974 ct 9424 9885 9363 9790 9389 9762 ct +9749 10085 m 9724 10113 9623 10064 9523 9974 ct 9424 9885 9363 9790 9389 9762 ct 9414 9734 9515 9783 9615 9872 ct 9714 9961 9775 10057 9749 10085 ct p ef -9868 10017 m 9838 10029 9770 9934 9715 9804 ct 9661 9674 9641 9558 9671 9545 ct +9868 10017 m 9838 10029 9770 9934 9715 9804 ct 9661 9674 9641 9558 9671 9545 ct 9702 9533 9770 9628 9824 9758 ct 9879 9888 9898 10004 9868 10017 ct p ef -9242 10064 m 9249 10032 9371 10032 9513 10064 ct 9656 10097 9765 10149 9758 10181 ct +9242 10064 m 9249 10032 9371 10032 9513 10064 ct 9656 10097 9765 10149 9758 10181 ct 9751 10213 9629 10213 9487 10180 ct 9344 10148 9235 10096 9242 10064 ct p ef -6841 4401 m 6726 4212 7272 3670 8061 3191 ct 8849 2711 9581 2475 9696 2664 ct +6841 4401 m 6726 4212 7272 3670 8061 3191 ct 8849 2711 9581 2475 9696 2664 ct 9811 2853 9265 3395 8477 3875 ct 7688 4355 6956 4590 6841 4401 ct p ef -9097 6042 m 8862 6353 8161 6221 7532 5745 ct 6902 5270 6583 4632 6818 4321 ct +9097 6042 m 8862 6353 8161 6221 7532 5745 ct 6902 5270 6583 4632 6818 4321 ct 7053 4009 7754 4142 8384 4617 ct 9013 5092 9333 5730 9097 6042 ct p ef -7880 5222 m 7747 5124 7957 4611 8349 4075 ct 8742 3540 9168 3185 9302 3283 ct +7880 5222 m 7747 5124 7957 4611 8349 4075 ct 8742 3540 9168 3185 9302 3283 ct 9435 3381 9225 3894 8833 4430 ct 8440 4965 8014 5320 7880 5222 ct p ef -9003 6100 m 8784 6059 8750 5255 8927 4303 ct 9103 3351 9423 2612 9642 2652 ct +9003 6100 m 8784 6059 8750 5255 8927 4303 ct 9103 3351 9423 2612 9642 2652 ct 9861 2693 9895 3498 9719 4450 ct 9543 5401 9222 6140 9003 6100 ct p ef -0 10008 t +0 10008 t pom count op_count sub {pop} repeat countdictstack dict_count sub {end} repeat b4_inc_state restore %%PageTrailer %%Trailer %%EOF Index: www/fossil2.eps ================================================================== --- www/fossil2.eps +++ www/fossil2.eps @@ -1,6 +1,6 @@ -%!PS-Adobe-3.0 EPSF-3.0 +%!PS-Adobe-3.0 EPSF-3.0 %%BoundingBox: 0 0 555 735 %%Pages: 0 %%Creator: Sun Microsystems, Inc. %%Title: none %%CreationDate: none @@ -48,155 +48,155 @@ %%EndSetup %%Page: 1 1 %%BeginPageSetup %%EndPageSetup pum -0.02833 0.02833 s +0.02833 0.02833 s 0 -25940 t /tm matrix currentmatrix def gs tm setmatrix --1000 -1000 t -1 1 s +-1000 -1000 t +1 1 s 1000 1000 m 20589 1000 l 20589 26939 l 1000 26939 l 1000 1000 l eoclip newpath gs 1000 1000 m 20589 1000 l 20589 26939 l 1000 26939 l 1000 1000 l eoclip newpath 1000 1000 m 20590 1000 l 20590 26940 l 1000 26940 l 1000 1000 l eoclip newpath -0.500 c 7207 8311 m 7036 8281 6989 7726 7104 7073 ct 7220 6420 7453 5913 7624 5944 ct +0.500 c 7207 8311 m 7036 8281 6989 7726 7104 7073 ct 7220 6420 7453 5913 7624 5944 ct 7796 5974 7842 6529 7727 7182 ct 7612 7835 7378 8341 7207 8311 ct p ef -7607 10301 m 7446 10335 7220 9925 7106 9386 ct 6991 8847 7030 8381 7191 8347 ct +7607 10301 m 7446 10335 7220 9925 7106 9386 ct 6991 8847 7030 8381 7191 8347 ct 7353 8312 7578 8723 7693 9262 ct 7807 9800 7768 10267 7607 10301 ct p ef -8749 11736 m 8627 11825 8288 11574 7995 11173 ct 7701 10772 7562 10374 7685 10284 ct +8749 11736 m 8627 11825 8288 11574 7995 11173 ct 7701 10772 7562 10374 7685 10284 ct 7808 10194 8146 10446 8440 10847 ct 8734 11247 8872 11646 8749 11736 ct p ef -10683 12127 m 10664 12260 10204 12303 9657 12224 ct 9111 12145 8683 11972 8702 11840 ct +10683 12127 m 10664 12260 10204 12303 9657 12224 ct 9111 12145 8683 11972 8702 11840 ct 8721 11707 9181 11664 9727 11743 ct 10274 11822 10702 11995 10683 12127 ct p ef -10761 12053 m 10721 11951 11064 11721 11526 11540 ct 11989 11359 12397 11296 12437 11397 ct -12477 11499 12134 11729 11671 11910 ct 11209 12091 10801 12154 10761 12053 ct +10761 12053 m 10721 11951 11064 11721 11526 11540 ct 11989 11359 12397 11296 12437 11397 ct +12477 11499 12134 11729 11671 11910 ct 11209 12091 10801 12154 10761 12053 ct p ef -12410 11353 m 12366 11314 12500 11087 12710 10847 ct 12920 10607 13127 10444 13171 10483 ct -13216 10522 13082 10749 12872 10989 ct 12662 11229 12455 11392 12410 11353 ct +12410 11353 m 12366 11314 12500 11087 12710 10847 ct 12920 10607 13127 10444 13171 10483 ct +13216 10522 13082 10749 12872 10989 ct 12662 11229 12455 11392 12410 11353 ct p ef -7901 12525 m 7790 12525 7700 12212 7700 11826 ct 7700 11440 7790 11127 7901 11127 ct +7901 12525 m 7790 12525 7700 12212 7700 11826 ct 7700 11440 7790 11127 7901 11127 ct 8012 11127 8102 11440 8102 11826 ct 8102 12212 8012 12525 7901 12525 ct p ef -7825 12576 m 7765 12669 7414 12548 7043 12306 ct 6671 12065 6419 11793 6479 11700 ct +7825 12576 m 7765 12669 7414 12548 7043 12306 ct 6671 12065 6419 11793 6479 11700 ct 6540 11607 6891 11728 7262 11969 ct 7633 12211 7886 12483 7825 12576 ct p ef -6460 11695 m 6434 11723 6333 11674 6233 11584 ct 6133 11495 6072 11399 6098 11371 ct +6460 11695 m 6434 11723 6333 11674 6233 11584 ct 6133 11495 6072 11399 6098 11371 ct 6123 11342 6225 11392 6325 11481 ct 6425 11571 6485 11666 6460 11695 ct p ef -13184 10437 m 13129 10414 13185 10156 13309 9862 ct 13434 9569 13580 9349 13634 9372 ct +13184 10437 m 13129 10414 13185 10156 13309 9862 ct 13434 9569 13580 9349 13634 9372 ct 13688 9395 13632 9653 13508 9947 ct 13384 10240 13238 10460 13184 10437 ct p ef -9899 11524 m 9790 11524 9700 11211 9700 10825 ct 9700 10439 9790 10126 9899 10126 ct -10008 10126 10098 10439 10098 10825 ct 10098 11211 10008 11524 9899 11524 ct +9899 11524 m 9790 11524 9700 11211 9700 10825 ct 9700 10439 9790 10126 9899 10126 ct +10008 10126 10098 10439 10098 10825 ct 10098 11211 10008 11524 9899 11524 ct p ef -9827 11575 m 9767 11668 9416 11547 9045 11305 ct 8673 11064 8421 10792 8481 10699 ct +9827 11575 m 9767 11668 9416 11547 9045 11305 ct 8673 11064 8421 10792 8481 10699 ct 8542 10606 8893 10727 9264 10968 ct 9635 11210 9888 11482 9827 11575 ct p ef -6085 9230 m 5976 9132 6098 8819 6357 8533 ct 6616 8247 6915 8096 7024 8194 ct +6085 9230 m 5976 9132 6098 8819 6357 8533 ct 6616 8247 6915 8096 7024 8194 ct 7133 8293 7012 8605 6753 8892 ct 6493 9178 6194 9329 6085 9230 ct p ef -5910 9183 m 5806 9210 5629 8885 5516 8456 ct 5403 8028 5396 7658 5501 7630 ct +5910 9183 m 5806 9210 5629 8885 5516 8456 ct 5403 8028 5396 7658 5501 7630 ct 5605 7602 5782 7928 5895 8357 ct 6008 8785 6014 9155 5910 9183 ct p ef -8630 9344 m 8547 9270 8691 8977 8950 8691 ct 9209 8405 9486 8234 9568 8308 ct +8630 9344 m 8547 9270 8691 8977 8950 8691 ct 9209 8405 9486 8234 9568 8308 ct 9650 8383 9507 8675 9248 8961 ct 8989 9247 8712 9419 8630 9344 ct p ef -8566 9557 m 8478 9625 8187 9395 7917 9044 ct 7646 8693 7498 8353 7586 8285 ct +8566 9557 m 8478 9625 8187 9395 7917 9044 ct 7646 8693 7498 8353 7586 8285 ct 7674 8217 7965 8448 8235 8799 ct 8505 9150 8654 9490 8566 9557 ct p ef -6578 11626 m 6548 11638 6479 11543 6424 11413 ct 6370 11283 6351 11166 6381 11153 ct +6578 11626 m 6548 11638 6479 11543 6424 11413 ct 6370 11283 6351 11166 6381 11153 ct 6412 11141 6481 11236 6535 11366 ct 6589 11496 6609 11613 6578 11626 ct p ef -5952 11673 m 5959 11641 6081 11641 6224 11674 ct 6366 11706 6476 11759 6469 11791 ct +5952 11673 m 5959 11641 6081 11641 6224 11674 ct 6366 11706 6476 11759 6469 11791 ct 6462 11823 6340 11823 6197 11791 ct 6055 11758 5945 11706 5952 11673 ct p ef -5384 7616 m 5358 7644 5257 7595 5157 7505 ct 5057 7416 4996 7320 5022 7292 ct +5384 7616 m 5358 7644 5257 7595 5157 7505 ct 5057 7416 4996 7320 5022 7292 ct 5047 7263 5149 7313 5249 7402 ct 5349 7492 5409 7587 5384 7616 ct p ef -5502 7547 m 5472 7559 5403 7464 5348 7334 ct 5294 7204 5275 7087 5305 7074 ct +5502 7547 m 5472 7559 5403 7464 5348 7334 ct 5294 7204 5275 7087 5305 7074 ct 5336 7062 5405 7157 5459 7287 ct 5513 7417 5533 7534 5502 7547 ct p ef -4875 7594 m 4882 7562 5004 7562 5147 7594 ct 5289 7627 5399 7679 5392 7712 ct +4875 7594 m 4882 7562 5004 7562 5147 7594 ct 5289 7627 5399 7679 5392 7712 ct 5385 7744 5263 7744 5120 7711 ct 4978 7679 4868 7626 4875 7594 ct p ef -9763 8248 m 9738 8220 9798 8124 9897 8035 ct 9996 7946 10097 7896 10122 7924 ct +9763 8248 m 9738 8220 9798 8124 9897 8035 ct 9996 7946 10097 7896 10122 7924 ct 10147 7951 10087 8047 9988 8136 ct 9889 8225 9787 8275 9763 8248 ct p ef -9639 8179 m 9608 8166 9628 8050 9682 7920 ct 9737 7790 9806 7694 9836 7707 ct +9639 8179 m 9608 8166 9628 8050 9682 7920 ct 9737 7790 9806 7694 9836 7707 ct 9867 7719 9847 7836 9793 7966 ct 9739 8096 9669 8192 9639 8179 ct p ef -10269 8228 m 10277 8260 10166 8312 10024 8344 ct 9881 8376 9759 8376 9752 8344 ct +10269 8228 m 10277 8260 10166 8312 10024 8344 ct 9881 8376 9759 8376 9752 8344 ct 9745 8311 9855 8259 9998 8227 ct 10140 8195 10262 8196 10269 8228 ct p ef -9749 10085 m 9724 10113 9622 10064 9523 9975 ct 9424 9886 9363 9791 9388 9762 ct +9749 10085 m 9724 10113 9622 10064 9523 9975 ct 9424 9886 9363 9791 9388 9762 ct 9414 9734 9516 9784 9615 9872 ct 9714 9961 9774 10057 9749 10085 ct p ef -9868 10017 m 9839 10029 9770 9933 9715 9803 ct 9661 9673 9642 9557 9671 9544 ct +9868 10017 m 9839 10029 9770 9933 9715 9803 ct 9661 9673 9642 9557 9671 9544 ct 9701 9532 9770 9628 9824 9758 ct 9879 9888 9898 10004 9868 10017 ct p ef -9242 10063 m 9249 10031 9371 10031 9514 10064 ct 9656 10096 9766 10149 9759 10181 ct +9242 10063 m 9249 10031 9371 10031 9514 10064 ct 9656 10096 9766 10149 9759 10181 ct 9752 10213 9630 10213 9487 10181 ct 9345 10148 9235 10096 9242 10063 ct p ef -6841 4401 m 6726 4212 7272 3669 8060 3190 ct 8848 2710 9581 2475 9696 2664 ct +6841 4401 m 6726 4212 7272 3669 8060 3190 ct 8848 2710 9581 2475 9696 2664 ct 9811 2853 9265 3396 8477 3875 ct 7689 4354 6956 4590 6841 4401 ct p ef -9098 6041 m 8863 6352 8161 6220 7532 5745 ct 6903 5271 6583 4632 6818 4321 ct +9098 6041 m 8863 6352 8161 6220 7532 5745 ct 6903 5271 6583 4632 6818 4321 ct 7053 4009 7755 4142 8384 4617 ct 9013 5091 9333 5730 9098 6041 ct p ef -7879 5222 m 7746 5124 7956 4610 8348 4075 ct 8740 3540 9167 3185 9300 3283 ct +7879 5222 m 7746 5124 7956 4610 8348 4075 ct 8740 3540 9167 3185 9300 3283 ct 9433 3380 9224 3895 8832 4430 ct 8440 4964 8012 5319 7879 5222 ct p ef -9004 6100 m 8786 6059 8751 5255 8927 4303 ct 9103 3351 9424 2612 9642 2652 ct +9004 6100 m 8786 6059 8751 5255 8927 4303 ct 9103 3351 9424 2612 9642 2652 ct 9861 2693 9896 3498 9719 4449 ct 9543 5401 9222 6140 9004 6100 ct p ef -106 lw 1 lj 9435 13668 m 9429 13652 l 9421 13637 l 9412 13622 l 9401 13607 l -9390 13593 l 9377 13579 l 9363 13565 l 9347 13552 l 9331 13539 l 9313 13526 l -9295 13515 l 9275 13503 l 9254 13493 l 9233 13482 l 9211 13473 l 9188 13464 l -9164 13456 l 9139 13448 l 9114 13441 l 9088 13435 l 9062 13430 l 9035 13425 l -9008 13422 l 8981 13419 l 8953 13416 l 8925 13415 l 8898 13414 l 8870 13414 l -8842 13415 l 8814 13417 l 8787 13419 l 8759 13422 l 8732 13426 l 8706 13431 l -8680 13437 l 8654 13443 l 8629 13450 l 8605 13458 l 8581 13466 l 8558 13475 l -8536 13485 l 8514 13495 l 8494 13506 l 8475 13517 l 8456 13529 l 8439 13542 l -8423 13555 l 8408 13568 l 8394 13582 l 8381 13596 l 8370 13611 l 8360 13626 l -8351 13641 l 8344 13656 l 8338 13672 l 8333 13687 l 8330 13703 l 8328 13719 l -8327 13735 l 8328 13751 l 8330 13767 l 8334 13783 l 8338 13798 l 8345 13814 l -8352 13829 l 8361 13844 l 8372 13859 l 8383 13874 l 8396 13888 l 8410 13902 l -8425 13915 l 8441 13928 l 8459 13940 l 8477 13952 l 8497 13964 l 8517 13974 l -8539 13985 l 8561 13994 l 8584 14003 l 8608 14011 l 8632 14019 l 8657 14026 l -8683 14032 l 8709 14037 l 8736 14042 l 8763 14046 l 8790 14049 l 8818 14052 l +106 lw 1 lj 9435 13668 m 9429 13652 l 9421 13637 l 9412 13622 l 9401 13607 l +9390 13593 l 9377 13579 l 9363 13565 l 9347 13552 l 9331 13539 l 9313 13526 l +9295 13515 l 9275 13503 l 9254 13493 l 9233 13482 l 9211 13473 l 9188 13464 l +9164 13456 l 9139 13448 l 9114 13441 l 9088 13435 l 9062 13430 l 9035 13425 l +9008 13422 l 8981 13419 l 8953 13416 l 8925 13415 l 8898 13414 l 8870 13414 l +8842 13415 l 8814 13417 l 8787 13419 l 8759 13422 l 8732 13426 l 8706 13431 l +8680 13437 l 8654 13443 l 8629 13450 l 8605 13458 l 8581 13466 l 8558 13475 l +8536 13485 l 8514 13495 l 8494 13506 l 8475 13517 l 8456 13529 l 8439 13542 l +8423 13555 l 8408 13568 l 8394 13582 l 8381 13596 l 8370 13611 l 8360 13626 l +8351 13641 l 8344 13656 l 8338 13672 l 8333 13687 l 8330 13703 l 8328 13719 l +8327 13735 l 8328 13751 l 8330 13767 l 8334 13783 l 8338 13798 l 8345 13814 l +8352 13829 l 8361 13844 l 8372 13859 l 8383 13874 l 8396 13888 l 8410 13902 l +8425 13915 l 8441 13928 l 8459 13940 l 8477 13952 l 8497 13964 l 8517 13974 l +8539 13985 l 8561 13994 l 8584 14003 l 8608 14011 l 8632 14019 l 8657 14026 l +8683 14032 l 8709 14037 l 8736 14042 l 8763 14046 l 8790 14049 l 8818 14052 l 8846 14053 l 8873 14054 l 8901 14054 l 8929 14053 l 8957 14051 l ps -8347 14443 m 8354 14459 l 8362 14474 l 8371 14489 l 8382 14504 l 8394 14518 l -8407 14533 l 8421 14546 l 8436 14560 l 8453 14573 l 8471 14585 l 8490 14597 l -8510 14608 l 8530 14619 l 8552 14629 l 8575 14639 l 8598 14647 l 8622 14656 l -8647 14663 l 8673 14670 l 8699 14676 l 8725 14681 l 8752 14685 l 8779 14689 l -8807 14692 l 8835 14694 l 8863 14695 l 8891 14696 l 8919 14696 l 8947 14695 l -8975 14693 l 9002 14690 l 9030 14687 l 9057 14682 l 9083 14677 l 9109 14672 l -9135 14665 l 9160 14658 l 9184 14650 l 9208 14641 l 9231 14632 l 9253 14622 l -9274 14612 l 9294 14600 l 9313 14589 l 9332 14576 l 9349 14564 l 9364 14550 l -9379 14537 l 9393 14523 l 9405 14508 l 9416 14494 l 9425 14479 l 9434 14463 l -9441 14448 l 9446 14432 l 9451 14416 l 9453 14400 l 9455 14384 l 9455 14368 l -9453 14352 l 9451 14336 l 9446 14320 l 9441 14305 l 9434 14289 l 9426 14274 l -9416 14259 l 9405 14244 l 9393 14230 l 9380 14216 l 9365 14202 l 9349 14189 l -9332 14176 l 9314 14164 l 9295 14152 l 9275 14141 l 9254 14130 l 9232 14120 l -9209 14111 l 9185 14102 l 9161 14094 l 9136 14087 l 9110 14081 l 9084 14075 l +8347 14443 m 8354 14459 l 8362 14474 l 8371 14489 l 8382 14504 l 8394 14518 l +8407 14533 l 8421 14546 l 8436 14560 l 8453 14573 l 8471 14585 l 8490 14597 l +8510 14608 l 8530 14619 l 8552 14629 l 8575 14639 l 8598 14647 l 8622 14656 l +8647 14663 l 8673 14670 l 8699 14676 l 8725 14681 l 8752 14685 l 8779 14689 l +8807 14692 l 8835 14694 l 8863 14695 l 8891 14696 l 8919 14696 l 8947 14695 l +8975 14693 l 9002 14690 l 9030 14687 l 9057 14682 l 9083 14677 l 9109 14672 l +9135 14665 l 9160 14658 l 9184 14650 l 9208 14641 l 9231 14632 l 9253 14622 l +9274 14612 l 9294 14600 l 9313 14589 l 9332 14576 l 9349 14564 l 9364 14550 l +9379 14537 l 9393 14523 l 9405 14508 l 9416 14494 l 9425 14479 l 9434 14463 l +9441 14448 l 9446 14432 l 9451 14416 l 9453 14400 l 9455 14384 l 9455 14368 l +9453 14352 l 9451 14336 l 9446 14320 l 9441 14305 l 9434 14289 l 9426 14274 l +9416 14259 l 9405 14244 l 9393 14230 l 9380 14216 l 9365 14202 l 9349 14189 l +9332 14176 l 9314 14164 l 9295 14152 l 9275 14141 l 9254 14130 l 9232 14120 l +9209 14111 l 9185 14102 l 9161 14094 l 9136 14087 l 9110 14081 l 9084 14075 l 9057 14070 l 9030 14066 l 9003 14062 l 8975 14059 l 8948 14057 l ps -10974 13668 m 10968 13652 l 10960 13637 l 10951 13622 l 10940 13607 l -10929 13593 l 10916 13579 l 10902 13565 l 10886 13552 l 10870 13539 l -10853 13526 l 10834 13515 l 10814 13503 l 10794 13493 l 10772 13482 l -10750 13473 l 10727 13464 l 10703 13456 l 10679 13448 l 10653 13441 l -10628 13435 l 10602 13430 l 10575 13425 l 10548 13422 l 10521 13419 l -10493 13416 l 10465 13415 l 10438 13414 l 10410 13414 l 10382 13415 l -10354 13417 l 10327 13419 l 10300 13422 l 10273 13426 l 10246 13431 l -10220 13437 l 10194 13443 l 10169 13450 l 10145 13458 l 10121 13466 l -10098 13475 l 10076 13485 l 10055 13495 l 10035 13506 l 10015 13517 l -9997 13529 l 9980 13542 l 9964 13555 l 9949 13568 l 9935 13582 l 9922 13596 l -9911 13611 l 9901 13626 l 9892 13641 l 9885 13656 l 9879 13672 l 9874 13687 l -9871 13703 l 9869 13719 l 9868 13735 l 9869 13751 l 9871 13767 l 9875 13783 l -9879 13798 l 9886 13814 l 9893 13829 l 9902 13844 l 9912 13859 l 9924 13874 l -9937 13888 l 9951 13902 l 9966 13915 l 9982 13928 l 10000 13940 l -10018 13952 l 10037 13964 l 10058 13974 l 10079 13985 l 10101 13994 l -10124 14003 l 10148 14011 l 10173 14019 l 10198 14026 l 10223 14032 l -10250 14037 l 10276 14042 l 10303 14046 l 10330 14049 l 10358 14052 l -10386 14053 l 10413 14054 l 10441 14054 l 10469 14053 l 10497 14051 l +10974 13668 m 10968 13652 l 10960 13637 l 10951 13622 l 10940 13607 l +10929 13593 l 10916 13579 l 10902 13565 l 10886 13552 l 10870 13539 l +10853 13526 l 10834 13515 l 10814 13503 l 10794 13493 l 10772 13482 l +10750 13473 l 10727 13464 l 10703 13456 l 10679 13448 l 10653 13441 l +10628 13435 l 10602 13430 l 10575 13425 l 10548 13422 l 10521 13419 l +10493 13416 l 10465 13415 l 10438 13414 l 10410 13414 l 10382 13415 l +10354 13417 l 10327 13419 l 10300 13422 l 10273 13426 l 10246 13431 l +10220 13437 l 10194 13443 l 10169 13450 l 10145 13458 l 10121 13466 l +10098 13475 l 10076 13485 l 10055 13495 l 10035 13506 l 10015 13517 l +9997 13529 l 9980 13542 l 9964 13555 l 9949 13568 l 9935 13582 l 9922 13596 l +9911 13611 l 9901 13626 l 9892 13641 l 9885 13656 l 9879 13672 l 9874 13687 l +9871 13703 l 9869 13719 l 9868 13735 l 9869 13751 l 9871 13767 l 9875 13783 l +9879 13798 l 9886 13814 l 9893 13829 l 9902 13844 l 9912 13859 l 9924 13874 l +9937 13888 l 9951 13902 l 9966 13915 l 9982 13928 l 10000 13940 l +10018 13952 l 10037 13964 l 10058 13974 l 10079 13985 l 10101 13994 l +10124 14003 l 10148 14011 l 10173 14019 l 10198 14026 l 10223 14032 l +10250 14037 l 10276 14042 l 10303 14046 l 10330 14049 l 10358 14052 l +10386 14053 l 10413 14054 l 10441 14054 l 10469 14053 l 10497 14051 l ps -9888 14443 m 9895 14459 l 9903 14474 l 9912 14489 l 9923 14504 l 9934 14518 l -9948 14533 l 9962 14546 l 9977 14560 l 9994 14573 l 10012 14585 l -10031 14597 l 10050 14608 l 10071 14619 l 10093 14629 l 10115 14639 l -10139 14647 l 10163 14656 l 10188 14663 l 10213 14670 l 10239 14676 l -10265 14681 l 10292 14685 l 10320 14689 l 10347 14692 l 10375 14694 l -10403 14695 l 10431 14696 l 10459 14696 l 10487 14695 l 10514 14693 l -10542 14690 l 10569 14687 l 10596 14682 l 10623 14677 l 10649 14672 l -10675 14665 l 10700 14658 l 10724 14650 l 10748 14641 l 10770 14632 l -10792 14622 l 10813 14612 l 10834 14600 l 10853 14589 l 10871 14576 l -10888 14564 l 10904 14550 l 10918 14537 l 10932 14523 l 10944 14508 l -10955 14494 l 10965 14479 l 10973 14463 l 10980 14448 l 10985 14432 l -10990 14416 l 10992 14400 l 10994 14384 l 10994 14368 l 10992 14352 l -10990 14336 l 10986 14320 l 10980 14305 l 10973 14289 l 10965 14274 l -10955 14259 l 10944 14244 l 10932 14230 l 10919 14216 l 10904 14202 l -10888 14189 l 10871 14176 l 10853 14164 l 10834 14152 l 10814 14141 l -10793 14130 l 10771 14120 l 10748 14111 l 10725 14102 l 10700 14094 l -10675 14087 l 10650 14081 l 10624 14075 l 10597 14070 l 10570 14066 l +9888 14443 m 9895 14459 l 9903 14474 l 9912 14489 l 9923 14504 l 9934 14518 l +9948 14533 l 9962 14546 l 9977 14560 l 9994 14573 l 10012 14585 l +10031 14597 l 10050 14608 l 10071 14619 l 10093 14629 l 10115 14639 l +10139 14647 l 10163 14656 l 10188 14663 l 10213 14670 l 10239 14676 l +10265 14681 l 10292 14685 l 10320 14689 l 10347 14692 l 10375 14694 l +10403 14695 l 10431 14696 l 10459 14696 l 10487 14695 l 10514 14693 l +10542 14690 l 10569 14687 l 10596 14682 l 10623 14677 l 10649 14672 l +10675 14665 l 10700 14658 l 10724 14650 l 10748 14641 l 10770 14632 l +10792 14622 l 10813 14612 l 10834 14600 l 10853 14589 l 10871 14576 l +10888 14564 l 10904 14550 l 10918 14537 l 10932 14523 l 10944 14508 l +10955 14494 l 10965 14479 l 10973 14463 l 10980 14448 l 10985 14432 l +10990 14416 l 10992 14400 l 10994 14384 l 10994 14368 l 10992 14352 l +10990 14336 l 10986 14320 l 10980 14305 l 10973 14289 l 10965 14274 l +10955 14259 l 10944 14244 l 10932 14230 l 10919 14216 l 10904 14202 l +10888 14189 l 10871 14176 l 10853 14164 l 10834 14152 l 10814 14141 l +10793 14130 l 10771 14120 l 10748 14111 l 10725 14102 l 10700 14094 l +10675 14087 l 10650 14081 l 10624 14075 l 10597 14070 l 10570 14066 l 10543 14062 l 10515 14059 l 10488 14057 l ps -7205 14684 m 6849 14684 6559 14412 6559 14078 ct 6559 13744 6849 13472 7205 13472 ct +7205 14684 m 6849 14684 6559 14412 6559 14078 ct 6559 13744 6849 13472 7205 13472 ct 7561 13472 7851 13744 7851 14078 ct 7851 14412 7561 14684 7205 14684 ct pc 5427 13589 m 5427 14657 l ps 5374 13560 m 6242 13560 l ps 5374 13914 m 6090 13914 l ps 11776 13397 m 11776 14697 l ps @@ -205,11 +205,11 @@ gr gs 1000 1000 m 20589 1000 l 20589 26939 l 1000 26939 l 1000 1000 l eoclip newpath gr gr -0 25940 t +0 25940 t pom count op_count sub {pop} repeat countdictstack dict_count sub {end} repeat b4_inc_state restore %%PageTrailer %%Trailer %%EOF Index: www/fossil_prompt.sh ================================================================== --- www/fossil_prompt.sh +++ www/fossil_prompt.sh @@ -13,11 +13,12 @@ function get_fossil_data() { fossil_info_project_name="" eval `get_fossil_data2` } function get_fossil_data2() { - fossil info 2> /dev/null | sed 's/"//g'|grep "^[^ ]*:" | while read LINE ; do + fossil info 2> /dev/null |tr '\042\047\140' _|grep "^[^ ]*:" | + while read LINE ; do local field=`echo $LINE | sed 's/:.*$//' | sed 's/-/_/'` local value=`echo $LINE | sed 's/^[^ ]*: *//'` echo fossil_info_${field}=\"${value}\" done } Index: www/fossil_prompt.wiki ================================================================== --- www/fossil_prompt.wiki +++ www/fossil_prompt.wiki @@ -3,11 +3,11 @@ Dan Kennedy has contributed a [./fossil_prompt.sh?mimetype=text/plain | bash script] that manipulates the bash prompt to show the status of the Fossil repository that the user is currently visiting. -The prompt shows the branch, version, and timestamp for the +The prompt shows the branch, version, and time stamp for the current checkout, and the prompt changes colors from blue to red when there are uncommitted changes. To try out this script, simply download it from the link above, then type: ADDED www/gitusers.md Index: www/gitusers.md ================================================================== --- /dev/null +++ www/gitusers.md @@ -0,0 +1,189 @@ +# Hints For Users With Prior Git Experience + +This document is a semi-random collection of hints intended to help +new users of Fossil who have had prior exposure to Git. In other words, +this document tries to describe the differences in how Fossil works +from the perspective of Git users. + +## Help Improve This Document + +If you have a lot of prior Git experience, and you are new to Fossil +and are struggling with some concepts, please ask for help on the +[Fossil Forum][1]. The people who write this document are intimately +familiar with Fossil and less familiar with Git. It is difficult for +us to anticipate the perspective of people who are initimately familiar +with Git and less familiar with Fossil. Asking questions on the Forum +will help us to improve the document. + +[1]: https://fossil-scm.org/forum + +Specific suggestions on how to improve this document are also welcomed, +of course. + +## Repositories And Checkouts Are Distinct + +A repository and a check-out are distinct concepts in Fossil, whereas +the two are often conflated with Git. A repository is a database in +which the entire history of a project is stored. A check-out is a +directory hierarchy that contains a snapshot of your project that you +are currently working on. See [detailed definitions][2] for more +information. With Git, the repository and check-out are closely +related - the repository is the contents of the "`.git`" subdirectory +at the root of your check-out. But with Fossil, the repository and +the check-out are completely separate. A Fossil repository can reside +in the same directory hierarchy with the check-out as with Git, but it +is more common to put the repository in a separate directory. + +[2]: ./whyusefossil.wiki#definitions + +Fossil repositories are a single file, rather than being a directory +hierarchy as with the "`.git`" folder in Git. The repository file +can be named anything you want, but it is best to use the "`.fossil`" +suffix. Many people choose to gather all of their Fossil repositories +in a single directory on their machine, such as "`~/Fossils`" or +"`C:\Fossils`". This can help humans to keep their repositories +organized, but Fossil itself doesn't really care. + +Because Fossil cleanly separates the repository from the check-out, it +is routine to have multiple check-outs from the same repository. Each +check-out can be on a separate branch, or on the same branch. Each +check-out operates independently of the others. + +Each Fossil check-out contains a file (usually named "`.fslckout`" on +unix or "`_FOSSIL_`" on Windows) that keeps track of the status of that +particular check-out and keeps a pointer to the repository. If you +move or rename the repository file, the check-outs won't be able to find +it and will complain. But you can freely move check-outs around without +causing any problems. + +## There Is No Staging Area + +Fossil omits the "Git index" or "staging area" concept. When you +type "`fossil commit`" _all_ changes in your check-out are committed, +automatically. There is no need for the "-a" option as with Git. + +If you only want to commit just some of the changes, you can list the names +of the files you want to commit as arguments, like this: + + fossil commit src/main.c doc/readme.md + +## Create Branches After-The-Fact + +Fossil perfers that you create new branches when you commit using +the "`--branch` _BRANCH-NAME_" command-line option. For example: + + fossil commit --branch my-new-branch + +It is not necessary to create branches ahead of time, as in Git, though +that is allowed using the "`fossil branch new`" command, if you +prefer. Fossil also allows you to move a check-in to a different branch +*after* you commit it, using the "`fossil amend`" command. +For example: + + fossil amend current --branch my-new-branch + +## Autosync + +Fossil has a feature called "[autosync][5]". Autosync defaults on. +When autosync is enabled, Fossil automatically pushes your changes +to the remote server whenever you "`fossil commit`". It also automatically +pulls all remote changes down to your local repository before you +"`fossil update`". + +[5]: ./concepts.wiki#workflow + +Autosync provides most of the advantages of a centralized version +control system while retaining the advantages of distributed version +control. Your work stays synced up with your coworkers at all times. +If your local machine dies catastrophically, you haven't lost any +(committed) work. But you can still work and commit while off network, +with changes resyncing automatically when you get back on-line. + +## Syncing Is All-Or-Nothing + +Fossil does not support the concept of syncing, pushing, or pulling +individual branches. When you sync/push/pull in Fossil, you sync/push/pull +everything - all branches, all wiki, all tickets, all forum posts, +all tags, all technotes - everything. + +## The Main Branch Is Called "`trunk`", not "`master`" + +In Fossil, the traditional name and the default name for the main branch +is "`trunk`". The "`trunk`" branch in Fossil corresponds to the +"`master`" branch in Git. + +These naming conventions are so embedded in each system, that the +"trunk" branch name is automatically translated to "master" when +a [Fossil repo is mirrored to GitHub][6]. + +[6]: ./mirrortogithub.md + +## The "`fossil status`" Command Does Not Show Unmanaged Files + +The "`fossil status`" command shows you what files in your check-out have +been edited and scheduled for adding or removing at the next commit. +But unlike "`git status`", the "`fossil status`" command does not warn +you about unmanaged files in your local check-out. There is a separate +"`fossil extras`" command for that. + +## There Is No Rebase + +Fossil does not support rebase. +This is a [deliberate design decision][3] that has been thoroughly, +carefully, and throughtfully discussed, many times. If you are fond +of rebase, you should read the [Rebase Considered Harmful][3] document +carefully before expressing your views. + +[3]: ./rebaseharm.md + +## Branch and Tag Names + +Fossil has no special restrictions on the names of tags and branches, +though you might want to to keep [Git's tag and branch name restrictions][4] +in mind if you plan on mirroring your Fossil repository to GitHub. + +[4]: https://git-scm.com/docs/git-check-ref-format + +Fossil does not require tag and branch names to be unique. It is +common, for example, to put a "`release`" tag on every release for a +Fossil-hosted project. + +## Only One "origin" At A Time + +A Fossil repository only keeps track of one "origin" server at a time. +If you specify a new "origin" it forgets the previous one. Use the +"`fossil remote`" command to see or change the "origin". + +Fossil uses a very different sync protocol than Git, so it isn't as +important for Fossil to keep track of multiple origins as it is with +Git. So only having a single origin has never been a big enough problem +in Fossil that somebody felt the need to extend it. + +Maybe we will add multiple origin support to Fossil someday. Patches +are welcomed if you want to have a go at it. + +## Cherry-pick Is An Option To The "merge" Command + +In Git, "`git cherry-pick`" is a separate command. +In Fossil, "`fossil merge --cherrypick`" is an option on the merge +command. Otherwise, they work mostly the same. + +Except, the Fossil file format remembers cherrypicks and actually +shows them as dashed lines on the graphical DAG display, whereas +there is no provision for recording cherry-picks in the Git file +format, so you have to talk about the cherry-pick in the commit +comment if you want to remember it. + +## The "`fossil mv`" and "`fossil rm`" Commands Do Not Actually Rename Or Delete The Files (by default) + +By default, +the "`fossil mv`" and "`fossil rm`" commands work like they do in CVS in +that they schedule the changes for the next commit, but do not actually +rename or delete the files in your check-out. You can to add the "--hard" +option to also changes the files in your check-out. +If you run + + fossil setting --global mv-rm-files 1 + +it makes a notation in your per-user "~/.fossil" settings file so that +the "--hard" behavior becomes the new default. ADDED www/globs.md Index: www/globs.md ================================================================== --- /dev/null +++ www/globs.md @@ -0,0 +1,596 @@ +# File Name Glob Patterns + + +A [glob pattern][glob] is a text expression that matches one or more +file names using wild cards familiar to most users of a command line. +For example, `*` is a glob that matches any name at all and +`Readme.txt` is a glob that matches exactly one file. + +A glob should not be confused with a [regular expression][regexp] (RE), +even though they use some of the same special characters for similar +purposes, because [they are not fully compatible][greinc] pattern +matching languages. Fossil uses globs when matching file names with the +settings described in this document, not REs. + +[glob]: https://en.wikipedia.org/wiki/Glob_(programming) +[greinc]: https://unix.stackexchange.com/a/57958/138 +[regexp]: https://en.wikipedia.org/wiki/Regular_expression + +These settings hold one or more file glob patterns to cause Fossil to +give matching named files special treatment. Glob patterns are also +accepted in options to certain commands and as query parameters to +certain Fossil UI web pages. + +Where Fossil also accepts globs in commands, this handling may interact +with your OS’s command shell or its C runtime system, because they may +have their own glob pattern handling. We will detail such interactions +below. + + +## Syntax + +Where Fossil accepts glob patterns, it will usually accept a *list* of +such patterns, each individual pattern separated from the others +by white space or commas. If a glob must contain white spaces or +commas, it can be quoted with either single or double quotation marks. +A list is said to match if any one glob in the list +matches. + +A glob pattern matches a given file name if it successfully consumes and +matches the *entire* name. Partial matches are failed matches. + +Most characters in a glob pattern consume a single character of the file +name and must match it exactly. For instance, “a” in a glob simply +matches the letter “a” in the file name unless it is inside a special +character sequence. + +Other characters have special meaning, and they may include otherwise +normal characters to give them special meaning: + +:Pattern |:Effect +--------------------------------------------------------------------- +`*` | Matches any sequence of zero or more characters +`?` | Matches exactly one character +`[...]` | Matches one character from the enclosed list of characters +`[^...]` | Matches one character *not* in the enclosed list + +Note that unlike [POSIX globs][pg], these special characters and +sequences are allowed to match `/` directory separators as well as the +initial `.` in the name of a hidden file or directory. This is because +Fossil file names are stored as complete path names. The distinction +between file name and directory name is “below” Fossil in this sense. + +[pg]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13 + +The bracket expresssions above require some additional explanation: + + * A range of characters may be specified with `-`, so `[a-f]` matches + exactly the same characters as `[abcdef]`. Ranges reflect Unicode + code points without any locale-specific collation sequence. + Therefore, this particular sequence never matches the Unicode + pre-composed character `é`, for example. (U+00E9) + + * This dependence on character/code point ordering may have other + effects to surprise you. For example, the glob `[A-z]` not only + matches upper and lowercase ASCII letters, it also matches several + punctuation characters placed between `Z` and `a` in both ASCII and + Unicode: `[`, `\`, `]`, `^`, `_`, and \`. + + * You may include a literal `-` in a list by placing it last, just + before the `]`. + + * You may include a literal `]` in a list by making the first + character after the `[` or `[^`. At any other place, `]` ends the list. + + * You may include a literal `^` in a list by placing it anywhere + except after the opening `[`. + + * Beware that a range must be specified from low value to high + value: `[z-a]` does not match any character at all, preventing the + entire glob from matching. + +Some examples of character lists: + +:Pattern |:Effect +--------------------------------------------------------------------- +`[a-d]` | Matches any one of `a`, `b`, `c`, or `d` but not `ä` +`[^a-d]` | Matches exactly one character other than `a`, `b`, `c`, or `d` +`[0-9a-fA-F]` | Matches exactly one hexadecimal digit +`[a-]` | Matches either `a` or `-` +`[][]` | Matches either `]` or `[` +`[^]]` | Matches exactly one character other than `]` +`[]^]` | Matches either `]` or `^` +`[^-]` | Matches exactly one character other than `-` + +White space means the specific ASCII characters TAB, LF, VT, FF, CR, +and SPACE. Note that this does not include any of the many additional +spacing characters available in Unicode such as +U+00A0, NO-BREAK SPACE. + +Because both LF and CR are white space and leading and trailing spaces +are stripped from each glob in a list, a list of globs may be broken +into lines between globs when the list is stored in a file, as for a +versioned setting. + +Note that 'single quotes' and "double quotes" are the ASCII straight +quote characters, not any of the other quotation marks provided in +Unicode and specifically not the "curly" quotes preferred by +typesetters and word processors. + + +## File Names to Match + +Before it is compared to a glob pattern, each file name is transformed +to a canonical form: + + * all directory separators are changed to `/` + * redundant slashes are removed + * all `.` path components are removed + * all `..` path components are resolved + +(There are additional details we are ignoring here, but they cover rare +edge cases and follow the principle of least surprise.) + +The glob must match the *entire* canonical file name to be considered a +match. + +The goal is to have a name that is the simplest possible for each +particular file, and that will be the same regardless of the platform +you run Fossil on. This is important when you have a repository cloned +from multiple platforms and have globs in versioned settings: you want +those settings to be interpreted the same way everywhere. + +Beware, however, that all glob matching in Fossil is case sensitive +regardless of host platform and file system. This will not be a surprise +on POSIX platforms where file names are usually treated case +sensitively. However, most Windows file systems are case preserving but +case insensitive. That is, on Windows, the names `ReadMe` and `README` +are usually names of the same file. The same is true in other cases, +such as by default on macOS file systems and in the file system drivers +for Windows file systems running on non-Windows systems. (e.g. exfat on +Linux.) Therefore, write your Fossil glob patterns to match the name of +the file as checked into the repository. + +Some example cases: + +:Pattern |:Effect +-------------------------------------------------------------------------------- +`README` | Matches only a file named `README` in the root of the tree. It does not match a file named `src/README` because it does not include any characters that consume (and match) the `src/` part. +`*/README` | Matches `src/README`. Unlike Unix file globs, it also matches `src/library/README`. However it does not match the file `README` in the root of the tree. +`*README` | Matches `src/README` as well as the file `README` in the root of the tree as well as `foo/bar/README` or any other file named `README` in the tree. However, it also matches `A-DIFFERENT-README` and `src/DO-NOT-README`, or any other file whose name ends with `README`. +`src/README` | Matches `src\README` on Windows because all directory separators are rewritten as `/` in the canonical name before the glob is matched. This makes it much easier to write globs that work on both Unix and Windows. +`*.[ch]` | Matches every C source or header file in the tree at the root or at any depth. Again, this is (deliberately) different from Unix file globs and Windows wild cards. + +## Where Globs are Used + +### Settings that are Globs + +These settings are all lists of glob patterns: + +:Setting |:Description +-------------------------------------------------------------------------------- +`binary-glob` | Files that should be treated as binary files for committing and merging purposes +`clean-glob` | Files that the [`clean`][] command will delete without prompting or allowing undo +`crlf-glob` | Files in which it is okay to have `CR`, `CR`+`LF` or mixed line endings. Set to "`*`" to disable CR+LF checking +`crnl-glob` | Alias for the `crlf-glob` setting +`encoding-glob` | Files that the [`commit`][] command will ignore when issuing warnings about text files that may use another encoding than ASCII or UTF-8. Set to "`*`" to disable encoding checking +`ignore-glob` | Files that the [`add`][], [`addremove`][], [`clean`][], and [`extras`][] commands will ignore +`keep-glob` | Files that the [`clean`][] command will keep + +All may be [versioned, local, or global](settings.wiki). Use `fossil +settings` to manage local and global settings, or a file in the +repository's `.fossil-settings/` folder at the root of the tree named +for each for versioned setting. + +Using versioned settings for these not only has the advantage that +they are tracked in the repository just like the rest of your project, +but you can more easily keep longer lists of more complicated glob +patterns than would be practical in either local or global settings. + +The `ignore-glob` is an example of one setting that frequently grows +to be an elaborate list of files that should be ignored by most +commands. This is especially true when one (or more) IDEs are used in +a project because each IDE has its own ideas of how and where to cache +information that speeds up its browsing and building tasks but which +need not be preserved in your project's history. + + +### Commands that Refer to Globs + +Many of the commands that respect the settings containing globs have +options to override some or all of the settings. These options are +usually named to correspond to the setting they override, such as +`--ignore` to override the `ignore-glob` setting. These commands are: + + * [`add`][] + * [`addremove`][] + * [`changes`][] + * [`clean`][] + * [`commit`][] + * [`extras`][] + * [`merge`][] + * [`settings`][] + * [`status`][] + * [`touch`][] + * [`unset`][] + +The commands [`tarball`][] and [`zip`][] produce compressed archives of a +specific checkin. They may be further restricted by options that +specify glob patterns that name files to include or exclude rather +than archiving the entire checkin. + +The commands [`http`][], [`cgi`][], [`server`][], and [`ui`][] that +implement or support with web servers provide a mechanism to name some +files to serve with static content where a list of glob patterns +specifies what content may be served. + +[`add`]: /help?cmd=add +[`addremove`]: /help?cmd=addremove +[`changes`]: /help?cmd=changes +[`clean`]: /help?cmd=clean +[`commit`]: /help?cmd=commit +[`extras`]: /help?cmd=extras +[`merge`]: /help?cmd=merge +[`settings`]: /help?cmd=settings +[`status`]: /help?cmd=status +[`touch`]: /help?cmd=touch +[`unset`]: /help?cmd=unset + +[`tarball`]: /help?cmd=tarball +[`zip`]: /help?cmd=zip + +[`http`]: /help?cmd=http +[`cgi`]: /help?cmd=cgi +[`server`]: /help?cmd=server +[`ui`]: /help?cmd=ui + + +### Web Pages that Refer to Globs + +The [`/timeline`][] page supports the query parameter `chng=GLOBLIST` that +names a list of glob patterns defining which files to focus the +timeline on. It also has the query parameters `t=TAG` and `r=TAG` that +names a tag to focus on, which can be configured with `ms=STYLE` to +use a glob pattern to match tag names instead of the default exact +match or a couple of other comparison styles. + +The pages [`/tarball`][] and [`/zip`][] generate compressed archives +of a specific checkin. They may be further restricted by query +parameters that specify glob patterns that name files to include or +exclude rather than taking the entire checkin. + +[`/timeline`]: /help?cmd=/timeline +[`/tarball`]: /help?cmd=/tarball +[`/zip`]: /help?cmd=/zip + + +## Platform Quirks + +Fossil glob patterns are based on the glob pattern feature of POSIX +shells. Fossil glob patterns also have a quoting mechanism, discussed +above. Because other parts of your operating system may interpret glob +patterns and quotes separately from Fossil, it is often difficult to +give glob patterns correctly to Fossil on the command line. Quotes and +special characters in glob patterns are likely to be interpreted when +given as part of a `fossil` command, causing unexpected behavior. + +These problems do not affect [versioned settings files](settings.wiki) +or Admin → Settings in Fossil UI. Consequently, it is better to +set long-term `*-glob` settings via these methods than to use `fossil +settings` commands. + +That advice does not help you when you are giving one-off glob patterns +in `fossil` commands. The remainder of this section gives remedies and +workarounds for these problems. + + +### POSIX Systems + +If you are using Fossil on a system with a POSIX-compatible shell +— Linux, macOS, the BSDs, Unix, Cygwin, WSL etc. — the shell +may expand the glob patterns before passing the result to the `fossil` +executable. + +Sometimes this is exactly what you want. Consider this command for +example: + + $ fossil add RE* + +If you give that command in a directory containing `README.txt` and +`RELEASE-NOTES.txt`, the shell will expand the command to: + + $ fossil add README.txt RELEASE-NOTES.txt + +…which is compatible with the `fossil add` command's argument list, +which allows multiple files. + +Now consider what happens instead if you say: + + $ fossil add --ignore RE* src/*.c + +This *does not* do what you want because the shell will expand both `RE*` +and `src/*.c`, causing one of the two files matching the `RE*` glob +pattern to be ignored and the other to be added to the repository. You +need to say this in that case: + + $ fossil add --ignore 'RE*' src/*.c + +The single quotes force a POSIX shell to pass the `RE*` glob pattern +through to Fossil untouched, which will do its own glob pattern +matching. There are other methods of quoting a glob pattern or escaping +its special characters; see your shell's manual. + +Beware that Fossil's `--ignore` option does not override explicit file +mentions: + + $ fossil add --ignore 'REALLY SECRET STUFF.txt' RE* + +You might think that would add everything beginning with `RE` *except* +for `REALLY SECRET STUFF.txt`, but when a file is both given +explicitly to Fossil and also matches an ignore rule, Fossil asks what +you want to do with it in the default case; and it does not even ask +if you gave the `-f` or `--force` option along with `--ignore`. + +The spaces in the ignored file name above bring us to another point: +such file names must be quoted in Fossil glob patterns, lest Fossil +interpret it as multiple glob patterns, but the shell interprets +quotation marks itself. + +One way to fix both this and the previous problem is: + + $ fossil add --ignore "'REALLY SECRET STUFF.txt'" READ* + +The nested quotation marks cause the inner set to be passed through to +Fossil, and the more specific glob pattern at the end — that is, +`READ*` vs `RE*` — avoids a conflict between explicitly-listed +files and `--ignore` rules in the `fossil add` command. + +Another solution would be to use shell escaping instead of nested +quoting: + + $ fossil add --ignore "\"REALLY SECRET STUFF.txt\"" READ* + +It bears repeating that the two glob patterns here are not interpreted +the same way when running this command from a *subdirectory* of the top +checkout directory as when running it at the top of the checkout tree. +If these files were in a subdirectory of the checkout tree called `doc` +and that was your current working directory, the command would have to +be: + + $ fossil add --ignore "'doc/REALLY SECRET STUFF.txt'" READ* + +instead. The Fossil glob pattern still needs the `doc/` prefix because +Fossil always interprets glob patterns from the base of the checkout +directory, not from the current working directory as POSIX shells do. + +When in doubt, use `fossil status` after running commands like the +above to make sure the right set of files were scheduled for insertion +into the repository before checking the changes in. You never want to +accidentally check something like a password, an API key, or the +private half of a public cryptographic key into Fossil repository that +can be read by people who should not have such secrets. + + +### Windows + +Before we get into Windows-specific details here, beware that this +section does not apply to the several Microsoft Windows extensions that +provide POSIX semantics to Windows, for which you want to use the advice +in [the POSIX section above](#posix) instead: + + * the ancient and rarely-used [Microsoft POSIX subsystem][mps]; + * its now-discontinued replacement feature, [Services for Unix][sfu]; or + * their modern replacement, the [Windows Subsystem for Linux][wsl] + +[mps]: https://en.wikipedia.org/wiki/Microsoft_POSIX_subsystem +[sfu]: https://en.wikipedia.org/wiki/Windows_Services_for_UNIX +[wsl]: https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux + +(The latter is sometimes incorrectly called "Bash on Windows" or "Ubuntu +on Windows," but the feature provides much more than just Bash or Ubuntu +for Windows.) + +Neither standard Windows command shell — `cmd.exe` or PowerShell +— expands glob patterns the way POSIX shells do. Windows command +shells rely on the command itself to do the glob pattern expansion. The +way this works depends on several factors: + + * the version of Windows you are using + * which OS upgrades have been applied to it + * the compiler that built your Fossil executable + * whether you are running the command interactively + * whether the command is built against a runtime system that does this + at all + * whether the Fossil command is being run from a file named `*.BAT` vs + being named `*.CMD` + +Usually (but not always!) the C runtime library that your `fossil.exe` +executable is built against does this glob expansion on Windows so the +program proper does not have to. This may then interact with the way the +Windows command shell you’re using handles argument quoting. Because of +these differences, it is common to find perfectly valid Fossil command +examples that were written and tested on a POSIX system which then fail +when tried on Windows. + +The most common problem is figuring out how to get a glob pattern passed +on the command line into `fossil.exe` without it being expanded by the C +runtime library that your particular Fossil executable is linked to, +which tries to act like [the POSIX systems described above](#posix). Windows is +not strongly governed by POSIX, so it has not historically hewed closely +to its strictures. + +For example, consider how you would set `crlf-glob` to `*` in order to +get normal Windows text files with CR+LF line endings past Fossil's +"looks like a binary file" check. The naïve approach will not work: + + C:\...> fossil setting crlf-glob * + +The C runtime library will expand that to the list of all files in the +current directory, which will probably cause a Fossil error because +Fossil expects either nothing or option flags after the setting's new +value, not a list of file names. (To be fair, the same thing will happen +on POSIX systems, only at the shell level, before `.../bin/fossil` even +gets run by the shell.) + +Let's try again: + + C:\...> fossil setting crlf-glob '*' + +Quoting the argument like that will work reliably on POSIX, but it may +or may not work on Windows. If your Windows command shell interprets the +quotes, it means `fossil.exe` will see only the bare `*` so the C +runtime library it is linked to will likely expand the list of files in +the current directory before the `setting` command gets a chance to +parse the command line arguments, causing the same failure as above. +This alternative only works if you’re using a Windows command shell that +passes the quotes through to the executable *and* you have linked Fossil +to a C runtime library that interprets the quotes properly itself, +resulting in a bare `*` getting clear down to Fossil’s `setting` command +parser. + +An approach that *will* work reliably is: + + C:\...> echo * | fossil setting crlf-glob --args - + +This works because the built-in Windows command `echo` does not expand its +arguments, and the `--args -` option makes Fossil read further command +arguments from its standard input, which is connected to the output +of `echo` by the pipe. (`-` is a common Unix convention meaning +"standard input," which Fossil obeys.) A [batch script][fng.cmd] to automate this trick was +posted on the now-inactive Fossil Mailing List. + +[fng.cmd]: https://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg25099.html + +(Ironically, this method will *not* work on POSIX systems because it is +not up to the command to expand globs. The shell will expand the `*` in +the `echo` command, so the list of file names will be passed to the +`fossil` standard input, just as with the first example above!) + +Another (usually) correct approach which will work on both Windows and +POSIX systems: + + C:\...> fossil setting crlf-glob *, + +This works because the trailing comma prevents the glob pattern from +matching any files, unless you happen to have files named with a +trailing comma in the current directory. If the pattern matches no +files, it is passed into Fossil's `main()` function as-is by the C +runtime system. Since Fossil uses commas to separate multiple glob +patterns, this means "all files from the root of the Fossil checkout +directory downward and nothing else," which is of course equivalent to +"all managed files in this repository," our original goal. + + +## Experimenting + +To preview the effects of command line glob pattern expansion for +various glob patterns (unquoted, quoted, comma-terminated), for any +combination of command shell, OS, C run time, and Fossil version, +preceed the command you want to test with [`test-echo`][] like so: + + $ fossil test-echo setting crlf-glob "*" + C:\> echo * | fossil test-echo setting crlf-glob --args - + +The [`test-glob`][] command is also handy to test if a string +matches a glob pattern. + +[`test-echo`]: /help?cmd=test-echo +[`test-glob`]: /help?cmd=test-glob + + +## Converting `.gitignore` to `ignore-glob` + +Many other version control systems handle the specific case of +ignoring certain files differently from Fossil: they have you create +individual "ignore" files in each folder, which specify things ignored +in that folder and below. Usually some form of glob patterns are used +in those files, but the details differ from Fossil. + +In many simple cases, you can just store a top level "ignore" file in +`.fossil-settings/ignore-glob`. But as usual, there will be lots of +edge cases. + +[Git has a rich collection of ignore files][gitignore] which +accumulate rules that affect the current command. There are global +files, per-user files, per workspace unmanaged files, and fully +version controlled files. Some of the files used have no set name, but +are called out in configuration files. + +[gitignore]: https://git-scm.com/docs/gitignore + +In contrast, Fossil has a global setting and a local setting, but the local setting +overrides the global rather than extending it. Similarly, a Fossil +command's `--ignore` option replaces the `ignore-glob` setting rather +than extending it. + +With that in mind, translating a `.gitignore` file into +`.fossil-settings/ignore-glob` may be possible in many cases. Here are +some of features of `.gitignore` and comments on how they relate to +Fossil: + + * "A blank line matches no files...": same in Fossil. + * "A line starting with # serves as a comment....": not in Fossil. + * "Trailing spaces are ignored unless they are quoted..." is similar + in Fossil. All whitespace before and after a glob is trimmed in + Fossil unless quoted with single or double quotes. Git uses + backslash quoting instead, which Fossil does not. + * "An optional prefix "!" which negates the pattern...": not in + Fossil. + * Git's globs are relative to the location of the `.gitignore` file: + Fossil's globs are relative to the root of the workspace. + * Git's globs and Fossil's globs treat directory separators + differently. Git includes a notation for zero or more directories + that is not needed in Fossil. + +### Example + +In a project with source and documentation: + + work + +-- doc + +-- src + +The file `doc/.gitignore` might contain: + + # Finished documents by pandoc via LaTeX + *.pdf + # Intermediate files + *.tex + *.toc + *.log + *.out + *.tmp + +Entries in `.fossil-settings/ignore-glob` with similar effect, also +limited to the `doc` folder: + + doc/*.pdf + doc/*.tex, doc/*.toc, doc/*.log, doc/*.out, doc/*.tmp + + + + + +## Implementation and References + +The implementation of the Fossil-specific glob pattern handling is here: + +:File |:Description +-------------------------------------------------------------------------------- +[`src/glob.c`][] | pattern list loading, parsing, and generic matching code +[`src/file.c`][] | application of glob patterns to file names + +[`src/glob.c`]: https://www.fossil-scm.org/index.html/file/src/glob.c +[`src/file.c`]: https://www.fossil-scm.org/index.html/file/src/file.c + +See the [Adding Features to Fossil][aff] document for broader details +about finding and working with such code. + +The actual pattern matching leverages the `GLOB` operator in SQLite, so +you may find [its documentation][gdoc], [source code][gsrc] and [test +harness][gtst] helpful. + +[aff]: ./adding_code.wiki +[gdoc]: https://sqlite.org/lang_expr.html#like +[gsrc]: https://www.sqlite.org/src/artifact?name=9d52522cc8ae7f5c&ln=570-768 +[gtst]: https://www.sqlite.org/src/artifact?name=66a2c9ac34f74f03&ln=586-673 ADDED www/grep.md Index: www/grep.md ================================================================== --- /dev/null +++ www/grep.md @@ -0,0 +1,146 @@ +# Fossil grep vs POSIX grep + +As of Fossil 2.7, there is a `grep` command which acts roughly like +POSIX's `grep -E` over all historical versions of a single file name. +This document explains the commonalities and divergences between [POSIX +`grep`](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html) +and Fossil `grep`. + + +## Options + +Fossil `grep` supports only a small subset of the options specified for +POSIX `grep`: + +| Option | Meaning +|--------|------------------------------------------------------------- +| `-i` | ignore case in matches +| `-l` | list a checkin ID prefix for matching historical versions of the file +| `-v` | print each checkin ID considered, regardless of whether it matches + +That leaves many divergences at the option level from POSIX `grep`: + +* There is no built-in way to get a count of matches, as with `grep + -c`. + +* You cannot give more than one pattern, as with `grep -e` or `grep + -f`. + +* There is no equivalent of `grep -F` to do literal fixed-string + matches only. + +* `fossil grep -l` does not do precisely the same thing as POSIX + `grep -l`: it lists checkin ID prefixes, not file names. + +* Fossil always gives the line number in its output, which is to say + that it acts like `grep -n`. There is no way to disable the line + number in `fossil grep` output. + +* There is no way to suppress all output, returning only a status code + to indicate whether the pattern matched, as with `grep -q`. + +* There is no way to suppress error output, as with `grep -s`. + +* Fossil `grep` does not accept a directory name for Fossil to + expand to the set of all files under that directory. This means + Fossil `grep` has no equivalent of the common POSIX `grep -R` + extension. (And if it did, it would probably have a different + option letter, since `-R` in Fossil has a different meaning, by + convention.) + +* You cannot invert the match, as with `grep -v`. + +Patches to remove those limitations will be thoughtfully considered. + + +## Regular Expression Dialect + +Fossil contains a built-in regular expression engine implementing a +subset of the [POSIX extended regular expression][ere] dialect: + +[ere]: https://en.wikipedia.org/wiki/Regular_expression#POSIX_extended + +| Atom | Meaning +|---------|------------------------------------------------------------- +| `X*` | zero or more occurrences of X +| `X+` | one or more occurrences of X +| `X?` | zero or one occurrences of X +| `X{p,q}`| between p and q occurrences of X, inclusive +| `(X)` | match X +| X\|Y| X or Y +| `^X` | X occurring at the beginning of a line +| `X$` | X occurring at the end of a line +| `.` | Match any single character +| `\c` | Character `c` where `c` is one of {}()[]\|\*+?.\\ +| `\c` | C-language escapes for `c` in `afnrtv`. ex: `\t` or `\n` +| `\uXXXX`| Where XXXX is exactly 4 hex digits, Unicode value XXXX +| `\xXX` | Where XX is exactly 2 hex digits, Unicode value XX +| `[abc]` | Any single character from the set `abc` +| `[^abc]`| Any single character not in the set `abc` +| `[a-z]` | Any single character in the range `a-z` +| `[^a-z]`| Any single character not in the range `a-z` +| `\b` | Word boundary +| `\w` | Word character: `[A-Za-z0-9_]` +| `\W` | Non-word character: `[^A-Za-z0-9_]` +| `\d` | Digit: `[0-9]` +| `\D` | Non-digit: `[^0-9]` +| `\s` | Whitespace character: `[ \t\r\n\v\f]` +| `\S` | Non-whitespace character: `[^ \t\r\n\v\f]` + +There are several restrictions in Fossil `grep` relative to a fully +POSIX compatible regular expression engine. Among them are: + +* There is currently no support for POSIX character classes such as + `[:lower:]`. + +* Fossil `grep` does not currently attempt to take your operating + system's locale settings into account when doing this match. Since + Fossil has no way to mark a given file as having a particular + encoding, Fossil `grep` assumes the input files are in UTF-8 format. + + This means Fossil `grep` will not work correctly if the files in + your repository are in an encoding that is not backwards-compatible + with ASCII, such as UTF-16. Partially compatible encodings such as + ISO 8859 should work with Fossil `grep` as long as you stick to + their ASCII-compatible subset. + +The Fossil `grep` language is not a strict subset of POSIX extended +regular expressions. Some of the features documented above are +well-understood extensions to it, such as the "word" features `\b`, `\w` +and `\W`. + +Fossil `grep` is based on the Unicode engine from [SQLite's FTS5 +feature][fts5]. This means it does do things like Unicode-aware case +folding. Therefore, it is usually a user error to attempt to substitute +`[a-z]` for a lack of the POSIX character class `[:lower:]` if you are +grepping over pretty much any human written language other than English. +Use `fossil grep -i` instead, which does Unicode case folding. + +[fts5]: https://www.sqlite.org/fts5.html + + +## Algorithm Details + +Fossil `grep` uses a [nondeterministic finite automaton][nfa] for +matching, so the performance is bounded by ***O(nm)*** where ***n*** is +the size of the regular expression and ***m*** is the size of the input +string. + +[nfa]: https://en.wikipedia.org/wiki/Nondeterministic_finite_automaton + +In order to avoid [ReDoS attacks][redos], the Fossil regular expression +matcher was purposely written to avoid [implementation choices][rei] +which have the potential to require exponential evaluation time. This +constrains the possible feature set we can support in the Fossil `grep` +dialect. For instance, we are unlikely to ever add support for +[backtracking][bt]. + +[redos]: https://en.wikipedia.org/wiki/ReDoS +[rei]: https://en.wikipedia.org/wiki/Regular_expression#Implementations_and_running_times +[bt]: https://en.wikipedia.org/wiki/Backtracking + +The `X{p,q}` operator expands to `p` copies of `X` followed by `q-p` +copies of `X?` before RE evaluation. The ***O(nm)*** performance bound +above remains true for this case, but realize that it applies to the RE +*after* this expansion, not to the form as given by the user. In other +words, as `q-p` increases, so does the RE evaluation time. Index: www/hacker-howto.wiki ================================================================== --- www/hacker-howto.wiki +++ www/hacker-howto.wiki @@ -1,14 +1,17 @@ -Fossil Hackers How-To +Fossil Developer How-To The following links are of interest to programmers who want to modify -or enhance Fossil. Ordinary users can safely ignore this information. +or enhance Fossil itself. Ordinary users can safely ignore this information. * [./build.wiki | How To Compile And Install Fossil] * [./customskin.md | Theming Fossil] + * [./adding_code.wiki#newcmd | Adding New Commands To Fossil] * [./makefile.wiki | The Fossil Build Process] * [./tech_overview.wiki | A Technical Overview of Fossil] - * [./adding_code.wiki | Adding Features To Fossil] * [./contribute.wiki|Contributing Code Or Enhancements To The Fossil Project] + * [./fileformat.wiki|Fossil Artifact File Format] + * [./sync.wiki|The Sync Protocol] * [./style.wiki | Coding Style Guidelines] * [./checkin.wiki | Pre-checkin Checklist] * [../test/release-checklist.wiki | Release Checklist] + * [./backoffice.md | The "backoffice" subsystem] ADDED www/hashes.md Index: www/hashes.md ================================================================== --- /dev/null +++ www/hashes.md @@ -0,0 +1,155 @@ +# Hashes: Fossil Artifact Identification + +All artifacts in Fossil are identified by a unique hash, currently using +[the SHA3 algorithm by default][hpol], but historically using the SHA1 +algorithm: + + + + + +
        Algorithm<Raw Bits Hexadecimal digits
        SHA3-256 256 64
        SHA1 160 40
        + +There are many types of artifacts in Fossil: commits (a.k.a. check-ins), +tickets, ticket comments, wiki articles, forum postings, file data +belonging to check-ins, etc. ([More info...](./concepts.wiki#artifacts)). + +There is a loose hierarchy of terms used instead of “hash” in various +parts of the Fossil UI, which we cover in the sections below. + + +## Names + +Several Fossil interfaces accept [a wide variety of check-in +names][cin]: commit artifact hashes, ISO8601 date strings, branch names, +etc. Fossil interfaces that accept any of these options usually +document the parameter as “NAME”, so we will use that form to refer to +this specialized use. + +Artifact hashes are only one of many different types of NAME. We use +the broad term “NAME” to refer to the whole class of options. We use +more specific terms when we mean one particular type of NAME. + + +## Versions + +When an artifact hash refers to a specific commit, Fossil sometimes +calls it a “VERSION,” a “commit ID,” or a “check-in ID.” +We may eventually settle on one of these terms, but all three are +currently in common use within Fossil’s docs, UI, and programming +interfaces. + +A VERSION is a specific type of artifact hash, distinct +from, let us say, a wiki article artifact hash. + +A unique prefix of a VERSION hash is itself a VERSION. That is, if your +repository has exactly one commit artifact with a hash prefix of +“abc123”, then that is a valid version string as long as it remains +unambiguous. + + + +## UUIDs + +Fossil uses the term “UUID” as a short alias for “artifact hash” in its +internals. There are a few places where this leaks out into external +interfaces, which we cover in the sections below. Going forward, we +prefer one of the terms above in public interfaces instead. + +Whether this short alias is correct is debateable. + +One argument is that since "UUID" is an acronym for “Universally Unique +Identifier,” and both SHA1 and SHA3-256 are larger and stronger than the +128-bit algorithms used by “proper” UUIDs, Fossil artifact hashes are +*more universally unique*. It is therefore quibbling to say that Fossil +UUIDs are not actually UUIDs. One wag suggested that Fossil artifact +hashes be called MUIDs: multiversally unique IDs. + +The common counterargument is that the acronym “UUID” was created for [a +particular type of universally-unique ID][uuid], with particular ASCII +and bitfield formats, and with particular meaning given to certain of +its bits. In that sense, no Fossil “UUID” can be used as a proper UUID. + +Be warned: attempting to advance the second position on the Fossil +discussion forum will get you nowhere at this late date. We’ve had the +debates, we’ve done the engineering, and we’ve made our evaluation. It’s +a settled matter: internally within Fossil, “UUID” is defined as in this +section’s leading paragraph. + +To those who remain unconvinced, “fixing” this would require touching +almost every source code file in Fossil in a total of about a thousand +separate locations. (Not exaggeration, actual data.) This would be a +massive undertaking simply to deal with a small matter of terminology, +with a high risk of creating bugs and downstream incompatibilities. +Therefore, we are highly unlikely to change this ourselves, and we are +also unlikely to accept a patch that attempts to fix it. + + +### Repository DB Schema + +The primary place where you find "UUID" in Fossil is in the `blob.uuid` +table column, in code dealing with that column, and in code manipulating +*other* data that *refers* to that column. This is a key lookup column +in the most important Fossil DB table, so it influences broad swaths of +the Fossil internals. + +For example, C code that refers to SQL result data on `blob.uuid` +usually calls the variable `zUuid`. That value may then be inserted into +a table like `ticket.tkt_uuid`, creating a reference back to +`blob.uuid`, and then be passed to a function like `uuid_to_rid()`. +There is no point renaming a single one of these in isolation: it would +create needless terminology conflicts, making the code hard to read and +understand, risking the creation of new bugs. + +You may have local SQL code that digs into the repository DB using these +column names. While you may rest easy, assured now that we are highly +unlikely to ever rename these columns, the Fossil repository DB schema +is not considered an external user interface, and internal interfaces +are subject to change at any time. We suggest switching to a more stable +API: [the JSON API][japi], [`timeline.rss`][trss], [TH1][th1], etc. + + +### TH1 Scripting Interfaces + +Some [TH1][th1] interfaces expose Fossil internals flowing from +`blob.uuid`, so “UUID” is a short alias for “artifact hash” in TH1. For +example, the `$tkt_uuid` variable — available when [customizing +the ticket system][ctkt] — is a ticket artifact hash, exposing the +`ticket.tkt_uuid` column, which has a SQL relation to `blob.uuid`. + +TH1 is a longstanding public programming interface. We cannot rename its +interfaces without breaking existing TH1 Fossil customizations. We are +also unlikely to provide a parallel set of variables with “better” +names, since that would create a mismatch with respect to the internals +they expose, creating a different sort of developer confusion in its +place. + + +### JSON API Parameters and Outputs + +[The JSON API][japi] frequently uses the term “UUID” in the same sort of way, +most commonly in [artifact][jart] and [timeline][jtim] APIs. As with +TH1, we can’t change this without breaking code that uses the JSON +API as originally designed, so we take the same stance. + + +### `manifest.uuid` + +If you have [the `manifest` setting][mset] enabled, Fossil writes a file +called `manifest.uuid` at the root of the check-out tree containing the +commit hash for the current checked-out version. Because this is a +public interface that existing code depends on, we are unwilling to +rename the file. + + +[cin]: ./checkin_names.wiki +[ctkt]: ./custom_ticket.wiki +[hpol]: ./hashpolicy.wiki +[japi]: ./json-api/ +[jart]: ./json-api/api-artifact.md +[jtim]: ./json-api/api-timeline.md +[mset]: /help?cmd=manifest +[th1]: ./th1.md +[trss]: /help?cmd=/timeline.rss +[tvb]: ./branching.wiki +[uuid]: https://en.wikipedia.org/wiki/Universally_unique_identifier ADDED www/hashpolicy.wiki Index: www/hashpolicy.wiki ================================================================== --- /dev/null +++ www/hashpolicy.wiki @@ -0,0 +1,199 @@ +Hash Policy + +

        Executive Summary

        + +Or: How To Avoid Reading This Article + +There was much angst over the [http://www.shattered.io|SHAttered attack] +against SHA1 when it was announced in early 2017. If you are concerned +about this and its implications for Fossil, simply +[./quickstart.wiki#install|upgrade to Fossil 2.1 or later], and the +problem will go away. Everything will continue to work as before. + + * Legacy repositories will continue working just as + they always have, without any conversions or upgrades. + * Historical check-ins will keep their same historical + SHA1 names. + * New check-ins will get more secure SHA3-256 hash names. + * Everything will continue as if nothing happened. + * Your workflow will be unchanged. + +But if you are curious and want a deeper understanding of what is +going on, read on... + + +

        Introduction

        + +The first snapshot-based distributed version control system +was [http://www.monotone.ca|Monotone]. Many of the ideas behind the design +of Fossil were copied from Monotone, including the use of a SHA1 hash to +assign names to artifacts. Git and Mercurial did the same thing. + +The SHA1 hash algorithm is used only to create names for artifacts in Fossil +(and in Git, Mercurial, and Monotone). It is not used for security. +Nevertheless, when the [http://www.shattered.io|SHAttered attack] found +two different PDF files with the same SHA1 hash, many users learned that +"SHA1 is broken". They see that Fossil (and Git, Mercurial, and Monotone) +use SHA1 and they therefore conclude that "Fossil is broken". This is +not true, but it is a public relations problem. So the decision +was made to migrate Fossil away from SHA1. + +This article describes how that migration is occurring. + +

        Use Of Hardened SHA1

        + +In Fossil version 2.0 ([/timeline?c=version-2.0|2017-03-03]), +the internal SHA1 implementation was changed from a generic +FIPS PUB 180-4 SHA1 implementation to a "Hardened SHA1" +[[https://github.com/cr-marcstevens/sha1collisiondetection|1]] +[[https://marc-stevens.nl/research/papers/C13-S.pdf|2]]. + +The Hardened SHA1 algorithm automatically detects when the artifact +being hashed is specifically designed to exploit the known weaknesses +in the SHA1 algorithm, and when it detects such an attack it changes +the hash algorithm (by increasing the number of rounds in the compression +function) to make the algorithm secure again. If the attack detection +gets a false possible, that means that Hardened SHA1 will get a different +answer than the standard FIPS PUB 180-4 SHA1, but the creators of +Hardened SHA1 (see the second paper +[[https://marc-stevens.nl/research/papers/C13-S.pdf|2]]) +report that the probability of a false positive is vanishingly small - +less than 1 false positive out of 1027 +hashes. + +Hardened SHA1 is slower (and a lot bigger) but Fossil does not do that +much hashing, so performance is not really an issue. + +All versions of Fossil moving forward will use Hardened SHA1. So if +someone says "SHA1 is broken, and Fossil uses SHA1, therefore Fossil is +broken," you can rebut the argument by pointing out that Fossil uses +Hardened SHA1, not generic SHA1, and Hardened SHA1 is not +broken. + +

        Support For SHA3-256

        + +Prior to Fossil version 2.0 ([/timeline?c=version-2.0|2017-03-03]), +all artifacts in all Fossil repositories were named +by only a SHA1 hash. +Version 2.0 extended the [./fileformat.wiki|Fossil file format] +to allow artifacts to be named by either SHA1 or SHA3-256 hashes. +(SHA3-256 is the only variant of SHA3 that +Fossil uses for artifact naming, so for the remainder of this article +it will be called simply "SHA3". Similarly, "Hardened SHA1" will +shortened to "SHA1" in the remaining text.) + +To be clear: Fossil (version 2.0 and later) +allows the SHA1 and SHA3 hashes to be mixed within +the same repository. Older check-ins, created years ago, +continue to be named using their legacy SHA1 hashes while +newer check-ins are named using modern SHA3 hashes. There +is no need to "convert" a repository from SHA1 over to SHA3. +You can see this in Fossil itself. The recent +[9d9ef82234f63758] check-in uses a SHA3 hash whereas the older +[1669115ab9d05c18] check-in uses a SHA1 hash. + +Other than permitting the use of SHA3 in addition to SHA1, there +were no file format changes in Fossil version 2.0 relative +to the previous version 1.37. Both Fossil 2.0 and Fossil 1.37 read +and write all the same repositories and sync with one another, as long +as none of the repositories contain artifacts named using SHA3. If +a repository does contain artifacts named using SHA3, Fossil 1.37 will +not know how to interpret those artifacts and will generate various warnings +and errors. + +

        How Fossil Decides Which Hash Algorithm To Use For New Artifacts

        + +If newer versions of Fossil are able to use either SHA1 or SHA3 to +name artifacts, which hash algorithm is actually used? That question +is answered by the "hash policy". These are the supported hash policies: + + + + + + + + + + + + + + + + + + + + + +
        sha1Name all new artifacts using the (Hardened) SHA1 hash algorithm.
        autoName new artifacts using the SHA1 hash algorithm, but if any +artifacts are encountered which are already named using SHA3, then +automatically switch the hash policy to "sha3"
        sha3Name new artifacts using the SHA3 hash algorithm if the artifact +does not already have a SHA1 name. If the artifact already has a SHA1 +name, then continue to use the older SHA1 name. Use SHA3 for new +artifacts that have never before been encountered.
        sha3-onlyName new artifacts using the SHA3 hash algorithm even if the artifact +already has a SHA1 name. In other words, force the use of SHA3. This can +cause some artifacts to be added to the repository twice, once under their +SHA1 name and again under their SHA3 name, but delta compression will +prevent that from causing repository size problems.
        shun-sha1Like "sha3-only" but at this level do not accept a push of SHA1-named +artifacts. If another Fossil instance tries to push a SHA1-named artifact, +that artifact is discarded and ignored. +
        + +For Fossil 2.0, and obviously also for Fossil 1.37 and before, the +only hash policy supported was the one now called "sha1", meaning that +all new artifacts were named +using a SHA1 hash. +Even though Fossil 2.0 added the capability of understanding SHA3 hashes, it +never actually generates any SHA3 hashes. + +From Fossil 2.1 through 2.9, the default hash policy for legacy repositories +changed to "auto", meaning that +Fossil continued to generate only SHA1 hashes until it +encountered one artifact with a SHA3 hash. Once those older versions of +Fossil saw a single SHA3 hash, they +automatically switched to "sha3" mode and thereafter generated +only SHA3 hashes. + +When a new repository is created by cloning, the hash policy is copied +from the parent. + +For new repositories created using the +[/help?cmd=new|fossil new] command the default hash policy is "sha3". +That means new repositories +will normally hold nothing except SHA3 hashes. The hash policy for new +repositories can be overridden using the "--sha1" option to the +"fossil new" command. + +If you are still on Fossil 2.1 through 2.9 but you want Fossil to go +ahead and start using SHA3 hashes, change the hash policy to +"sha3" using a command like this: + +
        +fossil hash-policy sha3 +
        + +The next check-in will use a SHA3 hash, so that when that check-in is pushed +to colleagues, their clones will include the new SHA3-named artifact, so +their local Fossil instances will automatically convert their clones to +"sha3" mode as well. + +Of course, if some members of your team stubbornly refuse to upgrade past +Fossil 1.37, you should avoid changing the hash policy and creating +artifacts with SHA3 names, because once you do that your recalcitrant +coworkers will no longer be able to collaborate. + +

        A Pure SHA3 Future

        + +Fossil 2.10 changed the default hash policy to "sha3" mode even for +legacy repositories, so if you +upgrade to the latest version of Fossil, all of your new artifacts will +use a SHA3 hash. Legacy SHA1 artifacts continue to use their original +names, but new artifacts will use SHA3 names. You might not even notice +this automatic change over to stronger hashes. + +We decided to make the change to pure SHA3 since the last known distributor +of Fossil 1.x binaries — Debian 9 — was finally replaced in June 2019 +by Debian 10, which included Fossil 2.8. All other known sources of +Fossil 1.x binaries upgraded well before that point. ADDED www/history.md Index: www/history.md ================================================================== --- /dev/null +++ www/history.md @@ -0,0 +1,95 @@ +# The History And Purpose Of Fossil + +Fossil is a [distributed version control system (DVCS)][100] written +beginning in [2007][105] by the [architect of SQLite][110] for the +purpose of managing the [SQLite project][115]. + +[100]: https://en.wikipedia.org/wiki/Distributed_version_control +[105]: /timeline?a=1970-01-01&n=10 +[110]: https://sqlite.org/crew.html +[115]: https://sqlite.org/ + +Though Fossil was originally written specifically to support SQLite, +it is now also used by countless other projects. The SQLite architect (drh) +is still the top committer to Fossil, but there are also +[many other contributors][120]. + +[120]: /reports?type=ci&view=byuser + +## History + +The SQLite project start out using [CVS][300], as CVS was the most +commonly used version control system in that era (circa 2000). CVS +was an amazing version control system for its day in that it allowed +multiple developers to be editing the same file at the same time. + +[300]: https://en.wikipedia.org/wiki/Concurrent_Versions_System + +Though innovative and much loved in its time, CVS was not without problems. +Among those was a lack of visibility into the project history and the +lack of integrated bug tracking. To try to address these deficiencies, +the SQLite author developed the [CVSTrac][305] wrapper for CVS beginning +in [2002][310]. + +[305]: http://cvstrac.org/ +[310]: http://cvstrac.org/fossil/timeline?a=19700101&n=10 + +CVSTrac greatly improved the usability of CVS and was adopted by +other projects. CVSTrac also [inspired the design][315] of [Trac][320], +which was a similar system that was (and is) far more widely used. + +[315]: https://trac.edgewall.org/wiki/TracHistory +[320]: https://trac.edgewall.org/ + +Historians can see the influence of CVSTrac on the development of +SQLite. [Early SQLite check-ins][325] that happened before CVSTrac +often had a check-in comment that was just a "smiley". +That was not an unreasonable check-in comment, as check-in comments +were scarcely seen and of questionable utility in raw CVS. CVSTrac +changed that, making check-in comments more visible and more useful. +The SQLite developers reacted by creating [better check-in comments][330]. + +[325]: https://sqlite.org/src/timeline?a=19700101&n=10 +[330]: https://sqlite.org/src/timeline?c=20030101&n=10&nd + +At about this same time, the [Monotone][335] system appeared. +Monotone was one of the first distributed version control systems. As far as +this author is aware, Monotone was the first VCS to make use of +SHA1 to identify artifacts. Monotone stored its content in an SQLite +database, which is what brought it to the attention of the SQLite architect. +These design choices were a major source of inspiration for Fossil. + +[335]: https://www.monotone.ca/ + +Beginning around 2005, the need for a better version control system +for SQLite began to become evident. The SQLite architect looked +around for a suitable replacement. Monotone, Git, and Mercurical were +all considered. But at that time, none of these supported sync +over ordinary HTTP, none could be run from an inexpensive shell +account on a leased server (this was before the widespread availability +of affordable virtual machines), and none of them supported anything +resembling the wiki and ticket features of CVSTrac that had been +found to be so useful. And so, the SQLite architect began writing +his own DVCS. + +Early prototypes were done in [TCL][340]. As experiments proceeded, +however, it was found that the low-level byte manipulates needed for +things like delta compression and computing diffs +were better implemented in plain old C. +Experiments continued. Finally, a prototype capable of self-hosting +was devised on [2007-07-16][345]. + +[340]: https://www.tcl.tk/ +[345]: https://fossil-scm.org/fossil/timeline?c=200707211410&n=10 + +The first project hosted by Fossil was Fossil itself. After a +few months of development work, the code was considered stable enough +to begin hosting the [SQLite documentation repository][350] which was +split off from the main SQLite CVS repository on [2007-11-12][355]. +After two years of development work on Fossil, the +SQLite source code itself was transfered to Fossil on +[2009-08-11][360]. + +[350]: https://www.sqlite.org/docsrc/doc/trunk/README.md +[355]: https://www.sqlite.org/docsrc/timeline?c=200711120345&n=10 +[360]: https://sqlite.org/src/timeline?c=b0848925babde524&n=12&y=ci ADDED www/image-format-vs-repo-size.ipynb Index: www/image-format-vs-repo-size.ipynb ================================================================== --- /dev/null +++ www/image-format-vs-repo-size.ipynb @@ -0,0 +1,1641 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Image Format vs Fossil Repository Size\n", + "\n", + "## Prerequisites\n", + "\n", + "This notebook was developed with [JupyterLab][jl]. To follow in my footsteps, install that and the needed Python packages:\n", + "\n", + " $ pip install jupyterlab matplotlib pandas wand\n", + "\n", + "In principle, it should also work with [Anaconda Navigator][an], but because [Wand][wp] is not currently in the Anaconda base package set, you may run into difficulties making it work, as we did on macOS. There seems to be some sandboxing that causes problems with OS interaction in that environment. Therefore, we recommend using straight JupyterLab.\n", + "\n", + "This notebook was originally written for the Python 2 kernel because macOS does not include Python 3, but it was later updated for Python 3. It should still be compatible with Python 2, though.\n", + "\n", + "[an]: https://www.anaconda.com/distribution/\n", + "[jl]: https://github.com/jupyterlab/\n", + "[wp]: http://wand-py.org/\n", + "\n", + "\n", + "## Running\n", + "\n", + "The next cell generates the test repositories. This takes about 45 seconds to run, primarily due to the `sleep 1` synchronization call, made 40 times in the main test loop.\n", + "\n", + "The one after that produces the bar chart from the collected data, all but instantaneously.\n", + "\n", + "This split allows you to generate the expensive experimental data in a single pass, then play as many games as you like with the generated data.\n", + "\n", + "\n", + "## Discussion\n", + "\n", + "That is kept in [a separate document](image-format-vs-repo-size.md) so we can share that document with Fossil's Markdown renderer." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Experiment completed in 44.186978816986084 seconds.\n" + ] + } + ], + "source": [ + "import os\n", + "import random\n", + "import time\n", + "\n", + "from wand.color import Color\n", + "from wand.drawing import Drawing\n", + "from wand.image import Image\n", + "\n", + "import pandas as pd\n", + "\n", + "size = 256\n", + "iterations = 10\n", + "start = time.time()\n", + "repo_sizes = []\n", + "\n", + "formats = ['JPEG', 'BMP', 'TIFF', 'PNG']\n", + "for f in formats:\n", + " ext = f.lower()\n", + " tdir = 'test' + '-' + ext\n", + " repo = tdir + '.fossil'\n", + " ifn = 'test.' + ext\n", + " ipath = os.path.join(tdir, ifn)\n", + " rs = []\n", + " \n", + " def add_repo_size():\n", + " rs.append(os.path.getsize(repo) / 1024.0 / 1024.0)\n", + "\n", + " try:\n", + " # Create test repo\n", + " if not os.path.exists(tdir): os.mkdir(tdir, 0o700)\n", + " cmd = 'cd {0} ; fossil init ../{1} && fossil open --nested ../{1} && fossil set binary-glob \"*.{2}\"'.format(\n", + " tdir, repo, ext\n", + " )\n", + " if os.system(cmd) != 0:\n", + " raise RuntimeError('Failed to create test repo ' + repo)\n", + " add_repo_size()\n", + "\n", + " # Create test image and add it to the repo\n", + " img = Image(width = size, height = size, depth = 8,\n", + " background = 'white')\n", + " img.alpha_channel = 'remove'\n", + " img.evaluate('gaussiannoise', 1.0)\n", + " img.save(filename = ipath)\n", + " cmd = 'cd {0} ; fossil add {1} && fossil ci -m \"initial\"'.format(\n", + " tdir, ifn\n", + " )\n", + " if os.system(cmd) != 0:\n", + " raise RuntimeError('Failed to add ' + ifn + ' to test repo')\n", + " #print \"Created test repo \" + repo + \" for format \" + f + \".\"\n", + " add_repo_size()\n", + "\n", + " # Change a random pixel to a random RGB value and check it in\n", + " # $iterations times.\n", + " for i in range(iterations):\n", + " with Drawing() as draw:\n", + " x = random.randint(0, size - 1)\n", + " y = random.randint(0, size - 1)\n", + "\n", + " r = random.randint(0, 255)\n", + " g = random.randint(0, 255)\n", + " b = random.randint(0, 255)\n", + " \n", + " draw.fill_color = Color('rgb({0},{1},{2})'.format(\n", + " r, g, b\n", + " ))\n", + " draw.color(x, y, 'point')\n", + " draw(img)\n", + " img.save(filename = ipath)\n", + " \n", + " # ImageMagick appears to use some kind of asynchronous\n", + " # file saving mechanism, so we have to give it time to\n", + " # complete.\n", + " time.sleep(1.0)\n", + " \n", + " cmd = 'cd {0} ; fossil ci -m \"change {1} step {2}\"'.format(\n", + " tdir, f, i\n", + " )\n", + " if os.system(cmd) != 0:\n", + " raise RuntimeError('Failed to change ' + f + ' image, step ' + str(i))\n", + " add_repo_size()\n", + " \n", + " # Repo complete for this format\n", + " repo_sizes.append(pd.Series(rs, name=f))\n", + "\n", + " finally:\n", + " if os.path.exists(ipath): os.remove(ipath)\n", + " if os.path.exists(tdir):\n", + " os.system('cd ' + tdir + ' ; fossil close -f')\n", + " os.rmdir(tdir)\n", + " if os.path.exists(repo): os.remove(repo)\n", + " \n", + "print(\"Experiment completed in \" + str(time.time() - start) + \" seconds.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
        " + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "%config InlineBackend.figure_formats = ['svg']\n", + "\n", + "import matplotlib as mpl\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Merge per-format test data into a single DataFrame without the first\n", + "# first 3 rows: the initial empty repo state (boring) and the repo DB\n", + "# size as it \"settles\" in its first few checkins.\n", + "data = pd.concat(repo_sizes, axis=1).drop(range(3))\n", + "\n", + "mpl.rcParams['figure.figsize'] = (6, 4)\n", + "ax = data.plot(kind = 'bar', colormap = 'coolwarm',\n", + " grid = False, width = 0.8,\n", + " edgecolor = 'white', linewidth = 2)\n", + "ax.axes.set_xlabel('Checkin index')\n", + "ax.axes.set_ylabel('Repo size (MiB)')\n", + "plt.savefig('image-format-vs-repo-size.svg', transparent=True)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} ADDED www/image-format-vs-repo-size.md Index: www/image-format-vs-repo-size.md ================================================================== --- /dev/null +++ www/image-format-vs-repo-size.md @@ -0,0 +1,292 @@ +# Image Format vs Fossil Repo Size + +## The Problem + +Fossil has a [delta compression][dc] feature which removes redundant +information from a file — with respect to the version checked in at the +tip of the current working branch — when checking in a subsequent +version.¹ That delta is then [zlib][zl]-compressed before being stored +in the Fossil repository database file. + +Storing pre-compressed data files in a Fossil repository defeats both of +these space-saving measures: + +1. Binary data compression algorithms — whether lossless as with zlib + or lossy as with JPEG — turn the file data into [pseudorandom + noise][prn].² + + Typical data compression algorithms are not [hash functions][hf], + where the goal is that a change to each bit in the input has a + statistically even chance of changing every bit in the output, but + because they do approach that pathological condition, pre-compressed + data tends to defeat Fossil’s delta compression algorithm, there + being so little correlation between two different outputs from the + binary data compression algorithm. + +2. An ideal lossless binary data compression algorithm cannot be + applied more than once to make the data even smaller, since random + noise is incompressible. The consequence for our purposes here is + that pre-compressed data doesn’t benefit from Fossil’s zlib + compression. + +You might then ask, what does it matter if the space savings comes from +the application file format (e.g. JPEG, Zip, etc.) or from Fossil +itself? It really doesn’t, as far as point 2 above goes, but point 1 +causes the Fossil repository to balloon out of proportion to the size of +the input data change on each checkin. This article will illustrate that +problem, quantify it, and give a solution to it. + +[dc]: ./delta_format.wiki +[hf]: https://en.wikipedia.org/wiki/Hash_function +[prn]: https://en.wikipedia.org/wiki/Pseudorandomness +[zl]: http://www.zlib.net/ + + +## Affected File Formats + +In this article’s core experiment, we use 2D image file formats, but +this article’s advice also applies to many other file types. For just a +few examples out of what must be thousands: + +* **Microsoft Office**: The [OOXML document format][oox] used from + Office 2003 onward (`.docx`, `.xlsx`, `.pptx`, etc.) are Zip files + containing an XML document file and several collateral files. + +* **Libre Office**: Its [ODF][odf] format is designed in more or less + the same way as OOXML. + +* **Java**: A Java [`.jar` file][jcl] is a Zip file containing JVM + `.class` files, manifest files, and more. + +* **Windows Installer:** An [`*.msi` file][wi] is a proprietary + database format that contains, among other things, [Microsoft + Cabinet][cab]-compressed files, which in turn may hold Windows + executables, which [may themselves be compressed][exc]. + +* **SVG, PDF, TIFF, etc.**: Many file formats are available in both + compressed and uncompressed forms. You should use the uncompressed + form with Fossil wherever practical, as we will show below. + + +[cab]: https://en.wikipedia.org/wiki/Cabinet_(file_format) +[exc]: https://en.wikipedia.org/wiki/Executable_compression +[jcl]: https://en.wikipedia.org/wiki/Java_(programming_language) +[odf]: https://en.wikipedia.org/wiki/OpenDocument +[oox]: https://en.wikipedia.org/wiki/Office_Open_XML +[wi]: https://en.wikipedia.org/wiki/Windows_Installer + + + +## Demonstration + +The companion `image-format-vs-repo-size.ipynb` file ([download][nbd], +[preview][nbp]) is a [Jupyter][jp] notebook implementing the following +experiment: + +1. Create an empty Fossil repository; save its initial size. + +2. Use [ImageMagick][im] via [Wand][wp] to generate a JPEG file of a + particular size — currently 256 px² — filled with Gaussian noise to + make data compression more difficult than with a solid-color image. + +3. Check that image into the new Fossil repo, and remember that size. + +4. Change a random pixel in the image to a random RGB value, save that + image, check it in, and remember the new Fossil repo size. + +5. Iterate on step 4 some number of times — currently 10 — and remember + the Fossil repo size at each step. + +6. Repeat the above steps for BMP, TIFF,³ and PNG. + +7. Create a bar chart showing how the Fossil repository size changes + with each checkin. + +We chose to use Jupyter for this because it makes it easy for you to +modify the notebook to try different things. Want to see how the +results change with a different image size? Easy, change the `size` +value in the second cell of the notebook. Want to try more image +formats? You can put anything ImageMagick can recognize into the +`formats` list. Want to find the break-even point for images like those +in your own repository? Easily done with a small amount of code. + +[im]: https://www.imagemagick.org/ +[jp]: https://jupyter.org/ +[nbd]: ./image-format-vs-repo-size.ipynb +[nbp]: https://nbviewer.jupyter.org/urls/fossil-scm.org/fossil/doc/trunk/www/image-format-vs-repo-size.ipynb +[wp]: http://wand-py.org/ + + +## Results + +Running the notebook gives a bar chart something like⁴ this: + +![results bar chart](./image-format-vs-repo-size.svg) + +There are a few key things we want to draw your attention to in that +chart: + +* BMP and uncompressed TIFF are nearly identical in size for all + checkins, and the repository growth rate is negligible.⁵ We owe this + economy to Fossil’s delta compression feature. + +* The JPEG and TIFF bars increase by large amounts on most checkins + even though each checkin encodes only a *single-pixel change*! + +* Because JPEG’s lossy nature allows it to start smaller and have + smaller size increases than than PNG, the crossover point with + BMP/TIFF isn’t until 7-9 checkins in typical runs of this [Monte + Carlo experiment][mce]. Given a choice among these four file + formats and a willingness to use lossy image compression, a rational + tradeoff is to choose JPEG for repositories where each image will + change fewer than that number of times. + +[mce]: https://en.wikipedia.org/wiki/Monte_Carlo_method + + +## Automated Recompression + +Since programs that produce and consume binary-compressed data files +often make it either difficult or impossible to work with the +uncompressed form, we want an automated method for producing the +uncompressed form to make Fossil happy while still having the compressed +form to keep our content creation applications happy. This `Makefile` +should⁶ do that for BMP, PNG, SVG, and XLSX files: + + .SUFFIXES: .bmp .png .svg .svgz + + .svgz.svg: + gzip -dc < $< > $@ + + .svg.svgz: + gzip -9c < $< > $@ + + .bmp.png: + convert -quality 95 $< $@ + + .png.bmp: + convert $< $@ + + SS_FILES := $(wildcard spreadsheet/*) + + + all: $(SS_FILES) illus.svg image.bmp doc-big.pdf + + reconstitute: illus.svgz image.png + ( cd spreadsheet ; zip -9 ../spreadsheet.xlsx) * ) + qpdf doc-big.pdf doc-small.pdf + + + $(SS_FILES): spreadsheet.xlsx + unzip $@ -d $< + + doc-big.pdf: doc-small.pdf + qpdf --stream-data=uncompress $@ $< + +This `Makefile` allows you to treat the compressed version as the +process input, but to actually check in only the changes against the +uncompressed version by typing “`make`” before “`fossil ci`”. This is +not actually an extra step in practice, since if you’ve got a +`Makefile`-based project, you should be building (and testing!) it +before checking each change in anyway! + +Because this technique is based on dependency rules, only the necessary +files are generated on each `make` command. + +You only have to run “`make reconstitute`” *once* after opening a fresh +Fossil checkout to produce those compressed sources. After that, you +work with the compressed files in your content creation programs. Your +build system might include some kind of bootstrapping or +auto-configuration step that you could attach this to, so that it +doesn’t need to be run by hand. + +This `Makefile` illustrates two primary strategies: + + +### Input and Output File Formats Differ by Extension + +In the case of SVG and the bitmap image formats, the file name extension +differs between the cases, so we can use `make` suffix rules to get the +behavior we want. The top half of the `Makefile` just tells `make` how +to map from `*.svg` to `*.svgz` and vice versa, and the same for `*.bmp` +to/from `*.png`. + + +### Input and Output Use the Same Extension + +We don’t have that luxury for Excel and PDF files, each for a different +reason: + +* **Excel:** Excel has no way to work with the unpacked Zip file + contents at all, so we have to unpack it into a subdirectory, which + is what we check into Fossil. On making a fresh Fossil checkout, we + have to pack that subdirectory’s contents back up into an `*.xlsx` + file with “`make reconstitute`” so we can edit it with Excel again. + +* **PDF:** All PDF readers can display an uncompressed PDF file, but + many PDF-*producing* programs have no option for uncompressed + output. Since the file name extension is the same either way, we + treat the compressed PDF as the source to the process, yielding an + automatically-uncompressed PDF for the benefit of Fossil. Unlike + with the Excel case, there is no simple “file base name to directory + name” mapping, so we just created the `-big` to `-small` name scheme + here. + +---- + + +## Footnotes and Digressions + +1. Several other programs also do delta compression, so they’ll also be + affected by this problem: [rsync][rs], [Unison][us], [Git][git], + etc. When using file copying and synchronization programs *without* + delta compression, it’s best to use the most highly-compressed file + format you can tolerate, since they copy the whole file any time any + bit of it changes. + +2. In fact, a good way to gauge the effectiveness of a given + compression scheme is to run its output through the same sort of + tests we use to gauge how “random” a given [PRNG][prng] is. Another + way to look at it is that if there is a discernible pattern in the + output of a compression scheme, it’s information that could be + further compressed. + +3. We're using *uncompressed* TIFF here, not [LZW][lzw]- or + Zip-compressed TIFF, either of which would give similar results to + PNG, which is always zlib-compressed. + +4. The raw data changes somewhat from one run to the next due to the + use of random noise in the image to make the zlib/PNG compression + more difficult, and the random pixel changes. Those test design + choices make this a [Monte Carlo experiment][mce]. We’ve found that + the overall character of the results doesn’t change from one run to + the next. + + The code in the notebook’s third cell drops the first three columns + of data because the first column (the empty repository size) is + boring, and the subsequent two checkins show the SQLite DB file + format settling in with its first few checkins. There’s a single + line in the notebook you can comment out to get a bar chart with + these data included. + + If you do this, you’ll see a mildly interesting result: the size of + the first checkin in the BMP and TIFF cases is roughly the same as + that for the PNG case, because both PNG and Fossil use the zlib + binary data compression algorithm. + +5. A low-tech format like BMP will have a small edge in practice + because TIFF metadata includes the option for multiple timestamps, + UUIDs, etc., which bloat the checkin size by creating many small + deltas. If you don't need the advantages of TIFF, a less capable + image file format will give smaller checkin sizes for a given amount + of change. + +6. The `Makefile` above is not battle-tested. Please report bugs and + needed extensions [on the forum][for]. + +[for]: https://fossil-scm.org/forum/forumpost/15e677f2c8 +[git]: https://git-scm.com/ +[lzw]: https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch +[prng]: https://en.wikipedia.org/wiki/Pseudorandom_number_generator +[rs]: https://rsync.samba.org/ +[us]: http://www.cis.upenn.edu/~bcpierce/unison/ ADDED www/image-format-vs-repo-size.svg Index: www/image-format-vs-repo-size.svg ================================================================== --- /dev/null +++ www/image-format-vs-repo-size.svg @@ -0,0 +1,1426 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: www/index.wiki ================================================================== --- www/index.wiki +++ www/index.wiki @@ -2,71 +2,73 @@

        What Is Fossil?

          -
        • [http://www.fossil-scm.org/download.html | Download] +
        • [/uv/download.html | Download]
        • [./quickstart.wiki | Quick Start]
        • [./build.wiki | Install] -
        • [../COPYRIGHT-BSD2.txt | License] -
        • [./faq.wiki | FAQ] +
        • [https://fossil-scm.org/forum | Support/Forum ] +
        • [./hints.wiki | Tips & Hints]
        • [./changes.wiki | Change Log] +
        • [../COPYRIGHT-BSD2.txt | License] +
        • [./userlinks.wiki | User Links]
        • [./hacker-howto.wiki | Hacker How-To] -
        • [./hints.wiki | Tip & Hints] +
        • [./fossil-v-git.wiki | Fossil vs. Git]
        • [./permutedindex.html | Documentation Index] -
        • [http://www.fossil-scm.org/schimpf-book/home | Jim Schimpf's book] -
        • Mailing list -
            -
          • [http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/fossil-users | sign-up] -
          • [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org | archives] -

        Fossil is a simple, high-reliability, distributed software configuration management system with these advanced features: - 1. Integrated Bug Tracking, Wiki, and Technotes - + 1. Integrated Bug Tracking, Wiki, Forum, and Technotes - In addition to doing [./concepts.wiki | distributed version control] like Git and Mercurial, Fossil also supports [./bugtheory.wiki | bug tracking], - [./wikitheory.wiki | wiki], and [./event.wiki | technotes]. + [./wikitheory.wiki | wiki], [./forum.wiki | forum], and + [./event.wiki | technotes]. 2. Built-in Web Interface - - Fossil has a built-in and intuitive [./webui.wiki | web interface] - with a rich assortment of information pages - ([./webpage-ex.md|examples]) designed to promote situational awareness. - + Fossil has a built-in, + [https://fossil-scm.org/skins/index.html | themeable], + and intuitive [./webui.wiki | web interface] + with a rich variety of information pages + ([./webpage-ex.md|examples]) promoting situational awareness. +

        This entire website is just a running instance of Fossil. The pages you see here are all [./wikitheory.wiki | wiki] or [./embeddeddoc.wiki | embedded documentation] or (in the case of - the [/uv/download.html|download] page) + the [/uv/download.html|download] page) [./unvers.wiki | unversioned files]. When you clone Fossil from one of its [./selfhost.wiki | self-hosting repositories], you get more than just source code - you get this entire website. 3. Self-Contained - Fossil is a single self-contained stand-alone executable. To install, simply download a - precompiled binary - for Linux, Mac, OpenBSD, or Windows and put it on your $PATH. + [/uv/download.html | precompiled binary] + for Linux, Mac, or Windows and put it on your $PATH. [./build.wiki | Easy-to-compile source code] is also available. 4. Simple Networking - No custom protocols or TCP ports. Fossil uses ordinary HTTP (or HTTPS or SSH) for network communications, so it works fine from behind restrictive firewalls, including [./quickstart.wiki#proxy|proxies]. The protocol is [./stats.wiki | bandwidth efficient] to the point that Fossil can be - used comfortably over dial-up. + used comfortably over dial-up or over the exceedingly slow Wifi on + airliners. - 5. CGI/SCGI Enabled - No server is required, but if you want to - set one up, Fossil supports four easy - [./server.wiki | server configurations]. + 5. Simple Server Setup - No server is required, but if you want to + set one up, Fossil supports [./server/ | several different server + configurations] including CGI, SCGI, and direct HTTP. + You can also easily set up your Fossil repository to automatically + [./mirrortogithub.md | mirror content on GitHub]. 6. Autosync - Fossil supports [./concepts.wiki#workflow | "autosync" mode] which helps to keep projects moving forward by reducing the amount of needless @@ -81,74 +83,22 @@ the repository are consistent prior to each commit. 8. Free and Open-Source - Uses the [../COPYRIGHT-BSD2.txt|2-clause BSD license].


        -

        Links For Fossil Users:

        - - * [./permutedindex.html | Documentation index] with [/search?c=d | full text search]. - * [./reviews.wiki | Testimonials] from satisfied Fossil users and - [./quotes.wiki | Quotes] about Fossil and other DVCSes. - * [./faq.wiki | Frequently Asked Questions] - * The [./concepts.wiki | concepts] behind Fossil. - * [./quickstart.wiki | Quick Start] guide to using Fossil. - * [./qandc.wiki | Questions & Criticisms] directed at Fossil. - * [./build.wiki | Compiling and Installing] - * "Fuel" is cross-platform GUI front-end for Fossil - written in Qt. [http://fuelscm.org/]. - Fuel is an independent project run by a different group of - developers. - * Fossil supports [./embeddeddoc.wiki | embedded documentation] - that is versioned along with project source code. - * Fossil uses an [./fileformat.wiki | enduring file format] that is - designed to be readable, searchable, and extensible by people - not yet born. - * A tutorial on [./branching.wiki | branching], what it means and how - to do it using Fossil. - * The [./selfcheck.wiki | automatic self-check] mechanism - helps insure project integrity. - * Fossil contains a [./wikitheory.wiki | built-in wiki]. - * An [./event.wiki | Event] is a special kind of wiki page associated - with a point in time rather than a name. - * [./settings.wiki | Settings] control the behaviour of Fossil. - * [./ssl.wiki | Use SSL] to encrypt communication with the server. - * There is a - [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list] - (with publicly readable - [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org | archives]) - available for discussing Fossil issues. - * [./stats.wiki | Performance statistics] taken from real-world projects - hosted on Fossil. - * How to [./shunning.wiki | delete content] from a Fossil repository. - * How Fossil does [./password.wiki | password management]. - * On-line [/help | help]. - * Documentation on the - [http://www.sqliteconcepts.org/THManual.pdf | TH1 scripting language], - used to customize [./custom_ticket.wiki | ticketing], and several other - subsystems, including [./customskin.md | theming]. - * List of [./th1.md | TH1 commands provided by Fossil itself] that expose - its key functionality to TH1 scripts. - * A free hosting server for Fossil repositories is available at - [http://chiselapp.com/]. - * How to [./server.wiki | set up a server] for your repository. - * Customizing the [./custom_ticket.wiki | ticket system]. - * Methods to [./checkin_names.wiki | identify a specific check-in]. - * [./inout.wiki | Import and export] from and to Git. - * [./fossil-v-git.wiki | Fossil versus Git]. - * [./fiveminutes.wiki | Up and running in 5 minutes as a single user] - (contributed by Gilles Ganault on 2013-01-08). - * [./antibot.wiki | How Fossil defends against abuse by spiders and bots]. - -

        Links For Fossil Developers:

        - - * [./contribute.wiki | Contributing] code or documentation to the - Fossil project. - * [./theory1.wiki | Thoughts On The Design Of Fossil]. - * [./pop.wiki | Principles Of Operation] - * [./tech_overview.wiki | A Technical Overview Of Fossil]. - * The [./fileformat.wiki | file format] used by every content - file stored in the repository. - * The [./delta_format.wiki | format of deltas] used to - efficiently store changes between file revisions. - * The [./delta_encoder_algorithm.wiki | encoder algorithm] used to - efficiently generate deltas. - * The [./sync.wiki | synchronization protocol]. +

        [/timeline?t=release|Latest Release]: 2.11.1 (2020-06-08)

        + + * [/uv/download.html|Download] + * [./changes.wiki#v2_11|Change Summary] + +
        +

        Quick Start

        + + 1. [/uv/download.html|Download] or install using a package manager or + [./build.wiki|compile from sources]. + 2. fossil init new-repository + 3. fossil open new-repository + 4. fossil add files-or-directories + 5. fossil commit -m "commit message" + 6. fossil ui + 7. Repeat steps 4, 5, and 6, in any order, as necessary. + See the [./quickstart.wiki|Quick Start Guide] for more detail. Index: www/inout.wiki ================================================================== --- www/inout.wiki +++ www/inout.wiki @@ -1,10 +1,10 @@ Import And Export -Fossil has the ability to import and export repositories from and to +Fossil has the ability to import and export repositories from and to [http://git-scm.com/ | Git]. And since most other version control -systems will also import/export from Git, that means that you can +systems will also import/export from Git, that means that you can import/export a Fossil repository to most version control systems using Git as an intermediary.

        Git → Fossil

        @@ -20,11 +20,11 @@ command is the name of a new Fossil repository that is created to hold the Git content. The --git option is not actually required. The git-fast-export file format is currently the only VCS interchange format that Fossil understands. But -future versions of Fossil might be enhanced to understand other VCS +future versions of Fossil might be enhanced to understand other VCS interchange formats, and so for compatibility, use of the --git option is recommended.

        Fossil → Git

        @@ -43,21 +43,69 @@ Note that the "fossil export --git" command only exports the versioned files. Tickets and wiki and events are not exported, since Git does not understand those concepts. As with the "import" command, the --git option is not required -since the git-fast-export file format is currently the only VCS interchange +since the git-fast-export file format is currently the only VCS interchange format that Fossil will generate. However, future versions of Fossil might add the ability to generate other -VCS interchange formats, and so for compatibility, the use of the --git +VCS interchange formats, and so for compatibility, the use of the --git option recommended. -An anonymous user sends this comment: - -
        -The main Fossil branch is called "trunk", while the main git branch is -called "master". After you've exported your FOSSIL repo to git, you won't -see any files and gitk will complain about a missing "HEAD". You can -resolve this problem by merging "trunk" with "master" -(first verify using git status that you are on the "master" branch): -git merge trunk -
        +

        Mirror A Fossil Repository In Git

        + +Fossil version 2.9 and later supports a simple mechanism for +doing a Git or +[./mirrortogithub.md|GitHub mirror of a Fossil repository]. +See that separate document for details. Fossil is self-hosting, +but a [https://github.com/drhsqlite/fossil-mirror|GitHub mirror of Fossil] +is available as a proof-of-concept. + +

        Bidirectional Synchronization

        +Fossil also has the ability to synchronize with a Git repository via repeated +imports and/or exports. To do this, it uses marks files to store a record of +artifacts which are known by both Git and Fossil to exist at a given point in +time. + +To illustrate, consider the example of a remote Fossil repository that a +user wants to import into a local Git repository. First, the user would clone +the remote repository and import it into a new Git repository: + +
        +fossil clone /path/to/remote/repo.fossil repo.fossil
        +mkdir repo
        +cd repo
        +fossil open ../repo.fossil
        +mkdir ../repo.git
        +cd ../repo.git
        +git init .
        +fossil export --git --export-marks ../repo/fossil.marks  \
        +       ../repo.fossil | git fast-import                  \
        +       --export-marks=../repo/git.marks
        +
        + +Once the import has completed, the user would need to git checkout +trunk. At any point after this, new changes can be imported from the +remote Fossil repository: + +
        +cd ../repo
        +fossil pull
        +cd ../repo.git
        +fossil export --git --import-marks ../repo/fossil.marks  \
        +       --export-marks ../repo/fossil.marks               \
        +       ../repo.fossil | git fast-import                  \
        +       --import-marks=../repo/git.marks                  \
        +       --export-marks=../repo/git.marks
        +
        + +Changes in the Git repository can be exported to the Fossil repository and then +pushed to the remote: + +
        +git fast-export --import-marks=../repo/git.marks                  \
        +    --export-marks=../repo/git.marks --all | fossil import --git  \
        +    --incremental --import-marks ../repo/fossil.marks             \
        +    --export-marks ../repo/fossil.marks ../repo.fossil
        +cd ../repo
        +fossil push
        +
        ADDED www/javascript.md Index: www/javascript.md ================================================================== --- /dev/null +++ www/javascript.md @@ -0,0 +1,279 @@ +# Use of JavaScript in Fossil + +## Philosophy + +The Fossil development project’s policy is to use JavaScript where it +helps make its web UI better, but to offer graceful fallbacks wherever +practical. The intent is that the UI be usable with JavaScript entirely +disabled. In every place where Fossil uses JavaScript, it is an +enhancement to provided functionality, and there is always another way +to accomplish a given end without using JavaScript. + +This is not to say that Fossil’s fall-backs for such cases are always as +elegant and functional as a no-JS purist might wish. That is simply +because [the vast majority of web users run with JS enabled](#stats), +and a minority of those run with some kind of conditional JavaScript +blocking in place. Fossil’s active developers do not deviate from that +norm enough that we have many no-JS purists among us, so the no-JS case +doesn’t get as much attention as some might want. We do [accept code +contributions][cg], and we are philosophically in favor of graceful +fall-backs, so you are welcome to appoint yourself the position of no-JS +czar for the Fossil project! + +Evil is in actions, not in nouns, so we do not believe JavaScript *can* +be evil. It is an active technology, but the actions that matter here +are those of writing the code and checking it into the Fossil project +repository. None of the JavaScript code in Fossil is evil, a fact we +enforce by being careful about who we give check-in rights on the +repository to and by policing what code does get contributed. The Fossil +project does not accept non-trivial outside contributions. + +We think it’s better to ask not whether Fossil requires JavaScript but +whether Fossil uses JavaScript *well*, so that [you can decide](#block) +to block or allow Fossil’s use of JavaScript. + +[cg]: ./contribute.wiki + + +## Blocking JavaScript + +Rather than either block JavaScript wholesale or give up on blocking +JavaScript entirely, we recommend that you use tools like [NoScript][ns] +or [uBlock Origin][ub] to selectively block problematic uses of +JavaScript so the rest of the web can use the technology productively, +as it was intended. There are doubtless other useful tools of this sort; +we recommend only these two due to our limited experience, not out of +any wish to exclude other tools. + +The primary difference between these two for our purposes is that +NoScript lets you select scripts to run on a page on a case-by-case +basis, whereas uBlock Origin delegates those choices to a group of +motivated volunteers who maintain whitelists and blacklists to control +all of this; you can then override UBO’s stock rules as needed. + +[ns]: https://noscript.net/ +[ub]: https://github.com/gorhill/uBlock/ + + +## How Many Users Run with JavaScript Disabled Anyway? + +There are several studies that have directly measured the web audience +to answer this question: + +* [What percentage of browsers with javascript disabled?][s1] +* [How many people are missing out on JavaScript enhancement?][s2] +* [Just how many web users really disable cookies or JavaScript?][s3] + +Our sense of this data is that only about 0.2% of web users had +JavaScript disabled while participating in these studies. + +The Fossil user community is not typical of the wider web, but if we +were able to comprehensively survey our users, we’d expect to find an +interesting dichotomy. Because Fossil is targeted at software +developers, who in turn are more likely to be power-users, we’d expect +to find Fossil users to be more in favor of some amount of JavaScript +blocking than the average web user. Yet, we’d also expect to find that +our user base has a disproportionately high number who run [powerful +conditional blocking plugins](#block) in their browsers, rather than +block JS entirely. We suspect that between these two forces, the number +of no-JS purists among Fossil’s user base is still a tiny minority. + +[s1]: https://blockmetry.com/blog/javascript-disabled +[s2]: https://gds.blog.gov.uk/2013/10/21/how-many-people-are-missing-out-on-javascript-enhancement/ +[s3]: https://w3techs.com/technologies/overview/client_side_language/all + + +## No Third-Party JavaScript in Fossil + +Fossil does not use any third-party JavaScript libraries, not even very +common ones like jQuery. Every bit of JavaScript served by the stock +version of Fossil was written specifically for the Fossil project and is +stored [in its code repository](https://fossil-scm.org/fossil/file). + +Therefore, if you want to hack on the JavaScript code served by Fossil +and mechanisms like [skin editing][cs] don’t suffice for your purposes, +you can hack on the JavaScript in your local instance directly, just as +you can hack on its C, SQL, and Tcl code. Fossil is free and open source +software, under [a single license][2cbsd]. + +[2cbsd]: https://fossil-scm.org/home/doc/trunk/COPYRIGHT-BSD2.txt +[cs]: ./customskin.md + + +## Fossil Does Not Snoop On You + +There is no tracking or other snooping technology in Fossil other than +that necessary for basic security, such as IP address logging on +check-ins. (This is in part why we have no [comprehensive user +statistics](#stats)!) + +Fossil attempts to set two cookies on all web clients: a login session +cookie and a display preferences cookie. These cookies are restricted to +the Fossil instance, so even this limited data cannot leak between +Fossil instances or into other web sites. + +There is some server-side event logging, but that is done entirely +without JavaScript, so it’s off-topic here. + + +## Places Where Fossil’s Web UI Uses JavaScript + +The remainder of this document will explain how Fossil currently uses +JavaScript and what it does when these uses are blocked. + + +### Timeline Graph + +Fossil’s [web timeline][wt] uses JavaScript to render the graph +connecting the visible check-ins to each other, so you can visualize +parent/child relationships, merge actions, etc. We’re not sure it’s even +possible to render this in static HTML, even with the aid of SVG, due to +the vagaries of web layout among browser engines, screen sizes, etc. + +Fossil also uses JavaScript to handle clicks on the graph nodes to allow +diffs between versions, to display tooltips showing local context, etc. + +_Graceful Fallback:_ When JavaScript is disabled, this column of the +timeline simply collapses to zero width. All of the information you can +get from the timeline can be retrieved from Fossil in other ways not +using JavaScript: the “`fossil timeline`” command, the “`fossil info`” +command, by clicking around within the web UI, etc. + +_Potential Workaround:_ The timeline could be enhanced with `
      @@ -36,11 +37,11 @@
      1. Fossil is distributed. You can view and/or edit tickets, wiki, and code while off network, then sync your changes later. With Trac, you can only view and edit tickets and wiki while you are connected to the server.
      2. -
      3. Fossil is lightweight and fully self-contained. It is very easy +
      4. Fossil is lightweight and fully self-contained. It is very easy to setup on a low-resource machine. Fossil does not require an administrator.
      5. Fossil integrates code versioning into the same repository with wiki and tickets. There is nothing extra to add or install. Fossil is an all-in-one turnkey solution.
      6. @@ -48,25 +49,25 @@ Love the concept here. Anyone using this for real work yet?
        -Fossil is self-hosting. +Fossil is self-hosting. In fact, this page was probably delivered to your web-browser via a working fossil instance. The same virtual machine that hosts http://www.fossil-scm.org/ (a Linode 720) also hosts 24 other fossil repositories for various small projects. -The documentation files for +The documentation files for SQLite are hosted in a fossil repository here, for example. Other projects are also adopting fossil. But fossil does not yet have the massive user base of git or mercurial.
        -Fossil looks like the bug tracker that would be in your +Fossil looks like the bug tracker that would be in your Linksys Router's administration screen.

        I take a pragmatic approach to software: form follows function. To me, it is more important to have a reliable, fast, efficient, @@ -83,11 +84,11 @@ keeps the bug-tracking database in a versioned file. That file can then be pushed and pulled along with the rest repository.

        Fossil already does push and pull bugs along with the files -in your repository. +in your repository. But fossil does not track bugs as files in the source tree. That approach to bug tracking was rejected for three reasons:

        1. Check-ins in fossil are immutable. So if @@ -108,11 +109,11 @@

          These points are reiterated in the opening paragraphs of the Bug-Tracking In Fossil document.

        -Fossil is already the name of a plan9 versioned +Fossil is already the name of a plan9 versioned append-only filesystem.
        I did not know that. Perhaps they selected the name for the same reason that I did: because a repository with immutable artifacts preserves @@ -137,22 +138,22 @@ Subversion or Bazaar.

        I have no doubt that Trac has many features that fossil lacks. But that is not the point. Fossil has several key features that Trac lacks and that -I need: most notably the fact that +I need: most notably the fact that fossil supports disconnected operation.

        As for bloat: Fossil is a single self-contained executable. -You do not need any other packages +You do not need any other packages (diff, patch, merge, cvs, svn, rcs, git, python, perl, tcl, apache, sqlite, and so forth) in order to run fossil. Fossil runs just fine in a chroot jail all by itself. And the self-contained fossil executable is much less than 1MB in size. (Update 2015-01-12: Fossil has -grown in the years since the previous sentence was written but is still +grown in the years since the previous sentence was written but is still much less than 2MB according to "size" when compiled using -Os on x64 Linux.) Fossil is the very opposite of bloat.

        Index: www/quickstart.wiki ================================================================== --- www/quickstart.wiki +++ www/quickstart.wiki @@ -1,26 +1,28 @@ Fossil Quick Start Guide

        Fossil Quick Start

        -

        This is a guide to get you started using fossil quickly +

        This is a guide to help you get started using Fossil quickly and painlessly.

        -

        Installing

        +

        Installing

        Fossil is a single self-contained C program. You need to - either download a - precompiled binary + either download a + precompiled + binary or compile it yourself from sources. - Install fossil by putting the fossil binary + Install Fossil by putting the fossil binary someplace on your $PATH.

        - +

        General Work Flow

        Fossil works with repository files (a database with the project's complete history) and with checked-out local trees (the working directory you use to do your work). + (See [./whyusefossil.wiki#definitions | definitions] for more background.) The workflow looks like this:

        • Create or clone a repository file. ([/help/init|fossil init] or [/help/clone | fossil clone]) @@ -34,11 +36,11 @@

          Starting A New Project

          To start a new project with fossil, create a new empty repository this way: ([/help/init | more info])

          - +
          fossil init repository-filename

          Cloning An Existing Repository

          @@ -46,36 +48,36 @@

          Most fossil operations interact with a repository that is on the local disk drive, not on a remote system. Hence, before accessing a remote repository it is necessary to make a local copy of that repository. Making a local copy of a remote repository is called "cloning".

          - +

          Clone a remote repository as follows: ([/help/clone | more info])

          - +
          fossil clone URL repository-filename
          - +

          The URL specifies the fossil repository you want to clone. The repository-filename is the new local filename into which the cloned repository will be written. For example: - +

          fossil clone http://www.fossil-scm.org/ myclone.fossil
          -

          If the remote repository requires a login, include a +

          If the remote repository requires a login, include a userid in the URL like this:

          fossil clone http://userid@www.fossil-scm.org/ myclone.fossil
          - +

          You will be prompted separately for the password. - Use "%HH" escapes for special characters in the userid. + Use "%HH" escapes for special characters in the userid. Examples: "%40" in place of "@" and "%2F" in place of "/".

          If you are behind a restrictive firewall, you might need to specify an HTTP proxy.

          @@ -85,31 +87,31 @@ information above and beyond the versioned files, including some sensitive information such as password hashes and email addresses. If you want to share Fossil repositories directly, consider running the [/help/scrub|fossil scrub] command to remove sensitive information before transmitting the file. - +

          Importing From Another Version Control System

          Rather than start a new project, or clone an existing Fossil project, - you might prefer to + you might prefer to import an existing Git project into Fossil using the [/help/import | fossil import] command.

          Checking Out A Local Tree

          To work on a project in fossil, you need to check out a local copy of the source tree. Create the directory you want to be the root of your tree and cd into that directory. Then do this: ([/help/open | more info])

          - +
          fossil open repository-filename
          - +

          This leaves you with the newest version of the tree - checked out. + checked out. From anywhere underneath the root of your local tree, you can type commands like the following to find out the status of your local tree:

          @@ -122,11 +124,11 @@ [/help/branch | fossil branch]

          Note that Fossil allows you to make multiple check-outs in separate directories from the same repository. This enables you, - for example, to do builds from multiple branches or versions at + for example, to do builds from multiple branches or versions at the same time without having to generate extra clones.

          To switch a checkout between different versions and branches, use:

          @@ -140,17 +142,17 @@ version, whereas [/help/checkout | checkout] does not automatically sync and does a "hard" switch, overwriting local changes if told to do so.

          Configuring Your Local Repository

          - +

          When you create a new repository, either by cloning an existing project or create a new project of your own, you usually want to do some local configuration. This is easily accomplished using the web-server - that is built into fossil. Start the fossil webserver like this: + that is built into fossil. Start the fossil web server like this: ([/help/ui | more info])

          - +
          fossil ui repository-filename

          You can omit the repository-filename from the command above @@ -163,15 +165,15 @@ where to find your web browser using a command like this:

          fossil setting web-browser path-to-web-browser
          - +

          By default, fossil does not require a login for HTTP connections coming in from the IP loopback address 127.0.0.1. You can, and perhaps should, change this after you create a few users.

          - +

          When you are finished configuring, just press Control-C or use the kill command to shut down the mini-server.

          Making Changes

          @@ -194,18 +196,18 @@

          You will be prompted for check-in comments using whatever editor is specified by your VISUAL or EDITOR environment variable.

          In the default configuration, the [/help/commit|commit] command will also automatically [/help/push|push] your changes, but that - feature can be disabled. (More information about + feature can be disabled. (More information about [./concepts.wiki#workflow|autosync] and how to disable it.) - Remember that your coworkers can not see your changes until you + Remember that your coworkers can not see your changes until you commit and push them.

          Sharing Changes

          -

          When [./concepts.wiki#workflow|autosync] is turned off, +

          When [./concepts.wiki#workflow|autosync] is turned off, the changes you [/help/commit | commit] are only on your local repository. To share those changes with other repositories, do:

          @@ -241,11 +243,11 @@ the VERSION, then fossil moves you to the latest version of the branch your are currently on.

          The default behavior is for [./concepts.wiki#workflow|autosync] to be turned on. That means that a [/help/pull|pull] automatically occurs - when you run [/help/update|update] and a [/help/push|push] happens + when you run [/help/update|update] and a [/help/push|push] happens automatically after you [/help/commit|commit]. So in normal practice, the push, pull, and sync commands are rarely used. But it is important to know about them, all the same.

          @@ -266,11 +268,11 @@ before you start editing, if you want, but most people just wait until they are ready to commit. To merge two branches back together, first [/help/update | update] to the branch you want to merge into. - Then do a [/help/merge|merge] another branch that you want to incorporate + Then do a [/help/merge|merge] of the other branch that you want to incorporate the changes from. For example, to merge "featureX" changes into "trunk" do this:

          fossil [/help/update|update] trunk
          @@ -280,11 +282,11 @@

          The argument to the [/help/merge|merge] command can be any of the version identifier forms that work for [/help/update|update]. ([./checkin_names.wiki|more info].) - The merge command has options to cherrypick individual + The merge command has options to cherry-pick individual changes, or to back out individual changes, if you don't want to do a full merge.

          The merge command puts all changes in your working check-out. No changes are made to the repository. @@ -336,17 +338,18 @@ server. For cross-machine collaboration, use the server command, which binds on all IP addresses and does not try to start a web browser.

          Servers are also easily configured as:

            -
          • [./server.wiki#inetd|inetd/xinetd] -
          • [./server.wiki#cgi|CGI] -
          • [./server.wiki#scgi|SCGI] +
          • [./server/any/inetd.md|inetd] +
          • [./server/debian/service.md|systemd] +
          • [./server/any/cgi.md|CGI] +
          • [./server/any/scgi.md|SCGI]

          The [./selfhost.wiki | self-hosting fossil repositories] use - CGI. + CGI.

          HTTP Proxies

          If you are behind a restrictive firewall that requires you to use @@ -382,19 +385,21 @@

          Or unset the environment variable. The fossil setting for the HTTP proxy takes precedence over the environment variable and the command-line option overrides both. If you have an persistent proxy setting that you want to override for a one-time sync, that is easily done on the command-line. For example, to sync with - a co-workers repository on your LAN, you might type:

          + a co-workers repository on your LAN, you might type:

          fossil sync http://192.168.1.36:8080/ --proxy off
          -

          More Hints

          - -

          A [/help | complete list of commands] is available, as is the - [./hints.wiki|helpful hints] document. See the - [./permutedindex.html#pindex|permuted index] for additional - documentation. - -

          Explore and have fun!

          + + + Index: www/quotes.wiki ================================================================== --- www/quotes.wiki +++ www/quotes.wiki @@ -5,19 +5,19 @@ by the creator of Fossil, so of course there is selection bias...

          On The Usability Of Git:

            -
          1. Git approaches the usability of iptables, which is to say, utterly +
          2. Git approaches the usability of iptables, which is to say, utterly unusable unless you have the manpage tattooed on you arm.
            by mml at [http://news.ycombinator.com/item?id=1433387]
          3. It's simplest to think of the state of your [git] repository -as a point in a high-dimensional "code-space", in which branches are +as a point in a high-dimensional "code-space", in which branches are represented as n-dimensional membranes, mapping the spatial loci of successive commits onto the projected manifold of each cloned repository.
            @@ -25,11 +25,11 @@
          4. Git is not a Prius. Git is a Model T. Its plumbing and wiring sticks out all over the place. You have to be a mechanic to operate it successfully or you'll be -stuck on the side of the road when it breaks down. +stuck on the side of the road when it breaks down. And it will break down.
            Nick Farina at [http://nfarina.com/post/9868516270/git-is-simpler]
            @@ -39,11 +39,11 @@
            Linus Torvalds - 2005-04-07 22:13:13
            Commit comment on the very first source-code check-in for git
            -
          5. I've been experimenting a lot with git at work. +
          6. I've been experimenting a lot with git at work. Damn, it's complicated. It has things to trip you up with that sane people just wouldn't ever both with including the ability to allow you to commit stuff in such a way that you can't find it again afterwards (!!!) Demented workflow complexity on acid? @@ -104,19 +104,19 @@
            Joe Prostko at [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg16716.html]
            -
          7. Fossil is awesome!!! I have never seen an app like that before, +
          8. Fossil is awesome!!! I have never seen an app like that before, such simplicity and flexibility!!!
            zengr at [http://stackoverflow.com/questions/138621/best-version-control-for-lone-developer]
          9. This is my favourite VCS. I can carry it on a USB. And it's a complete system, with it's own -server, ticketing system, Wiki pages, and a very, very helpful timeline visualization. And +server, ticketing system, Wiki pages, and a very, very helpful timeline visualization. And the entire program in a single file!
            thunderbong commenting on hacker news: [https://news.ycombinator.com/item?id=9131619]
            @@ -127,30 +127,38 @@

            On Git Versus Fossil

            1. -Just want to say thanks for fossil making my life easier.... +After prolonged exposure to fossil, i tend to get the jitters when I work with git... + +
              +sriku - at [https://news.ycombinator.com/item?id=16104427] +
              + + +
            2. +Just want to say thanks for fossil making my life easier.... Also [for] not having a misanthropic command line interface.
              Joshua Paine at [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg02736.html]
            3. We use it at a large university to manage code that small teams write. -The runs everywhere, ease of installation and portability is something that -seems to be a good fit with the environment we have (highly ditrobuted, -sometimes very restrictive firewalls, OSX/Win/Linux). We are happy with it -and teaching a Msc/Phd student (read complete novice) fossil has just +The runs everywhere, ease of installation and portability is something that +seems to be a good fit with the environment we have (highly ditrobuted, +sometimes very restrictive firewalls, OSX/Win/Linux). We are happy with it +and teaching a Msc/Phd student (read complete novice) fossil has just been a smoother ride than Git was.
              viablepanic at [http://www.reddit.com/r/programming/comments/bxcto/why_not_fossil_scm/]
              -
            4. In the fossil community - and hence in fossil itself - development history -is pretty much sacrosanct. The very name "fossil" was to chosen to +
            5. In the fossil community - and hence in fossil itself - development history +is pretty much sacrosanct. The very name "fossil" was to chosen to reflect the unchanging nature of things in that history.

              In git (or rather, the git community), the development history is part of the published aspect of the project, so it provides tools for rearranging that history so you can present what you "should" have done rather ADDED www/rebase01.graphml Index: www/rebase01.graphml ================================================================== --- /dev/null +++ www/rebase01.graphml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + C0 + + + + + + + + + + + C1 + + + + + + + + + + + C2 + + + + + + + + + + + C3 + + + + + + + + + + + C5 + + + + + + + + + + + C4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADDED www/rebase01.svg Index: www/rebase01.svg ================================================================== --- /dev/null +++ www/rebase01.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + C0 + + + + + + + C1 + + + + + + + C2 + + + + + + + C3 + + + + + + + C5 + + + + + + + C4 + + + + + + + + + + + + + + + ADDED www/rebase02.graphml Index: www/rebase02.graphml ================================================================== --- /dev/null +++ www/rebase02.graphml @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + C0 + + + + + + + + + + + C1 + + + + + + + + + + + C2 + + + + + + + + + + + C3 + + + + + + + + + + + C4' + + + + + + + + + + + C4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADDED www/rebase02.svg Index: www/rebase02.svg ================================================================== --- /dev/null +++ www/rebase02.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + C0 + + + + + + + C1 + + + + + + + C2 + + + + + + + C3 + + + + + + + C4' + + + + + + + C4 + + + + + + + + + + + + + ADDED www/rebase03.graphml Index: www/rebase03.graphml ================================================================== --- /dev/null +++ www/rebase03.graphml @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + main + + + + + + + + + + + feature + + + + + + + + + + + C0 + + + + + + + + + + + C1 + + + + + + + + + + + C2 + + + + + + + + + + + C6 + + + + + + + + + + + C4 + + + + + + + + + + + C3 + + + + + + + + + + + C5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADDED www/rebase03.svg Index: www/rebase03.svg ================================================================== --- /dev/null +++ www/rebase03.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + main + + + + + + + feature + + + + + + + C0 + + + + + + + C1 + + + + + + + C2 + + + + + + + C6 + + + + + + + C4 + + + + + + + C3 + + + + + + + C5 + + + + + + + + + + + + + + + ADDED www/rebase04.graphml Index: www/rebase04.graphml ================================================================== --- /dev/null +++ www/rebase04.graphml @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + C0 + + + + + + + + + + + C1 + + + + + + + + + + + C2 + + + + + + + + + + + C6 + + + + + + + + + + + C4 + + + + + + + + + + + C3 + + + + + + + + + + + C5 + + + + + + + + + + + C3' + + + + + + + + + + + C5' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADDED www/rebase04.svg Index: www/rebase04.svg ================================================================== --- /dev/null +++ www/rebase04.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + C0 + + + + + + + C1 + + + + + + + C2 + + + + + + + C6 + + + + + + + C4 + + + + + + + C3 + + + + + + + C5 + + + + + + + C3' + + + + + + + C5' + + + + + + + + + + + + + + + + + + + ADDED www/rebase05.graphml Index: www/rebase05.graphml ================================================================== --- /dev/null +++ www/rebase05.graphml @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + C0 + + + + + + + + + + + C1 + + + + + + + + + + + C2 + + + + + + + + + + + C6 + + + + + + + + + + + C4 + + + + + + + + + + + C3 + + + + + + + + + + + C5 + + + + + + + + + + + C7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ADDED www/rebase05.svg Index: www/rebase05.svg ================================================================== --- /dev/null +++ www/rebase05.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + C0 + + + + + + + C1 + + + + + + + C2 + + + + + + + C6 + + + + + + + C4 + + + + + + + C3 + + + + + + + C5 + + + + + + + C7 + + + + + + + + + + + + + + + + + + + ADDED www/rebaseharm.md Index: www/rebaseharm.md ================================================================== --- /dev/null +++ www/rebaseharm.md @@ -0,0 +1,425 @@ +# Rebase Considered Harmful + +Fossil deliberately omits a "rebase" command because the original +designer of Fossil (and [original author][vhist] of this article) considers rebase to be +an anti-pattern to be avoided. This article attempts to +explain that point of view. + +[vhist]: /finfo?name=www/rebaseharm.md&ubg + +## 1.0 Rebasing is dangerous + +Most people, even strident advocates of rebase, agree that rebase can +cause problems when misused. The Git rebase documentation talks about the +[golden rule of rebasing][golden]: never rebase on a public +branch. Horror stories of misused rebase abound, and the rebase +documentation devotes considerable space toward explaining how to +recover from rebase errors and/or misuse. + +## 2.0 Rebase provides no new capabilities + +Sometimes sharp and dangerous tools are justified, +because they accomplish things that cannot be +done otherwise, or at least cannot be done easily. +Rebase does not fall into that category, +because it provides no new capabilities. + +### 2.1 A rebase is just a merge with historical references omitted + +A rebase is really nothing more than a merge (or a series of merges) +that deliberately forgets one of the parents of each merge step. +To help illustrate this fact, +consider the first rebase example from the +[Git documentation][gitrebase]. The merge looks like this: + +![merge case](./rebase01.svg) + +And the rebase looks like this: + +![rebase case](./rebase02.svg) + +As the [Git documentation][gitrebase] points out, check-ins C4\' and C5 +are identical. The only difference between C4\' and C5 is that C5 +records the fact that C4 is its merge parent but C4\' does not. + +Thus, a rebase is just a merge that forgets where it came from. + +The Git documentation acknowledges this fact (in so many words) and +justifies it by saying "rebasing makes for a cleaner history." I read +that sentence as a tacit admission that the Git history display +capabilities are weak and need active assistance from the user to +keep things manageable. +Surely a better approach is to record +the complete ancestry of every check-in but then fix the tool to show +a "clean" history in those instances where a simplified display is +desirable and edifying, but retain the option to show the real, +complete, messy history for cases where detail and accuracy are more +important. + +So, another way of thinking about rebase is that it is a kind of +merge that intentionally forgets some details in order to +not overwhelm the weak history display mechanisms available in Git. +Wouldn't it be better, less error-prone, and easier on users +to enhance the history display mechanisms in Git so that rebasing +for a clean, linear history became unnecessary? + +### 2.2 Rebase does not actually provide better feature-branch diffs + +Another argument, often cited, is that rebasing a feature branch +allows one to see just the changes in the feature branch without +the concurrent changes in the main line of development. +Consider a hypothetical case: + +![unmerged feature branch](./rebase03.svg) + +In the above, a feature branch consisting of check-ins C3 and C5 is +run concurrently with the main line in check-ins C4 and C6. Advocates +for rebase say that you should rebase the feature branch to the tip +of main in order to remove main-line development differences from +the feature branch's history: + +![rebased feature branch](./rebase04.svg) + +You could choose to collapse C3\' and C5\' into a single check-in +as part of this rebase, but that's a side issue we'll deal with +[separately](#collapsing). + +Because Fossil purposefully lacks rebase, the closest you can get to this same check-in +history is the following merge: + +![merged feature branch](./rebase05.svg) + +Check-ins C5\' and C7 check-ins hold identical code. The only +difference is in their history. + +The argument from rebase advocates +is that with merge it is difficult to see only the changes associated +with the feature branch without the commingled mainline changes. +In other words, diff(C2,C7) shows changes from both the feature +branch and from the mainline, whereas in the rebase case +diff(C6,C5\') shows only the feature branch changes. + +But that argument is comparing apples to oranges, since the two diffs +do not have the same baseline. The correct way to see only the feature +branch changes in the merge case is not diff(C2,C7) but rather diff(C6,C7). + +

              +
              RebaseMergeWhat You See +
              diff(C2,C5\')diff(C2,C7)Commingled branch and mainline changes +
              diff(C6,C5\')diff(C6,C7)Branch changes only +
              + +Remember: C7 and C5\' are bit-for-bit identical, so the output of the +diff is not determined by whether you select C7 or C5\' as the target +of the diff, but rather by your choice of the diff source, C2 or C6. + +So, to help with the problem of viewing changes associated with a feature +branch, perhaps what is needed is not rebase but rather better tools to +help users identify an appropriate baseline for their diffs. + +## 3.0 Rebase encourages siloed development + +The [golden rule of rebasing][golden] is that you should never do it +on public branches, so if you are using rebase as intended, that means +you are keeping private branches. Or, to put it another way, you are +doing siloed development. You are not sharing your intermediate work +with collaborators. This is not good for product quality. + +[Nagappan, et. al][nagappan] studied bugs in Windows Vista and found +that best predictor of bugs is the distance on the org-chart between +the stake-holders. The bug rate is inversely related to the +amount of communication among the engineers. +Similar findings arise in other disciplines. Keeping +private branches does not prove that developers are communicating +insufficiently, but it is a key symptom that problem. + +[Weinberg][weinberg] argues programming should be "egoless." That +is to say, programmers should avoid linking their code with their sense of +self, as that makes it more difficult for them to find and respond +to bugs, and hence makes them less productive. Many developers are +drawn to private branches out of sense of ego. "I want to get the +code right before I publish it." I sympathize with this sentiment, +and am frequently guilty of it myself. It is humbling to display +your stupid mistake to the whole world on an Internet that +never forgets. And yet, humble programmers generate better code. + +What is the fastest path to solid code? Is it to continue staring at +your private branch to seek out every last bug, or is it to publish it +as-is, whereupon the many eyeballs will immediately see that last stupid +error in the code? Testing and development are often done by separate +groups within a larger software development organization, because +developers get too close to their own code to see every problem in it. + +Given that, is it better for those many eyeballs to find your problems +while they're still isolated on a feature branch, or should that vetting +wait until you finally push a collapsed version of a private working +branch to the parent repo? Will the many eyeballs even see those errors +when they’re intermingled with code implementing some compelling new feature? + +## 4.0 Rebase commits untested check-ins to the blockchain + +Rebase adds new check-ins to the blockchain without giving the operator +an opportunity to test and verify those check-ins. Just because the +underlying three-way merge had no conflict does not mean that the resulting +code actually works. Thus, rebase runs the very real risk of adding +non-functional check-ins to the permanent record. + +Of course, a user can also commit untested or broken check-ins without +the help of rebase. But at least with an ordinary commit or merge +(in Fossil at least), the operator +has the *opportunity* to test and verify the merge before it is committed, +and a chance to back out or fix the change if it is broken without leaving +busted check-ins on the blockchain to complicate future bisects. + +With rebase, pre-commit testing is not an option. + +## 5.0 Rebase causes timestamp confusion + +Consider the earlier example of rebasing a feature branch: + +![rebased feature branch, again](./rebase04.svg) + +What timestamps go on the C3\' and C5\' check-ins? If you choose +the same timestamps as the original C3 and C5, then you have the +odd situation C3' is older than its parent C6. We call that a +"timewarp" in Fossil. Timewarps can also happen due to misconfigured +system clocks, so they are not unique to rebase, but they are very +confusing and so best avoided. The other option is to provide new +unique timestamps for C3' and C5' but then you lose the information +about when those check-ins were originally created, which can make +historical analysis of changes more difficult. It might also +complicate the legal defense of prior art claims. + +## 6.0 Rebasing is lying about the project history + +By discarding parentage information, rebase attempts to deceive the +reader about how the code actually came together. + +The [Git rebase documentation][gitrebase] admits as much. They acknowledge +that when you view a repository as record of what actually happened, +doing a rebase is "blasphemous" and "you're _lying_ about what +actually happened", but then goes on to justify rebase as follows: + +> +_"The opposing point of view is that the commit history is the **story of +how your project was made.** You wouldn't publish the first draft of a +book, and the manual for how to maintain your software deserves careful +editing. This is the camp that uses tools like rebase and filter-branch +to tell the story in the way that's best for future readers."_ + +This counter-argument assumes you must +change history in order to enhance readability, which is not true. + +In fairness to the Git documentation authors, changing the +project history appears to be the only way to make editorial +changes in Git. +But it does not have to be that way. +Fossil demonstrates how "the story of your project" +can be enhanced without changing the actual history +by allowing users to: + + 1. Edit check-in comments to fix typos or enhance clarity + 2. Attach supplemental notes to check-ins or whole branches + 3. Cross-reference check-ins with each other, or with + wiki, tickets, forum posts, and/or embedded documentation + 4. Cause mistaken or unused branches to be hidden from + routine display + 5. Fix faulty check-in date/times resulting from misconfigured + system clocks + 6. And so forth.... + +These changes are accomplished not by removing or modifying existing +repository entries, but rather by adding new supplemental records. +The original incorrect or unclear inputs are preserved and are +readily accessible. The original history is preserved. +But for routine display purposes, the more +readable edited presentation is provided. + +A repository can be a true and accurate +representation of history even without getting everything perfect +on the first draft. Those are not contradictory goals, at least +not in theory. + +Unfortunately, Git does not currently provide the ability to add +corrections or clarifications or supplimental notes to historical check-ins. +Hence, once again, +rebase can be seen as an attempt to work around limitations +of Git. Git could be enhanced to support editorial changes +to check-ins. +Wouldn't it be better to fix the version control tool +rather than requiring users to fabricate a fictitious project history? + +## 7.0 Collapsing check-ins throws away valuable information + +One of the oft-cited advantages of rebasing in Git is that it lets you +collapse multiple check-ins down to a single check-in to make the +development history “clean.” The intent is that development appear as +though every feature were created in a single step: no multi-step +evolution, no back-tracking, no false starts, no mistakes. This ignores +actual developer psychology: ideas rarely spring forth from fingers to +files in faultless finished form. A wish for collapsed, finalized +check-ins is a wish for a counterfactual situation. + +The common counterargument is that collapsed check-ins represent a +better world, the ideal we're striving for. What that argument overlooks +is that we must throw away valuable information to get there. + +### 7.1 Individual check-ins support developer empathy + +Ideally, future developers of our software can understand every feature +in it using only context available in the version of the code they start +work with. Prior to widespread version control, developers had no choice +but to work that way. Pre-existing codebases could only be understood +as-is or not at all. Developers in that world had an incentive to +develop software that was easy to understand retrospectively, even if +they were selfish people, because they knew they might end up being +those future developers! + +Yet, sometimes we come upon a piece of code that we simply cannot +understand. If you have never asked yourself, "What was this code's +developer thinking?" you haven't been developing software for very long. + +When a developer can go back to the individual check-ins leading up to +the current code, they can work out the answers to such questions using +only the level of empathy necessary to be a good developer. To +understand such code using only the finished form, you are asking future +developers to make intuitive leaps that the original developer was +unable to make. In other words, you are asking your future maintenance +developers to be smarter than the original developers! That's a +beautiful wish, but there's a sharp limit to how far you can carry it. +Eventually you hit the limits of human brilliance. + +When the operation of some bit of code is not obvious, both Fossil and +Git let you run a [`blame`](/help?cmd=blame) on the code file to get +information about each line of code, and from that which check-in last +touched a given line of code. If you squash the check-ins on a branch +down to a single check-in, you throw away the information leading up to +that finished form. Fossil not only preserves the check-ins surrounding +the one that included the line of code you're trying to understand, its +[superior data model][sdm] lets you see the surrounding check-ins in +both directions; not only what lead up to it, but what came next. Git +can't do that short of crawling the block-chain backwards from the tip +of the branch to the check-in you’re looking at, an expensive operation. + +We believe it is easier to understand a line of code from the 10-line +check-in it was a part of — and then to understand the surrounding +check-ins as necessary — than it is to understand a 500-line check-in +that collapses a whole branch's worth of changes down to a single +finished feature. + +[sdm]: ./fossil-v-git.wiki#durable + +### 7.2 Bisecting works better on small check-ins + +Git lets a developer write a feature in ten check-ins but collapse it +down to an eleventh check-in and then deliberately push only that final +collapsed check-in to the parent repo. Someone else may then do a bisect +that blames the merged check-in as the source of the problem they’re +chasing down; they then have to manually work out which of the 10 steps +the original developer took to create it to find the source of the +actual problem. + +An equivalent push in Fossil will send all 11 check-ins to the parent +repository so that a later investigator doing the same sort of bisect +sees the complete check-in history. That bisect will point the +investigator at the single original check-in that caused the problem. + +### 7.3 Multiple check-ins require multiple check-in comments + +The more comments you have from a given developer on a given body of +code, the more concise documentation you have of that developer's +thought process. To resume the bisecting example, a developer trying to +work out what the original developer was thinking with a given change +will have more success given a check-in comment that explains what the +one check-in out of ten blamed by the "bisect" command was trying to +accomplish than if they must work that out from the eleventh check-in's +comment, which only explains the "clean" version of the collapsed +feature. + +### 7.4 Cherry-picks work better with small check-ins + +While working on a new feature in one branch, you may come across a bug +in the pre-existing code that you need to fix in order for work on that +feature to proceed. You could choose to switch briefly back to the +parent branch, develop the fix there, check it in, then merge the parent +back up to the feature branch in order to continue work, but that's +distracting. If the fix isn't for a critical bug, fixing it on the +parent branch can wait, so it's better to maintain your mental working +state by fixing the problem in place on the feature branch, then check +the fix in on the feature branch, resume work on the feature, and later +merge that fix down into the parent branch along with the feature. + +But now what happens if another branch *also* needs that fix? Let us say +our code repository has a branch for the current stable release, a +development branch for the next major version, and feature branches off +of the development branch. If we rebase each feature branch down into +the development branch as a single check-in, pushing only the rebase +check-in up to the parent repo, only that fix's developer has the +information locally to perform the cherry-pick of the fix onto the +stable branch. + +Developers working on new features often do not care about old stable +versions, yet that stable version may have an end user community that +depends on that version, who either cannot wait for the next stable +version or who wish to put off upgrading to it for some time. Such users +want backported bug fixes, yet the developers creating those fixes have +poor incentives to provide those backports. Thus the existence of +maintenance and support organizations, who end up doing such work. +(There is [a famous company][rh] that built a multi-billion dollar +enterprise on such work.) + +This work is far easier when each cherry-pick transfers completely and +cleanly from one branch to another, and we increase the likelihood of +achieving that state by working from the smallest check-ins that remain +complete. If a support organization must manually disentangle a fix from +a feature check-in, they are likely to introduce new bugs on the stable +branch. Even if they manage to do their work without error, it takes +them more time to do the cherry-pick that way. + +[rh]: https://en.wikipedia.org/wiki/Red_Hat + +### 7.5 Back-outs also work better with small check-ins + +The inverse of the cherry-pick merge is the back-out merge. If you push +only a collapsed version of a private working branch up to the parent +repo, those working from that parent repo cannot automatically back out +any of the individual check-ins that went into that private branch. +Others must either manually disentangle the problematic part of your +merge check-in or back out the entire feature. + +## 8.0 Cherry-pick merges work better than rebase + +Perhaps there are some cases where a rebase-like transformation +is actually helpful, but those cases are rare, and when they do +come up, running a series of cherry-pick merges achieves the same +topology with several advantages: + + 1. Cherry-pick merges preserve an honest record of history. + (They do in Fossil at least. Git's file format does not have + a slot to record cherry-pick merge history, unfortunately.) + + 2. Cherry-picks provide an opportunity to [test each new check-in + before it is committed][tbc] to the blockchain + + 3. Cherry-pick merges are "safe" in the sense that they do not + cause problems for collaborators if you do them on public branches. + + 4. Cherry-picks keep both the original and the revised check-ins, + so both timestamps are preserved. + +[tbc]: ./fossil-v-git.wiki#testing + +## 9.0 Summary and conclusion + +Rebasing is an anti-pattern. It is dishonest. It deliberately +omits historical information. It causes problems for collaboration. +And it has no offsetting benefits. + +For these reasons, rebase is intentionally and deliberately omitted +from the design of Fossil. + + +[golden]: https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing +[gitrebase]: https://git-scm.com/book/en/v2/Git-Branching-Rebasing +[nagappan]: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-2008-11.pdf +[weinberg]: https://books.google.com/books?id=76dIAAAAMAAJ Index: www/reviews.wiki ================================================================== --- www/reviews.wiki +++ www/reviews.wiki @@ -1,8 +1,8 @@ Reviews External links: - + * [http://nixtu.blogspot.com/2010/03/fossil-dvcs-on-go-first-impressions.html | Fossil DVCS on the Go - First Impressions] * [http://blog.mired.org/2011/02/fossil-sweet-spot-in-vcs-space.html | Fossil - a sweet spot in the VCS space] by Mike Meyer. * [http://blog.s11n.net/?p=72|Four reasons to take a closer look at the Fossil SCM] by Stephan Beal @@ -22,27 +22,27 @@ Joshua Paine on 2010-10-22:
              -With one of my several hats on, I'm in a small team using git. Another -team member just checked some stuff into trunk that should have been on -a branch. Nothing else had happened since, so in fossil I would have -just edited that commit and put it on a new branch. In git that can't -actually be done without danger once other people have pulled, so I had -to create a new commit rolling back the changes, then branch and cherry -pick the earlier changes, then figure out how to make my new branch -shared instead of private. Just want to say thanks for fossil making my -life easier on most of my projects, and being able to move commits to -another branch after the fact and shared-by-default branches are good +With one of my several hats on, I'm in a small team using git. Another +team member just checked some stuff into trunk that should have been on +a branch. Nothing else had happened since, so in fossil I would have +just edited that commit and put it on a new branch. In git that can't +actually be done without danger once other people have pulled, so I had +to create a new commit rolling back the changes, then branch and cherry +pick the earlier changes, then figure out how to make my new branch +shared instead of private. Just want to say thanks for fossil making my +life easier on most of my projects, and being able to move commits to +another branch after the fact and shared-by-default branches are good features. Also not having a misanthropic command line interface.
              Stephan Beal writes on 2009-01-11:
              -Sometime in late 2007 I came across a link to fossil on +Sometime in late 2007 I came across a link to fossil on sqlite.org. It was a good thing I bookmarked it, because I was never able to find the link again (it might have been in a bug report or something). The reasons I first took a close look at it were (A) it stemmed from the sqlite project, which I've held in high regards for years (e.g. I Index: www/selfcheck.wiki ================================================================== --- www/selfcheck.wiki +++ www/selfcheck.wiki @@ -13,12 +13,12 @@ part to the defensive measures described here, no data has been lost. The integrity checks are doing their job well.

              Atomic Check-ins With Rollback

              -The fossil repository is stored in an -SQLite database file. +The Fossil repository is stored in an +SQLite database file. ([./tech_overview.wiki | Addition information] about the repository file format.) SQLite is very mature and stable and has been in wide-spread use for many years, so we are confident it will not cause repository corruption. SQLite @@ -25,47 +25,47 @@ databases do not corrupt even if a program or system crash or power failure occurs in the middle of the update. If some kind of crash does occur in the middle of a change, then all the changes are rolled back the next time that the database is accessed. -A check-in operation in fossil makes many changes to the repository +A check-in operation in Fossil makes many changes to the repository database. But all these changes happen within a single transaction. If something goes wrong in the middle of the commit, even if that something is a power failure or OS crash, then the transaction is rolled back and the database is unchanged.

              Verification Of Delta Encodings Prior To Transaction Commit

              -The content files that comprise the global state of a fossil repository +The content files that comprise the global state of a Fossil repository are stored in the repository as a tree. The leaves of the tree are stored as zlib-compressed BLOBs. Interior nodes are deltas from their descendants. A lot of encoding is going on. There is zlib-compression which is relatively well-tested but still might cause corruption if used improperly. And there is the relatively -new delta-encoding mechanism designed expressly for fossil. We want +new [./delta_encoder_algorithm.wiki | delta-encoding mechanism] designed expressly for Fossil. We want to make sure that bugs in these encoding mechanisms do not lead to loss of data. To increase our confidence that everything in the repository is -recoverable, fossil makes sure it can extract an exact replica +recoverable, Fossil makes sure it can extract an exact replica of every content file that it changes just prior to transaction commit. So during the course of check-in (or other repository operation) many different files in the repository might be modified. Some files are simply compressed. Other files are delta encoded and then compressed. -While all this is going on, fossil makes a record of every file -that is encoded and the SHA1 hash of the original content of that -file. Then just before transaction commit, fossil re-extracts -the original content of all files that were written, computes -the SHA1 checksum again, and verifies that the checksums match. +While all this is going on, Fossil makes a record of every file +and the SHA1 or SHA3-256 hash of the original content of that +file. Then just before transaction commit, Fossil re-extracts +the original content of all files that were written, recomputes +the hash, and verifies that the recomputed hash still matches. If anything does not match up, an error message is printed and the transaction rolls back. -So, in other words, fossil always checks to make sure it can +So, in other words, Fossil always checks to make sure it can re-extract a file before it commits a change to that file. -Hence bugs in fossil are unlikely to corrupt the repository in -a way that prevents us from extracting historical versions of +Hence bugs in Fossil are unlikely to corrupt the repository in +a way that prevents us from extracting historical versions of files.

              Checksum Over All Files In A Check-in

              Manifest artifacts that define a check-in have two fields (the @@ -73,20 +73,20 @@ and of all other files in the manifest. Prior to any check-in commit, these checksums are verified to ensure that the check-in agrees exactly with what is on disk. Similarly, the repository checksum is verified after a checkout to make sure that the entire repository was checked out correctly. -Note that these added checks use a different hash (MD5 instead -of SHA1) in order to avoid common-mode failures in the hash +Note that these added checks use a different hash algorithm (MD5) +in order to avoid common-mode failures in the hash algorithm implementation. -

              Checksums On Control Artifacts And Deltas

              +

              Checksums On Structural Artifacts And Deltas

              -Every [./fileformat.wiki | control artifact] in a fossil repository +Every [./fileformat.wiki | structural artifact] in a Fossil repository contains a "Z-card" bearing an MD5 checksum over the rest of the -artifact. Any mismatch causes the control artifact to be ignored. +artifact. Any mismatch causes the structural artifact to be ignored. The [./delta_format.wiki | file delta format] includes a 32-bit checksum of the target file. Whenever a file is reconstructed from a delta, that checksum is verified to make sure the reconstruction was done correctly. @@ -93,16 +93,17 @@

              Reliability Versus Performance

              Some version control systems make a big deal out of being "high performance" or the "fastest version control system". Fossil makes no such claims and has -no such ambition. Indeed, profiling indicates that fossil bears a +no such ambition. Indeed, profiling indicates that Fossil bears a substantial performance cost for doing all of the checksumming and verification outlined above. Fossil takes the philosophy of the tortoise: reliability is more important than raw speed. The developers of -fossil see no merit in getting the wrong answer quickly. +Fossil see no merit in getting the wrong answer quickly. -Fossil may not be the fastest versioning system, but it is "fast enough". -Fossil runs quickly enough to stay out of the developers way. -Most operations complete in under a second. +Fossil may not be the fastest versioning system, but it is fast enough. +Fossil runs quickly enough to stay out of the developer's way. +Most operations complete in milliseconds, faster than you can press +the "Enter" key. Index: www/selfhost.wiki ================================================================== --- www/selfhost.wiki +++ www/selfhost.wiki @@ -1,29 +1,31 @@ Fossil Self-Hosting Repositories -Fossil has self-hosted since 2007-07-21. As of this writing (2009-08-24) +Fossil has self-hosted since 2007-07-21. As of 2017-07-25 there are three publicly accessible repositories for the Fossil source code: - 1. [http://www.fossil-scm.org/] - 2. [http://www2.fossil-scm.org/] - 3. [http://www3.fossil-scm.org/site.cgi] + 1. [https://www.fossil-scm.org/] + 2. [https://www2.fossil-scm.org/] + 3. [https://www3.fossil-scm.org/site.cgi] The canonical repository is (1). Repositories (2) and (3) automatically -stay in synchronization with (1) via a +stay in synchronization with (1) via a cron job that invokes "fossil sync" at regular intervals. +Repository (2) also publishes a +[./mirrortogithub.md|GitHub mirror of Fossil] as a demonstration. Note that the two secondary repositories are more than just read-only mirrors. All three servers support full read/write capabilities. -Changes (such as new tickets or wiki or check-ins) can be implemented +Changes (such as new tickets or wiki or check-ins) can be implemented on any of the three servers and those changes automatically propagate to the other two servers. Server (1) runs as a CGI script on a -Linode 1024 located in Dallas, TX -- on the same virtual machine that +Linode 8192 located in Dallas, TX +- on the same virtual machine that hosts SQLite and over a dozen other smaller projects. This demonstrates that Fossil can run on a low-power host processor. Multiple fossil-based projects can easily be hosted on the same machine, even if that machine is itself one of several dozen virtual machines on @@ -33,34 +35,43 @@
               #!/usr/bin/fossil
               repository: /fossil/fossil.fossil
               
              -Server (3) runs as a CGI script on a shared hosting account at -Hurricane Electric in Fremont, CA. -This server demonstrates the ability of +Server (3) ran for 10 years as a CGI script on a shared hosting account at +Hurricane Electric in Fremont, CA. +This server demonstrated the ability of Fossil to run on an economical shared-host web account with no privileges beyond port 80 HTTP access and CGI. It is not necessary to have a dedicated computer with administrator privileges to run Fossil. -As far as we are aware, -Fossil is the only full-featured configuration management system +As far as we are aware, +Fossil is the only full-featured configuration management system that can run in -such a restricted environment. The CGI script that runs on the -Hurricane Electric server is the same as the CGI script shown above, +such a restricted environment. The CGI script that ran on the +Hurricane Electric server was the same as the CGI script shown above, except that the pathnames are modified to suit the environment:
               #!/home/hwaci/bin/fossil
               repository: /home/hwaci/fossil/fossil.fossil
               
              + +In recent years, virtual private servers have become a more flexible and +less expensive hosting option compared to shared hosting accounts. +So on 2017-07-25, server (3) was moved +onto a $5/month "droplet" [https://en.wikipedia.org/wiki/Virtual_private_server|VPS] +from [https://www.digitalocean.com|Digital Ocean] +located in San Francisco. Server (3) is synchronized with the canonical server (1) by running the following command via cron:
               /home/hwaci/bin/fossil sync -R /home/hwaci/fossil/fossil.fossil
               
              Server (2) is a -Linode 512 located in Newark, NJ +Linode 4096 located in Newark, NJ and set up just like the canonical server (1) with the addition of a -cron job for synchronization as in server (3). +cron job for synchronization. The same cron job also runs the +[/help?cmd=git|fossil git export] command after each sync in order to +[./mirrortogithub.md#ex1|mirror all changes to GitHub]. DELETED www/server.wiki Index: www/server.wiki ================================================================== --- www/server.wiki +++ /dev/null @@ -1,371 +0,0 @@ -How To Configure A Fossil Server -

              Introduction

              -

              A server is not necessary to use Fossil, but a server does help in collaborating with -peers. A Fossil server also works well as a complete website for a project. -For example, the complete [https://www.fossil-scm.org/] website, including the -page you are now reading, -is just a Fossil server displaying the content of the -self-hosting repository for Fossil.

              -

              This article is a guide for setting up your own Fossil server. -

              See "[./aboutcgi.wiki|How CGI Works In Fossil]" for background -information on the underlying CGI technology. -See "[./sync.wiki|The Fossil Sync Protocol]" for information on the -wire protocol used for client/server communication.

              -
              -

              Overview

              -There are basically four ways to set up a Fossil server: -
                -
              1. A stand-alone server -
              2. Using inetd or xinetd or stunnel -
              3. CGI -
              4. SCGI (a.k.a. SimpleCGI) -
              -Each of these can serve either a single repository, or a directory hierarchy -containing many repositories with names ending in ".fossil". -
              - -

              Standalone server

              -The easiest way to set up a Fossil server is to use either the -[/help/server|server] or the [/help/ui|ui] commands: -
                -
              • fossil server REPOSITORY -
              • fossil ui REPOSITORY -
              -

              -The REPOSITORY argument is either the name of the repository file, or -a directory containing many repositories. -Both of these commands start a Fossil server, usually on TCP port 8080, though -a higher numbered port might also be used if 8080 is already occupied. You can -access these using URLs of the form http://localhost:8080/, or if -REPOSITORY is a directory, URLs of the form -http://localhost:8080/repo/ where repo is the base -name of the repository file without the ".fossil" suffix. -The difference between "ui" and "server" is that "ui" will -also start a web browser and point it -to the URL mentioned above, and the "ui" command binds to -the loopback IP address (127.0.0.1) only so that the "ui" command cannot be -used to serve content to a different machine. -

              -

              -If one of the commands above is run from within an open checkout, -then the REPOSITORY argument can be omitted and the checkout is used as -the repository. -

              -

              -Both commands have additional command-line options that can be used to refine -their behavior. See the [/help/server|online documentation] for an overview. -

              -
              - -

              Fossil as an inetd/xinetd or stunnel service

              -

              -A Fossil server can be launched on-demand by inetd or xinetd using -the [/help/http|fossil http] command. To launch Fossil from inetd, modify -your inetd configuration file (typically "/etc/inetd.conf") to contain a -line something like this: -

              -
              -80 stream tcp nowait.1000 root /usr/bin/fossil /usr/bin/fossil http /home/fossil/repo.fossil
              -
              -
              -In this example, you are telling "inetd" that when an incoming connection -appears on TCP port "80", that it should launch the binary "/usr/bin/fossil" -program with the arguments shown. -Obviously you will -need to modify the pathnames for your particular setup. -The final argument is either the name of the fossil repository to be served, -or a directory containing multiple repositories. -

              -

              -If you use a non-standard TCP port on -systems where the port-specification must be a symbolic name and cannot be -numeric, add the desired name and port to /etc/services. For example, if -you want your Fossil server running on TCP port 12345 instead of 80, you -will need to add: -

              -
              -fossil          12345/tcp  #fossil server
              -
              -
              -and use the symbolic name ('fossil' in this example) instead of the numeral ('12345') -in inetd.conf. For details, see the relevant section in your system's documentation, e.g. -the [https://www.freebsd.org/doc/en/books/handbook/network-inetd.html|FreeBSD Handbook] in -case you use FreeBSD. -

              -

              -If your system is running xinetd, then the configuration is likely to be -in the file "/etc/xinetd.conf" or in a subfile of "/etc/xinetd.d". -An xinetd configuration file will appear like this:

              -
              -
              -service http
              -{
              -  port = 80
              -  socket_type = stream
              -  wait = no
              -  user = root
              -  server = /usr/bin/fossil
              -  server_args = http /home/fossil/repos/
              -}
              -
              -
              -

              -The xinetd example above has Fossil configured to serve multiple -repositories, contained under the "/home/fossil/repos/" directory. -

              -

              -In both cases notice that Fossil was launched as root. This is not required, -but if it is done, then Fossil will automatically put itself into a chroot -jail for the user who owns the fossil repository before reading any information -off of the wire. -

              -

              -Inetd or xinetd must be enabled, and must be (re)started whenever their configuration -changes - consult your system's documentation for details. -

              -

              -[https://www.stunnel.org/ | Stunnel version 5] is an inetd-like process that -accepts and decodes SSL-encrypted connections. Fossil can be run directly from -stunnel in a manner similar to inetd and xinetd. This can be used to provide -a secure link to a Fossil project. The configuration needed to get stunnel5 -to invoke Fossil is very similar to the inetd and xinetd examples shown above. -The relevant parts of an stunnel configuration might look something -like the following: -

              
              -[https]
              -accept       = www.ubercool-project.org:443
              -TIMEOUTclose = 0
              -exec         = /usr/bin/fossil
              -execargs     = /usr/bin/fossil http /home/fossil/ubercool.fossil --https
              -
              -See the stunnel5 documentation for further details about the /etc/stunnel/stunnel.conf -configuration file. Note that the [/help/http|fossil http] command should include -the --https option to let Fossil know to use "https" instead of "http" as the scheme -on generated hyperlinks. -

              -Using inetd or xinetd or stunnel is a more complex setup -than the "standalone" server, but it has the -advantage of only using system resources when an actual connection is -attempted. If no-one ever connects to that port, a Fossil server will -not (automatically) run. It has the disadvantage of requiring "root" access -and therefore may not normally be available to lower-priced "shared" servers -on the internet. -

              -
              - -

              Fossil as CGI

              -

              -A Fossil server can also be run from an ordinary web server as a CGI program. -This feature allows Fossil to be seamlessly integrated into a larger website. -CGI is how the [./selfhost.wiki | self-hosting fossil repositories] are -implemented. -

              -

              -To run Fossil as CGI, create a CGI script (here called "repo") in the CGI directory -of your web server and having content like this: -

              -#!/usr/bin/fossil
              -repository: /home/fossil/repo.fossil
              -
              -

              - -

              -As always, adjust your paths appropriately. -It may be necessary to set permissions properly, or to modify an ".htaccess" -file or make other server-specific changes. Consult the documentation -for your particular web server. In particular, the following permissions are -normally required (but, again, may be different for a particular -configuration): - -

                -
              • The Fossil binary must be readable/executable, and ALL directories leading up to it -must be readable by the process which executes the CGI.
              • -
              • ALL directories leading to the CGI script must also be readable and the CGI -script itself must be executable for the user under which it will run (which often differs -from the one running the web server - consult your site's documentation or administrator).
              • -
              • The repository file AND the directory containing it must be writable by the same account -which executes the Fossil binary (again, this might differ from the WWW user). The directory -needs to be writable so that sqlite can write its journal files.
              • -
              • Fossil must be able to create temporary files, the default directory -for which depends on the OS. When the CGI process is operating within -a chroot, ensure that this directory exists and is readable/writeable -by the user who executes the Fossil binary.
              • -
              -

              - -

              -Once the script is set up correctly, and assuming your server is also set -correctly, you should be able to access your repository with a URL like: -http://mydomain.org/cgi-bin/repo (assuming the "repo" script is -accessible under "cgi-bin", which would be a typical deployment on Apache -for instance). -

              -

              -To serve multiple repositories from a directory using CGI, use the "directory:" -tag in the CGI script rather than "repository:". You might also want to add -a "notfound:" tag to tell where to redirect if the particular repository requested -by the URL is not found: -

              -#!/usr/bin/fossil
              -directory: /home/fossil/repos
              -notfound: http://url-to-go-to-if-repo-not-found/
              -
              -

              -

              -Once deployed, a URL like: http://mydomain.org/cgi-bin/repo/XYZ -will serve up the repository "/home/fossil/repos/XYZ.fossil" (if it exists). -

              -
              - - -

              Fossil as SCGI

              - -

              -The [/help/server|fossil server] command, described above as a way of -starting a stand-alone web server, can also be used for SCGI. Simply add -the --scgi command-line option and the stand-alone server will interpret -and respond to the SimpleCGI or SCGI protocol rather than raw HTTP. This can -be used in combination with a webserver (such as [http://nginx.org|Nginx]) -that does not support CGI. A typical Nginx configuration to support SCGI -with Fossil would look something like this: -

              -location /demo_project/ {
              -    include scgi_params;
              -    scgi_pass localhost:9000;
              -    scgi_param SCRIPT_NAME "/demo_project";
              -    scgi_param HTTPS "on";
              -}
              -
              -

              -Note that Fossil requires the SCRIPT_NAME variable -in order to function properly, but Nginx does not provide this -variable by default. -So it is necessary to provide the SCRIPT_NAME parameter in the configuration. -Failure to do this will cause Fossil to return an error. -

              -

              -All of the features of the stand-alone server mode described above, -such as the ability to serve a directory full of Fossil repositories -rather than just a single repository, work the same way in SCGI mode. -

              -

              -For security, it is probably a good idea to add the --localhost option -to the [/help/server|fossil server] command to prevent Fossil from accepting -off-site connections. And one might want to specify the listening TCP port -number, rather than letting Fossil choose one for itself, just to avoid -ambiguity. A typical command to start a Fossil SCGI server -would be something like this: -

              -fossil server $REPOSITORY --scgi --localhost --port 9000
              -
              -
              - -

              Securing a repository with SSL

              -

              -Using either CGI or SCGI, it is trivial to use SSL to -secure the server. Simply set up the Fossil CGI scripts etc. as above, -but modify the Apache (or IIS, etc.) server to require SSL (that is, a -URL with "https://") in order to access the CGI script directory. This -may also be accomplished (on Apache, at least) using appropriate -".htaccess" rules. -

              -

              -If you are using "inetd" to serve your repository, then you simply need -to add "/usr/bin/stunnel" (perhaps on a different path, depending on your -setup) before the command line to launch Fossil. -

              -

              -At this stage, the standalone server (e.g. "fossil server") does not -support SSL. -

              -

              -For more information, see Using SSL with Fossil. -

              -
              - - -

              Managing Server Load

              -

              -A Fossil server is very efficient and normally presents a very light -load on the server. -The Fossil [./selfhost.wiki | self-hosting server] is a 1/24th slice VM at -[http://www.linode.com | Linode.com] hosting 65 other repositories in -addition to Fossil (and including some very high-traffic sites such -as [http://www.sqlite.org] and [http://system.data.sqlite.org]) and -it has a typical load of 0.05 to 0.1. A single HTTP request to Fossil -normally takes less than 10 milliseconds of CPU time to complete. So -requests can be arriving at a continuous rate of 20 or more per second -and the CPU can still be mostly idle. -

              -However, there are some Fossil web pages that can consume large -amounts of CPU time, especially on repositories with a large number -of files or with long revision histories. High CPU usage pages include -[/help?cmd=/zip | /zip], [/help?cmd=/tarball | /tarball], -[/help?cmd=/annotate | /annotate] and others. On very large repositories, -these commands can take 15 seconds or more of CPU time. -If these kinds of requests arrive too quickly, the load average on the -server can grow dramatically, making the server unresponsive. -

              -Fossil provides two capabilities to help avoid server overload problems -due to excessive requests to expensive pages: -

                -
              1. An optional cache is available that remembers the 10 most recently - requested /zip or /tarball pages and returns the precomputed answer - if the same page is requested again. -

              2. Page requests can be configured to fail with a - [http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.3 | "503 Server Overload"] - HTTP error if an expensive request is received while the host load - average is too high. -

              -Both of these load-control mechanisms are turned off by default, but they -are recommended for high-traffic sites. -

              -The webpage cache is activated using the [/help?cmd=cache|fossil cache init] -command-line on the server. Add a -R option to specify the specific repository -for which to enable caching. If running this command as root, be sure to -"chown" the cache database (which is a separate file in the same directory -and with the same name as the repository but with the suffix changed to ".cache") -to give it write permission for the userid of the webserver. -

              -To activate the server load control feature -visit the /Admin/Access setup page in the administrative web -interface and in the "Server Load Average Limit" box -enter the load average threshold above which "503 Server -Overload" replies will be issued for expensive requests. On the -self-host Fossil server, that value is set to 1.5. But you could easily -set it higher on a multi-core server. -

              -The maximum load average can also be set on the command line using -commands like this: -

              -fossil set max-loadavg 1.5
              -fossil all set max-loadavg 1.5
              -
              -The second form is especially useful for changing the maximum load average -simultaneously on a large number of repositories. -

              -Note that this load-average limiting feature is only available on operating -systems that support the "getloadavg()" API. Most modern Unix systems have -this interface, but Windows does not, so the feature will not work on Windows. -Note also that Linux implements "getloadavg()" by accessing the "/proc/loadavg" -file in the "proc" virtual filesystem. If you are running a Fossil instance -inside a chroot() jail on Linux, you will need to make the "/proc" file -system available inside that jail in order for this feature to work. On -the self-hosting Fossil repository, this was accomplished by adding a line -to the "/etc/fstab" file that looks like: -

              -chroot_jail_proc /home/www/proc proc ro 0 0
              -
              -The /home/www/proc pathname should be adjusted so that the "/proc" component is -in the root of the chroot jail, of course. -

              -To see if the load-average limiter is functional, visit the [/test_env] page -of the server to view the current load average. If the value for the load -average is greater than zero, that means that it is possible to activate -the load-average limiter on that repository. If the load average shows -exactly "0.0", then that means that Fossil is unable to find the load average -(either because it is in a chroot() jail without /proc access, or because -it is running on a system that does not support "getloadavg()") and so the -load-average limiter will not function. - -

              ADDED www/server/any/althttpd.md Index: www/server/any/althttpd.md ================================================================== --- /dev/null +++ www/server/any/althttpd.md @@ -0,0 +1,42 @@ +# Serving via althttpd + +[Althttpd][althttpd] +is a light-weight web server that has been used to implement the SQLite and +Fossil websites for well over a decade. Althttpd strives for simplicity, +security, ease of configuration, and low resource usage. + +To set up a Fossil server as CGI on a host running the althttpd web +server, follow these steps. +
                +Get the althttpd webserver running on the host. This is easily +done by following the [althttpd documentation][althttpd]. + +
              1. Create a CGI script for your Fossil respository. The script will +be typically be two lines of code that look something like this: + +~~~ + #!/usr/bin/fossil + repository: /home/yourlogin/fossils/project.fossil +~~~ + +Modify the filenames to conform to your system, of course. The +CGI script accepts [other options][cgi] besides the +repository:" line. You can add in other options as you desire, +but the single "repository:" line is normally all that is needed +to get started. + +

              2. Make the CGI script executable. + +

              3. Verify that the fossil repository file and the directory that contains +the repository are both writable by whatever user the web server is +running and. +

              + +And you are done. Visit the URL that corresponds to the CGI script +you created to start using your Fossil server. + +*[Return to the top-level Fossil server article.](../)* + + +[althttpd]: https://sqlite.org/docsrc/doc/trunk/misc/althttpd.md +[cgi]: ../../cgi.wiki ADDED www/server/any/cgi.md Index: www/server/any/cgi.md ================================================================== --- /dev/null +++ www/server/any/cgi.md @@ -0,0 +1,68 @@ +# Serving via CGI + +A Fossil server can be run from most ordinary web servers as a CGI +program. This feature allows Fossil to seamlessly integrate into a +larger website. We use CGI for the [self-hosting Fossil repository web +site](../../selfhost.wiki). + +To run Fossil as CGI, create a CGI script (here called "repo") in the +CGI directory of your web server with content like this: + + #!/usr/bin/fossil + repository: /home/fossil/repo.fossil + +Adjust the paths appropriately. It may be necessary to set certain +permissions on this file or to modify an `.htaccess` file or make other +server-specific changes. Consult the documentation for your particular +web server. The following permissions are *normally* required, but, +again, may be different for a particular configuration: + +* The Fossil binary (`/usr/bin/fossil` in the example above) + must be readable/executable. + +* *All* directories leading up to the Fossil binary must be readable + by the process which executes the CGI. + +* The CGI script must be executable for the user under which it will + run, which often differs from the one running the web server. + Consult your site's documentation or the web server’s system + administrator. + +* *All* directories leading to the CGI script must be readable by the + web server. + +* The repository file *and* the directory containing it must be + writable by the same account which executes the Fossil binary. + (This might differ from the user the web server normally runs + under.) The directory holding the repository file(s) needs to be + writable so that SQLite can write its journal files. + +* Fossil must be able to create temporary files in a + [directory that varies by host OS](../../env-opts.md#temp). When the + CGI process is operating [within a chroot](../../chroot.md), + ensure that this directory exists and is readable/writeable by the + user who executes the Fossil binary. + +Once the CGI script is set up correctly, and assuming your server is +also set correctly, you should be able to access your repository with a +URL like: http://mydomain.org/cgi-bin/repo This is assuming you +are running a web server like Apache that uses a “`cgi-bin`” directory +for scripts like our “`repo`” example. + +To serve multiple repositories from a directory using CGI, use the +"directory:" tag in the CGI script rather than "repository:". You +might also want to add a "notfound:" tag to tell where to redirect if +the particular repository requested by the URL is not found: + + #!/usr/bin/fossil + directory: /home/fossil/repos + notfound: http://url-to-go-to-if-repo-not-found/ + +Once deployed, a URL like: http://mydomain.org/cgi-bin/repo/XYZ +will serve up the repository `/home/fossil/repos/XYZ.fossil` if it +exists. + +Additional options available to the CGI script are [documented +separately](../../cgi.wiki). + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/any/inetd.md Index: www/server/any/inetd.md ================================================================== --- /dev/null +++ www/server/any/inetd.md @@ -0,0 +1,52 @@ +# Serving via inetd + +A Fossil server can be launched on-demand by `inetd` by using the +[`fossil http`](/help/http) command. To do so, add a line like the +following to its configuration file, typically `/etc/inetd.conf`: + + 80 stream tcp nowait.1000 root /usr/bin/fossil /usr/bin/fossil http /home/fossil/repo.fossil + +In this example, you are telling `inetd` that when an incoming +connection appears on TCP port 80 that it should launch the program +`/usr/bin/fossil` with the arguments shown. Obviously you will need to +modify the pathnames for your particular setup. The final argument is +either the name of the fossil repository to be served or a directory +containing multiple repositories. + +If you use a non-standard TCP port on systems where the port +specification must be a symbolic name and cannot be numeric, add the +desired name and port to `/etc/services`. For example, if you want your +Fossil server running on TCP port 12345 instead of 80, you will need to +add: + + fossil 12345/tcp # fossil server + +and use the symbolic name “`fossil`” instead of the numeric TCP port +number (“12345” in the above example) in `inetd.conf`. + +Notice that we configured `inetd` to launch Fossil as root. See the +top-level section on “[The Fossil Chroot +Jail](../../chroot.md)” for the consequences of this and +alternatives to it. + +You can instead configure `inetd` to bind to a higher-numbered TCP port, +allowing Fossil to be run as a normal user. In that case, Fossil will +not put itself into a chroot jail, because it assumes you have set up +file permissions and such on the server appropriate for that user. + +The `inetd` daemon must be enabled for this to work, and it must be +restarted whenever its configuration file changes. + +This is a more complicated method than the [standalone HTTP server +method](./none.md), but it has the advantage of only using system +resources when an actual connection is attempted. If no one ever +connects to that port, a Fossil server will not (automatically) run. It +has the disadvantage of requiring "root" access, which may not be +available to you, either due to local IT policy or because of +restrictions at your shared Internet hosting service. + +For further details, see the relevant section in your system's +documentation. The FreeBSD Handbook covers `inetd` in [this +chapter](https://www.freebsd.org/doc/en/books/handbook/network-inetd.html). + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/any/none.md Index: www/server/any/none.md ================================================================== --- /dev/null +++ www/server/any/none.md @@ -0,0 +1,51 @@ +# Standalone HTTP Server + +The easiest way to set up a Fossil server is to use either the +[`server`](/help/server) or [`ui`](/help/ui) command: + +* **fossil server** _REPOSITORY_ +* **fossil ui** _REPOSITORY_ + +The _REPOSITORY_ argument is either the name of the repository file or a +directory containing many repositories named “`*.fossil`”. Both of these +commands start a Fossil server, usually on TCP port 8080, though a +higher numbered port will be used instead if 8080 is already occupied. + +You can access these using URLs of the form **http://localhost:8080/**, +or if _REPOSITORY_ is a directory, URLs of the form +**http://localhost:8080/**_repo_**/** where _repo_ is the base name of +the repository file without the “`.fossil`” suffix. + +There are several key differences between “`ui`” and “`server`”: + +* “`ui`” always binds the server to the loopback IP address (127.0.0.1) + so that it cannot serve to other machines. + +* Anyone who visits this URL is treated as the all-powerful Setup + user, which is why the first difference exists. + +* “`ui`” launches a local web browser pointed at this URL. + +You can omit the _REPOSITORY_ argument if you run one of the above +commands from within a Fossil checkout directory to serve that +repository: + + $ fossil ui # or... + $ fossil server + +You can abbreviate Fossil sub-commands as long as they are unambiguous. +“`server`” can currently be as short as “`ser`”. + +You can serve a directory containing multiple `*.fossil` files like so: + + $ fossil server --port 9000 --repolist /path/to/repo/dir + +There is an [example script](/file/tools/fslsrv) in the Fossil +distribution that wraps `fossil server` to produce more complicated +effects. Feel free to take it, study it, and modify it to suit your +local needs. + +See the [online documentation](/help/server) for more information on the +options and arguments you can give to these commands. + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/any/scgi.md Index: www/server/any/scgi.md ================================================================== --- /dev/null +++ www/server/any/scgi.md @@ -0,0 +1,73 @@ +# Serving via SCGI + +There is an alternative to running Fossil as a [standalone HTTP +server](./none.md), which is to run it in SimpleCGI (a.k.a. SCGI) mode, +which uses the same [`fossil server`](/help/server) command as for HTTP +service. Simply add the `--scgi` command-line option and the stand-alone +server will speak the SCGI protocol rather than raw HTTP. + +This can be used with a web server such as [nginx](http://nginx.org) +which does not support [Fossil’s CGI mode](./cgi.md). + +A basic nginx configuration to support SCGI with Fossil looks like this: + + location /code/ { + include scgi_params; + scgi_param SCRIPT_NAME "/code"; + scgi_pass localhost:9000; + } + +The `scgi_params` file comes with nginx, and it simply translates nginx +internal variables to `scgi_param` directives to create SCGI environment +variables for the proxied program; in this case, Fossil. Our explicit +`scgi_param` call to define `SCRIPT_NAME` adds one more variable to this +set, which is necessary for this configuration to work properly, because +our repo isn’t at the root of the URL hierarchy. Without it, when Fossil +generates absolute URLs, they’ll be missing the `/code` part at the +start, which will typically cause [404 errors][404]. + +The final directive simply tells nginx to proxy all calls to URLs under +`/code` down to an SCGI program on TCP port 9000. We can temporarily +set Fossil up as a server on that port like so: + + $ fossil server /path/to/repo.fossil --scgi --localhost --port 9000 & + +The `--scgi` option switches Fossil into SCGI mode from its default, +which is [stand-alone HTTP server mode](./none.md). All of the other +options discussed in that linked document — such as the ability to serve +a directory full of Fossil repositories rather than just a single +repository — work the same way in SCGI mode. + +The `--localhost` option is simply good security: we’re using nginx to +expose Fossil service to the outside world, so there is no good reason +to allow outsiders to contact this Fossil SCGI server directly. + +Giving an explicit non-default TCP port number via `--port` is a good +idea to avoid conflicts with use of Fossil’s default TCP service port, +8080, which may conflict with local uses of `fossil ui` and such. + +We characterized the SCGI service start command above as “temporary” +because running Fossil in the background like that means it won’t start +back up on a reboot of the server. A simple solution to that is to add +that command to `/etc/rc.local` on systems that have it. However, you +might want to consider setting Fossil up as an OS service instead, so +that you get the benefits of the platform’s service management +framework: + +* [Linux (systemd)](../debian/service.md) +* [Windows service](../windows/service.md) +* [macOS (launchd)](../macos/service.md) +* [xinetd](../any/xinetd.md) +* [inetd](../any/inetd.md) + +We go into more detail on nginx service setup with Fossil in our +[Debian/Ubuntu specific guide](../debian/nginx.md). Then in [a later +article](../../tls-nginx.md) that builds upon that, we show how to add +TLS encryption to this basic SCGI + nginx setup on Debian type OSes. + +Similarly, our [OpenBSD specific guide](../openbsd/httpd.md) details how +to setup a Fossil server using httpd and FastCGI on OpenBSD. + +*[Return to the top-level Fossil server article.](../)* + +[404]: https://en.wikipedia.org/wiki/HTTP_404 ADDED www/server/any/stunnel.md Index: www/server/any/stunnel.md ================================================================== --- /dev/null +++ www/server/any/stunnel.md @@ -0,0 +1,79 @@ +# Serving via stunnel + +[`stunnel`](https://www.stunnel.org/) is a TLS/SSL proxy for programs +that themselves serve only via HTTP, such as Fossil. (Fossil *can* speak +HTTPS, but only as a client.) `stunnel` decodes the HTTPS data from the +outside world as HTTP before passing it to Fossil, and it encodes the +HTTP replies from Fossil as HTTPS before sending them to the remote host +that made the request. + +You can run `stunnel` in one of two modes: socket listener — much like +in our [`inetd` doc](./inetd.md) — and as an HTTP reverse proxy. We’ll +cover both cases here, separately. + + +## Socket Activation + +The following `stunnel.conf` configuration configures it to run Fossil +in socket listener mode, launching Fossil only when an HTTPS hit comes +in, then shutting it back down as soon as the transaction is complete: + +```dosini + [fossil] + accept = 443 + TIMEOUTclose = 0 + exec = /usr/bin/fossil + execargs = /usr/bin/fossil http /home/fossil/ubercool.fossil --https + cert = /etc/letsencrypt/live/ubercool-project.org/fullchain.pem + key = /etc/letsencrypt/live/ubercool-project.org/privkey.pem + ciphers = ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES128-SHA:DES-CBC3-SHA + options = CIPHER_SERVER_PREFERENCE +``` + +This configuration shows the TLS certificate generated by the [Let’s +Encrypt](https://letsencrypt.org) [Certbot](https://certbot.eff.org) in +[certonly mode](https://certbot.eff.org/lets-encrypt/debianbuster-other). +There are other ways to get TLS certificates, but this is a popular and +free option. + +You will need to adjust the site names and paths in this example. Where +this file goes varies by OS type, so check the man pages on your system +to find out where it should be locally. + +See the `stunnel` documentation for further details about this +configuration file. + +It is important that the [`fossil http`](/help/http) command in that +configuration include the `--https` option to let Fossil know to use +“`https://`” instead of “`http://`” in generated hyperlinks. + + + +## Reverse Proxy + +You can instead have Fossil running in the background in [standalone +HTTP server mode](./none.md), bound to a high random TCP port number on +localhost via the `--localhost` and `--port` flags, then configure +`stunnel` to reverse proxy public HTTPS connections down to it via HTTP. + +The configuration is the same as the above except that you drop the +`exec` and `execargs` directives and add this instead: + +```dosini + connect = 9000 +``` + +That tells `stunnel` to connect to an already-running process listening +on the given TCP port number. + +There are a few advantages to this mode: + +1. At the cost of some server memory and a tiny bit of idle CPU time, + Fossil remains running so that hits can be served a smidge faster + than in socket listener mode, where the Fossil binary has to be + loaded and re-initialized on each HTTPS hit. + +2. The socket listener mode doesn’t work on all platforms that + `stunnel` runs on, particularly [on Windows](../windows/stunnel.md). + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/any/xinetd.md Index: www/server/any/xinetd.md ================================================================== --- /dev/null +++ www/server/any/xinetd.md @@ -0,0 +1,27 @@ +# Serving via xinetd + +Some operating systems have replaced the old Unix `inetd` daemon with +`xinetd`, which has a similar mission but with a very different +configuration file format. + +The typical configuration file is either `/etc/xinetd.conf` or a subfile +in the `/etc/xinetd.d` directory. You need a configuration something +like this for Fossil: + + service http + { + port = 80 + socket_type = stream + wait = no + user = root + server = /usr/bin/fossil + server_args = http /home/fossil/repos/ + } + +This example configures Fossil to serve multiple repositories under the +`/home/fossil/repos/` directory. + +Beyond this, see the general commentary in our article on [the `inetd` +method](./inetd.md) as they also apply to service via `xinetd`. + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/debian/nginx.md Index: www/server/debian/nginx.md ================================================================== --- /dev/null +++ www/server/debian/nginx.md @@ -0,0 +1,221 @@ +# Serving via nginx on Debian and Ubuntu + +This document is an extension of [the platform-independent SCGI +instructions][scgii], which may suffice for your purposes if your needs +are simple. + +Here, we add more detailed information on nginx itself, plus details +about running it on Debian type OSes. We focus on Debian 10 (Buster) and +Ubuntu 18.04 here, which are common Tier 1 OS offerings for [virtual +private servers][vps]. This material may not work for older OSes. It is +known in particular to not work as given for Debian 9 and older! + +If you want to add TLS to this configuration, that is covered [in a +separate document][tls] which was written with the assumption that +you’ve read this first. + +[scgii]: ../any/scgi.md +[tls]: ../../tls-nginx.md +[vps]: https://en.wikipedia.org/wiki/Virtual_private_server + + +## Benefits + +This scheme is considerably more complicated than the [standalone HTTP +server](../any/none.md) and [CGI options](../any/cgi.md). Even with the +benefit of this guide and pre-built binary packages, it requires quite a +bit of work to set it up. Why should you put up with this complexity? +Because it gives many benefits that are difficult or impossible to get +with the less complicated options: + +* **Power** — nginx is one of the most powerful web servers in the + world. The chance that you will run into a web serving wall that you + can’t scale with nginx is very low. + + To give you some idea of the sort of thing you can readily + accomplish with nginx, your author runs a single public web server + that provides transparent name-based virtual hosting for four + separate domains: + + * One is entirely static, not involving any dynamic content or + Fossil integration at all. + + * Another is served almost entirely by Fossil, with a few select + static content exceptions punched past Fossil, which are handled + entirely via nginx. + + * The other two domains are aliases for one another — e.g. + `example.com` and `example.net` — with most of the content being + static. This pair of domains has three different Fossil repo + proxies attached to various sections of the URI hierarchy. + + By using nginx, I was able to do all of the above with minimal + repetition between the site configurations. + +* **Integration** — Because nginx is so popular, it integrates with +many different technologies, and many other systems integrate with it in +turn. This makes it great middleware, sitting between the outer web +world and interior site services like Fossil. It allows Fossil to +participate seamlessly as part of a larger web stack. + +* **Availability** — nginx is already in most operating system binary +package repositories, so you don’t need to go out of your way to get it. + + +## Fossil Service Modes + +Fossil provides four major ways to access a repository it’s serving +remotely, three of which are straightforward to use with nginx: + +* **HTTP** — Fossil has a built-in HTTP server: [`fossil + server`](../any/none.md). While this method is efficient and it’s + possible to use nginx to proxy access to another HTTP server, we + don’t see any particularly good reason to make nginx reinterpret + Fossil’s own implementation of HTTP when we have a better option. + (But see [below](#http).) + +* **CGI** — This method is simple but inefficient, because it launches + a separate Fossil instance on every HTTP hit. + + Since Fossil is a relatively small self-contained program, and it’s + designed to start up quickly, this method can work well in a + surprisingly large number of cases. + + Nevertheless, we will avoid this option in this document because + we’re already buying into a certain amount of complexity here in + order to gain power. There’s no sense in throwing away any of that + hard-won performance on CGI overhead. + +* **SCGI** — The [SCGI protocol][scgip] provides the simplicity of CGI + without its performance problems. + +* **SSH** — This method exists primarily to avoid the need for HTTPS, + but we *want* HTTPS. (We’ll get to that in [another document][tls].) + There is probably a way to get nginx to proxy Fossil to HTTPS via + SSH, but it would be pointlessly complicated. + +SCGI it is, then. + +[scgip]: https://en.wikipedia.org/wiki/Simple_Common_Gateway_Interface + + +## Installing the Dependencies + +The first step is to install some non-default packages we’ll need. SSH into +your server, then say: + + $ sudo apt install fossil nginx + + +## Running Fossil in SCGI Mode + +For the following nginx configuration to work, it needs to contact a +Fossil instance speaking the SCGI protocol. There are [many ways](../) +to set that up. For Debian type systems, we recommend +following [our systemd system service guide](service.md). + +There are other ways to arrange for Fossil to run as a service backing +nginx, but however you do it, you need to match up the TCP port numbers between it +and those in the nginx configuration below. + + +## Configuration + +On Debian and Ubuntu systems the primary user-level configuration file +for nginx is `/etc/nginx/sites-enabled/default`. I recommend that this +file contain only a list of include statements, one for each site that +server hosts: + + include local/example.com + include local/foo.net + +Those files then each define one domain’s configuration. Here, +`/etc/nginx/local/example.com` contains the configuration for +`*.example.com` and its alias `*.example.net`; and `local/foo.net` +contains the configuration for `*.foo.net`. + +The configuration for our `example.com` web site, stored in +`/etc/nginx/sites-enabled/local/example.com` is: + + server { + server_name .example.com .example.net ""; + include local/generic; + + access_log /var/log/nginx/example.com-https-access.log; + error_log /var/log/nginx/example.com-https-error.log; + + # Bypass Fossil for the static documentation generated from + # our source code by Doxygen, so it merges into the embedded + # doc URL hierarchy at Fossil’s $ROOT/doc without requiring that + # these generated files actually be stored in the repo. This + # also lets us set aggressive caching on these docs, since + # they rarely change. + location /code/doc/html { + root /var/www/example.com/code/doc/html; + + location ~* \.(html|ico|css|js|gif|jpg|png)$ { + expires 7d; + add_header Vary Accept-Encoding; + access_log off; + } + } + + # Redirect everything else to the Fossil instance + location /code { + include scgi_params; + scgi_param SCRIPT_NAME "/code"; + scgi_pass 127.0.0.1:12345; + } + } + +As you can see, this is a pure extension of [the basic nginx service +configuration for SCGI][scgii], showing off a few ideas you might want to +try on your own site, such as static asset proxying. + +The `local/generic` file referenced above helps us reduce unnecessary +repetition among the multiple sites this configuration hosts: + + root /var/www/$host; + + listen 80; + listen [::]:80; + + charset utf-8; + +There are some configuration directives that nginx refuses to substitute +variables into, citing performance considerations, so there is a limit +to how much repetition you can squeeze out this way. One such example is +the `access_log` and `error_log` directives, which follow an obvious +pattern from one host to the next. Sadly, you must tolerate some +repetition across `server { }` blocks when setting up multiple domains +on a single server. + +The configuration for `foo.net` is similar. + +See [the nginx docs](http://nginx.org/en/docs/) for more ideas. + + +## Proxying HTTP Anyway + +[Above](#modes), we argued that proxying SCGI is a better option than +making nginx reinterpret Fossil’s own implementation of HTTP. If you +want Fossil to speak HTTP, just [set Fossil up as a standalone +server](../any/none.md). And if you want nginx to [provide TLS +encryption for Fossil][tls], proxying HTTP instead of SCGI provides no +benefit. + +However, it is still worth showing the proper method of proxying +Fossil’s HTTP server through nginx if only to make reading nginx +documentation on other sites easier: + + location /code { + rewrite ^/code(/.*) $1 break; + proxy_pass http://127.0.0.1:12345; + } + +The most common thing people get wrong when hand-rolling a configuration +like this is to get the slashes wrong. Fossil is senstitive to this. For +instance, Fossil will not collapse double slashes down to a single +slash, as some other HTTP servers will. + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/debian/service.md Index: www/server/debian/service.md ================================================================== --- /dev/null +++ www/server/debian/service.md @@ -0,0 +1,216 @@ +# Serving via systemd on Debian and Ubuntu + +[`systemd`][sdhome] is the default service management framework on +Debian [since version 8][wpa] and Ubuntu since version 15.04, both +released in April 2015. + +There are multiple ways to get a service to launch under `systemd`. +We’re going to show two methods which correspond approximately to two of +our generic Fossil server setup methods, the [`inetd`](../any/inetd.md) +and [standalone HTTP server](../any/none.md) methods. + +[sdhome]: https://www.freedesktop.org/wiki/Software/systemd/ +[wpa]: https://en.wikipedia.org/wiki/Systemd#Adoption + + + +## User Service + +A fun thing you can easily do with `systemd` that you can’t directly do +with older technologies like `inetd` and `xinetd` is to set a server up +as a “user” service. + +You can’t listen on TCP port 80 with this method due to security +restrictions on TCP ports in every OS where `systemd` runs, but you can +create a listener socket on a high-numbered (≥ 1024) TCP port, +suitable for sharing a Fossil repo to a workgroup on a private LAN. + +To do this, write the following in +`~/.local/share/systemd/user/fossil.service`: + +```dosini + [Unit] + Description=Fossil user server + After=network.target + + [Service] + WorkingDirectory=/home/fossil/museum + ExecStart=/home/fossil/bin/fossil server --port 9000 repo.fossil + Restart=always + RestartSec=3 + + [Install] + WantedBy=sockets.target + WantedBy=multi-user.target +``` + +Unlike with `inetd` and `xinetd`, we don’t need to tell `systemd` which +user and group to run this service as, because we’ve installed it +under the account we’re logged into, which `systemd` will use as the +service’s owner. + +We’ve told `systemd` that we want automatic service restarts with +back-off logic, making this much more robust than the by-hand launches +of `fossil` in the platform-independent Fossil server instructions. The +service will stay up until we explicitly tell it to shut down. + +A simple and useful modification to the above scheme is to add the +`--scgi` and `--localhost` flags to the `ExecStart` line to replace the +use of `fslsrv` in [the generic SCGI instructions](../any/scgi.md), +giving a much more robust configuration. + +Because we’ve set this up as a user service, the commands you give to +manipulate the service vary somewhat from the sort you’re more likely to +find online: + + $ systemctl --user daemon-reload + $ systemctl --user enable fossil + $ systemctl --user start fossil + $ systemctl --user status -l fossil + $ systemctl --user stop fossil + +That is, we don’t need to talk to `systemd` with `sudo` privileges, but +we do need to tell it to look at the user configuration rather than the +system-level configuration. + +This scheme isolates the permissions needed by the Fossil server, which +reduces the amount of damage it can do if there is ever a +remotely-triggerable security flaw found in Fossil. + +On some `systemd` based OSes, user services only run while that user is +logged in interactively. This is common on systems aiming to provide +desktop environments, where this is the behavior you often want. To +allow background services to continue to run after logout, say: + + $ sudo loginctl enable-linger $USER + +You can paste the command just like that into your terminal, since +`$USER` will expand to your login name. + + + +### System Service Alternative + +Another workaround for the problem with user services above is to +install the service as a system service instead. This is a better path +when you are proxying Fossil with a system-level service, such as +[nginx](./nginx.md). + +There are just a small set of changes required: + +1. Install the unit file to one of the persistent system-level unit + file directories. Typically, these are: + + /etc/systemd/system + /lib/systemd/system + +2. Add `User` and `Group` directives to the `[Service]` section so + Fossil runs as a normal user, preferrably one with access only to + the Fossil repo files, rather than running as `root`. + + +## Socket Activation + +Another useful method to serve a Fossil repo via `systemd` is via a +socket listener, which `systemd` calls “[socket activation][sa].” +It’s more complicated, but it has some nice properties. It is the +feature that allows `systemd` to replace `inetd`, `xinetd`, Upstart, and +several other competing technologies. + +We first need to define the privileged socket listener by writing +`/etc/systemd/system/fossil.socket`: + +```dosini + [Unit] + Description=Fossil socket + + [Socket] + Accept=yes + ListenStream=80 + NoDelay=true + + [Install] + WantedBy=sockets.target +``` + +Note the change of configuration directory from the `~/.local` directory +to the system level. We need to start this socket listener at the root +level because of the low-numbered TCP port restriction we brought up +above. + +This configuration says more or less the same thing as the socket part +of an `inted` entry [exemplified elsewhere in this +documentation](../any/inetd.md). + +Next, create the service definition file in that same directory as +`fossil@.service`: + +```dosini + [Unit] + Description=Fossil socket server + After=network.target + + [Service] + WorkingDirectory=/home/fossil/museum + ExecStart=/home/fossil/bin/fossil http repo.fossil + StandardInput=socket + + [Install] + WantedBy=sockets.target + WantedBy=multi-user.target +``` + +We’ll explain the “`@`” in the file name below. + +Notice that we haven’t told `systemd` which user and group to run Fossil +under. Since this is a system-level service definition, that means it +will run as root, which then causes Fossil to [automatically drop into a +`chroot(2)` jail](../../chroot.md) rooted at the `WorkingDirectory` +we’ve configured above, shortly each `fossil http` call starts. + +The `Restart*` directives we had in the user service configuration above +are unnecessary for this method, since Fossil isn’t supposed to remain +running under it. Each HTTP hit starts one Fossil instance, which +handles that single client’s request and then immediately shuts down. + +Next, you need to tell `systemd` to reload its system-level +configuration files and enable the listening socket: + + $ sudo systemctl daemon-reload + $ sudo systemctl enable fossil.socket + +And now you can manipulate the socket listener: + + $ sudo systemctl start fossil.socket + $ sudo systemctl status -l fossil.socket + $ sudo systemctl stop fossil.socket + +Notice that we’re working with the *socket*, not the *service*. The fact +that we’ve given them the same base name and marked the service as an +instantiated service with the “`@`” notation allows `systemd` to +automatically start an instance of the service each time a hit comes in +on the socket that `systemd` is monitoring on Fossil’s behalf. To see +this service instantiation at work, visit a long-running Fossil page +(e.g. `/tarball`) and then give a command like this: + + $ sudo systemctl --full | grep fossil + +This will show information about the `fossil` socket and service +instances, which should show your `/tarball` hit handler, if it’s still +running: + + fossil@20-127.0.0.1:80-127.0.0.1:38304.service + +You can feed that service instance description to a `systemctl kill` +command to stop that single instance without restarting the whole +`fossil` service, for example. + +In all of this, realize that we’re able to manipulate a single socket +listener or single service instance at a time, rather than reload the +whole externally-facing network configuration as with the far more +primitive `inetd` service. + +[sa]: http://0pointer.de/blog/projects/socket-activation.html + + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/index.html Index: www/server/index.html ================================================================== --- /dev/null +++ www/server/index.html @@ -0,0 +1,336 @@ +
              + + + + +

              No Server Required

              + +

              Fossil does not require a central server, but a server can be useful.

              + +

              A Fossil server does not require much memory, CPU, or disk space +and can run comfortably on a generic $5/month virtual host +or on a small device like a Raspberry Pi, or it can co-exist +on a host running other services without getting in the way. + +

              This article is a quick-reference guide for setting up your own +Fossil server, with links to more detailed instructions specific to +particular systems, should you want extra help.

              + + +

              Repository Prep

              + +

              Prior to serving a Fossil repository to others, consider running fossil ui locally and taking these +minimum recommended preparation steps:

              + +
                +
              1. Fossil creates only one user in a new repository and gives it the all-powerful Setup capability. + The 10-digit random password generated for that user is fairly strong + against remote attack, even without explicit password guess rate + limiting, but because that user has so much power, you may want to + give it a much stronger password under Admin → Users.

              2. + +
              3. Run the Admin → Security-Audit tool to verify that other + security-related permissions and settings are as you want them. + Consider clicking the “Take it private” link on that page to lock down + the security on that site to a level appropriate to a private + repository, even if you will eventually want some public service. It's + better to start from a secure position and open up service + feature-by-feature as necessary than it is to start from a fully open + position and lock down features one by one to achieve a secure + stance.

              4. +
              + +

              With the repository secured, it is safe to upload a copy of the +repository file to your server and proceed with server setup, below. +Further configuration steps can wait until after +the server is running.

              + + +

              Activation Methods

              + +

              There are basically four ways to run a Fossil server:

              + +
                +
              1. CGI +
              2. Socket listener +
              3. Stand-alone HTTP server +
              4. SCGI +
              + +

              All of these methods can serve either a single repository or a +directory hierarchy containing mulitiple repositories.

              + +

              You are not restricted to a single server setup. The same Fossil +repository can be served using two or more of the above techniques at +the same time. These methods use clean, well-defined, standard +interfaces (CGI, SCGI, and HTTP) which allow you to easily migrate from +one method to another in response to changes in hosting providers or +administrator preferences.

              + +

              CGI

              + +

              Most ordinary web servers can run Fossil as a +CGI script. This method is known to work with Apache, +lighttpd, and althttpd. The Fossil server +administrator places a short CGI script in +the web server's document hierarchy and when a client requests the URL +that corresponds to that script, Fossil runs and generates the +response.

              + +

              CGI is a good choice for merging Fossil into an existing web site, +particularly on hosts that have CGI set up and working. +The Fossil self-hosting repositories are +implemented with CGI underneath althttpd.

              + +

              Socket Listener

              + +

              Socket listener daemons such as +inetd, xinetd, stunnel, launchd, and systemd +can be configured to invoke the the +fossil http command to handle +each incoming HTTP request. The "fossil http" command reads +the HTTP request off of standard input, computes an appropriate +reply, and writes the reply on standard output. There is a separate +invocation of the "fossil http" command for each HTTP request. +The socket listener daemon takes care of relaying content to and from +the client, and (in the case of stunnel) +handling TLS decryption and encryption. + +

              Stand-alone HTTP Server

              + +

              This is the easiest method. +A stand-alone server uses the +fossil server command to run a +process that listens for incoming HTTP requests on a socket and then +dispatches a copy of itself to deal with each incoming request. You can +expose Fossil directly to the clients in this way or you can interpose a +reverse proxy +layer between the clients and Fossil.

              + +

              SCGI

              + +

              The Fossil standalone server can also handle SCGI. +When the fossil server command is +run with the extra --scgi option, it listens for incoming +SCGI requests rather than HTTP requests. This allows Fossil to +respond to requests from web servers such as +nginx that don't support CGI. SCGI is a simpler protocol to proxy +than HTTP, since the HTTP doesn't have to be re-interpreted in terms of +the proxy's existing HTTP implementation, but it's more complex to set +up because you also have to set up an SCGI-to-HTTP proxy for it. It is +worth taking on this difficulty only when you need to integrate Fossil +into an existing web site already being served by an SCGI-capable web +server.

              + +

              Activation Tutorials

              + +

              We've broken the configuration for each method out into a series of +sub-articles. Some of these are generic, while others depend on +particular operating systems or front-end software:

              + +
              + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
              ⇩ OS / Method ⇨directinetdstunnelCGISCGIalthttpdproxyservice
              Any
              Debian/Ubuntu
              macOS
              OpenBSD
              Windows
              + +

              Where there is a check mark in the "Any" row, the method for that is +generic enough that it works across OSes that Fossil is known to work +on. The check marks below that usually just link to this generic +documentation.

              + +

              The method in the "proxy" column is for the platform's default +web server configured as a reverse proxy for +Fossil's built-in HTTP server: nginx, IIS, Apache, etc.

              + +

              We welcome contributions to fill gaps +() in the table above.

              + + + +

              Post-Activation Configuration

              + +

              After the server is up and running, log into it as the Setup user and +visit the Admin menu to finish configuring that repository for +service:

              + +
                +
              1. Add user accounts for your other team members. Use categories to define access policies + rather than redundantly give each new user the same individual capabilities.

              2. + +
              3. Test access to the repository from each category of non-Setup + user that you created. You may have to give your user categories some + overlooked capabilities, particularly if you followed our earlier advice to take the repository private + prior to setting up the server.

              4. + +
              5. Modify the repository's look and feel by customizing the skin.

              6. + +
              7. If the repository includes embedded documentation, consider + activating the search feature (Admin → Search) so that visitors can do + full-text search on your documentation.

              8. + +
              9. Now that others can be making changes to the repository, + consider monitoring them via email alerts + or the timeline RSS + feed.

              10. + +
              11. Turn on the various logging features.

              12. +
              + +

              Reload the Admin → Security-Audit page occasionally during this +process to double check that you have not mistakenly configured the +server in a way that might expose information that you want to keep +private.

              + + +

              Further Details

              + + + +
              ADDED www/server/macos/service.md Index: www/server/macos/service.md ================================================================== --- /dev/null +++ www/server/macos/service.md @@ -0,0 +1,179 @@ +# Serving via launchd on macOS + +[`launchd`][ldhome] is the default service management framework on macOS +[since the release of Tiger in 2005][wpa]. If you want a Fossil server +to launch in the background on a Mac, it’s the way Apple wants you to do +it. `launchd` is to macOS as `systemd` is to most modern Linux desktop +systems. (Indeed, `systemd` arguably reinvented the perfectly good, +pre-existing `launchd` wheel.) + +Unlike in [our `systemd` article](../debian/service.md), we’re not going +to show the per-user method here, because those so-called +[LaunchAgents][la] only start when a user is logged into the GUI, and +they stop when that user logs out. This does not strike us as proper +“server” behavior, so we’ll stick to system-level LaunchDaemons instead. + +However, we will still give two different configurations, just as in the +`systemd` article: one for a standalone HTTP server, and one using +socket activation. + +For more information on `launchd`, the single best resource we’ve found +is [](launchd.info). The next best is: + + $ man launchd.plist + +[la]: http://www.grivet-tools.com/blog/2014/launchdaemons-vs-launchagents/ +[ldhome]: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html +[wpa]: https://en.wikipedia.org/wiki/Launchd + + + +## Standalone HTTP Server + +To configure `launchd` to start Fossil as a standalone HTTP server, +write the following as `com.example.dev.FossilHTTP.plist`: + +```xml + + + + + Label + com.example.dev.FossilHTTP + ProgramArguments + + /usr/local/bin/fossil + server + --port + 9000 + repo.fossil + + WorkingDirectory + /Users/you/museum + KeepAlive + + RunAtLoad + + StandardErrorPath + /tmp/fossil-error.log + StandardOutPath + /tmp/fossil-info.log + UserName + you + GroupName + staff + InitGroups + + + +``` + +In this example, we’re assuming your development organization uses the +domain name “`dev.example.org`”, that your short macOS login name is +“`you`”, and that you store your Fossils in “`~/museum`”. Adjust these +elements of the plist file to suit your local situation. + +You might be wondering about the use of `UserName`: isn’t Fossil +supposed to drop privileges and enter [a `chroot(2)` +jail](../../chroot.md) when it’s started as root like this? Why do we +need to give it a user name? Won’t Fossil use the owner of the +repository file to set that? All I can tell you is that in testing here, +if you leave the user and group configuration at the tail end of that +plist file out, Fossil will remain running as root! + +Install that file and set it to start with: + + $ sudo install -o root -g wheel -m 644 com.example.dev.FossilHTTP.plist \ + /Library/LaunchDaemons/ + $ sudo launchctl load -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist + +Because we set the `RunAtLoad` key, this will also launch the daemon. + +Stop the daemon with: + + $ sudo launchctl unload -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist + + +## Socket Listener + +Another useful method to serve a Fossil repo via `launchd` is by setting +up a socket listener: + +```xml + + + + + Label + com.example.dev.FossilSocket + ProgramArguments + + /usr/local/bin/fossil + http + repo.fossil + + Sockets + + Listeners + + SockServiceName + 9001 + SockType + stream + SockProtocol + TCP + SockFamily + IPv4 + + + inetdCompatibility + + Wait + + + WorkingDirectory + /Users/you/museum + UserName + you + GroupName + staff + InitGroups + + + +``` + +Save it as “`com.example.dev.FossilSocket.plist`” and install and load +it into `launchd` as above. + +This version differs in several key ways: + +1. We’re calling Fossil as `fossil http` rather than `fossil server` to + make it serve a single request and then shut down immediately. + +2. We’ve told `launchd` to listen on our TCP port number instead of + passing it to `fossil`. + +3. We’re running the daemon in `inetd` compatibility mode of `launchd` + with “wait” mode off, which tells it to attach the connected socket + to the `fossil` process’s stdio handles. + +4. We’ve removed the `Standard*Path` keys because they interfere with + our use of stdio handles for HTTP I/O. You might therefore want to + start with the first method and then switch over to this one only + once you’ve got the daemon launching debugged, since once you tie up + stdio this way, you won’t be able to get logging information from + Fossil via that path. (Fossil does have some internal logging + mechanisms, but you can’t get at them until Fossil is launching!) + +5. We’ve removed the `KeepAlive` and `RunAtLoad` keys because those + options aren’t appropriate to this type of service. + +6. Because we’re running it via a socket listener instead of as a + standalone HTTP server, the Fossil service only takes system + resources when it’s actually handling an HTTP hit. If your Fossil + server is mostly idle, this method will be a bit more efficient than + the first option. + + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/openbsd/httpd.md Index: www/server/openbsd/httpd.md ================================================================== --- /dev/null +++ www/server/openbsd/httpd.md @@ -0,0 +1,282 @@ +# Serving via httpd on OpenBSD + +[`httpd`][httpd] is the default web server that is included in the base +install on OpenBSD. It's minimal and lightweight but secure and capable, +and provides a clean interface for setting up a Fossil server using +FastCGI. + +This article will detail the steps required to setup a TLS-enabled +``httpd`` configuration that serves multiple Fossil repositories out of +a single directory within a chroot, and allow ``ssh`` access to create +new repositories remotely. + +**NOTE:** The following instructions assume an OpenBSD 6.7 installation. + +[httpd]: https://www.openbsd.org/papers/httpd-asiabsdcon2015.pdf + +## Install Fossil + +Use the OpenBSD package manager ``pkg_add`` to install Fossil, making +sure to select the statically linked binary. + +```console + $ doas pkg_add fossil + quirks-3.325 signed on 2020-06-12T06:24:53Z + Ambiguous: choose package for fossil + 0: + 1: fossil-2.10v0 + 2: fossil-2.10v0-static + Your choice: 2 + fossil-2.10v0-static: ok +``` + +This installs Fossil into the chroot. To facilitate local use, create a +symbolic link of the fossil executable into ``/usr/local/bin``. + +```console + $ doas ln -s /var/www/bin/fossil /usr/local/bin/fossil +``` + +As a privileged user, create the file ``/var/www/cgi-bin/scm`` with the +following contents to make the CGI script that ``httpd`` will execute in +response to ``fsl.domain.tld`` requests; all paths are relative to the +``/var/www`` chroot. + +```sh + #!/bin/fossil + directory: /htdocs/fsl.domain.tld + notfound: https://domain.tld + repolist + errorlog: /logs/fossil.log +``` + +The ``directory`` directive instructs Fossil to serve all repositories +found in ``/var/www/htdocs/fsl.domain.tld``, while ``errorlog`` sets +logging to be saved to ``/var/www/logs/fossil.log``; create the +repository directory and log file, and make the script executable. + +```console + $ doas mkdir /var/www/htdocs/fsl.domain.tld + $ doas touch /var/www/logs/fossil.log + $ doas chmod 755 /var/www/cgi-bin/scm +``` + +## Setup chroot + +Fossil needs both ``/dev/random`` and ``/dev/null``, which aren't +accessible from within the chroot, so need to be constructed; ``/var``, +however, is mounted with the ``nodev`` option. Rather than removing +this default setting, create a small memory filesystem with +[`mount_mfs(8)`][mfs] upon which ``/var/www/dev`` will be mounted so +that the ``random`` and ``null`` device files can be created. + +```console + $ doas mkdir /var/www/dev + $ doas mount_mfs -s 1M /dev/sd0b /var/www/dev + $ doas cd /var/www/dev + $ doas /dev/MAKEDEV urandom + $ doas mknod -m 666 null c 2 2 + $ ls -l + total 0 + crw-rw-rw- 1 root daemon 2, 2 Jun 20 08:56 null + lrwxr-xr-x 1 root daemon 7 Jun 18 06:30 random@ -> urandom + crw-r--r-- 1 root wheel 45, 0 Jun 18 06:30 urandom +``` + +[mfs]: https://man.openbsd.org/mount_mfs.8 + +To make the mountable memory filesystem permanent, open ``/etc/fstab`` +as a privileged user and add the following line to automate creation of +the filesystem at startup: + +```console + swap /var/www/dev mfs rw,-s=1048576 0 0 +``` + +The same user that executes the fossil binary must have writable access +to the repository directory that resides within the chroot; on OpenBSD +this is ``www``. In addition, grant repository directory ownership to +the user who will push to, pull from, and create repositories. + +```console + $ doas chown -R user:www /var/www/htdocs/fsl.domain.tld +``` + +## Configure httpd + +On OpenBSD, [httpd.conf(5)][httpd] is the configuration file for +``httpd``. To setup the server to serve all Fossil repositores within +the directory specified in the CGI script, and automatically redirect +standard HTTP requests to HTTPS—apart from [Let's Encrypt][LE] +challenges issued in response to [acme-client(1)][acme] certificate +requests—create ``/etc/httpd.conf`` as a privileged user with the +following contents. + +[LE]: https://letsencrypt.org +[acme]: https://man.openbsd.org/acme-client.1 +[httpd.conf(5)]: https://man.openbsd.org/httpd.conf.5 + +```apache + server "fsl.domain.tld" { + listen on * port http + root "/htdocs/fsl.domain.tld" + location "/.well-known/acme-challenge/*" { + root "/acme" + request strip 2 + } + location * { + block return 301 "https://$HTTP_HOST$REQUEST_URI" + } + location "/*" { + fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" } + } + } + + server "fsl.domain.tld" { + listen on * tls port https + root "/htdocs/fsl.domain.tld" + tls { + certificate "/etc/ssl/domain.tld.fullchain.pem" + key "/etc/ssl/private/domain.tld.key" + } + hsts { + max-age 15768000 + preload + subdomains + } + connection max request body 104857600 + directory index "index.cgi" + location "/*" { + fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" } + } + location "/.well-known/acme-challenge/*" { + root "/acme" + request strip 2 + } + } +``` + +**NOTE:** If not already in possession of a HTTPS certificate, comment +out the ``https`` server block and proceed to securing a free +[Let's Encrypt Certificate](#letsencrypt); otherwise skip to +[Start httpd](#starthttpd). + +## Let's Encrypt Certificate + +In order for ``httpd`` to serve HTTPS, secure a free certificate from +Let's Encrypt using ``acme-client``. Before issuing the +request, however, ensure you have a zone record for the subdomain with +your registrar or nameserver. Then open ``/etc/acme-client.conf`` as a +privileged user to configure the request. + +```dosini + authority letsencrypt { + api url "https://acme-v02.api.letsencrypt.org/directory" + account key "/etc/acme/letsencrypt-privkey.pem" + } + + authority letsencrypt-staging { + api url "https://acme-staging.api.letsencrypt.org/directory" + account key "/etc/acme/letsencrypt-staging-privkey.pem" + } + + domain domain.tld { + alternative names { www.domain.tld fsl.domain.tld } + domain key "/etc/ssl/private/domain.tld.key" + domain certificate "/etc/ssl/domain.tld.crt" + domain full chain certificate "/etc/ssl/domain.tld.fullchain.pem" + sign with letsencrypt + } +``` + +Issue the certificate request. + +```console + $ doas acme-client -vv domain.tld + acme-client: /etc/acme/letsencrypt-privkey.pem: account key exists (not creating) + acme-client: /etc/acme/letsencrypt-privkey.pem: loaded RSA account key + acme-client: /etc/ssl/private/domain.tld.key: generated RSA domain key + acme-client: https://acme-v01.api.letsencrypt.org/directory: directories + acme-client: acme-v01.api.letsencrypt.org: DNS: 172.65.32.248 + ... + N(Q????Z???j?j?>W#????b???? H????eb??T??*? DNosz(???n{L}???D???4[?B] (1174 bytes) + acme-client: /etc/ssl/domain.tld.crt: created + acme-client: /etc/ssl/domain.tld.fullchain.pem: created +``` + +A successful result will output the public certificate, full chain of +trust, and private key into the ``/etc/ssl`` directory as specified in +``acme-client.conf``. + +```console + $ doas ls -lR /etc/ssl + -r--r--r-- 1 root wheel 2.3K Mar 2 01:31:03 2018 domain.tld.crt + -r--r--r-- 1 root wheel 3.9K Mar 2 01:31:03 2018 domain.tld.fullchain.pem + + /etc/ssl/private: + -r-------- 1 root wheel 3.2K Mar 2 01:31:03 2018 domain.tld.key +``` + +Make sure to reopen ``/etc/httpd.conf`` to uncomment the second server +block responsible for serving HTTPS requests before proceeding. + +## Start httpd + +With ``httpd`` configured to serve Fossil repositories out of +``/var/www/htdocs/fsl.domain.tld``, and the certificates and key in +place, enable and start ``slowcgi``—OpenBSD's FastCGI wrapper server +that will execute the above Fossil CGI script—before checking the syntax +of the ``httpd.conf`` configuration file is correct, and starting the +server. + +```console + $ doas rcctl enable slowcgi + $ doas rcctl start slowcgi + slowcgi(ok) + $ doas httpd -vnf /etc/httpd.conf + configuration OK + $ doas rcctl start httpd + httpd(ok) +``` + +## Configure Client + +To facilitate creating new repositories and pushing them to the server, +add the following function to your ``~/.cshrc`` or ``~/.zprofile`` or +the config file for whichever shell you are using on your development +box. + +```sh + finit() { + fossil init $1.fossil && \ + chmod 664 $1.fossil && \ + fossil open $1.fossil && \ + fossil user password $USER $PASSWD && \ + fossil remote-url https://$USER:$PASSWD@fsl.domain.tld/$1 && \ + rsync --perms $1.fossil $USER@fsl.domain.tld:/var/www/htdocs/fsl.domain.tld/ >/dev/null && \ + chmod 644 $1.fossil && \ + fossil ui + } +``` + +This enables a new repository to be made with ``finit repo``, which will +create the fossil repository file ``repo.fossil`` in the current working +directory; by default, the repository user is set to the environment +variable ``$USER``. It then opens the repository and sets the user +password to the ``$PASSWD`` environment variable (which you can either +set with ``export PASSWD 'password'`` on the command line or add to a +*secured* shell environment file), and the ``remote-url`` to +https://fsl.domain.tld/repo with the credentials of ``$USER`` who is +authenticated with ``$PASSWD``. Finally, it ``rsync``'s the file to the +server before opening the local repository in your browser where you +can adjust settings such as anonymous user access, and set pertinent +repository details. Thereafter, you can add files with ``fossil add``, +and commit with ``fossil ci -m 'commit message'`` where Fossil, by +default, will push to the ``remote-url``. It's suggested you read +the [Fossil documentation][documentation]; with a sane and consistent +development model, the system is much more efficient and cohesive than +``git``—so the learning curve is not steep at all. + +[documentation]: https://fossil-scm.org/home/doc/trunk/www/permutedindex.html + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/whyuseaserver.wiki Index: www/server/whyuseaserver.wiki ================================================================== --- /dev/null +++ www/server/whyuseaserver.wiki @@ -0,0 +1,47 @@ +Benefits Of A Fossil Server + +

              No Server Required

              + +Fossil does not require a central server. +Data sharing and synchronization can be entirely peer-to-peer. +Fossil uses +[https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type|conflict-free replicated data types] +to ensure that (in the limit) all participating peers see the same content. + +

              But, A Server Can Be Useful

              + +Fossil does not require a server, but a server can be very useful. +Here are a few reasons to set up a Fossil server for your project: + + 1. A server works as a complete project website.

              + Fossil does more than just version control. It also supports + [../tickets.wiki|trouble-tickets], + [../wikitheory.wiki|wiki], and a [../forum.wiki|forum]. + The [../embeddeddoc.wiki|embedded documentation] + feature provides a great mechanism for providing project documentation. + The [../unvers.wiki|unversioned files] feature is a convenient way + to host builds and downloads on the project website. + + 2. A server gives developers a common point of rendezvous for + syncing their work.

              + It is possible for developers to synchronize peer-to-peer but + that requires the developers coordinate the sync, which in turn + requires that the developers both want to sync at the same moment. + A server aleviates this time dependency by allowing each developer + to sync whenever it is convenient (for example, automatically syncing + after each commit and before each update). Developers all stay + in sync with each other, without having to interrupt each other + constantly to set up a peer-to-peer sync. + + 3. A server provides project leaders with up-to-date status.

              + Project coordinators and BDFLs can click on a link or two at the + central Fossil server for a project, and quickly tell what is + going on. They can do this from anywhere, even from their phones, + without needing to actually sync to the device they are using. + + 4. A server provides automatic off-site backups.

              + A Fossil server is an automatic remote backup for all the work + going into a project. You can even set up multiple servers, at + multiple sites, with automatic synchronization between them, for + added redundancy. Such a set up means that no work is lost due + to a single machine failure. ADDED www/server/windows/cgi-bin-perm.png Index: www/server/windows/cgi-bin-perm.png ================================================================== --- /dev/null +++ www/server/windows/cgi-bin-perm.png cannot compute difference between binary files ADDED www/server/windows/cgi-exec-perm.png Index: www/server/windows/cgi-exec-perm.png ================================================================== --- /dev/null +++ www/server/windows/cgi-exec-perm.png cannot compute difference between binary files ADDED www/server/windows/cgi-install-iis.png Index: www/server/windows/cgi-install-iis.png ================================================================== --- /dev/null +++ www/server/windows/cgi-install-iis.png cannot compute difference between binary files ADDED www/server/windows/cgi-script-map.png Index: www/server/windows/cgi-script-map.png ================================================================== --- /dev/null +++ www/server/windows/cgi-script-map.png cannot compute difference between binary files ADDED www/server/windows/cgi.md Index: www/server/windows/cgi.md ================================================================== --- /dev/null +++ www/server/windows/cgi.md @@ -0,0 +1,115 @@ +# Serving via IIS + CGI + +## This Is Not the Method You Are Looking For + +Setting up CGI service under IIS is surprisingly complicated compared to +running Fossil as a CGI under most other operating systems. We recommend +that you use the simpler [reverse proxying method](./iis.md) instead +unless there is some compelling reason why that method cannot work for +you, such as its dependence on non-stock IIS extensions. (Keep in mind +that both extensions it requires are by Microsoft, not third parties!) + +Once you’ve got this scheme working, it gives the same benefits as those +listed at the top of the linked-to document. + +There is a small benefit you get from using CGI over reverse proxying on +other OSes, which is that the Fossil program only runs briefly in order +to serve each HTTP hit. Once the request is done, that Fossil instance +shuts back down, releasing all of its resources. You don’t need to keep +a background Fossil HTTP server running full-time to provide CGI-based +Fossil service. + +You lose a lot of that benefit on Windows: + +1. It only matters to start with on servers that are highly RAM + constrained. (Roughly ≤ 128 MiB.) Our configuration steps below + assume you’re using the Windows and IIS GUIs, which have RAM + requirements well in excess of this, making Fossil’s resource + requirements a drop in the bucket next to them. On the [Azure + B1s][b1s] virtual machine I used to prepare these instructions, the + Windows Server Manager GUI kept filling the VM’s 1 GiB of RAM + during feature installation and crashing. I had to upgrade the VM’s + RAM to 2 GiB just to get useful work done! + +2. Process creation on Windows is [much more expensive][cp] than on the + other OSes Fossil runs on, so the benefits of firing up a Fossil + executable to process each HTTP request are partially swamped by the + overhead of doing so. + +Therefore, unless you’re willing to replace all of the GUI configuration +steps below with command line equivalents, or shut the GUI down entirely +after configuring IIS, CGI is a much less compelling option on Windows. + +**WARNING:** The following tutorial appears to fail with the current +(2019-08-17) version of Fossil, [apparently][fbug] due to an inability +of Fossil to detect that it’s being run in CGI mode. + +[b1s]: https://azure.microsoft.com/en-us/blog/introducing-b-series-our-new-burstable-vm-size/ +[cp]: https://stackoverflow.com/a/48244/142454 +[fbug]: https://fossil-scm.org/forum/forumpost/de18dc32c0 + + +## Install IIS with CGI Support + +The steps for this are identical to those for the [reverse proxying IIS +setup](./iis.md#install) except that you need to enable CGI in the last +step, since it isn’t installed by default. For Windows Server, the path +is: + +![Install CGI in IIS](./cgi-install-iis.png) + +The path is similar on the consumer-focused versions of Windows, once +you get to that last step. + + +## Setup + +1. Install the Fossil executable to `c:\inetpub\wwwroot\bin` on the web + server. We can’t use an executable you might already have because IIS + runs under a separate user account, so we need to give that + executable special permissions, and that’s easiest to do under the + IIS tree: + + ![IIS fossil.exe execute permission](./cgi-bin-perm.png) + +2. In IIS Manager (a.k.a. `INETMGR`) drill down into the Sites folder + in the left-side pane and right-click your web site’s + configuration. (e.g. “Default Web Site”) + +3. On that menu say “Add Virtual Directory.” Give it the alias “`cgi`” + and point it at a suitable directory, such as + “`c:\inetpub\wwwroot\cgi`”. + +4. Double-click the “Handler Mappings” icon, then in the right-side + pane, click “Add Script Map...” Apply the following settings: + + ![IIS script map dialog](./cgi-script-map.png) + + The Executable path must point to the path we set up in step 1, not + to some other `fossil.exe` you may have elsewhere on your system. + You will need to change the default “`*.dll`” filter in the Open + dialog to “`*.exe`” in order to see it when browsing via the “`...`” + button. + +5. Create a file called `repo.fslcgi` within the CGI directory you + chose in step 3, with a single line like this: + + repository: c:\Users\SOMEONE\museum\repo.fossil + + Give the actual path to the repository, of course. + +6. Up at the top level of IIS Manager, double-click the “ISAPI and CGI + Restrictions” icon, then click “Add...” in the right-side pane. + Give the script you just created permission to execute: + + ![IIS CGI execute permission](./cgi-exec-perm.png) + +7. In the right-side pane, click “Restart” to apply this configuration, + then test it by visiting the newly-available URL in a browser: + + http://localhost/cgi/repo.fslcgi + +For more complicated setups such as “directory” mode, see [the generic +CGI instructions](../any/cgi.md). + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/windows/iis.md Index: www/server/windows/iis.md ================================================================== --- /dev/null +++ www/server/windows/iis.md @@ -0,0 +1,134 @@ +# Serving via IIS + +## Why Bother? + +The first part of the scheme below sets Fossil up as an HTTP server, so +you might be wondering why you wouldn’t just modify that to make it +listen on all network interfaces on TCP port 80, so you can avoid the +need for IIS entirely. For simple use cases, you can indeed do without +IIS, but there are several use cases where adding it is helpful: + +1. Proxying Fossil with IIS lets you [add TLS encryption][tls], which + [Fossil does not currently speak](../../ssl.wiki) in its server role. + +2. The URL rewriting we do below allows Fossil to be part of a larger + site already being served with IIS. + +3. You can have a mixed-mode site, with Fossil acting as a powerful + dynamic content management service and IIS as a fast static content + server. The pure-Fossil alternative requires that you check all of + your static content into Fossil as versioned or unversioned + artifacts. + +This article shows how you can get any combination of those benefits by +using IIS as a reverse proxy for `fossil server`. + +There are other ways to use IIS to serve Fossil, such as [via +CGI](./cgi.md). + + +## Background Fossil Service Setup + +You will need to have the Fossil HTTP server running in the background, +serving some local repository, bound to localhost on a fixed +high-numbered TCP port. For the purposes of testing, simply start it by +hand in your command shell of choice: + + fossil serve --port 9000 --localhost repo.fossil + +That command assumes you’ve got `fossil.exe` in your `%PATH%` and you’re +in a directory holding `repo.fossil`. See [the platform-independent +instructions](../any/none.md) for further details. + +For a more robust setup, we recommend that you [install Fossil as a +Windows service](./service.md), which will allow Fossil to start at +system boot, before anyone has logged in interactively. + + +## Install IIS + +IIS might not be installed in your system yet, so follow the path +appropriate to your host OS. We’ve tested only the latest Microsoft +OSes as of the time of this writing, but the basic process should be +similar on older OSes. + + +### Windows Server 2019 + +1. Start “Server Manager” +2. Tell it you want to “Add roles and features” +3. Select “Role-based or feature-based installation” +4. Select your local server +5. In the Server Roles section, enable “Web Server (IIS)” + +### Windows + +1. Open Control Panel +2. Go to “Programs” +3. Select “Turn Windows features on or off” in the left-side pane +4. In the “Windows Features” dialog, enable “Internet Information + Services” + +The default set of IIS features there will suffice for this tutorial, +but you might want to enable additional features. + + +## Setting up the Proxy + +The stock IIS setup doesn’t have reverse proxying features, but they’re +easily added through extensions. You will need to install the +[Application Request Routing][arr] and [URL Rewrite][ure] extensions. In +my testing here, URL Rewrite showed up immediately after installing it, +but I had to reboot the server to get ARR to show up. (Yay Windows.) + +You can install these things through the direct links above, or you can +do it via the Web Platform Installer feature of IIS Manager (a.k.a. +`INETMGR`). + +Set these extensions up in IIS Manager like so: + +1. Double-click the “Application Request Routing Cache” icon. + +2. Right-click in the window that results, and select “Server Proxy + Settings...” + +3. Check the “Enable Proxy” box in the dialog. Click the “Apply” text + in the right-side pane. + +4. Return to the top server-level configuration area of IIS Manager and + double-click the “URL Rewrite” icon. Alternately, you might find + “URL Rewrite” in the right-side pane from within the ARR settings. + +5. Right click in the window that results, and click “Add Rule(s)...” + Tell it you want a “Blank rule” under “Inbound rules”. + +6. In the dialog that results, create a new rule called “Fossil repo + proxy.” Set the “Pattern” to “`^(.*)$`” and “Rewrite URL” set to + “`http://localhost:9000/{R:1}`”. That tells it to take everything in + the path part of the URL and send it down to localhost:9000, where + `fossil server` is listening. + +7. Click “Apply” in the right-side pane, then get back to the top level + configuration for the server, and click “Restart” in that same pane. + +At this point, if you go to `http://localhost/` in your browser, you +should see your Fossil repository’s web interface instead of the default +IIS web site, as before you did all of the above. + +This is a very simple configuration. You can do more complicated and +interesting things with this, such as redirecting only `/code` URLs to +Fossil by setting the Pattern in step 6 to “`^/code(.*)$`”. (You would +also need to pass `--baseurl http://example.com/code` in the `fossil +server` command to make this work properly.) IIS would then directly +serve all other URLs. You could also intermix ASP.NET applications in +the URL scheme in this way. + +See the documentation on [URL Rewrite rules][urr] for more ideas. + +*[Return to the top-level Fossil server article.](../)* + + +[arr]: https://www.iis.net/downloads/microsoft/application-request-routing +[tls]: https://docs.microsoft.com/en-us/iis/manage/configuring-security/understanding-iis-url-authorization +[ure]: https://www.iis.net/downloads/microsoft/url-rewrite +[urr]: https://docs.microsoft.com/en-us/iis/extensions/url-rewrite-module/creating-rewrite-rules-for-the-url-rewrite-module ADDED www/server/windows/index.md Index: www/server/windows/index.md ================================================================== --- /dev/null +++ www/server/windows/index.md @@ -0,0 +1,8 @@ +# Using Windows as a Fossil Server + +- [Fossil server command](./none.md) +- [Fossil as CGI (IIS)](./iis.md) +- [Fossil as a Service](./service.md) +- [Using stunnel with Fossil on Windows](./stunnel.md) + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/windows/none.md Index: www/server/windows/none.md ================================================================== --- /dev/null +++ www/server/windows/none.md @@ -0,0 +1,69 @@ +# Serving as a Standalone Server on Windows + +On Windows, this method works more or less identically to how it’s +documented in [the generic instructions](../any/none.md). + +...but only while `fossil.exe` is actually running, which is the source +of much trouble on Windows. This problem has two halves: + + +## No App Startup Without Desktop + +The easy methods for starting a program in Windows at system start all +require an interactive desktop. There is no *easy* way to start an arbitrary +program on Windows at boot before anyone has logged in. In Unix +terms, Windows has no simple equivalent to [the `/etc/rc.local` file][rcl]. + +You can partially get around the first problem by setting your `fossil +server` call up as one of the user’s interactive startup items. Windows +10 has its own [idiosyncratic way of doing this][si10], and in older +systems you have [several alternatives to this][si7]. Regardless of the +actual mechanism, these will cause the Fossil standalone HTTP server to +start on an *interactive desktop login* only. While you’re sitting at +the Windows login screen, the Fossil server is *down*. + +[rcl]: http://nixdoc.net/man-pages/FreeBSD/man8/rc.local.8.html +[si10]: https://www.tenforums.com/tutorials/2944-add-delete-enable-disable-startup-items-windows-10-a.html +[si7]: https://www.wikihow.com/Change-Startup-Programs-in-Windows-7 + + + +## No Simple Background Mode + +Windows also lacks a direct equivalent of the Bourne shell’s “`&`” control operator to +run a program in the background, which you can give in Unix’s `rc.local` +file, which is just a normal Bourne shell script. + +By “background,” I mean +“not attached to any interactive user’s login session.” When the +`rc.local` script exits in Unix, any program it backgrounded *stays +running*. There is no simple and direct equivalent to this mechanism in +Windows. + +If you set `fossil server` to run on interactive login, as above, it +will shut right back down again when that user logs back out. + +With Windows 10, it’s especially problematic because you can no longer +make the OS put off updates arbitrarily: your Fossil server will go down +every time Windows Update decides it needs to reboot your computer, and +then Fossil service will *stay* down until someone logs back into that +machine interactively. + + +## Better Solutions + +Because of these problems, we only recommend setting `fossil server` up +on Windows this way when +you’re a solo developer or you work in a small office where everyone +arrives more or less at the same time each day, and everyone goes home +about the same time each day, so that one user can keep the Fossil +server up through the working day. + +If your needs go at all beyond this, you should expect proper “server” +behavior, which you can get on Windows by [registering Fossil as a +Windows service](./service.md), which solves the interactive startup and +shutdown problems above, at a bit of complexity over the Startup Items +method. You may also want to consider putting that service behind [an +IIS front-end proxy](./iis.md) to add additional web serving features. + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/windows/service.md Index: www/server/windows/service.md ================================================================== --- /dev/null +++ www/server/windows/service.md @@ -0,0 +1,91 @@ +# Fossil as a Windows Service + +If you need Fossil to start automatically on Windows, it is suggested to install +Fossil as a Windows Service. + +## Assumptions + +1. You have Administrative access to a Windows 2012r2 or above server. +2. You have PowerShell 5.1 or above installed. + +## Place Fossil on Server + +However you obtained your copy of Fossil, it is recommended that you follow +Windows conventions and place it within `\Program Files\FossilSCM`. Since +Fossil 2.10 is a 64bit binary, this is the proper location for the executable. +This way Fossil is at an expected location and you will have minimal issues with +Windows interfering in your ability to run Fossil as a service. You will need +Administrative rights to place fossil at the recommended location. If you will +only be running Fossil as a service, you do not need to add this location to the +path, though you may do so if you wish. + +## Installing Fossil as a Service + +Luckily the hard work to use Fossil as a Windows Service has been done by the +Fossil team. We simply have to install it with the proper command line options. +Fossil on Windows has a command `fossil winsrv` to allow installing Fossil as a +service on Windows. This command is only documented on the windows executable +of Fossil. You must also run the command as administrator for it to be +successful. + +### Fossil winsrv Example + +The simplest form of the command is: + +``` +fossil winsrv create --repository D:/Path/to/Repo.fossil +``` + +This will create a windows service named 'Fossil-DSCM' running under the local +system account and accessible on port 8080 by default. `fossil winsrv` can also +start, stop, and delete the service. For all available options, please execute +`fossil help winsrv` on a windows install of Fossil. + +If you wish to server a directory of repositories, the `fossil winsrv` command +requires a slightly different set of options vs. `fossil server`: + +``` +fossil winsrv create --repository D:/Path/to/Repos --repolist +``` + + +### Advanced service installation using PowerShell + +As great as `fossil winsrv` is, it does not have one to one reflection of all of +the `fossil server` [options](/help?cmd=server). When you need to use some of +the more advanced options, such as `--https`, `--skin`, or `--extroot`, you will +need to use PowerShell to configure and install the Windows service. + +PowerShell provides the [New-Service](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/new-service?view=powershell-5.1) +command, which we can use to install and configure Fossil as a service. The +below should all be entered as a single line in an Administrative PowerShell +console. + +```PowerShell +New-Service -Name fossil -DisplayName fossil -BinaryPathName '"C:\Program Files\FossilSCM\fossil.exe" server --port 8080 --repolist "D:/Path/to/Repos"' -StartupType Automatic +``` + +Please note the use of forward slashes in the repolist path passed to Fossil. +Windows will accept either back slashes or forward slashes in path names, but +Fossil has a preference for forward slashes. The use of `--repolist` will make +this a multiple repository server. If you want to serve only a single +repository, then leave off the `--repolist` parameter and provide the full path +to the proper repository file. Other options are listed in the +[fossil server](/help?cmd=server) documentation. + +The service will be installed by default to use the Local Service account. +Since Fossil only needs access to local files, this is fine and causes no +issues. The service will not be running once installed. You will need to start +it to proceed (the `-StartupType Automatic` parameter to `New-Service` will +result in the service auto-starting on boot). This can be done by entering + +```PowerShell +Start-Service -Name fossil +``` + +in the PowerShell console. + +Congratulations, you now have a base http accessible Fossil server running on +Windows. + +*[Return to the top-level Fossil server article.](../)* ADDED www/server/windows/stunnel.md Index: www/server/windows/stunnel.md ================================================================== --- /dev/null +++ www/server/windows/stunnel.md @@ -0,0 +1,148 @@ +# Using stunnel with Fossil on Windows + +While there are many ways to configure Fossil as a server using various web +servers (Apache, IIS, nginx, etc.), this document will focus on setting up a +minimal Fossil server using only Fossil's native [server +capabilities](../any/none.md) and [stunnel](https://www.stunnel.org/) +to provide a TLS proxy. It is recommended for public repositories to go to the +extra step of configuring stunnel to provide a proper HTTPS setup. + +## Assumptions + +1. You have Administrative access to a Windows 2012r2 or above server. +2. You have PowerShell 5.1 or above installed. +3. You have acquired a certificate either from a Public CA or an Internal CA. + +These instructions were tested with Fossil 2.10 and stunnel 5.55. Other +versions may not function in a similar manner. There is a bug in Fossil 2.9 and +earlier that prevents these versions of Fossil from properly constructing https +URLs when used with stunnel as a proxy. Please make sure you are using Fossil +2.10 or later on Windows. + +## Configure Fossil Service for https + +Due to the need for the `--https` option for successfully using Fossil with +stunnel, we will use [Advanced service installation using PowerShell](./service.md#PowerShell). +We will need to change the command to install the Fossil Service to configure +it properly for use with stunnel as an https proxy. Run the following: + +```PowerShell +New-Service -Name fossil-secure -DisplayName fossil-secure -BinaryPathName '"C:\Program Files\FossilSCM\fossil.exe" server --localhost --port 9000 --https --repolist "D:/Path/to/Repos"' -StartupType Automatic +``` + +The use of `--localhost` means Fossil will only listen for traffic on the local +host on the designated port - 9000 in this case - and will not respond to +network traffic. Using `--https` will tell Fossil to generate HTTPS URLs rather +than HTTP ones. + +`New-Service` does not automatically start a service on install, so you will +need to enter the following to avoid rebooting the server: + +```PowerShell +Start-Service -Name fossil-secure +``` + +## Install stunnel 5.55 + +Download stunnel from the [downloads](https://www.stunnel.org/downloads.html) +page. Select the latest stunnel windows package (at the time of writing this is +`stunnel-5.55-win64-installer.exe`). Execute the installer and make sure you +install openSSL tools when you install stunnel. You will need this to convert +your certificate from PFX to PEM format. + +Even though the installer says it is for win64, it installs stunnel by default +to `\Program Files (x86)\stunnel`. + +## Get your certificate ready for Stunnel + +Whether you use a Public Certificate Authority or Internal Certificate +Authority, the next step is exporting the certificate from Windows into a format +useable by Stunnel. + +### Export Certificate from Windows + +If your certificate is installed via Windows Certificate Management, you will +need to export the certificate into a usable format. You can do this either +using the Windows Certificate Management Console, or PowerShell. + +#### Certificate Management Console + +Start `mmc.exe` as an Administrator. Select 'File>Add/Remove Snapin', select +'Certificates' from the list, and click 'Add'. Select 'Computer Account', +'Next', 'Local Computer', and then 'Finish'. In the Console Root, expand +'Certificates', then 'Personal', and select 'Certificates'. In the middle pane +find and select your certificate. Right click the certificate and select +'All Tasks>Export'. You want to export as PFX the Private Key, include all +certificates in the certification path, and use a password only to secure the +file. Enter a path and file name to a working directory and complete the +export. + +Continue with [Convert Certificate from PFX to PEM](#convert). + +#### PowerShell + +If you know the Friendly +Name of the Certificate this is relatively easy. Since you need to export +the private key as well, you must run the following from an Administrative +PowerShell console. + +```PowerShell +$passwd = ConvertTo-SecureString -string "yourpassword" -Force -AsPlainText + +Get-ChildItem Cert:\LocalMachine\My | Where{$_.FriendlyName -eq "FriendlyName"} | +Export-PfxCertificate -FilePath fossil-scm.pfx -Password $passwd +``` + +You will now have your certificate stored as a PFX file. + + +### Convert Certificate from PFX to PEM + +For this step you will need the openssl tools that were installed with stunnel. + +```PowerShell +# Add stunnel\bin directory to path for this session. +$env:PATH += ";${env:ProgramFiles(x86)}\stunnel\bin" +# Export Private Key +openssl.exe pkcs12 -in fossil-scm.pfx -out fossil-scm.key -nocerts -nodes +# Export the Certificate +openssl.exe pkcs12 -in fossil-scm.pfx -out fossil-scm.pem -nokeys +``` + +Now move `fossil-scm.key` and `fossil-scm.pem` to your stunnel config directory +(by default this should be located at `\Program Files (x86)\stunne\config`). + +## stunnel Configuration + +Use the reverse proxy configuration given in the generic [Serving via +stunnel document](../any/stunnel.md#proxy). On Windows, the +`stunnel.conf` file is located at `\Program Files (x86)\stunnel\config`. + +You will need to modify it to point at the PEM and key files generated +above. + +After completing the above configuration restart the stunnel service in Windows +with the following: + +```PowerShell +Restart-Service -Name stunnel +``` + +## Open up port 443 in the Windows Firewall + +The following instructions are for the [Windows Advanced +Firewall](https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-firewall/windows-firewall-with-advanced-security). +If you are using a different Firewall, please consult your Firewall +documentation for how to open port 443 for inbound traffic. + +The following command should be entered all on one line. + +```PowerShell +New-NetFirewallRule -DisplayName "Allow Fossil Inbound" -Description "Allow Fossil inbound on port 443 using Stunnel as TLS Proxy." + -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow -Program "C:\Program Files (x86)\Stunnel\bin\stunnel.exe" +``` + +You should now be able to access your new Fossil Server via HTTPS. + + +*[Return to the top-level Fossil server article.](../)* ADDED www/serverext.wiki Index: www/serverext.wiki ================================================================== --- /dev/null +++ www/serverext.wiki @@ -0,0 +1,303 @@ +CGI Server Extensions + +

              1.0 Introduction

              + +If you have a [./server/|Fossil server] for your project, +you can add [https://en.wikipedia.org/wiki/Common_Gateway_Interface|CGI] +extensions to that server. These extensions work like +any other CGI program, except that they also have access to the Fossil +login information and can (optionally) leverage the "skins" of Fossil +so that they appear to be more tightly integrated into the project. + +An example of where this is useful is the +[https://sqlite.org/src/ext/checklist|checklist application] on +the [https://sqlite.org/|SQLite] project. The checklist +helps the SQLite developers track which release tests have passed, +or failed, or are still to be done. The checklist program began as a +stand-alone CGI which kept its own private user database and implemented +its own permissions and login system and provided its own CSS. By +converting checklist into a Fossil extension, the same login that works +for the [https://sqlite.org/src|main SQLite source repository] also works +for the checklist. Permission to change elements of the checklist +is tied on permission to check-in to the main source repository. And +the standard Fossil header menu and footer appear on each page of +the checklist. + +

              2.0 How It Works

              + +CGI Extensions are disabled by default. +An administrator activates the CGI extension mechanism by specifying +an "Extension Root Directory" or "extroot" as part of the server setup. +If the Fossil server is itself run as +[./server/any/cgi.md|CGI], then add a line to the +[./cgi.wiki#extroot|CGI script file] that says: + +
              +extroot: DIRECTORY
              +
              + +Or, if the Fossil server is being run using the +"[./server/any/none.md|fossil server]" or +"[./server/any/none.md|fossil ui]" or +"[./server/any/inetd.md|fossil http]" commands, then add an extra +"--extroot DIRECTORY" option to that command. + +The DIRECTORY is the DOCUMENT_ROOT for the CGI. +Files in the DOCUMENT_ROOT are accessed via URLs like this: + +
              +https://example-project.org/ext/FILENAME +
              + +In other words, access files in DOCUMENT_ROOT by appending the filename +relative to DOCUMENT_ROOT to the [/help?cmd=/ext|/ext] +page of the Fossil server. +Files that are readable but not executable are returned as static +content. Files that are executable are run as CGI. + +

              2.1 Example #1

              + +The source code repository for SQLite is a Fossil server that is run +as CGI. The URL for the source code repository is [https://sqlite.org/src]. +The CGI script looks like this: + +
              +#!/usr/bin/fossil +repository: /fossil/sqlite.fossil +errorlog: /logs/errors.txt +extroot: /sqlite-src-ext +
              + +The "extroot: /sqlite-src-ext" line tells Fossil that it should look for +extension CGIs in the /sqlite-src-ext directory. (All of this is happening +inside of a chroot jail, so putting the document root in a top-level +directory is a reasonable thing to do.) + +When a URL like "https://sqlite.org/src/ext/checklist" is received by the +main webserver, it figures out that the /src part refers to the main +Fossil CGI script and so it runs that script. Fossil gets the remainder +of the URL to work with: "/ext/checklist". Fossil extracts the "/ext" +prefix and uses that to determine that this a CGI extension request. +Then it takes the leftover "/checklist" part and appends it to the +"extroot" to get the filename "/sqlite-src-ext/checklist". Fossil finds +that file to be executable, so it runs it as CGI and returns the result. + +The /sqlite-src-ext/checklist file is a +[https://wapp.tcl.tk|Wapp program]. The current source code to the +this program can be seen at +[https://www.sqlite.org/src/ext/checklist/3070700/self] and +recent historical versions are available at +[https://sqlite.org/docsrc/finfo/misc/checklist.tcl] with +older legacy at [https://sqlite.org/checklistapp/timeline?n=all] + +There is a cascade of CGIs happening here. The web server that receives +the initial HTTP request runs Fossil as a CGI based on the +"https://sqlite.org/src" portion of the URL. The Fossil instance then +runs the checklist sub-CGI based on the "/ext/checklists" suffix. The +output of the sub-CGI is read by Fossil and then relayed on to the +main web server which in turn relays the result back to the original client. + +

              2.2 Example #2

              + +The [https://fossil-scm.org/home|Fossil self-hosting repository] is also +a CGI that looks like this: + +
              +#!/usr/bin/fossil +repository: /fossil/fossil.fossil +errorlog: /logs/errors.txt +extroot: /fossil-extroot +
              + +The extroot for this Fossil server is /fossil-extroot and in that directory +is an executable file named "fileup1" - another [https://wapp.tcl.tk|Wapp] +script. (The extension mechanism is not required to use Wapp. You can use +any kind of program you like. But the creator of SQLite and Fossil is fond +of [https://www.tcl.tk|Tcl/Tk] and so he tends to gravitate toward Tcl-based +technologies like Wapp.) The fileup1 script is a demo program that lets +the user upload a file using a form, and then displays that file in the reply. +There is a link on the page that causes the fileup1 script to return a copy +of its own source-code, so you can see how it works. + +

              3.0 CGI Inputs

              + +The /ext extension mechanism is an ordinary CGI interface. Parameters +are passed to the CGI program using environment variables. The following +standard CGI environment variables are supported: + + * AUTH_TYPE + * AUTH_CONTENT + * CONTENT_LENGTH + * CONTENT_TYPE + * DOCUMENT_ROOT + * GATEWAY_INTERFACE + * HTTP_ACCEPT + * HTTP_ACCEPT_ENCODING + * HTTP_COOKIE + * HTTP_HOST + * HTTP_IF_MODIFIED_SINCE + * HTTP_IF_NONE_MATCH + * HTTP_REFERER + * HTTP_USER_AGENT + * PATH_INFO + * QUERY_STRING + * REMOTE_ADDR + * REMOTE_USER + * REQUEST_METHOD + * REQUEST_URI + * SCRIPT_DIRECTORY + * SCRIPT_FILENAME + * SCRIPT_NAME + * SERVER_NAME + * SERVER_PORT + * SERVER_PROTOCOL + +Do a web search for +"[https://duckduckgo.com/?q=cgi+environment_variables|cgi environment variables]" +to find more detail about what each of the above variables mean and how +they are used. +Live listings of the values of some or all of these environment variables +can be found at links like these: + + * [https://fossil-scm.org/home/test_env] + * [https://sqlite.org/src/ext/checklist/top/env] + +In addition to the standard CGI environment variables listed above, +Fossil adds the following: + + * FOSSIL_CAPABILITIES + * FOSSIL_NONCE + * FOSSIL_REPOSITORY + * FOSSIL_URI + * FOSSIL_USER + +The FOSSIL_USER string is the name of the logged-in user. This variable +is missing or is an empty string if the user is not logged in. The +FOSSIL_CAPABILITIES string is a list of +[./caps/ref.html|Fossil capabilities] that +indicate what permissions the user has on the Fossil repository. +The FOSSIL_REPOSITORY environment variable gives the filename of the +Fossil repository that is running. The FOSSIL_URI variable shows the +prefix of the REQUEST_URI that is the Fossil CGI script, or is an +empty string if Fossil is being run by some method other than CGI. + +The [https://sqlite.org/src/ext/checklist|checklist application] uses the +FOSSIL_USER environment variable to determine the name of the user and +the FOSSIL_CAPABILITIES variable to determine if the user is allowed to +mark off changes to the checklist. Only users with check-in permission +to the Fossil repository are allowed to mark off checklist items. That +means that the FOSSIL_CAPABILITIES string must contain the letter "i". +Search for "FOSSIL_CAPABILITIES" in the +[https://sqlite.org/src/ext/checklist/top/self|source listing] to see how +this happens. + +If the CGI output is one of the forms for which Fossil inserts its own +header and footer, then the inserted header will include a +Content Security Policy (CSP) restriction on the use of javascript within +the webpage. Any <script>...</script> elements within the +CGI output must include a nonce or else they will be suppressed by the +web browser. The FOSSIL_NONCE variable contains the value of that nonce. +So, in other words, to get javascript to work, it must be enclosed in: + +
              + +
              + +Except, of course, the $FOSSIL_NONCE is replaced by the value of the +FOSSIL_NONCE environment variable. + +

              3.1 Input Content

              + +If the HTTP request includes content (for example if this is a POST request) +then the CONTENT_LENGTH value will be positive and the data for the content +will be readable on standard input. + +

              4.0 CGI Outputs

              + +CGI programs construct a reply by writing to standard output. The first +few lines of output are parameters intended for the web server that invoked +the CGI. These are followed by a blank line and then the content. + +Typical parameter output looks like this: + +
              +Status: 200 Ok +Content-Type: text/html +
              + +CGI programs can return any content type they want - they are not restricted +to text replies. It is OK for a CGI program to return (for example) +image/png. + +The fields of the CGI response header can be any valid HTTP header fields. +Those that Fossil does not understand are simply relayed back to up the +line to the requester. + +Fossil takes special action with some content types. If the Content-Type +is "text/x-fossil-wiki" or "text/x-markdown" then Fossil +converts the content from [/wiki_rules|Fossil-Wiki] or +[/md_rules|Markdown] into HTML, adding its +own header and footer text according to the repository skin. Content +of type "text/html" is normally passed straight through +unchanged. However, if the text/html content is of the form: + +
              +
              +... HTML content there ... +
              +
              + +In other words, if the outer-most markup of the HTML is a <div> +element with a single class of "fossil-doc", +then Fossil will adds its own header and footer to the HTML. The +page title contained in the added header will be extracted from the +"data-title" attribute. + +Except for the three cases noted above, Fossil makes no changes or +additions to the CGI-generated content. Fossil just passes the verbatim +content back up the stack towards the requester. + +

              5.0 Filename Restrictions

              + +For security reasons, Fossil places restrictions on the names of files +in the extroot directory that can participate in the extension CGI +mechanism: + + 1. Filenames must consist of only ASCII alphanumeric characters, + ".", "_", and "-", and of course "/" as the file separator. + Files with names that includes spaces or + other punctuation or special characters are ignored. + + 2. No element of the pathname can begin with "." or "-". Files or + directories whose names begin with "." or "-" are ignored. + +If a CGI program requires separate data files, it is safe to put those +files in the same directory as the CGI program itself as long as the names +of the data files contain special characters that cause them to be ignored +by Fossil. + +

              6.0 Trouble-Shooting Hints

              + +Remember that the /ext will return any file in the extroot directory +hierarchy as static content if the file is readable but not executable. +When initially setting up the /ext mechanism, it is sometimes helpful +to verify that you are able to receive static content prior to starting +work on your CGIs. Also remember that CGIs must be +executable files. + +Fossil likes to run inside a chroot jail, and will automatically put +itself inside a chroot jail if it can. The sub-CGI program will also +run inside this same chroot jail. Make sure all embedded pathnames +have been adjusted accordingly and that all resources needed by the +CGI program are available within the chroot jail. + +If anything goes wrong while trying to process an /ext page, Fossil +returns a 404 Not Found error with no details. However, if the requester +is logged in as a user that has [./caps/ref.html#D | Debug] capability +then additional diagnostic information may be included in the output. + +If the /ext page has a "fossil-ext-debug=1" query parameter and if +the requester is logged in as a user with Debug privilege, then the +CGI output is returned verbatim, as text/plain and with the original +header intact. This is useful for diagnosing problems with the +CGI script. Index: www/settings.wiki ================================================================== --- www/settings.wiki +++ www/settings.wiki @@ -4,11 +4,11 @@ Settings control the behaviour of fossil. They are set with the fossil settings command, or through the web interface in the Settings page in the Admin section. -For a list of all settings, view the Settings page, or type +For a list of all settings, view the Settings page, or type fossil help settings from the command line.

              Repository settings

              @@ -16,17 +16,17 @@ a subset of settings are copied to your local repository. If you make a change to a setting on your local repository, it is not synced back to the server when you push or sync. If you make a change on the server, you need to manually make the change on -all repositories which are cloned from this repository. +all repositories which are cloned from this repository. You can also set a setting globally on your local machine. The value will be used for all repositories cloned to your machine, unless overridden explicitly in a particular repository. Global settings can be set by using the -global option on the fossil settings -command. +command.

              "Versionable" settings

              Most of the settings control the behaviour of fossil on your local machine, largely acting to reflect your preference on how you want to @@ -33,15 +33,15 @@ use Fossil, how you communicate with the server, or options for hosting a repository on the web. However, for historical reasons, some settings affect how you work with versioned files. These are allow-symlinks, -binary-glob, crnl-glob, empty-dirs, -encoding-glob, ignore-glob, keep-glob and -manifest. The most important is ignore-glob which -specifies which files should be ignored when looking for unmanaged files -with the extras command. +binary-glob, crlf-glob, crnl-glob, +empty-dirs, encoding-glob, ignore-glob, +keep-glob and manifest. The most important is +ignore-glob which specifies which files should be ignored when +looking for unmanaged files with the extras command. Because these options can change over time, and the inconvenience of replicating changes, these settings are "versionable". As well as being able to be set using the settings command or the web interface, you can create versioned files in the .fossil-settings Index: www/shunning.wiki ================================================================== --- www/shunning.wiki +++ www/shunning.wiki @@ -1,55 +1,119 @@ Deleting Content From Fossil -

              Deleting Content From Fossil

              + +

              Good Reasons for Removing Content from a Fossil Repository

              -Fossil is designed to keep all historical content forever. Users -of Fossil are discouraged from "deleting" content simply because it -has become obsolete. Old content is part of the historical record -(part of the "fossil record") and should be maintained indefinitely. -Such is the design intent of Fossil. +Fossil is designed to keep all historical content forever. Fossil +purposely makes it difficult for users to delete content. Old content +is part of the project's *ahem* fossil record and should be +maintained indefinitely to maintain an accurate history of the project. Nevertheless, there may occasionally arise legitimate reasons for -deleting content. Such reasons might include: - - * Spammers have inserted inappropriate content into a wiki page - or ticket that needs to be removed. - - * A file that contains trade secrets or that is under copyright - may have been accidentally committed and needs to be backed - out. - - * A malformed control artifact may have been inserted and is - disrupting the operation of Fossil. +deleting content. Such reasons include: + + * Spammers inserted inappropriate content into a wiki page, forum post, + or ticket. Fossil lets you easily hide or amend such content, but + since it is not a legitimate part of the project's history, there + is no value in keeping it, so it is best removed permanently. + + * A file that contains trade secrets or that is under someone else's + copyright was accidentally committed and needs to be backed out. + + * A malformed control artifact was inserted and is disrupting the + operation of Fossil. + + +

              Alternatives

              + +All of these are rare cases: Fossil is [./antibot.wiki | designed to +foil spammers up front], legally problematic check-ins should range from +rare to nonexistent, and you have to go way out of your way to force +Fossil to insert bad control artifacts. Therefore, before we get to +methods of permanently deleting content from a Fossil repos, let's give +some alternatives that usually suffice, which don't damage the project's +fossil record: + +
                +
              • When a forum post or wiki article is "deleted," what actually + happens is that a new empty version is added to the Fossil + [./blockchain.md | block chain]. The web interface interprets this + as "deleted," but the prior version remains available if you go + digging for it.

              • + +
              • When you close a ticket, it's marked in a way that causes it + to not show up in the normal ticket reports. You usually want to + give it a Resolution such as "Rejected" when this happens, plus + possibly a comment explaining why you're closing it. This is all new + information added to the ticket, not deletion.

              • + +
              • When you fossil rm a file, a new manifest is + checked into the repository with the same file list as for the prior + version minus the "removed" file. The file is still present in the + repository; it just isn't part of that version forward on that + branch.

              • + +
              • If you make a bad check-in, you can shunt it off to the side + by amending it to put it on a different branch, then continuing + development on the prior branch: +

                + $ fossil amend abcd1234 --branch BOGUS --hide
                + $ fossil up trunk
                +

                + The first command moves check-in ID abcd1234 (and any + subsequent check-ins on that branch!) to a branch called + BOGUS, then hides it so it doesn't show up on the + timeline. You can call this branch anything you like, and you can + re-use the same name as many times as you like. No content is + actually deleted: it's just shunted off to the side and hidden away. + You might find it easier to do this from the Fossil web UI in + the "edit" function for a check-in. +

                + The second command returns to the last good check-in on that branch + so you can continue work from that point.

              • + +
              • When the check-in you want to remove is followed by good + check-ins on the same branch, you can't use the previous method, + because it will move the good check-ins, too. The solution is: +

                + $ fossil merge --backout abcd1234 +

                That creates a diff in the check-out directory that backs out the + bad check-in abcd1234. You then fix up any merge conflicts, + build, test, etc., then check the reverting change into the + repository. Again, nothing is actually deleted; you're just adding + more information to the repository which corrects a prior + check-in.

              • +
              +

              Shunning

              Fossil provides a mechanism called "shunning" for removing content from -a repository. +a repository. -Every Fossil repository maintains a list of the SHA1 hash names of +Every Fossil repository maintains a list of the hash names of "shunned" artifacts. -Fossil will refuse to push or pull any shunned artifact. +Fossil will refuse to push or pull any shunned artifact. Furthermore, all shunned artifacts (but not the shunning list itself) are removed from the repository whenever the repository is reconstructed using the "rebuild" command.

              Shunning lists are local state

              The shunning list is part of the local state of a Fossil repository. -In other words, shunning does not propagate to a remote repository +In other words, shunning does not propagate to a remote repository using the normal "sync" mechanism. An artifact can be shunned from one repository but be allowed to exist in another. The fact that the shunning list does not propagate is a security feature. If the shunning list propagated then a malicious user (or a bug in the fossil code) might introduce a shun record that would -propagate through all repositories in a network and permanently +propagate through all repositories in a network and permanently destroy vital information. By refusing to propagate the shunning list, -Fossil ensures that no remote user will ever be able to remove +Fossil ensures that no remote user will ever be able to remove information from your personal repositories without your permission. -The shunning list does not propagate to a remote repository +The shunning list does not propagate to a remote repository by the normal "sync" mechanism, but it is still possible to copy shuns from one repository to another using the "configuration" command: fossil configuration pull shun remote-url
              @@ -56,12 +120,12 @@ fossil configuration push shun remote-url The two command above will pull or push shunning lists from or to the remote-url indicated and merge the lists on the receiving end. "Admin" privilege on the remote server is required in order to -push a shun list. In contrast, the shunning list will be automatically -received by default as part of a normal client "pull" operation unless +push a shun list. In contrast, the shunning list will be automatically +received by default as part of a normal client "pull" operation unless disabled by the "auto-shun" setting. Note that the shunning list remains in the repository even after the shunned artifact has been removed. This is to prevent the artifact from being reintroduced into the repository the next time it syncs with @@ -68,11 +132,11 @@ another repository that has not shunned the artifact.

              Managing the shunning list

              The complete shunning list for a repository can be viewed by a user -with "admin" privilege on the "/shun" URL of the web interface to Fossil. +with "admin" privilege on the "/shun" URL of the web interface to Fossil. That URL is accessible under the "Admin" button on the default menu bar. Items can be added to or removed from the shunning list. "Sync" operations are inhibited as soon as the artifact is added to the shunning list, but the content of the artifact is not actually removed from the repository until the next time the repository is rebuilt. Index: www/ssl.wiki ================================================================== --- www/ssl.wiki +++ www/ssl.wiki @@ -1,36 +1,304 @@ -SSL and Fossil - -

              Using SSL with Fossil

              - -If you are storing sensitive information in your repository, you should use SSL to encrypt all communications. This will protect the credentials used to access the server, as well preventing eavesdropping of the contents of your repository. - -To host a repository with SSL, you need to use an web server which supports SSL in front of the Fossil server. You can host it using the CGI option or by proxying Fossil's built in HTTP server. - -Your fossil client must be built with SSL support. The configure script will attempt to find OpenSSL on your system, but if necessary, you can specify the location with the --with-openssl option. Type ./configure --help for details. - -Make sure the URL you clone from uses the https: scheme to ensure you're using SSL. If your server is configured to serve the repository from http as well as https, it's easy to accidentally use unencrypted HTTP if you forget the all important 's'. - - -

              Certificates

              - -To verify the identify of a server, SSL uses certificates. Fossil needs to know which certificates you trust. - -If you are using a self-signed certificate, you'll be asked if you want to accept the certificate the first time you communicate with the server. Verify the certificate fingerprint is correct, then answer "always" to remember your decision. - -If you are using a certificate signed by a certificate authority, you need to specify the certificates you trust with the ssl-ca-location setting. Set this globally with the -global option for convenience. - -This should be set to the location of a file containing all the PEM encoded certificates you trust. You can obtain a certificate using a web browser, for example, Firefox, or just refer to your system's trusted CA roots which are usually stored somewhere in /etc. - - -

              Client side certificates

              - -You can also use client side certificates to add an extra layer of authentication, over and above Fossil's built in user management. If you are particularly paranoid, you'll want to use this to remove the ability of anyone on the internet from making any request to Fossil. Without presenting a valid client side certificate, the web server won't invoke the fossil CGI handler. - -Configure your server to request a client side certificate, and set up a certificate authority to sign your client certificates. For each person who needs to access the repository, create a private key and certificate signed with that CA. - -The PEM encoded private key and certificate should be stored in a single file, simply by concatenating the key and certificate files. Specify the location of this file with the ssl-identity setting, or the --ssl-identity option to the clone command. - -If you've password protected the private key, the password will be requested every time you connect to the server. This password is not stored by fossil, as doing so would defeat the purpose of having a password. - -If you attempt to connect to a server which requests a client certificate, but don't provide one, fossil will show an error message which explains what to do to authenticate with the server. - +Securing a Repository with TLS + +

              Using TLS-Encrypted Communications with Fossil

              + +If you are storing sensitive information in a repository accessible over +a network whose integrity you do not fully trust, you should use TLS to +encrypt all communications with it. This is most true for repositories +accessed over the Internet, especially if they will be accessed from +edge networks you do not control, since that admits of various forms of +[https://en.wikipedia.org/wiki/Man-in-the-middle_attack|man in the +middle attack]. + +TLS protects the credentials used to access the server, prevents +eavesdropping, prevents in-flight data modification, prevents server +identify spoofing, and more. + +There are two major aspects to this, both of which have to be addressed +in different ways. Those are the subjects of the next two major +sections. + + +

              Fossil TLS Configuration: Client Side

              + +Fossil itself has built-in support for TLS on the client side only. That +is to say, you can build it against [https://www.openssl.org/|the +OpenSSL library], which will allow it to clone and sync with a remote +Fossil repository via https URIs. + + +

              Building Against OpenSSL Automatically

              + +The configure script will attempt to find OpenSSL on your +system automatically. It first tries asking the pkg-config +system where the OpenSSL development files are, and if that fails, it +falls back to looking through a list of likely directories. + +If it can't find the files it needs, the most common solution is to +install the OpenSSL development package on your system via your OS's +package manager. Examples: + + * RHEL & Fedora: sudo yum install openssl-devel + * Debian & Ubuntu: sudo apt install libssl-dev + * FreeBSD: su -c 'pkg install openssl' + * macOS: sudo brew install openssl + * Cygwin: Install openssl-devel via Cygwin's + setup-*.exe program + +The macOS case requires explanation. Apple last shipped OpenSSL +develpoment files in OS X 10.6 (Snow Leopard), choosing to deprecate it +from that point forward. (Apple wants you to use their proprietary +platform-specific encryption methods instead.) Since macOS has no +built-in package manager, a number have sprung up out of the FOSS world. +It is not known to this author whether Fossil's current build system can +find OpenSSL as installed with any of these other package managers, so +unless you have a particular reason to avoid it, we recomend that you +use [https://brew.sh|Homebrew] on macOS to install OpenSSL as above. +Fossil's build system will seek it out and use it automatically. + + +

              Building Against a Non-Platform Version of +OpenSSL

              + +The Fossil build system has a few other methods for finding OpenSSL when +the automatic methods fail or when you'd prefer that Fossil use a +different version of OpenSSL than the one Fossil's build system picks on +its own. + +A good reason to do this is when the Fossil build system finds a +functioning version of OpenSSL which is nevertheless unsuitable. One +common case is that your OS is sufficiently outdated that the platform +version of OpenSSL can no longer communicate with remote systems +adhering to the latest advice on secure communications. An old OpenSSL +might not support any of the +[https://en.wikipedia.org/wiki/Cipher_suite|cipher suites] the remote +Fossil repository's HTTPS proxy is willing to offer, for example, so +that even though both sides are speaking a variant of TLS/SSL, the peers +cannot come to an agreement on the cryptography. + +If you've installed the OpenSSL development files somewhere that +Fossil's build system cannot find on its own, you can clue it in by +passing the --with-openssl option to the configure +script. Type ./configure --help for details. + +Another option is to download the source code to OpenSSL and build +Fossil against that private version of OpenSSL: + +
              +    cd compat             # relative to the Fossil source tree root
              +    tar xf /path/to/openssl-*.tar.gz
              +    ln -fs openssl-x.y.z openssl
              +    cd openssl
              +    ./config              # or, e.g. ./Configure darwin64-x86_64-cc
              +    make -j11
              +    cd ../..
              +    ./configure --with-openssl=tree
              +    make -j11
              +
              + +That will get you a Fossil binary statically linked to this in-tree +version of OpenSSL. + +Beware, taking this path typically opens you up to new problems, which +are conveniently covered in the next section! + + +

              Certificates

              + +To verify the identify of a server, TLS uses +[https://en.wikipedia.org/wiki/X.509#Certificates|X.509 certificates], a +scheme that depends on a trust hierarchy of so-called +[https://en.wikipedia.org/wiki/Certificate_authority | Certificate +Authorities]. The tree of trust relationships ultimately ends in the +CA roots, which are considered the ultimate arbiters of who to trust in +this scheme. + +The question then is, what CA roots does Fossil trust? + +If you are using a self-signed certificate, Fossil will initially not +know that it can trust your certificate, so you'll be asked if you want +to accept the certificate the first time you communicate with the +server. Verify the certificate fingerprint is correct, then answer +"always" if you want Fossil to remember your decision. + +If you are cloning from or syncing to Fossil servers that use a +certificate signed by a well-known CA or one of its delegates, Fossil +still has to know which CA roots to trust. When this fails, you get an +error message that looks like this in Fossil 2.11 and newer: + +
              +    Unable to verify SSL cert from www.fossil-scm.org
              +      subject: CN = sqlite.org
              +      issuer:  C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
              +      sha256:  bf26092dd97df6e4f7bf1926072e7e8d200129e1ffb8ef5276c1e5dd9bc95d52
              +    accept this cert and continue (y/N)?
              +
              + +In older versions, the message was much longer and began with this line: + +
              +    SSL verification failed: unable to get local issuer certificate
              +
              + +Fossil relies on the OpenSSL library to have some way to check a trusted +list of CA signing keys. There are two common ways this fails: + + #

              The OpenSSL library Fossil is linked to doesn't have a CA + signing key set at all, so that it initially trusts no certificates + at all.

              + #

              The OpenSSL library does have a CA cert set, but your Fossil server's + TLS certificate was signed by a CA that isn't in that set.

              + +A common reason to fall into the second trap is that you're using +certificates signed by a local private CA, as often happens in large +enterprises. You can solve this sort of problem by getting your local +CA's signing certificate in PEM format and pointing OpenSSL at it: + +
              +     fossil set --global ssl-ca-location /path/to/local-ca.pem
              +
              + +The use of --global with this option is common, since you may +have multiple reposotories served under certificates signed by that same +CA. However, if you have a mix of publicly-signed and locally-signed +certificates, you might want to drop the --global flag and set +this option on a per-repository basis instead. + +A common way to run into the broader first problem is that you're on +FreeBSD, which does not install a CA certificate set by default, even as +a dependency of the OpenSSL library. If you're using a certificate +signed by one of the major public CAs, you can solve this by installing +the ca_root_nss package. That package contains the Mozilla NSS +certificate bundle, which gets installed in a location that OpenSSL +checks by default, so you don't need to change any Fossil settings. +(This is the same certificate set that ships with Firefox, by the way.) + +The same sort of thing happens with the Windows build of OpenSSL, but +for a different core reason: Windows does ship with a stock CA +certificate set, but it's not in a format that OpenSSL understands how +to use. Rather than try to find a way to convert the data format, you +may find it acceptable to use the same Mozilla NSS cert set. I do not +know of a way to easily get this from Mozilla themselves, but I did find +a [https://curl.haxx.se/docs/caextract.html|third party source] for the +cacert.pem file. I suggest placing the file into your Windows +user home directory so that you can then point Fossil at it like so: + +
              +     fossil set --global ssl-ca-location %userprofile%\cacert.pem
              +
              + +This can also happen if you've linked Fossil to a version of OpenSSL +[#openssl-src|built from source]. That same cacert.pem fix can +work in that case, too. + +When you build Fossil on Linux platforms against the binary OpenSSL +package provided with the OS, you typically get a root cert store along +with the platform OpenSSL package, either built-in or as a hard +dependency. + + +

              Client-Side Certificates

              + +You can also use client side certificates to add an extra layer of +authentication, over and above Fossil's built in user management. If you +are particularly paranoid, you'll want to use this to remove the ability +of anyone on the internet from making any request to Fossil. Without +presenting a valid client side certificate, the web server won't invoke +the Fossil CGI handler. + +Configure your server to request a client side certificate, and set up a +certificate authority to sign your client certificates. For each person +who needs to access the repository, create a private key and certificate +signed with that CA. + +The PEM encoded private key and certificate should be stored in a single +file, simply by concatenating the key and certificate files. Specify the +location of this file with the ssl-identity setting, or the +--ssl-identity option to the clone command. + +If you've password protected the private key, the password will be +requested every time you connect to the server. This password is not +stored by fossil, as doing so would defeat the purpose of having a +password. + +If you attempt to connect to a server which requests a client +certificate, but don't provide one, fossil will show an error message +which explains what to do to authenticate with the server. + + +

              Fossil TLS Configuration: Server Side

              + +Fossil's built-in HTTP server feature does not currently have a built-in +way to serve via HTTP over TLS, a.k.a. HTTPS, even when you've linked +Fossil to OpenSSL. To serve a Fossil repository via HTTPS, you must put +it behind some kind of HTTPS proxy. We have a number of documents +elsewhere in this repository that cover your options for [./server/ +| serving Fossil repositories]. A few of the most useful of these are: + + * Serving via stunnel + * Serving via stunnel + althttpd + * Serving via SCGI (nginx) + + +

              Enforcing TLS Access

              + +To use TLS encryption in cloning and syncing to a remote Fossil +repository, be sure to use the https: URI scheme in +clone and sync commands. If your server is configured +to serve the repository via both HTTP and HTTPS, it's easy to +accidentally use unencrypted HTTP if you forget the all-important 's'. + +As of Fossil 2.8, there is a setting in the Fossil UI under Admin → +Access called "Redirect to HTTPS," which is set to "Off" by default. +Changing this only affects web UI access to the Fossil repository. It +doesn't affect clones and syncs done via the http URI scheme. + +In Fossil 2.7 and earlier, there was a much weaker form of this setting +affecting the /login page only. If you're using this setting, +you should migrate to the new setting as soon as possible, because the +old setting allows multiple ways of defeating it. + +WARNING: Enabling HTTPS redirects at the Fossil repo +level while running Fossil behind an HTTPS proxy can result in an +infinite redirect loop. It happens when the proxy mechanism presents +"http" URIs to Fossil, so Fossil issues a redirect, so the browser +fetches the page again, causing Fossil to see an "http" URI again, so +it issues a redirect...'round and 'round it goes until the web browser +detects it's in a redirect loop and gives up. This problem prevents you +from getting back into the Admin UI to fix it, but there are several +ways to fix it: + + #

              Reset via CLI. You can turn the setting back off from the + CLI with the command "fossil -R /path/to/repo.fossil set + redirect-to-https 0". (Currently doesn't work.)

              + #

              Backup first. This setting is stored in the Fossil + repository, so if you make a backup first on the server, you + can restore the repo file if enabling this feature creates a + redirect loop.

              + #

              Download, fix, and restore. You can copy the remote + repository file down to a local machine, use fossil ui to + fix the setting, and then upload it to the repository server + again.

              + +It's best to enforce TLS-only access at the front-end proxy level +anyway. It not only avoids the problem entirely, it can be significantly +more secure. The [./tls-nginx.md|nginx TLS proxy guide] shows one way +to achieve this.

              + + +

              Terminology Note

              + +This document is called ssl.wiki for historical reasons. The +TLS protocol was originally called SSL, and it went through several +revisions before being replaced by TLS. Years before this writing, SSL +finally became entirely obsolete due to weaknesses in the protocol fixed +in the later TLS series of protocols. + +Some people still use the term "SSL" when they actually mean "TLS," but +in the Fossil project, we always use "TLS" except when we must preserve +some sort of historical compatibility, as with this document's name in +order to avoid broken external URLs. The Fossil TLS-related settings +also often use "ssl" in their names, for the same reason. + +This series of protocols is also called "HTTPS" after the URI scheme +used to specify "HTTP over TLS." Index: www/stats.wiki ================================================================== --- www/stats.wiki +++ www/stats.wiki @@ -1,93 +1,93 @@ Fossil Performance

              Performance Statistics

              -The questions will inevitably arise: How does Fossil perform? +The questions will inevitably arise: How does Fossil perform? Does it use a lot of disk space or bandwidth? Is it scalable? In an attempt to answers these questions, this report looks at several projects that use fossil for configuration management and examines how well they are working. The following table is a summary of the results. -(Last updated on 2015-02-28.) +(Last updated on 2018-06-04.) Explanation and analysis follows the table. - + -
              Project Number Of Artifacts Number Of Check-insProject Duration
              (as of 2015-02-28)
              Project Duration
              (as of 2018-06-04)
              Uncompressed Size Repository Size Compression Ratio Clone Bandwidth
              [http://www.sqlite.org/src/timeline | SQLite] -56089 -14357 -5388 days
              14.75 years -
              3.4 GB -45.5 MB -73:1 -29.9 MB +77492 +20686 +6580 days
              18.02 years +
              5.6 GB +70.0 MB +80:1 +51.1 MB
              [http://core.tcl-lang.org/tcl/timeline | TCL] -139662 -18125 -6183 days
              16.93 years -
              6.6 GB -192.6 MB -34:1 -117.1 MB +[http://core.tcl.tk/tcl/timeline | TCL] +161991 +23146 +7375 days
              20.19 years +
              8.0 GB +222.0 MB +36:1 +150.5 MB
              [/timeline | Fossil] -29937 -8238 -2779 days
              7.61 years -
              2.3 GB -34.0 MB -67:1 -21.5 MB +39148 +11266 +3971 days
              10.87 years +
              3.8 GB +42.0 MB +90:1 +27.4 MB
              [http://www.sqlite.org/slt/timeline | SLT] -2278 -136 -2282 days
              6.25 years -
              2.0 GB -144.7 MB -13:1 -142.1 MB +2384 +169 +3474 days
              9.51 years +
              2.1 GB +145.9 MB +14:1 +143.4 MB
              [http://www.sqlite.org/th3.html | TH3] -8729 -2406 -2347 days
              6.43 years -
              386 MB -15.2 MB -25:1 -12.6 MB +12406 +3718 +3539 days
              9.69 years +
              544 MB +18.0 MB +30:1 +14.7 MB
              [http://www.sqlite.org/docsrc/timeline | SQLite Docs] -5503 -1631 -2666 days
              7.30 years -
              194 MB -10.9 MB -17:1 -8.37 MB +8752 +2783 +3857 days
              10.56 years +
              349.9 MB +16.3 MB +21:1 +13.57 MB

              Measured Attributes

              @@ -96,21 +96,21 @@ every ticket, and every check-in is a separate "artifact". One way to think of a Fossil project is as a bag of artifacts. Of course, there is a lot more than this going on in Fossil. Many of the artifacts have meaning and are related to other artifacts. But at a low level (for example when synchronizing two instances of the same project) the only thing that matters -is the unordered collection of artifacts. In fact, one of the key +is the unordered collection of artifacts. In fact, one of the key characteristics of Fossil is that the entire project history can be reconstructed simply by scanning the artifacts in an arbitrary order. The number of check-ins is the number of times that the "commit" command has been run. A single check-in might change a 3 or 4 files, or it might change dozens or hundreds of files. Regardless of the number of files changed, it still only counts as one check-in. The "Uncompressed Size" is the total size of all the artifacts within -the repository assuming they were all uncompressed and stored +the repository assuming they were all uncompressed and stored separately on the disk. Fossil makes use of delta compression between related versions of the same file, and then uses zlib compression on the resulting deltas. The total resulting repository size is shown after the uncompressed size. @@ -125,15 +125,15 @@ (230 bytes). Similarly, "MB" and "KB" means megabytes and kilobytes, not mebibytes and kibibytes.

              Analysis And Supplemental Data

              -Perhaps the two most interesting datapoints in the above table are SQLite +Perhaps the two most interesting data points in the above table are SQLite and SLT. SQLite is a long-running project with long revision chains. Some of the files in SQLite have been edited over a thousand times. Each of these edits is stored as a delta, and hence the SQLite project -gets excellent 73:1 compression. SLT, on the other hand, consists of +gets excellent 80:1 compression. SLT, on the other hand, consists of many large (megabyte-sized) SQL scripts that have one or maybe two edits each. There is very little delta compression occurring and so the overall repository compression ratio is much lower. Note also that quite a bit more bandwidth is required to clone SLT than SQLite. Index: www/style.wiki ================================================================== --- www/style.wiki +++ www/style.wiki @@ -1,63 +1,95 @@ Coding Style Fossil source code should following the style guidelines below. -General points: + The Fossil source tree includes a few files taken from external +sources +(examples: [https://github.com/antirez/linenoise|linenoise] and +[http://zlib.net/|zLib]) +and this externally sourced code might not comply with these style guidelines. + + +1. General points: - 10. No line of code exceeds 80 characters in length. (Occasional +
                +
              1. No line of code exceeds 80 characters in length. (Occasional exceptions are made for HTML text on @-lines.) - 11. There are no tab characters. +
              2. There are no tab characters. + +
              3. Line terminators are \n only. Do not use a \r\n line terminator. - 12. Line terminators are \n only. Do not use a \r\n line terminator. +
              4. 2-space indentation is used. Remember: No tabs. - 13. 2-space indentation is used. Remember: No tabs. - - 14. Comments contain no spelling or grammatical errors. (Abbreviations +
              5. Comments contain no spelling or grammatical errors. (Abbreviations and sentence fragments are acceptable when trying to fit a comment on a single line as long as the meaning is clear.) - 15. The tone of comments is professional and courteous. Comments +
              6. The tone of comments is professional and courteous. Comments contain no profanity, obscenity, or innuendo. - 16. All C-code conforms to ANSI C-89. +
              7. All C-code conforms to ANSI C-89. + Three well-defined existing exceptions are: +
                  + +
                1. -Wno-overlength-strings: The Fossil build system converts (some of the) source code comments + into strings, which may exceed the 509 character limit defined by ANSI. + (example: bld/page_index.h) + +
                2. -Wno-long-long: Fossil uses the 'long long' integer type, which is not strictly ANSI C-89 (defined in C99). + The use of 'long long' resolves many problems with 64-bit arithmetics, especially on 32-bit machines. + (http_ssl.c, sha3.c, shell.c, util.c) + +
                3. alloca(): By default, sqlite3.c is compiled with the -DSQLITE_USE_ALLOCA flag to use the alloca() function. + alloca() is not considered ANSI C, and normally not recommended due to portability issues, but + performance and/or memory consumption improvement may be a stronger argument in favor of its usage. + (sqlite3.c) +
                - 17. All comments and identifiers are in English. +
              8. All comments and identifiers are in English. - 18. The program is single-threaded. Do not use threads. +
              9. The program is single-threaded. Do not use threads. (One exception to this is the HTTP server implementation for Windows, which we do not know how to implement without the use of threads.) +
              + +2. C preprocessor macros: -C preprocessor macros: +
                - 20. The purpose of every preprocessor macros is clearly explained in a +
              1. The purpose of every preprocessor macros is clearly explained in a comment associated with its definition. - 21. Every preprocessor macro is used at least once. +
              2. Every preprocessor macro is used at least once. - 22. The names of preprocessor macros clearly reflect their use. +
              3. The names of preprocessor macros clearly reflect their use. - 23. Assumptions about the relative values of related macros are +
              4. Assumptions about the relative values of related macros are verified by asserts. Example: assert(READ_LOCK+1==WRITE_LOCK); +
              + -Function header comments: +3. Function header comments: - 30. Every function has a header comment describing the purpose and use +
                +
              1. Every function has a header comment describing the purpose and use of the function. - 31. Function header comment defines the behavior of the function in +
              2. Function header comment defines the behavior of the function in sufficient detail to allow the function to be re-implemented from scratch without reference to the original code. - 32. Functions that perform dynamic memory allocation (either directly +
              3. Functions that perform dynamic memory allocation (either directly or indirectly via subfunctions) say so in their header comments. +
              + -Function bodies: +4. Function bodies:
              1. The name of a function clearly reflects its purpose.
              2. Automatic variables are small, not large objects or arrays. Avoid @@ -78,44 +110,49 @@
            -Class (struct) declarations: +5. Class (struct) declarations: - 50. The purpose and use of every class (a.k.a. structure) is clearly defined +
              +
            1. The purpose and use of every class (a.k.a. structure) is clearly defined in the header comment of its declaration. - 51. The purpose and use of every class member is clearly defined either +
            2. The purpose and use of every class member is clearly defined either in the header comment of the class declaration or when the member is declared or both. - 52. The names of class members clearly reflect their use. +
            3. The names of class members clearly reflect their use. + +
            4. Invariants for classes are clearly defined. + +
            - 53. Invariants for classes are clearly defined. +6. Variables and class instances: -Variables and class instances: - - 60. The purpose and use of every variable is defined by a comment at the +
              +
            1. The purpose and use of every variable is defined by a comment at the variable definition. - 61. The names of variables clearly reflect their use. - - 62. Related variables have related names. (ex: aSavepoint and nSavepoint.) - - 63. Variables have minimum practical scope. - - 64. Automatic variables are small, not large objects or arrays. - - 65. Constants are "const". - - 66. Invariants on variables or groups of variables are defined and +
            2. The names of variables clearly reflect their use. + +
            3. Related variables have related names. (ex: aSavepoint and nSavepoint.) + +
            4. Variables have minimum practical scope. + +
            5. Automatic variables are small, not large objects or arrays. + +
            6. Constants are "const". + +
            7. Invariants on variables or groups of variables are defined and tested by asserts. - 67. When a variable that refers to the same value is used within +
            8. When a variable that refers to the same value is used within multiple scopes, the same name is used in all cases. - 68. When variables refer to different values, different names are used +
            9. When variables refer to different values, different names are used even when the names are in different scopes. - 69. Variable names with wide scope are sufficiently distinctive to allow +
            10. Variable names with wide scope are sufficiently distinctive to allow searching for them using grep. +
            Index: www/sync.wiki ================================================================== --- www/sync.wiki +++ www/sync.wiki @@ -1,37 +1,55 @@ The Fossil Sync Protocol -

            This document describes the wire protocol used to synchronize +

            This document describes the wire protocol used to synchronize content between two Fossil repositories.

            1.0 Overview

            The global state of a fossil repository consists of an unordered -collection of artifacts. Each artifact is identified by its SHA1 hash -expressed as a 40-character lower-case hexadecimal string. +collection of artifacts. Each artifact is identified by a cryptographic +hash of its content, expressed as a lower-case hexadecimal string. Synchronization is the process of sharing artifacts between -servers so that all servers have copies of all artifacts. Because +repositories so that all repositories have copies of all artifacts. Because artifacts are unordered, the order in which artifacts are received -at a server is inconsequential. It is assumed that the SHA1 hashes -of artifacts are unique - that every artifact has a different SHA1 hash. +is unimportant. It is assumed that the hash names +of artifacts are unique - that every artifact has a different hash. To a first approximation, synchronization proceeds by sharing lists -SHA1 hashes of available artifacts, then sharing those artifacts that -are not found on one side or the other of the connection. In practice, -a repository might contain millions of artifacts. The list of -SHA1 hashes for this many artifacts can be large. So optimizations are -employed that usually reduce the number of SHA1 hashes that need to be +hash values for available artifacts, then sharing the content of artifacts +whose names are missing from one side or the other of the connection. +In practice, a repository might contain millions of artifacts. The list of +hash names for this many artifacts can be large. So optimizations are +employed that usually reduce the number of hashes that need to be shared to a few hundred.

            Each repository also has local state. The local state determines the web-page formatting preferences, authorized users, ticket formats, and similar information that varies from one repository to another. -The local state is not using transferred during a sync. Except, +The local state is not usually transferred during a sync. Except, some local state is transferred during a [/help?cmd=clone|clone] -in order to initialize the local state of the new repository. And +in order to initialize the local state of the new repository. Also, +an administrator can sync local state using the [/help?cmd=configuration|config push] and [/help?cmd=configuration|config pull] -commands can be an administrator to sync local state.

            +commands. + + +

            1.1 Conflict-Free Replicated Datatypes

            + +

            The "bag of artifacts" data model used by Fossil +Fossil is apparently an implementation of a particular +[https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type|Conflict-Free Replicated +Datatype (CRDT)] +called a "G-Set" or "Grow-only Set". +The academic literature on CRDTs only began to appear in about 2011, and +Fossil predates that research by at least 4 years. But it is nice to know +that theorists have now proven that the underlying data model of Fossil can +provide strongly-consistent replicas using only peer-to-peer communication +and without any kind of central authority.

            + +

            If you are already familiar with CRDTs and were wondering if Fossil +used them, the answer is "yes". We just don't call them by that name.

            2.0 Transport

            All communication between client and server is via HTTP requests. @@ -40,28 +58,36 @@ request.

            The server might be running as an independent server using the server command, or it might be launched from inetd or xinetd using the http command. Or the server might -be launched from CGI. -(See "[./server.wiki|How To Configure A Fossil Server]" for details.) +be launched from CGI. +(See "[./server/|How To Configure A Fossil Server]" for details.) The specifics of how the server listens for incoming HTTP requests is immaterial to this protocol. -The important point is that the server is listening for requests and +The important point is that the server is listening for requests and the client is the issuer of the requests.

            A single push, pull, or sync might involve multiple HTTP requests. The client maintains state between all requests. But on the server side, each request is independent. The server does not preserve any information about the client from one request to the next.

            + +

            Note: Throughout this article, we use the terms "server" and "client" +to represent the listener and initiator of the interaction, respectively. +Nothing in this protocol requires that the server actually be a back-room +processor housed in a datacenter, nor does the client need to be a desktop +or handheld device. For the purposes of this article "client" simply means +the repository that initiates the conversation and "server" is the repository +that responds. Nothing more.

            2.0.1 Encrypted Transport

            In the current implementation of Fossil, the server only -understands HTTP requests. The client can send either +understands HTTP requests. The client can send either clear-text HTTP requests or encrypted HTTPS requests. But when -HTTPS requests are sent, they first must be decrypted by a webserver +HTTPS requests are sent, they first must be decrypted by a web server or proxy before being passed to the Fossil server. This limitation may be relaxed in a future release.

            2.1 Server Identification

            @@ -189,20 +215,20 @@
            file artifact-id size \n content
            file artifact-id delta-artifact-id size \n content
            -

            File cards are different from most other cards in that they are -followed by in-line "payload" data. The content of the artifact -or the artifact delta consists of the first size bytes of the +

            File cards are followed by in-line "payload" data. +The content of the artifact +or the artifact delta is the first size bytes of the x-fossil content that immediately follow the newline that -terminates the file card. Only file and cfile cards have this characteristic. +terminates the file card.

            The first argument of a file card is the ID of the artifact that is being transferred. The artifact ID is the lower-case hexadecimal -representation of the SHA1 hash of the artifact. +representation of the name hash for the artifact. The last argument of the file card is the number of bytes of payload that immediately follow the file card. If the file card has only two arguments, that means the payload is the complete content of the artifact. If the file card has three arguments, then the payload is a delta and second argument is @@ -231,11 +257,11 @@ cfile artifact-id delta-artifact-id usize csize \n content

          The first argument of the cfile card is the ID of the artifact that is being transferred. The artifact ID is the lower-case hexadecimal -representation of the SHA1 hash of the artifact. The second argument of +representation of the name hash for the artifact. The second argument of the cfile card is the original size in bytes of the artifact. The last argument of the cfile card is the number of compressed bytes of payload that immediately follow the cfile card. If the cfile card has only three arguments, that means the payload is the complete content of the artifact. If the cfile card has four arguments, then the payload is a @@ -271,11 +297,11 @@ uvfile name mtime hash size flags \n content

          The name field is the name of the unversioned file. The mtime is the last modification time of the file in seconds -since 1970. The hash field is the SHA1 hash of the content +since 1970. The hash field is the hash of the content for the unversioned file, or "-" for deleted content. The size field is the (uncompressed) size of the content in bytes. The flags field is an integer which is interpreted as an array of bits. The 0x0004 bit of flags indicates that the content is to be omitted. The content might be omitted if @@ -395,10 +421,13 @@ using a gimme card in either the reply or in the next message.

          If the second argument exists and is "1", then the artifact identified by the first argument is private on the sender and should be ignored unless a "--private" [/help?cmd=sync|sync] is occurring. + +

          The name "igot" comes from the English slang expression "I got" meaning +"I have".

          3.6.1 Unversioned Igot Cards

          Zero or more "uvigot" cards are sent from server to client when synchronizing unversioned content. The format of a uvigot card is @@ -408,13 +437,13 @@ uvigot name mtime hash size

        The name argument is the name of an unversioned file. The mtime is the last modification time of the unversioned file -in seconds since 1970. -The hash is the SHA1 hash of the unversioned file content, or -"-" if the file has been deleted. +in seconds since 1970. +The hash is the SHA1 or SHA3-256 hash of the unversioned file +content, or "-" if the file has been deleted. The size is the uncompressed size of the file in bytes.

        When the server sees a "pragma uv-hash" card for which the hash does not match, it sends uvigot cards for every unversioned file that it holds. The client will use this information to figure out which @@ -422,11 +451,11 @@ The server might also send a uvigot card when it receives a uvgimme card but its reply message size is already oversized and hence unable to hold the usual uvfile reply.

        When a client receives a "uvigot" card, it checks to see if the -file needs to be transfered from client to server or from server to client. +file needs to be transferred from client to server or from server to client. If a client-to-server transmission is needed, the client schedules that transfer to occur on a subsequent HTTP request. If a server-to-client transfer is needed, then the client sends a "uvgimme" card back to the server to request the file content. @@ -443,10 +472,14 @@

        The argument to the gimme card is the ID of the artifact that the sender wants. The receiver will typically respond to a gimme card by sending a file card in its reply or in the next message.

        +

        The "gimme" name means "give me". The imperative "give me" is +pronounced as if it were a single word "gimme" in some dialects of +English (including the dialect spoken by the original author of Fossil). +

        3.7.1 Unversioned Gimme Cards

        Sync synchronizing unversioned content, the client may send "uvgimme" cards to the server. A uvgimme card requests that the server send unversioned content to the client. The format of a uvgimme card is @@ -497,59 +530,73 @@

        reqconfig configuration-name
        -

        As of [/timeline?r=trunk&c=2015-03-19+03%3A57%3A46&n=20|2015-03-19], the configuration-name must be one of the +

        As of 2018-06-04, the configuration-name must be one of the following values: @@ -610,11 +657,11 @@

        New pragma names may be added to the protocol from time to time in order to enhance the capabilities of Fossil. Unknown pragmas are silently ignored, for backwards compatibility. -

        The following are the known pragma names as of 2016-08-03: +

        The following are the known pragma names as of 2019-06-30:

        1. send-private

          The send-private pragma instructs the server to send all of its private artifacts to the client. The server will only obey this @@ -649,32 +696,60 @@

        2. uv-pull-only

          A server sends the uv-pull-only pragma to the client in response to a uv-hash pragma with a mismatched content hash argument. This pragma indicates that there are differences in unversioned content -between the client and server but that content can only be transfered +between the client and server but that content can only be transferred from server to client. The server is unwilling to accept content from the client because the client login lacks the "write-unversioned" permission.

        3. uv-push-ok

          A server sends the uv-push-ok pragma to the client in response to a uv-hash pragma with a mismatched content hash argument. This pragma indicates that there are differences in unversioned content -between the client and server and that content can only be transfered +between the client and server and that content can only be transferred in either direction. The server is willing to accept content from the client because the client login has the "write-unversioned" permission.

          +
        4. ci-lock CHECKIN-HASH CLIENT-ID

          +

          A client sends the "ci-lock" pragma to the server to indicate +that it is about to add a new check-in as a child of the +CHECKIN-HASH check-in and on the same branch as CHECKIN-HASH. +If some other client has already indicated that it was also +trying to commit against CHECKIN-HASH, that indicates that a +fork is about to occur, and the server will reply with +a "ci-lock-fail" pragma (see below). Check-in locks +automatically expire when the check-in actually occurs, or +after a timeout (currently 24-hours but subject to change). + +

        5. ci-lock-fail LOGIN MTIME

          +

          When a server receives two or more "ci-lock" pragma messages +for the same check-in but from different clients, the second a +subsequent ci-lock will provoke a ci-lock-fail pragma in the +reply to let the client know that it if continues with the +check-in it will likely generate a fork. The LOGIN and MTIME +arguments are intended to provide information to the client to +help it generate a more useful error message. +

          + +
        6. ci-unlock CLIENT-ID

          +

          A client sends the "ci-unlock" pragma to the server after +a successful commit. This instructs the server to release +any lock on any check-in previously held by that client. +The ci-unlock pragma helps to avoid false-positive lock warnings +that might arise if a check-in is aborted and then restarted +on a branch.

        3.12 Comment Cards

        Any card that begins with "#" (ASCII 0x23) is a comment card and is silently ignored.

        -

        3.13 Error Cards

        +

        3.13 Message and Error Cards

        If the server discovers anything wrong with a request, it generates an error card in its reply. When the client sees the error card, it displays an error message to the user and aborts the sync operation. An error card looks like this:

        @@ -689,10 +764,19 @@ newline (ASCII 0x0a) is "\n" (ASCII 0x6C, x6E). A backslash (ASCII 0x5C) is represented as two backslashes "\\". Apart from space and newline, no other whitespace characters nor any unprintable characters are allowed in the error message.

        + +

        The server can also send a message card that also prints a +message on the client console, but which is not an error: + +

        +message message-text +
        + +

        The message-text uses the same format as an error message.

        3.14 Unknown Cards

        If either the client or the server sees a card that is not described above, then it generates an error and aborts.

        @@ -911,10 +995,11 @@
      7. cookie cookie-text
      8. reqconfig parameter-name
      9. config parameter-name size \n content
      10. pragma name value...
      11. error error-message +
      12. message text-messate
      13. # arbitrary-text...
      14. Phantoms are artifacts that a repository knows exist but does not possess.
      15. Clusters are artifacts that contain IDs of other artifacts.
      16. Clusters are created automatically on the server during a pull. Index: www/tech_overview.wiki ================================================================== --- www/tech_overview.wiki +++ www/tech_overview.wiki @@ -6,12 +6,12 @@

        1.0 Introduction

        At its lowest level, a Fossil repository consists of an unordered set of immutable "artifacts". You might think of these artifacts as "files", since in many cases the artifacts are exactly that. -But other "control artifacts" -are also included in the mix. These control artifacts define the relationships +But other "structural artifacts" are also included in the mix. +These structural artifacts define the relationships between artifacts - which files go together to form a particular version of the project, who checked in that version and when, what was the check-in comment, what wiki pages are included with the project, what are the edit histories of each wiki page, what bug reports or tickets are included, who contributed to the evolution of each ticket, and so forth. @@ -53,11 +53,11 @@ checkout for a project and contains state information that is unique to that working checkout. Fossil does not always use all three database files. The web interface, for example, typically only uses the repository database. And the -[/help/all | fossil setting] command only opens the configuration database +[/help/all | fossil settings] command only opens the configuration database when the --global option is used. But other commands use all three databases at once. For example, the [/help/status | fossil status] command will first locate the checkout database, then use the checkout database to find the repository database, then open the configuration database. Whenever multiple databases are used at the same time, @@ -68,30 +68,31 @@ database files are used by Fossil, with detailed discussion following.
        • css
        • header
        • footer +
        • details
        • logo-mimetype
        • logo-image
        • background-mimetype
        • background-image
        • index-page
        • timeline-block-markup
        • timeline-max-comment
        • timeline-plaintext -
          • adunit
          • adunit-omit-if-admin
          • adunit-omit-if-user -
          • white-foreground +
              +
            • th1-docs +
            • th1-hooks +
            • th1-setup +
            • tcl +
            • tcl-setup
            • project-name
            • short-project-name
            • project-description
            • index-page
            • manifest
            • binary-glob
            • clean-glob -
              • ignore-glob
              • keep-glob +
              • crlf-glob +
                • crnl-glob
                • encoding-glob
                • empty-dirs
                • allow-symlinks
                • dotfiles +
                • parent-project-code +
                • parent-projet-name +
                • hash-policy +
                • mv-rm-files
                • ticket-table
                • ticket-common
                • ticket-change
                • ticket-newpage -
                  • ticket-viewpage
                  • ticket-editpage +
                    • ticket-reportlist
                    • ticket-report-template
                    • ticket-key-template
                    • ticket-title-expr
                    • ticket-closed-expr +
                    • xfer-common-script +
                    • xfer-push-script +
                    • xfer-commit-script +
                    • xfer-ticket-script
                    • @reportfmt
                    • @user
                    • @concealed
                    • @shun
                    -

                    Configuration Database
                    "~/.fossil"

                    +

                    Configuration Database
                    "~/.fossil" or
                    +"~/.config/fossil.db"

                      -
                    • Global [/help/setting |settings] +
                    • Global [/help/settings |settings]
                    • List of active repositories used by the [/help/all | all] command

                    Repository Database
                    "project.fossil"

                    • [./fileformat.wiki | Global state of the project] encoded using delta-compression -
                    • Local [/help/setting|settings] +
                    • Local [/help/settings|settings]
                    • Web interface display preferences
                    • User credentials and permissions
                    • Metadata about the global state to facilitate rapid queries
                    -

                    Checkout Database
                    "_FOSSIL_"

                    +

                    Checkout Database
                    "_FOSSIL_" or ".fslckout"

                    • The repository database used by this checkout
                    • The version currently checked out
                    • Other versions [/help/merge | merged] in but not yet [/help/commit | committed] @@ -104,16 +105,17 @@
                    +

                    2.1 The Configuration Database

                    The configuration database holds cross-repository preferences and a list of all repositories for a single user. -The [/help/setting | fossil setting] command can be used to specify various +The [/help/settings | fossil settings] command can be used to specify various operating parameters and preferences for Fossil repositories. Settings can apply to a single repository, or they can apply globally to all repositories for a user. If both a global and a repository value exists for a setting, then the repository-specific value takes precedence. All of the settings have reasonable defaults, and so many users will never need to change them. @@ -123,18 +125,58 @@ The configuration database also maintains a list of repositories. This list is used by the [/help/all | fossil all] command in order to run various operations such as "sync" or "rebuild" on all repositories managed by a user. -On Unix systems, the configuration database is named ".fossil" and is -located in the user's home directory. On Windows, the configuration -database is named "_fossil" (using an underscore as the first character -instead of a dot) and is located in the directory specified by the -LOCALAPPDATA, APPDATA, or HOMEPATH environment variables, in that order. - -You can override this default location by defining the environment -variable FOSSIL_HOME pointing to an appropriate (writable) directory. + +

                    2.1.1 Location Of The Configuration Database

                    + +On Unix systems, the configuration database is named by the following +algorithm: + +
                    +
                    1. if environment variable FOSSIL_HOME exists + → $FOSSIL_HOME/.fossil +
                    2. if file ~/.fossil exists →~/.fossil +
                    3. if environment variable XDG_CONFIG_HOME exists +  →$XDG_CONFIG_HOME/fossil.db +
                    4. if the directory ~/.config exists +  →~/.config/fossil.db +
                    5. Otherwise →~/.fossil +
                    + +Another way of thinking of this algorithm is the following: + + * Use "$FOSSIL_HOME/.fossil" if the FOSSIL_HOME variable is defined + * Use the XDG-compatible name (usually ~/.config/fossil.db) on XDG systems + if the ~/.fossil file does not already exist + * Otherwise, use the traditional unix name of "~/.fossil" + +This algorithm is complex due to the need for historical compatibility. +Originally, the database was always just "~/.fossil". Then support +for the FOSSIL_HOME environment variable as added. Later, support for the +[https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html|XDG-compatible configation filenames] +was added. Each of these changes needed to continue to support legacy +installations. + +On Windows, the configuration database is the first of the following +for which the corresponding environment variables exist: + + * %FOSSIL_HOME%/_fossil + * %LOCALAPPDATA%/_fossil + * %APPDATA%/_fossil + * %USERPROFILES%/_fossil + * %HOMEDRIVE%%HOMEPATH%/_fossil + +The second case is the one that usually determines the name Note that the +FOSSIL_HOME environment variable can always be set to determine the +location of the configuration database. Note also that the configuration +database file itself is called ".fossil" or "fossil.db" on unix but +"_fossil" on windows. + +The [/help?cmd=info|fossil info] command will show the location of +the configuration database on a line that starts with "config-db:".

                    2.2 Repository Databases

                    The repository database is the file that is commonly referred to as "the repository". This is because the repository database contains, @@ -151,33 +193,36 @@ [./fileformat.wiki | enduring, global, shared state] of the project. The artifacts are stored as BLOBs, compressed using [http://www.zlib.net/ | zlib compression] and, where applicable, using [./delta_encoder_algorithm.wiki | delta compression]. The combination of zlib and delta compression results in a considerable -space savings. For the SQLite project, at the time of this writing, -the total size of all artifacts is over 2.0 GB but thanks to the -combined zlib and delta compression, that content only takes up -32 MB of space in the repository database, for a compression ratio -of about 64:1. The average size of a content BLOB in the database -is around 500 bytes. +space savings. For the SQLite project (when this paragraph was last +updated on 2020-02-08) +the total size of all artifacts is over 7.1 GB but thanks to the +combined zlib and delta compression, that content only takes less than +97 MB of space in the repository database, for a compression ratio +of about 74:1. The median size of all content BLOBs after delta +and zlib compression have been applied is 156 bytes. +The median size of BLOBs without compression is 45,312 bytes. Note that the zlib and delta compression is not an inherent part of the Fossil file format; it is just an optimization. The enduring file format for Fossil is the unordered set of artifacts. The compression techniques are just a detail of how the current implementation of Fossil happens to store these artifacts efficiently on disk. -All of the original uncompressed and undeltaed artifacts can be extracted +All of the original uncompressed and un-delta'd artifacts can be extracted from a Fossil repository database using the [/help/deconstruct | fossil deconstruct] command. Individual artifacts can be extracted using the [/help/artifact | fossil artifact] command. When accessing the repository database using raw SQL and the [/help/sqlite3 | fossil sql] command, the extension function -"content()" with a single argument which is the SHA1 hash -of an artifact will return the complete undeleted and uncompressed +"content()" with a single argument which is the SHA1 or +SHA3-256 hash +of an artifact will return the complete uncompressed content of that artifact. Going the other way, the [/help/reconstruct | fossil reconstruct] command will scan a directory hierarchy and add all files found to a new repository database. The [/help/import | fossil import] command @@ -204,11 +249,11 @@ The metadata is held in various SQL tables in the repository database. The metadata is designed to facilitate queries for the various timelines and reports that Fossil generates. As the functionality of Fossil evolves, the schema for the metadata can and does change. -But schema changes do no invalidate the repository. Remember that the +But schema changes do not invalidate the repository. Remember that the metadata contains no new information - only information that has been extracted from the canonical artifacts and saved in a more useful form. Hence, when the metadata schema changes, the prior metadata can be discarded and the entire metadata corpus can be recomputed from the canonical artifacts. That is what the @@ -235,11 +280,11 @@ * The project logo image * Fields of tickets that are considered "significant" and which are therefore collected from artifacts and made available for display * Templates for screens to view, edit, and create tickets * Ticket report formats and display preferences - * Local values for [/help/setting | settings] that override the + * Local values for [/help/settings | settings] that override the global values defined in the per-user configuration database. Though the display and processing preferences do not move between repository instances using [/help/sync | fossil sync], this information can be shared between repositories using the @@ -277,26 +322,25 @@ project - is intended to be an append-only database. In other words, new artifacts can be added but artifacts can never be removed. But it sometimes happens that inappropriate content is mistakenly or maliciously added to a repository. The only way to get rid of the undesired content is to [./shunning.wiki | "shun"] it. -The "shun" table in the repository database records the SHA1 hash of +The "shun" table in the repository database records the hash values for all shunned artifacts. The shun table can be pushed or pulled using the [/help/config | fossil config] command with the "shun" AREA argument. The shun table is also copied during a [/help/clone | clone]. +

                    2.3 Checkout Databases

                    -Unlike several other popular DVCSes, Fossil allows a single repository +Fossil allows a single repository to have multiple working checkouts. Each working checkout has a single database in its root directory that records the state of that checkout. -The checkout database is named "_FOSSIL_" by default, but can be renamed -to ".fslckout" if desired. (Future versions of Fossil might make -".fslckout" the default name.) The checkout database records information -such as the following: +The checkout database is named "_FOSSIL_" or ".fslckout". +The checkout database records information such as the following: * The name of the repository database file. * The version that is currently checked out. * Files that have been [/help/add | added], [/help/rm | removed], or [/help/mv | renamed] but not @@ -313,11 +357,11 @@ For Fossil commands that run from within a working checkout, the first thing that happens is that Fossil locates the checkout database. Fossil first looks in the current directory. If not found there, it looks in the parent directory. If not found there, the parent of the parent. And so forth until either the checkout database is found -or the search reaches the root of the filesystem. (In the latter case, +or the search reaches the root of the file system. (In the latter case, Fossil returns an error, of course.) Once the checkout database is located, it is used to locate the repository database. Notice that the checkout database contains a pointer to the repository database but that the repository database has no record of the checkout ADDED www/th1-hooks.md Index: www/th1-hooks.md ================================================================== --- /dev/null +++ www/th1-hooks.md @@ -0,0 +1,134 @@ +TH1 Hooks +========= + +** DRAFT ** + +The **TH1 hooks** feature allows TH1 scripts to be +configured that can monitor, create, alter, or cancel the execution of +Fossil commands and web pages. + +This feature requires the TH1 hooks feature to be enabled at compile-time. +Additionally, the "th1-hooks" repository setting must be enabled at runtime +in order to successfully make use of this feature. + +TH1 Hook Related User-Defined Procedures +---------------------------------------- + +In order to activate TH1 hooks, one or more of the following user-defined +procedures should be defined, generally from within the "th1-setup" script +(setting) for a repository. The following bullets summarize the available +TH1 hooks: + + * command\_hook -- _Called before execution of a command._ + * command\_notify -- _Called after execution of a command._ + * webpage\_hook -- _Called before rendering of a web page._ + * webpage\_notify -- _Called after rendering of a web page._ + +TH1 Hook Related Variables for Commands +--------------------------------------- + + * cmd\_name -- _Name of command being executed._ + * cmd\_args -- _Current command line arguments._ + * cmd\_flags -- _Bitmask of CMDFLAG values for the command being executed._ + +TH1 Hook Related Variables for Web Pages +---------------------------------------- + + * web\_name -- _Name of web page being rendered._ + * web\_args -- _Current web page arguments._ + * web\_flags -- _Bitmask of CMDFLAG values for the web page being rendered._ + +TH1 Hook Related Return Codes for Commands +----------------------------------------------------------------------- + + * TH\_OK -- _Command will be executed, notification will be executed._ + * TH\_ERROR -- _Command will be skipped, notification will be skipped, + error message will be emitted._ + * TH\_BREAK -- _Command will be skipped, notification will be skipped._ + * TH\_RETURN -- _Command will be executed, notification will be skipped._ + * TH\_CONTINUE -- _Command will be skipped, notification will be executed._ + +For commands that are not included in the Fossil binary, allowing their +execution will cause the standard "unknown command" error message to be +generated, which will typically exit the process. Therefore, adding a +new command generally requires using the TH_CONTINUE return code. + +TH1 Hook Related Return Codes for Web Pages +------------------------------------------------------------------------ + + * TH\_OK -- _Web page will be rendered, notification will be executed._ + * TH\_ERROR -- _Web page will be skipped, notification will be skipped, + error message will be emitted._ + * TH\_BREAK -- _Web page will be skipped, notification will be skipped._ + * TH\_RETURN -- _Web page will be rendered, notification will be skipped._ + * TH\_CONTINUE -- _Web page will be skipped, notification will be executed._ + +For web pages that are not included in the Fossil binary, allowing their +rendering will cause the standard "Not Found" error message to be generated, +which will cause an HTTP 404 status code to be sent. Therefore, adding a +new web page generally requires using the TH_CONTINUE return code. + +Triggering TH1 Return Codes from a Script +-------------------------------------------------------------------------- + + * TH\_OK -- _This is the default return code, nothing special needed._ + * TH\_ERROR -- _Use the **error** command._ + * TH\_BREAK -- _Use the **break** command._ + * TH\_RETURN -- _Use the **return -code 5** command._ + * TH\_CONTINUE -- _Use the **continue** command._ + +TH1 command_hook Procedure +----------------------------------------------------- + + * command\_hook + +This user-defined procedure, if present, is called just before the +execution of a command. The name of the command being executed will +be stored in the "cmd\_name" global variable. The arguments to the +command being executed will be stored in the "cmd\_args" global variable. +The associated CMDFLAG value will be stored in the "cmd\_flags" global +variable. Before exiting, the procedure should trigger the return +code that corresponds to the desired action +to take next. + +TH1 command_notify Procedure +--------------------------------------------------------- + + * command\_notify + +This user-defined procedure, if present, is called just after the +execution of a command. The name of the command being executed will +be stored in the "cmd\_name" global variable. The arguments to the +command being executed will be stored in the "cmd\_args" global variable. +The associated CMDFLAG value will be stored in the "cmd\_flags" global +variable. Before exiting, the procedure should trigger the return +code that corresponds to the desired action +to take next. + +TH1 webpage_hook Procedure +----------------------------------------------------- + + * webpage\_hook + +This user-defined procedure, if present, is called just before the +rendering of a web page. The name of the web page being rendered will +be stored in the "web\_name" global variable. The arguments to the +web page being rendered will be stored in the "web\_args" global variable. +The associated CMDFLAG value will be stored in the "web\_flags" global +variable. Before exiting, the procedure should trigger the return +code that corresponds to the desired action +to take next. + +TH1 webpage_notify Procedure +--------------------------------------------------------- + + * webpage\_notify + +This user-defined procedure, if present, is called just after the +rendering of a web page. The name of the web page being rendered will +be stored in the "web\_name" global variable. The arguments to the +web page being rendered will be stored in the "web\_args" global variable. +The associated CMDFLAG value will be stored in the "web\_flags" global +variable. Before exiting, the procedure should trigger the return +code that corresponds to the desired action +to take next. Index: www/th1.md ================================================================== --- www/th1.md +++ www/th1.md @@ -12,12 +12,12 @@ time all of the test cases for SQLite were written in Tcl and Tcl could not be easily compiled on the SymbianOS. So TH1 was developed as a cut-down version of Tcl that would facilitate running the SQLite test scripts on SymbianOS. -The testing of SQLite on SymbianOS was eventually accomplished by other -means. But Fossil was first being designed at about the same time. +Fossil was first being designed at about the same time that TH1 was +being developed for testing SQLite on SymbianOS. Early prototypes of Fossil were written in pure Tcl. But as the development shifted toward the use of C-code, the need arose to have a Tcl-like scripting language to help with code generation. TH1 was small and light-weight and used minimal resources and seemed ideally suited for the task. @@ -33,51 +33,83 @@ seem inefficient, but it is faster than people imagine, and numeric computations do not come up very often for the kinds of work that TH1 does, so it has never been a factor.) A TH1 script consist of a sequence of commands. -Each command is terminated by the first (unescaped) newline or ";" character. +Each command is terminated by the first *unescaped* newline or ";" character. The text of the command (excluding the newline or semicolon terminator) is broken into space-separated tokens. The first token is the command -name and subsequent tokens are the arguments. In this since, TH1 syntax +name and subsequent tokens are the arguments. In this sense, TH1 syntax is similar to the familiar command-line shell syntax. A token is any sequence of characters other than whitespace and semicolons. Or, all text without double-quotes is a single token even if it includes -whitespace and semicolons. Or, all text without nested {...} pairs is a +whitespace and semicolons. Or, all text within nested {...} pairs is a single token. The nested {...} form of tokens is important because it allows TH1 commands to have an appearance similar to C/C++. It is important to remember, though, that a TH1 script is really just a list of text commands, not a context-free language with a grammar like C/C++. This can be confusing to long-time -C/C++ programmers because TH1 does look a lot like C/C++. But the semantics +C/C++ programmers because TH1 does look a lot like C/C++, but the semantics of TH1 are closer to FORTH or Lisp than they are to C. -Consider the "if" command in TH1. +Consider the `if` command in TH1. if {$current eq "dev"} { puts "hello" } else { puts "world" } The example above is a single command. The first token, and the name -of the command, is "if". -The second token is '$current eq "dev"' - an expression. (The outer {...} +of the command, is `if`. +The second token is `$current eq "dev"` - an expression. (The outer {...} are removed from each token by the command parser.) The third token -is the 'puts "hello"', with its whitespace and newlines. The fourth token -is "else". And the fifth and last token is 'puts "world"'. +is the `puts "hello"`, with its whitespace and newlines. The fourth token +is `else"` And the fifth and last token is `puts "world"`. -The "if" command word by evaluating its first argument (the second token) -as an expression, and if that expression is true, evaluating its +The `if` command evaluates its first argument (the second token) +as an expression, and if that expression is true, evaluates its second argument (the third token) as a TH1 script. -If the expression is false and the third argument is "else" then +If the expression is false and the third argument is `else`, then the fourth argument is evaluated as a TH1 expression. So, you see, even though the example above spans five lines, it is really just a single command. + +All of this also explains the emphasis on *unescaped* characters above: +the curly braces `{ }` are string quoting characters in Tcl/TH1, not +block delimiters as in C. This is how we can have a command that extends +over multiple lines. It is also why the `else` keyword must be cuddled +up with the closing brace for the `if` clause's scriptlet. The following +is invalid Tcl/TH1: + + if {$current eq "dev"} { + puts "hello" + } + else { + puts "world" + } + +If you try to run this under either Tcl or TH1, the interpreter will +tell you that there is no `else` command, because with the newline on +the third line, you terminated the `if` command. + +Occasionally in Tcl/TH1 scripts, you may need to use a backslash at the +end of a line to allow a command to extend over multiple lines without +being considered two separate commands. Here's an example from one of +Fossil's test scripts: + + return [lindex [regexp -line -inline -nocase -- \ + {^uuid:\s+([0-9A-F]{40}) } [eval [getFossilCommand \ + $repository "" info trunk]]] end] + +Those backslashes allow the command to wrap nicely within a standard +terminal width while telling the interpreter to consider those three +lines as a single command. + Summary of Core TH1 Commands ---------------------------- The original Tcl language after when TH1 is modeled has a very rich @@ -105,10 +137,11 @@ * rename OLD NEW * return ?-code CODE? ?VALUE? * set VARNAME VALUE * string compare STR1 STR2 * string first NEEDLE HAYSTACK ?START-INDEX? + * string index STRING INDEX * string is CLASS STRING * string last NEEDLE HAYSTACK ?START-INDEX? * string length STRING * string range STRING FIRST LAST * string repeat STRING COUNT @@ -134,12 +167,14 @@ features of Fossil. The following is a summary of the extended commands: * anoncap * anycap * artifact + * cgiHeaderLine * checkout * combobox + * copybtn * date * decorate * dir * enable\_output * encode64 @@ -153,10 +188,11 @@ * http * httpize * insertCsrf * linecount * markdown + * nonce * puts * query * randhex * redirect * regexp @@ -164,22 +200,26 @@ * render * repository * searchable * setParameter * setting + * stime * styleHeader * styleFooter + * styleScript * tclEval * tclExpr * tclInvoke * tclIsSafe * tclMakeSafe * tclReady * trace - * stime + * unversioned content + * unversioned list * utime * verifyCsrf + * verifyLogin * wiki Each of the commands above is documented by a block comment above their implementation in the th\_main.c or th\_tcl.c source files. @@ -210,10 +250,17 @@ * artifact ID ?FILENAME? Attempts to locate the specified artifact and return its contents. An error is generated if the repository is not open or the artifact cannot be found. + +TH1 cgiHeaderLine Command +----------------------------------------------------- + + * cgiHeaderLine line + +Adds the specified line to the CGI header. TH1 checkout Command ------------------------------------------- * checkout ?BOOLEAN? @@ -232,10 +279,32 @@ CGI parameter and the name of a variable that contains the currently selected value. TEXT-LIST is a list of possible values for the combobox. NUMLINES is 1 for a true combobox. If NUMLINES is greater than one then the display is a listbox with the number of lines given. +TH1 copybtn Command +----------------------------------------- + + * copybtn TARGETID FLIPPED TEXT ?COPYLENGTH? + +Output TEXT with a click-to-copy button next to it. Loads the copybtn.js +Javascript module, and generates HTML elements with the following IDs: + + * TARGETID: The `` wrapper around TEXT. + * copy-TARGETID: The `` for the copy button. + +If the FLIPPED argument is non-zero, the copy button is displayed after TEXT. + +The optional COPYLENGTH argument defines the length of the substring of TEXT +copied to clipboard: + + * <= 0: No limit (default if the argument is omitted). + * >= 3: Truncate TEXT after COPYLENGTH (single-byte) characters. + * 1: Use the "hash-digits" setting as the limit. + * 2: Use the length appropriate for URLs as the limit (defined at + compile-time by `FOSSIL_HASH_DIGITS_URL`, defaults to 16). + TH1 date Command ----------------------------------- * date ?-local? @@ -249,11 +318,11 @@ Renders STRING as wiki content; however, only links are handled. No other markup is processed. TH1 dir Command -------------------------------------------- +--------------------------------- * dir CHECKIN ?GLOB? ?DETAILS? Returns a list containing all files in CHECKIN. If GLOB is given only the files matching the pattern GLOB within CHECKIN will be returned. @@ -265,11 +334,11 @@ TH1 enable\_output Command ------------------------------------------------------ * enable\_output BOOLEAN -Enable or disable sending output when the combobox, puts, or wiki +Enable or disable sending output when the combobox, copybtn, puts, or wiki commands are used. TH1 encode64 Command ------------------------------------------- @@ -342,10 +411,11 @@ 1. **tclPrivateStubs** -- _Uses Tcl private stubs (i.e. header-only)._ 1. **json** -- _Support for the JSON APIs._ 1. **markdown** -- _Support for Markdown documentation format._ 1. **unicodeCmdLine** -- _The command line arguments are Unicode._ 1. **dynamicBuild** -- _Dynamically linked to libraries._ + 1. **mman** -- _Uses POSIX memory APIs from "sys/mman.h"._ 1. **see** -- _Uses the SQLite Encryption Extension._ Specifying an unknown feature will return a value of false, it will not raise a script error. @@ -400,18 +470,25 @@ Returns one more than the number of \n characters in STRING. But never returns less than MIN or more than MAX. TH1 markdown Command ---------------------------------------------- +------------------------------------------- * markdown STRING Renders the input string as markdown. The result is a two-element list. The first element contains the body, rendered as HTML. The second element is the text-only title string. +TH1 nonce Command +------------------------------------- + + * nonce + +Returns the value of the cryptographic nonce for the request being processed. + TH1 puts Command ----------------------------------- * puts STRING @@ -438,14 +515,18 @@ omitted, use a value of 10. TH1 redirect Command ------------------------------------------- - * redirect URL + * redirect URL ?withMethod? -Issues an HTTP redirect (302) to the specified URL and then exits the -process. +Issues an HTTP redirect to the specified URL and then exits the process. +By default, an HTTP status code of 302 is used. If the optional withMethod +argument is present and non-zero, an HTTP status code of 307 is used, which +should force the user agent to preserve the original method for the request +(e.g. GET, POST) instead of (possibly) forcing the user agent to change the +method to GET. TH1 regexp Command --------------------------------------- * regexp ?-nocase? ?--? exp string @@ -517,24 +598,39 @@ ----------------------------------------- * setting name Gets and returns the value of the specified setting. + +TH1 stime Command +------------------------------------- + + * stime + +Returns the number of microseconds of CPU time consumed by the current +process in system space. TH1 styleHeader Command ------------------------------------------------- * styleHeader TITLE -Render the configured style header. +Render the configured style header for the selected skin. TH1 styleFooter Command ------------------------------------------------- * styleFooter -Render the configured style footer. +Render the configured style footer for the selected skin. + +TH1 styleScript Command +------------------------------------------------- + + * styleScript + +Render the configured JavaScript for the selected skin. TH1 tclEval Command ----------------------------------------- **This command requires the Tcl integration feature.** @@ -577,11 +673,11 @@ Returns non-zero if the Tcl interpreter is "safe". The Tcl interpreter will be created automatically if it has not been already. TH1 tclMakeSafe Command ---------------------------------------------- +------------------------------------------------- **This command requires the Tcl integration feature.** * tclMakeSafe @@ -603,17 +699,26 @@ * trace STRING Generates a TH1 trace message if TH1 tracing is enabled. -TH1 stime Command -------------------------------------- +TH1 unversioned content Command +----------------------------------------------------------------- + + * unversioned content FILENAME + +Attempts to locate the specified unversioned file and return its contents. +An error is generated if the repository is not open or the unversioned file +cannot be found. + +TH1 unversioned list Command +----------------------------------------------------------- - * stime + * unversioned list -Returns the number of microseconds of CPU time consumed by the current -process in system space. +Returns a list of the names of all unversioned files held in the local +repository. An error is generated if the repository is not open. TH1 utime Command ------------------------------------- * utime @@ -629,10 +734,18 @@ Before using the results of a form, first call this command to verify that this Anti-CSRF token is present and is valid. If the Anti-CSRF token is missing or is incorrect, that indicates a cross-site scripting attack. If the event of an attack is detected, an error message is generated and all further processing is aborted. + +TH1 verifyLogin Command +------------------------------------------------- + + * verifyLogin + +Returns non-zero if the specified user name and password represent a +valid login for the repository. TH1 wiki Command ----------------------------------- * wiki STRING Index: www/theory1.wiki ================================================================== --- www/theory1.wiki +++ www/theory1.wiki @@ -16,18 +16,18 @@

                    Fossil Is A NoSQL Database

                    We begin with the first question: Fossil is not based on a distributed NoSQL database because Fossil is a distributed NoSQL database. -Fossil is not based on SQLite. +Fossil is not based on SQLite. The current implementation of Fossil uses SQLite as a local store for the content of the distributed database and as a cache for meta-information about the distributed database that is precomputed for quick and easy presentation. But the use of SQLite in this role is an implementation detail and is not fundamental to the design. Some future version of Fossil might do away with SQLite and substitute a pile-of-files or -a key/value database in place of SQLite. +a key/value database in place of SQLite. (Actually, that is very unlikely to happen since SQLite works amazingly well in its current role, but the point is that omitting SQLite from Fossil is a theoretical possibility.) The underlying database that Fossil implements has nothing to do with @@ -38,11 +38,12 @@ been checked into the Fossil repository. Call these "content artifacts". Other artifacts, known as "control artifacts", contain ASCII text in a particular format that defines relationships between other artifacts, such as which content artifacts that go together to form a particular version of the -project. Each artifact is named by its SHA1 hash and is thus immutable. +project. Each artifact is named by its SHA1 or SHA3-256 hash and is +thus immutable. Artifacts can be added to the database but not removed (if we ignore the exceptional case of [./shunning.wiki | shunning].) Repositories synchronize by computing the union of their artifact sets. SQL and relation theory play no role in any of this. @@ -64,11 +65,11 @@ a NoSQL database) and there is the local relational database. The bag-of-artifacts database has a fixed format and is what defines a Fossil repository. Fossil will never modify the file format of the bag-of-artifacts database in an incompatible way because to do so would be to make something that is no longer "Fossil". The local relational database, on the other hand, -is a cache that contains information derived from the bag-of-artifacts. +is a cache that contains information derived from the bag-of-artifacts. The schema of the local relational database changes from time to time as the Fossil implementation is enhanced, and the content is recomputed from the unchanging bag of artifacts. The local relational database is an implementation detail which currently happens to use SQLite. @@ -89,11 +90,11 @@ the first question.

                    SQL Is A High-Level Scripting Language

                    The second concern states that Fossil does not use a high-level scripting -language. But that is not true. Fossil uses SQL (as implemented by SQLite) +language. But that is not true. Fossil uses SQL (as implemented by SQLite) as its scripting language. This misunderstanding likely arises because people fail to appreciate that SQL is a programming language. People are taught that SQL is a "query language" as if that were somehow different from a @@ -108,11 +109,11 @@ is an extraordinary high-level programming language, but it is still just a programming language. For certain types of problems, SQL has a huge advantage over other programming languages because it is so high level and because it allows -programmers to focus more on the what and less of the how +programmers to focus more on the what and less on the how of a computation. In other words, programmers tend to think about problems at a much higher level when using SQL; this can result in better applications. SQL is also very dense. In practice, this often means that a few @@ -125,11 +126,11 @@ out using SQL statements. It is true that these SQL statements are glued together with C code, but it turns out that C works surprisingly well in that role. Several early prototypes of Fossil were written in a scripting language (TCL). We normally find that TCL programs are shorter than the equivalent C code by a factor of 10 or more. But in the case of Fossil, -the use of TCL was actually making the code longer and more difficult to +the use of TCL was actually making the code longer and more difficult to understand. And so in the final design, we switched from TCL to C in order to make the code easier to implement and debug. Without the advantages of having SQLite built in, the design might well Index: www/tickets.wiki ================================================================== --- www/tickets.wiki +++ www/tickets.wiki @@ -10,28 +10,28 @@ Each ticket change artifact contains the following information:
                    • The ID of the ticket that was changed -
                    • The timestamp for when the change occurred +
                    • The time stamp for when the change occurred
                    • The user who made the change
                    • A list of key/value pairs that show what changed in the ticket
                    To determine the current state of a particular ticket, Fossil orders the change artifacts for that ticket from oldest to most recent, -then applies each change in timestamp order. +then applies each change in time stamp order. On each change artifact, there are one or more key/value pairs that implement the change. The key corresponds to a field of the ticket that is modified. The value may either replace the earlier value for that key, or the value may be appended to the prior value.

                    2.0 Ticket Tables

                    The low-level artifact format for ticket content is tedious and -cumbersome to access in realtime. To facility reporting and display +cumbersome to access in real time. To facility reporting and display of tickets, the low-level artifact information is collected and summarized in a pair of SQL tables in each local repository. Display and reporting of tickets is accomplished by querying these two tables. Note that only the low-level ticket change artifacts are synced. The @@ -132,12 +132,12 @@ Each row in the TICKETCHNG table corresponds to a single ticket change artifact. The tkt_id field is the integer primary key of the TICKET table entry for the corresponding ticket. The tkt_rid field is the integer primary key for the BLOB table entry that contains the low-level -artifact text. The tkt_mtime field is the timestamp on the ticket -change artifact, expressed as a julian day number. If the ticket +artifact text. The tkt_mtime field is the time stamp on the ticket +change artifact, expressed as a Julian day number. If the ticket change artifact contains a key/value pair where the key is "login", then the corresponding value is stored in the login field of the TICKETCHNG table. The same it true for "username", "mimetype", and "icomment" fields. Any time there is a key/value pair in the ticket change artifact and the key corresponds to the name of a field in the @@ -154,11 +154,11 @@ hexadecimal constant. The tkt_mtime and tkt_ctime fields hold the times of the most recent and the oldest ticket change artifacts for this ticket, respectively. To reconstruct the TICKET table, the ticket change -artifacts are visited in timestamp order. As each ticket change artifact is +artifacts are visited in time stamp order. As each ticket change artifact is visited, its key/value pairs are examined. For any key/value pair in which the key is the same as a field in the TICKET table, the value of that pair either replaces or is appended to the previous value of the corresponding field in the TICKET table. Whether a value is replaced or appended is determined by markings in the ticket change @@ -194,6 +194,6 @@ The TICKETCHNG table was added to support new-style tickets. In the new style, comment text is stored with the "icomment" (for "Incremental Comment") key and appears separately, and with its on mimetype, in multiple rows of the TICKETCHNG table. It then falls to the TH1 script code on the View Ticket Page to query the TICKETCHNG table and extract and format -the various comments in timestamp order. +the various comments in time stamp order. ADDED www/tls-nginx.md Index: www/tls-nginx.md ================================================================== --- /dev/null +++ www/tls-nginx.md @@ -0,0 +1,430 @@ +# Proxying Fossil via HTTPS with nginx + +One of the [many ways](./ssl.wiki) to provide TLS-encrypted HTTP access +(a.k.a. HTTPS) to Fossil is to run it behind a web proxy that supports +TLS. This document explains how to use the powerful [nginx web +server](http://nginx.org/) to do that. + +This document is an extension of the [Serving via nginx on Debian][nod] +document. Please read that first, then come back here to extend its +configuration with TLS. + +[nod]: ./server/debian/nginx.md + + +## Install Certbot + +The [nginx-on-Debian document][nod] had you install a few non-default +packages to the system, but there’s one more you need for this guide: + + $ sudo apt install certbot + +You can extend this guide to other operating systems by following the +instructions found via [the front Certbot web page][cb] instead, telling +it what OS and web stack you’re using. Chances are good that they’ve got +a good guide for you already. + + +# Configuring Let’s Encrypt, the Easy Way + +If your web serving needs are simple, [Certbot][cb] can configure nginx +for you and keep its certificates up to date. Simply follow Certbot’s +[nginx on Ubuntu 18.04 LTS guide][cbnu]. We’d recommend one small +change: to use the version of Certbot in the Ubuntu package repository +rather than download it from the Certbot site. + +You should be able to use the nginx configuration given in our [Serving +via nginx on Debian][nod] guide with little to no change. The main thing +to watch out for is that the TCP port number in the nginx configuration +needs to match the value you gave when starting Fossil. If you followed +that guide’s advice, it will be 9000. Another option is to use [the +`fslsrv` script](/file/tools/fslsrv), in which case the TCP port number +will be 12345 or higher. + + +# Configuring Let’s Encrypt, the Hard Way + +If you’re finding that you can’t get certificates to be issued or +renewed using the Easy Way instructions, the problem is usually that +your nginx configuration is too complicated for Certbot’s `--nginx` +plugin to understand. It attempts to rewrite your nginx configuration +files on the fly to achieve the renewal, and if it doesn’t put its +directives in the right locations, the domain verification can fail. + +Let’s Encrypt uses the [Automated Certificate Management +Environment][acme] protocol (ACME) to determine whether a given client +actually has control over the domain(s) for which it wants a certificate +minted. Let’s Encrypt will not blithely let you mint certificates for +`google.com` and `paypal.com` just because you ask for it! + +Your author’s configuration, glossed [in the HTTP-only guide][nod], +is complicated enough that +the current version of Certbot (0.28 at the time of this writing) can’t +cope with it. That’s the primary motivation for me to write this guide: +I’m addressing the “me” years hence who needs to upgrade to Ubuntu 20.04 +or 22.04 LTS and has forgotten all of this stuff. 😉 + + +## Step 1: Shifting into Manual + +The first thing to do is to turn off all of the Certbot automation, +because it’ll only get in our way. First, disable the Certbot package’s +automatic background updater: + + $ sudo systemctl disable certbot.timer + +Next, edit `/etc/letsencrypt/renewal/example.com.conf` to disable the +nginx plugins. You’re looking for two lines setting the “install” and +“auth” plugins to “nginx”. You can comment them out or remove them +entirely. + + +## Step 2: Configuring nginx + +This is a straightforward extension to [the HTTP-only +configuration](./server/debian/nginx.md#config): + + server { + server_name .foo.net; + + include local/tls-common; + + charset utf-8; + + access_log /var/log/nginx/foo.net-https-access.log; + error_log /var/log/nginx/foo.net-https-error.log; + + # Bypass Fossil for the static Doxygen docs + location /doc/html { + root /var/www/foo.net; + + location ~* \.(html|ico|css|js|gif|jpg|png)$ { + expires 7d; + add_header Vary Accept-Encoding; + access_log off; + } + } + + # Redirect everything else to the Fossil instance + location / { + include scgi_params; + scgi_pass 127.0.0.1:12345; + scgi_param HTTPS "on"; + scgi_param SCRIPT_NAME ""; + } + } + server { + server_name .foo.net; + root /var/www/foo.net; + include local/http-certbot-only; + access_log /var/log/nginx/foo.net-http-access.log; + error_log /var/log/nginx/foo.net-http-error.log; + } + +One big difference between this and the HTTP-only case is +that we need two `server { }` blocks: one for HTTPS service, and +one for HTTP-only service. + + +### HTTP over TLS (HTTPS) Service + +The first `server { }` block includes this file, `local/tls-common`: + + listen 443 ssl; + + ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; + + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + ssl_stapling on; + ssl_stapling_verify on; + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256”; + ssl_session_cache shared:le_nginx_SSL:1m; + ssl_prefer_server_ciphers on; + ssl_session_timeout 1440m; + +These are the common TLS configuration parameters used by all domains +hosted by this server. + +The first line tells nginx to accept TLS-encrypted HTTP connections on +the standard HTTPS port. It is the same as `listen 443; ssl on;` in +older versions of nginx. + +Since all of those domains share a single TLS certificate, we reference +the same `example.com/*.pem` files written out by Certbot with the +`ssl_certificate*` lines. + +The `ssl_dhparam` directive isn’t strictly required, but without it, the +server becomes vulnerable to the [Logjam attack][lja] because some of +the cryptography steps are precomputed, making the attacker’s job much +easier. The parameter file this directive references should be +generated automatically by the Let’s Encrypt package upon installation, +making those parameters unique to your server and thus unguessable. If +the file doesn’t exist on your system, you can create it manually, so: + + $ sudo openssl dhparam -out /etc/letsencrypt/dhparams.pem 2048 + +Beware, this can take a long time. On a shared Linux host I tried it on +running OpenSSL 1.1.0g, it took about 21 seconds, but on a fast, idle +iMac running LibreSSL 2.6.5, it took 8 minutes and 4 seconds! + +The next section is also optional. It enables [OCSP stapling][ocsp], a +protocol that improves the speed and security of the TLS connection +negotiation. + +The next section containing the `ssl_protocols` and `ssl_ciphers` lines +restricts the TLS implementation to only those protocols and ciphers +that are currently believed to be safe and secure. This section is the +one most prone to bit-rot: as new attacks on TLS and its associated +technologies are discovered, this configuration is likely to need to +change. Even if we fully succeed in [keeping this document +up-to-date](#evolution), the nature of this guide is to recommend static +configurations for your server. You will have to keep an eye on this +sort of thing and evolve your local configuration as the world changes +around it. + +Running a TLS certificate checker against your site occasionally is a +good idea. The most thorough service I’m aware of is the [Qualys SSL +Labs Test][qslt], which gives the site I’m basing this guide on an “A” +rating at the time of this writing. The long `ssl_ciphers` line above is +based on [their advice][qslc]: the default nginx configuration tells +OpenSSL to use whatever ciphersuites it considers “high security,” but +some of those have come to be considered “weak” in the time between that +judgement and the time of this writing. By explicitly giving the list of +ciphersuites we want OpenSSL to use within nginx, we can remove those +that become considered weak in the future. + +There are a few things you can do to get an even better +grade, such as to enable [HSTS][hsts], which prevents a particular +variety of [man in the middle attack][mitm] where our HTTP-to-HTTPS +permanent redirect is intercepted, allowing the attacker to prevent the +automatic upgrade of the connection to a secure TLS-encrypted one. I +didn’t enable that in the configuration above, because it is something a +site administrator should enable only after the configuration is tested +and stable, and then only after due consideration. There are ways to +lock your users out of your site by jumping to HSTS hastily. When you’re +ready, there are [guides you can follow][nest] elsewhere online. + + +### HTTP-Only Service + +While we’d prefer not to offer HTTP service at all, we need to do so for +two reasons: + +* The temporary reason is that until we get Let’s Encrypt certificates + minted and configured properly, we can’t use HTTPS yet at all. + +* The ongoing reason is that the Certbot [ACME][acme] HTTP-01 + challenge used by the Let’s Encrypt service only runs over HTTP. This is + not only because it has to work before HTTPS is first configured, + but also because it might need to work after a certificate is + accidentally allowed to lapse, to get that server back into a state + where it can speak HTTPS safely again. + +So, from the second `service { }` block, we include this file to set up +the minimal HTTP service we require, `local/http-certbot-only`: + + listen 80; + listen [::]:80; + + # This is expressed as a rewrite rule instead of an "if" because + # http://wiki.nginx.org/IfIsEvil + #rewrite ^(/.well-known/acme-challenge/.*) $1 break; + + # Force everything else to HTTPS with a permanent redirect. + #return 301 https://$host$request_uri; + +As written above, this configuration does nothing other than to tell +nginx that it’s allowed to serve content via HTTP on port 80 as well. +We’ll uncomment the `rewrite` and `return` directives below, when we’re +ready to begin testing. + +Notice that this configuration is very different from that in the +[HTTP-only nginx on Debian][nod] guide. Most of that guide’s nginx +directives moved up into the TLS `server { }` block, because we +eventually want this site to be as close to HTTPS-only as we can get it. + + +## Step 3: Dry Run + +We want to first request a dry run, because Let’s Encrypt puts some +rather low limits on how often you’re allowed to request an actual +certificate. You want to be sure everything’s working before you do +that. You’ll run a command something like this: + + $ sudo certbot certonly --webroot --dry-run \ + --webroot-path /var/www/example.com \ + -d example.com -d www.example.com \ + -d example.net -d www.example.net \ + --webroot-path /var/www/foo.net \ + -d foo.net -d www.foo.net + +There are two key options here. + +First, we’re telling Certbot to use its `--webroot` plugin instead of +the automated `--nginx` plugin. With this plugin, Certbot writes the +[ACME][acme] HTTP-01 challenge files to the static web document root +directory behind each domain. For this example, we’ve got two web +roots, one of which holds documents for two different second-level +domains (`example.com` and `example.net`) with `www` at the third level +being optional. This is a common sort of configuration these days, but +you needn’t feel that you must slavishly imitate it; the other web root +is for an entirely different domain, also with `www` being optional. +Since all of these domains are served by a single nginx instance, we +need to give all of this in a single command, because we want to mint a +single certificate that authenticates all of these domains. + +The second key option is `--dry-run`, which tells Certbot not to do +anything permanent. We’re just seeing if everything works as expected, +at this point. + + +### Troubleshooting the Dry Run + +If that didn’t work, try creating a manual test: + + $ mkdir -p /var/www/example.com/.well-known/acme-challenge + $ echo hi > /var/www/example.com/.well-known/acme-challenge/test + +Then try to pull that file over HTTP — not HTTPS! — as +`http://example.com/.well-known/acme-challenge/test`. I’ve found that +using Firefox or Safari is better for this sort of thing than Chrome, +because Chrome is more aggressive about automatically forwarding URLs to +HTTPS even if you requested “`http`”. + +In extremis, you can do the test manually: + + $ telnet foo.net 80 + GET /.well-known/acme-challenge/test HTTP/1.1 + Host: example.com + + HTTP/1.1 200 OK + Server: nginx/1.14.0 (Ubuntu) + Date: Sat, 19 Jan 2019 19:43:58 GMT + Content-Type: application/octet-stream + Content-Length: 3 + Last-Modified: Sat, 19 Jan 2019 18:21:54 GMT + Connection: keep-alive + ETag: "5c436ac2-4" + Accept-Ranges: bytes + + hi + +You type the first two lines at the remote system, plus the doubled +“Enter” to create the blank line, and you get something back that +hopefully looks like the rest of the text above. + +The key bits you’re looking for here are the “hi” line at the end — the +document content you created above — and the “200 OK” response code. If +you get a 404 or other error response, you need to look into your web +server logs to find out what’s going wrong. + +Note that it’s important to do this test with HTTP/1.1 when debugging a +name-based virtual hosting configuration like this. Unless you test only +with the primary domain name alias for the server, this test will fail. +Using the example configuration above, you can only use the +easier-to-type HTTP/1.0 protocol to test the `foo.net` alias. + +If you’re still running into trouble, the log file written by Certbot +can be helpful. It tells you where it’s writing it early in each run. + + + +## Step 4: Getting Your First Certificate + +Once the dry run is working, you can drop the `--dry-run` option and +re-run the long command above. (The one with all the `--webroot*` +flags.) This should now succeed, and it will save all of those flag +values to your Let’s Encrypt configuration file, so you don’t need to +keep giving them. + + + +## Step 5: Test It + +Edit the `local/http-certbot-only` file and uncomment the `redirect` and +`return` directives, then restart your nginx server and make sure it now +forces everything to HTTPS like it should: + + $ sudo systemctl restart nginx + +Test ideas: + +* Visit both Fossil and non-Fossil URLs + +* Log into the repo, log out, and log back in + +* Clone via `http`: ensure that it redirects to `https`, and that + subsequent `fossil sync` commands go directly to `https` due to the + 301 permanent redirect. + +This forced redirect is why we don’t need the Fossil Admin → Access +"Redirect to HTTPS on the Login page" setting to be enabled. Not only +is it unnecessary with this HTTPS redirect at the front-end proxy level, +it would actually [cause an infinite redirect loop if +enabled](./ssl.wiki#rloop). + + + +## Step 6: Re-Point Fossil at Your Repositories + +As of Fossil 2.9, the permanent HTTP-to-HTTPS redirect we enabled above +causes Fossil to remember the new URL automatically the first time it’s +redirected to it. All you need to do to switch your syncs to HTTPS is: + + $ cd ~/path/to/checkout + $ fossil sync + + +## Step 7: Renewing Automatically + +Now that the configuration is solid, you can renew the LE cert with the +`certbot` command from above without the `--dry-run` flag plus a restart +of nginx: + + sudo certbot certonly --webroot \ + --webroot-path /var/www/example.com \ + -d example.com -d www.example.com \ + -d example.net -d www.example.net \ + --webroot-path /var/www/foo.net \ + -d foo.net -d www.foo.net + sudo systemctl restart nginx + +I put those commands in a script in the `PATH`, then arrange to call that +periodically. Let’s Encrypt doesn’t let you renew the certificate very +often unless forced, and when forced there’s a maximum renewal counter. +Nevertheless, some people recommend running this daily and just letting +it fail until the server lets you renew. Others arrange to run it no +more often than it’s known to work without complaint. Suit yourself. + + +----------- + + +**Document Evolution** + +Large parts of this article have been rewritten several times now due to +shifting technology in the TLS and proxying spheres. + +There is no particularly good reason to expect that this sort of thing +will not continue to happen, so we consider this to be a living +document. If you do not have commit access on the `fossil-scm.org` +repository to update this document as the world changes around it, you +can discuss this document [on the forum][fd]. This document’s author +keeps an eye on the forum and expects to keep this document updated with +ideas that appear in that thread. + +[acme]: https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment +[cb]: https://certbot.eff.org/ +[cbnu]: https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx +[fd]: https://fossil-scm.org/forum/forumpost/ae6a4ee157 +[hsts]: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security +[lja]: https://en.wikipedia.org/wiki/Logjam_(computer_security) +[mitm]: https://en.wikipedia.org/wiki/Man-in-the-middle_attack +[nest]: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/ +[ocsp]: https://en.wikipedia.org/wiki/OCSP_stapling +[qslc]: https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices +[qslt]: https://www.ssllabs.com/ssltest/ Index: www/unvers.wiki ================================================================== --- www/unvers.wiki +++ www/unvers.wiki @@ -4,11 +4,11 @@ "Unversioned content" or "unversioned files" are files stored in a Fossil repository without history. Only the newest version of each unversioned file is retained. Though history is omitted, unversioned content is synced between -respositories. In the event of a conflict during a sync, the most recent +repositories. In the event of a conflict during a sync, the most recent version of each unversioned file is retained and older versions are discarded. Unversioned files are useful for storing ephemeral content such as builds or frequently changing web pages. The [https://www.fossil-scm.org/fossil/uv/download.html|download] page of @@ -20,21 +20,21 @@ Unversioned files are not a part of a check-out. Unversioned files are intended to be accessible as web pages using URLs of the form: "http://domain/cgi-script/uv/FILENAME". In other words, the URI method "uv" (short for "unversioned") followed by the name of the unversioned file will retrieve the content -of the file. The mimetype is inferred from the filename suffix. +of the file. The MIME type is inferred from the filename suffix. The content of unversioned files can also be retrieved using the [/help?cmd=unversioned|fossil unvers cat FILENAME] command. A list of all unversioned files on a server can be seen using the [/help?cmd=/uvlist|/uvlist] URL. ([/uvlist|example]).

                    Syncing Unversioned Files

                    -Unversioned content is synced between respositories, though not by default. +Unversioned content is synced between repositories, though not by default. Special commands or command-line options are required. Unversioned content can be synced using the following commands:
                     fossil sync -u
                    
                    ADDED   www/userlinks.wiki
                    Index: www/userlinks.wiki
                    ==================================================================
                    --- /dev/null
                    +++ www/userlinks.wiki
                    @@ -0,0 +1,53 @@
                    +Links For Fossil Users:
                    +
                    +  *  [./permutedindex.html | Documentation index] with [/search?c=d | full text search].
                    +  *  [./reviews.wiki | Testimonials] from satisfied Fossil users and
                    +     [./quotes.wiki | Quotes] about Fossil and other DVCSes.
                    +  *  [./faq.wiki | Frequently Asked Questions]
                    +  *  The [./concepts.wiki | concepts] behind Fossil.
                    +     [./whyusefossil.wiki#definitions | Another viewpoint].
                    +  *  [./quickstart.wiki | Quick Start] guide to using Fossil.
                    +  *  [./qandc.wiki | Questions & Criticisms] directed at Fossil.
                    +  *  [./build.wiki | Compiling and Installing]
                    +  *  Fossil supports [./embeddeddoc.wiki | embedded documentation]
                    +     that is versioned along with project source code.
                    +  *  Fossil uses an [./fileformat.wiki | enduring file format] that is
                    +     designed to be readable, searchable, and extensible by people
                    +     not yet born.
                    +  *  A tutorial on [./branching.wiki | branching], what it means and how
                    +     to do it using Fossil.
                    +  *  The [./selfcheck.wiki | automatic self-check] mechanism
                    +     helps insure project integrity.
                    +  *  Fossil contains a [./wikitheory.wiki | built-in wiki].
                    +  *  An [./event.wiki | Event] is a special kind of wiki page associated
                    +     with a point in time rather than a name.
                    +  *  [./settings.wiki | Settings] control the behaviour of Fossil.
                    +  *  [./ssl.wiki | Use SSL] to encrypt communication with the server.
                    +  *  The [https://fossil-scm.org/forum|Fossil forum] is, as of mid-2018,
                    +     the project's central communication channel. The
                    +     [https://www.mail-archive.com/fossil-users@lists.fossil-scm.org
                    +     | read-only mailing list archives] house discussions spanning Fossil's
                    +     first decade.
                    +  *  [./stats.wiki | Performance statistics] taken from real-world projects
                    +     hosted on Fossil.
                    +  *  How to [./shunning.wiki | delete content] from a Fossil repository.
                    +  *  How Fossil does [./password.wiki | password management].
                    +  *  On-line [/help | help].
                    +  *  Documentation on the
                    +     [http://www.sqliteconcepts.org/THManual.pdf | TH1 scripting language],
                    +     used to customize [./custom_ticket.wiki | ticketing], and several other
                    +     subsystems, including [./customskin.md | theming].
                    +  *  List of [./th1.md | TH1 commands provided by Fossil itself] that expose
                    +     its key functionality to TH1 scripts.
                    +  *  List of [./th1-hooks.md | TH1 hooks exposed by Fossil] that enable
                    +     customization of commands and web pages.
                    +  *  A free hosting server for Fossil repositories is available at
                    +     [http://chiselapp.com/].
                    +  *  How to [./server/ | set up a server] for your repository.
                    +  *  Customizing the [./custom_ticket.wiki | ticket system].
                    +  *  Methods to [./checkin_names.wiki | identify a specific check-in].
                    +  *  [./inout.wiki | Import and export] from and to Git.
                    +  *  [./fossil-v-git.wiki | Fossil versus Git].
                    +  *  [./fiveminutes.wiki | Up and running in 5 minutes as a single user]
                    +     (contributed by Gilles Ganault on 2013-01-08).
                    +  *  [./antibot.wiki | How Fossil defends against abuse by spiders and bots].
                    
                    Index: www/webpage-ex.md
                    ==================================================================
                    --- www/webpage-ex.md
                    +++ www/webpage-ex.md
                    @@ -2,131 +2,122 @@
                     =================
                     
                     Here are just a few examples of the many web pages supported
                     by Fossil.  Follow hyperlinks on the examples below to see many
                     other examples.
                    -
                     
                       *  Example
                    +     href='$ROOT/timeline?y=ci&n=100'>(Example) →
                          100 most recent check-ins.
                     
                       *  Example
                    +     href='$ROOT/finfo?name=src/file.c'>(Example) →
                          All changes to the src/file.c source file.
                     
                       *  Example
                    +     href='$ROOT/timeline?n=200&uf=0c3c2d086a'>(Example) →
                          All check-ins using a particular version of the src/file.c
                          source file.
                     
                       *  Example
                    +     href='$ROOT/timeline?n=11&y=ci&c=2014-01-01'>(Example) →
                          Check-ins proximate to an historical point in time (2014-01-01).
                     
                       *  Example
                    +     href='$ROOT/timeline?n=11&y=ci&c=2014-01-01&v=1'>(Example) →
                          The previous example augmented with file changes.
                     
                       *  Example
                    +     href='$ROOT/timeline?n=25&y=ci&a=1970-01-01'>(Example) →
                          First 25 check-ins after 1970-01-01.  (The first 25 check-ins of
                          the project.)
                     
                       *  Example
                    +     href='$ROOT/timeline?n=200&r=svn-import'>(Example) →
                          All check-ins of the "svn-import" branch together with check-ins
                          that merge with that branch.
                     
                       *  Example
                    +     href='$ROOT/timeline?n=200&t=svn-import'>(Example) →
                          All check-ins of the "svn-import" branch only.
                     
                       *  Example
                    +     href='$ROOT/timeline?n=100&y=ci&ubg'>(Example) →
                          100 most recent check-ins color coded by committer rather than by branch.
                     
                       *  Example
                    +     href='$ROOT/timeline?from=version-1.27&to=version-1.28'>(Example) →
                          All check-ins on the most direct path from
                          version-1.27 to version-1.28
                     
                       *  Example
                    +     href='$ROOT/timeline?namechng'>(Example) →
                          Show check-ins that contain file name changes
                     
                       *  Example
                    +     href='$ROOT/timeline?u=drh&c=2014-01-08&y=ci'>(Example) →
                          Show check-ins circa 2014-01-08 by user "drh".
                     
                       *  Example
                    +     href='$ROOT/timeline?from=version-1.34&to=version-1.35&chng=src/timeline.c,src/doc.c'>(Example) →
                          Show all check-ins between version-1.34 and version-1.35 that make
                          changes to either of the files src/timeline.c or src/doc.c.
                     
                           (Hint:  In the pages above, click the graph nodes
                          for any two check-ins or files to see a diff.)
                          
                     
                       *  Example
                    +     href='$ROOT/search?s=interesting+pages'>(Example) →
                          Full-text search for "interesting pages".
                     
                       *  Example
                    +     href='$ROOT/tree?ci=daff9d20621&type=tree'>(Example) →
                          All files for a particular check-in (daff9d20621480)
                     
                       *  Example
                    +     href='$ROOT/tree?ci=trunk&type=tree&mtime=1'>(Example) →
                          All files for the latest check-in on a branch (trunk) sorted by
                          last modification time.
                     
                       *  Example
                    +     href='$ROOT/fileage?name=svn-import'>(Example) →
                          Age of all files in the latest checking for branch "svn-import".
                     
                       *  Example
                    +     href='$ROOT/brlist'>(Example) →
                          Table of branches.  (Click on column headers to sort.)
                     
                       *  Example
                    +     href='$ROOT/stat'>(Example) →
                          Overall repository status.
                     
                       *  Example
                    +     href='$ROOT/reports?type=ci&view=byuser'>(Example) →
                          Number of check-ins per committer.
                     
                       *  Example
                    +     href='$ROOT/reports?view=byfile'>(Example) →
                          Number of check-ins for each source file.
                          (Click on column headers to sort.)
                     
                       *  
                    -       Example
                    +       (Example) →
                          Most recent change to each line of a particular source file in a
                          particular check-in.
                     
                       *  Example
                    +     href='$ROOT/taglist'>(Example) →
                          List of tags on check-ins.
                     
                       *  Example
                    +     href='$ROOT/bigbloblist'>(Example) →
                          The largest objects in the repository.
                     
                       *  Example
                    -     SHA1 prefix collisions
                    +     href='$ROOT/hash-collisions'>(Example) →
                    +     Hash prefix collisions
                     
                       *  Example
                    +     href='$ROOT/sitemap'>(Example) →
                          The "sitemap" containing links to many other pages
                    
                    Index: www/webui.wiki
                    ==================================================================
                    --- www/webui.wiki
                    +++ www/webui.wiki
                    @@ -6,10 +6,11 @@
                     
                       *  [./bugtheory.wiki | Ticketing and bug tracking]
                       *  [./wikitheory.wiki | Wiki]
                       *  [./embeddeddoc.wiki | On-line documentation]
                       *  [./event.wiki | Technical notes]
                    +  *  [./forum.wiki | Forum]
                       *  Timelines
                       *  Full text search over all of the above
                       *  Status information
                       *  Graphs of revision and branching history
                       *  File and version lists and differences
                    @@ -25,12 +26,11 @@
                     There are no extra programs to install or setup.
                     Everything you need is already pre-configured and built into the
                     self-contained, stand-alone Fossil executable.
                     
                     As an example of how useful this web interface can be,
                    -the entire [./index.wiki | Fossil website] (except for the
                    -[http://www.fossil-scm.org/download.html | download page]),
                    +the entire [./index.wiki | Fossil website],
                     including the document you are now reading,
                     is rendered using the Fossil web interface, with no enhancements,
                     and little customization.
                     
                     
                    @@ -52,11 +52,11 @@ repository, simply type this: fossil ui existing-repository.fossil Substitute the name of your repository, of course. -The "ui" command will start a webserver running (it figures out an +The "ui" command will start a web server running (it figures out an available TCP port to use on its own) and then automatically launches your web browser to point at that server. If you run the "ui" command from within an open check-out, you can omit the repository name: fossil ui @@ -108,11 +108,11 @@ You can view summary reports of branches in the check-in graph by visiting the "Branches" link on the menu bar. From those pages you can follow hyperlinks to get additional details. These screens allow you to easily keep track of what is going -on with separate subteams within your project team. +on with separate sub-teams within your project team. The "Files" link on the menu allows you to browse through the file hierarchy of the project and to view complete changes histories on individual files, with hyperlinks to the check-ins that made those changes, and with diffs and annotated diffs between versions. Index: www/whyusefossil.wiki ================================================================== --- www/whyusefossil.wiki +++ www/whyusefossil.wiki @@ -199,29 +199,35 @@ might commit different changes against the same check-in. This results in one parent node having two or more children.
                  • Command: merge → combines the work of multiple check-ins into a single check-out. That check-out can then be committed to create - a new that has two (or more) parents. + a new check-in that has two (or more) parents.

                    • Most check-ins have just one parent, and either zero or one child.

                    • When a check-in has two or more parents, one of those parents - is the "primary parent". All the other parent nodes are "secondary". + is the "primary parent". All the other parent nodes are "secondary" + or "merge" parents. Conceptually, the primary parent shows the main line of - development. Content from the secondary parents is added + development. Content from the merge parents is added into the main line.

                    • The "direct children" of a check-in X are all children that have X as their primary parent.

                    • A check-in node with no direct children is sometimes called a "leaf". +

                    • The "merge" command changes only the check-out. + The "commit" command must be run subsequently to make the merge + a permanent part of project.

                  • Definition: branch → a sequence of check-ins that are all linked together in the DAG through the primary parent.

                    • Branches are often given names which propagate to direct children. + The tradition in Fossil is to call the main branch "trunk". In + Git, the main branch is usually called "master".

                    • It is possible to have multiple branches with the same name. Fossil has no problem with this, but it can be confusing to humans, so best practice is to give each branch a unique name.

                    • The name of a branch can be changed by adding special tags to the first check-in of a branch. The name assigned by this @@ -229,18 +235,19 @@

                  • Why version control is important (reprise)

                    1. Every check-in and every individual file has a unique name - its - SHA1 hash. Team members can unambiguously identify any specific + SHA1 or SHA3-256 hash. Team members can unambiguously identify + any specific version of the overall project or any specific version of an individual file.

                    2. Any historical version of the whole project or of any individual file can be easily recreated at any time and by any team member.

                    3. Accidental changes to files can be detected by recomputing their - SHA1 hash. -

                    4. Files of unknown origin can be identified using their SHA1 hash. + cryptographic hash. +

                    5. Files of unknown origin can be identified using their hash.

                    6. Developers are able to work in parallel, review each others work, and easily merge their changes together. External revisions to the baseline can be easily incorporated into the latest changes.

                    7. Developers can follow experimental lines of development, then revert back to an earlier stable version if the experiment does Index: www/wikitheory.wiki ================================================================== --- www/wikitheory.wiki +++ www/wikitheory.wiki @@ -8,10 +8,12 @@ * Description and comments in [./bugtheory.wiki | bug reports]. * Check-in comments. * [./embeddeddoc.wiki | Embedded documentation] files whose name ends in ".wiki" or ".md" or ".markdown". * [./event.wiki | Technical notes]. + * [./forum.wiki | Forum messages]. + * Auxiliary notes on check-ins and branches. The [/wiki_rules | formatting rules for fossil wiki] are designed to be simple and intuitive. The idea is that wiki provides paragraph breaks, numbered and bulleted lists, and hyperlinking for simple documents together with a safe subset of HTML for more complex @@ -25,42 +27,60 @@ Each wiki page has its own revision history which is independent of the sequence of check-ins (check-ins). Wiki pages can branch and merge just like check-ins, though as of this writing (2008-07-29) there is no mechanism in the user interface to support branching and merging. The current implementation of the wiki shows the version of the wiki -page that has the most recent timestamp. +page that has the most recent time stamp. In other words, if two users make unrelated changes to the same wiki page on separate repositories and those repositories are synced, the wiki page will fork. The web interface will display whichever edit was checked in last. The other edit can be found in the history. The file format will support merging the branches back together, but there is no mechanism in the user interface (yet) to perform the merge. -Every change to a wiki page is a separate +Every change to a wiki page is a separate [./fileformat.wiki | control artifact] of type [./fileformat.wiki#wikichng | "Wiki Page"].

                      Embedded Documentation

                      Files in the source tree that use the ".wiki", ".md", or ".markdown" suffixes -can be accessed and displayed using special URLs to the fossil server. +can be accessed and displayed using special URLs to the fossil server. This allows -project documentation to be stored in the source tree and accessed +project documentation to be stored in the source tree and accessed online. (Details are described [./embeddeddoc.wiki | separately].) Some projects prefer to store their documentation in wiki. There is nothing wrong with that. But other projects prefer to keep documentation as part of the source tree, so that it is versioned along with the source tree and -so that only developers with check-in privileges can change it. +so that only developers with check-in privileges can change it. Embedded documentation serves this latter purpose. Both forms of documentation use the exact same markup. Some projects may choose to use both forms of documentation at the same time. Because the same format is used, it is trivial to move a file from wiki to embedded documentation or back again as the project evolves. -

                      Bug-reports and check-in comments

                      +

                      Bug-reports and check-in comments and Forum messages

                      The comments on check-ins and the text in the descriptions of bug reports both use wiki formatting. Exactly the same set of formatting rules apply. There is never a need to learn one formatting language for documentation and a different markup for bugs or for check-in comments. + + +

                      Auxiliary notes attached to check-ins or branches

                      + +Stand-alone wiki pages with special names "branch/BRANCHNAME" +or "checkin/HASH" are associated with the corresponding +branch or check-in. The wiki text appears in an "About" section of +timelines and info screens. Examples: + + * [/timeline?r=graph-test-branch] shows the text of the + [/wiki?name=branch/graph-test-branch&p|branch/graph-test-branch] + wiki page at the top of the timeline + * [/info/19c60b7fc9e2] shows the text of the + [/wiki?name=checkin/19c60b7fc9e2400e56a6f938bbad0e34ca746ca2eabdecac10945539f1f5e8c6&p|checkin/19c60b7fc9e2...] + wiki page in the "About" section. + +This special wiki pages are very useful for recording historical +notes.