staticsite-1.4.1/ 0000755 0001750 0001750 00000000000 13605113260 014446 5 ustar enrico enrico 0000000 0000000 staticsite-1.4.1/.coveragerc 0000644 0001750 0001750 00000000073 13601465045 016576 0 ustar enrico enrico 0000000 0000000 [run]
source = .
omit =
./setup.py
./ssite
./tests/*
staticsite-1.4.1/.staticsite 0000644 0001750 0001750 00000000232 13605100661 016621 0 ustar enrico enrico 0000000 0000000 dirs:
themes:
asset: yes
example:
asset: yes
nav: [doc/tutorial/README.md, doc/howto/README.md, doc/reference/README.md, doc/devel/README.md]
staticsite-1.4.1/LICENSE 0000644 0001750 0001750 00000104513 13601465045 015466 0 ustar enrico enrico 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
staticsite-1.4.1/MANIFEST.in 0000644 0001750 0001750 00000000525 13605101272 016206 0 ustar enrico enrico 0000000 0000000 include MANIFEST.in
include LICENSE
include README.md
include NEWS.md
include coverage.sh
include .coveragerc
include .staticsite
recursive-include example *
recursive-include themes *
recursive-include doc *
recursive-include tests *
recursive-include themes *
recursive-include devel *.py
recursive-include devel profile-view
exclude .egt
staticsite-1.4.1/NEWS.md 0000644 0001750 0001750 00000047470 13605112174 015563 0 ustar enrico enrico 0000000 0000000 # staticsite user-relevant changes
# New in version 1.4.1
* `ssite edit` can now filter by taxonomies
* Fixed generation of "continue reading" links in markdown inline pages
* Fixed use of markdown archetypes
# New in version 1.4
* New [images support](doc/reference/images.md) (see #39, #46)
* Use a horizontal rule with 3 or more *underscores* to introduce a
introduction/rest of the post split in [markdown pages](doc/reference/markdown.md)
* New `copyright` and `template_copyright` [metadata](doc/reference/metadata.md)
* Added `ssite shell` to play with the built `Site` object for a site
* Added [nav metadata](doc/reference/metadata.md) to add pages to the top navbar
* [`pages` header](doc/reference/pages.md) can now be just a string, defaulting
to filtering by `path`. (#34)
* `syndication` can be `true` to turn on syndication with default settings
* `syndication.add_to`, if omitted, defaults to adding syndication links to all
the pages in the syndication. It can be `false` to disable adding syndication
links to syndicated pages.
* `syndication.pages` and `syndicaton.filter` are now removed: use `pages` to
select which pages are syndicated
* [markdown pages](doc/reference/markdown.md) can now use markdown code blocks
as front matter delimiters, making markdown pages with front matter valid
markdown pages.
* [`site_path` metadata](doc/reference/metadata.md) is now normalized to be
absolute. The site path for the root page is now `/` instead of the empty
string, and all page site paths now begin with `/`. `build_path` is still
without leading slashes.
* Page lookup by `url_for()`, `page_for()`, `site_pages()` in themes, and front
matter headers like `pages` or `syndication.add_to`, is now relative to the
current page, unless an absolute path is used.
* Implemented `Page.find_pages`, so in templates you can use `page.find_pages`
instead of `site_pages`
* `site_pages()` does not sort by reverse date by default anymore.
* `template_copyright` defaults to `"© {{page.meta.date.year}} {{page.meta.author}}"`
* `author` defaults to the current user's name
* [syndicaton](doc/reference/syndication.md) archive pages are now autogenerated
* New [`page.meta.related` metadata](doc/reference/metadata.md)
* Feed links are now created based on `page.meta.related.rss_feed` and
`page.meta.related.atom_feed`
* Taxonomy now reuses blog and archive templates by default
* `ssite build` now warns of broken internal links
* Added tutorials and HOWTOs on making a blog (#36)
* Use [`content:` prefix for template names](templates.md) to distinguish
templates in content directory from templates in theme directories. The
content directory is no longer in the template search path by default.
* Added a link to the archive at the bottom of blog posts in default
`lib/blog.html`
## Upgrade notes
* Use `pages` instead of `syndication.pages` or `syndication.filter`
* If you looked up pages by site path, they are now absolute paths, instead of
paths relative to `/`
* If you looked up pages relative to pages up the parent chain of the current
page, that does not work anymore. Use paths to source files instead, which
don't change according to how the site is laid out.
* If you looked up pages by relative paths assuming they were anchored on the
site root, that does not work anymore: use absolute paths instead.
* If you relied on `site_pages` default sorting order, add a `sort="-date"` to
your `site_pages` invocations
* You can remove manually created archive pages now, and use the autogenerated
ones
* Feed links are now created based on `page.meta.related.rss_feed` and
`page.meta.related.atom_feed`: you may need to update your templates if they
still looked for `page.meta.syndication.rss_page` and
`page.meta.syndication.atom_page`
* The default template for taxonomy pages is now `taxonomy.html` instead of
`taxonomy/taxonomy.html`
* The default template for taxonomy categories is now `blog.html` instead of
`taxonomy/category.html`
* The default template for taxonomy category archives is now `archive.html`
instead of `taxonomy/archive.html`
* Use [`content:` prefix for template names](templates.md) to load templates
from the content directory: the content directory is no longer in the
template search path by default.
# New in version 1.3
* New [page metadata](doc/reference/metadata.md): `author`, `site_name`, `site_url`, and
`site_root`.
* The contents of a `.staticsite` file can also now be loaded from the
`index.html`/`index.md`/`index.rst` file in the directory, if present. This
is now the recommended way to set directory metadata
* If no title is set in the front matter of a jinja2 template page, it defaults
to the rendered `{% block title %}`
* `site_name`, if not set, defaults to the title of the toplevel index page, if
present
* `.taxonomy` files do not need to be listed in [`TAXONOMIES`
settings](doc/reference/settings.md) anymore: `TAXONOMIES` is now ignored in settings.
* Restructured theme directory organization. See Upgrade notes for details.
* Set `site_path` in a directory metadata to choose where that directory
appears in the target site. This replaces
[`settings.SITE_ROOT`](doc/reference/settings.md), which now acts as a default
`site_path` for the toplevel directory.
* Added `THEME_PATHS` [settings](doc/reference/settings.md), as a sequence of paths where
themes are looked up
* `THEME`, if set to a string, it represent a name of a theme to be looked up
under `THEME_PATHS`
* Themes are now installed in `/usr/share/staticsite/themes`, making it
possible to make multiple themes available system-wide for use
* Themes can now inherit from other themes. See [theme documentation](doc/reference/theme.md)
for details
* Added `page_for()` function to [templates](doc/reference/templates.md)
* Renamed `syndication.filter` to `syndication.pages` (see [syndication](doc/reference/syndication.md).
For backwards compatibility, `syndication.filter` still works as an alias for
`syndication.pages`.
* Added `syndicated_pages` function to templates. See [syndication documentation](doc/reference/syndication.md).
* Added [`syndicated` metadata](doc/reference/metadata.md) to allow excluding pages from
syndication.
* Added [`syndication_date` metadata](doc/reference/metadata.md) to allow to control when
a page gets syndicated.
* jinja2 pages are now [`indexed`](doc/reference/metadata.md) by default.
* jinja2 and data pages can now render inline as part of a blog. By default,
their `page_content` block is rendered, or the `content` block if
`page_content` does not exist.
* [data feature](doc/reference/data): use `data_type` instead of `type`. Any page
metadata with a `data_type` value will be tracked as data.
* Moved [reference documentation](doc/reference/README.md) to `doc/reference`
* Make build destination of theme static assets configurable via [`STATIC_PATH` setting](doc/reference/settings.md)
## Upgrade notes
### Templates
* If you used `SITE_NAME` or `site.site_name`, use `page.meta.site_name`
instead
* `blog.html` is now in `lib/blog.html` in default theme, to make space for the
introduction of a default blog page template.
* `tags.html` is now `taxonomy/taxonomy.html`
* `tag.html` is now `taxonomy/category.html`
* `tag-archive.html` is now `taxonomy/archive.html`
* `url_for` now always needs to access `page` from the current template
context. If you are importing template libraries like `lib/blog.html`, import
them [`with context`](https://jinja.palletsprojects.com/en/2.10.x/templates/#import-visibility)
so they can access `page`.
### Pages
* Since jinja2 pages are now [`indexed`](doc/reference/metadata.md) by default, they may
accidentally appear in blogs and syndication. You can use the `syndicated`
header to prevent them from being added. You can also apply `syndicated: no`
to multiple pages using the [`files:` matching patterns](doc/reference/contents.md) in
a directory index page.
* In [data pages](doc/reference/data.md), use `data_type` instead of `type`.
# New in version 1.2
* RestructuredText Feature, see , thanks to @valholl.
* Taxonomies:
* Renamed `tags` feature to `taxonomy`
* Taxonomies now need to be explicitly listed in settings as a `TAXONOMIES`
list of taxonomy names. staticsite prints a warning if a `.taxonomy` file is
found that is not listed in `TAXONOMIES`.
* You can use `tags: tagname` as short for `tags: [tagname]` if you
only have one tag
* Significantly reengineered 'taxonomy' feature.
* Taxonomy pages are now ordered by ascending dates. You need to reverse
them in templates (you can use the [`|reverse` jinja2 filter](https://jinja.palletsprojects.com/en/2.10.x/templates/#reverse))
if you want them sorted as newest first.
* Series are now generated from any category: `series_tags` is now ignored.
* Removed `series` feature, merged into `taxonomy`
* Page metadata:
* `description` can now be used for page metadata.
* `template_title` and `template_description`, if present while `title` and
`description` are not, are rendered with jinja2. See [doc/reference/metadata.md] for
details.
* `template` metadata can be used to choose a custom template to render the
page, similar to [Jekill's layouts](https://jekyllrb.com/docs/step-by-step/04-layouts/).
* `indexed` (true or false) is used to tell if a page appears in a
directory index and in [page filter](doc/reference/page-filter.md) results.
* Themes:
* Vendorized assets in `theme/static/` are now read by asset library name, as
if `static/` were the same as `/usr/share/javascript/`. Now you need to refer
to `/jquery/jquery.min.js` and `/bootstrap4/css/bootstrap.min.css` instead of
`jquery.min.js` and `css/bootstrap.min.css`.
* If a `config` file exists in the theme directory, it is loaded as
yaml/json/toml (same as a page front matter) and used as theme configuration
* `static_assets` in theme configuration can be used to load assets from
`/usr/share/javascript`
* Turned `inline_pages.html` template into a `blog.html` macro library for
blogs and category pages.
* Jinja2 pages
* New setting [`JINJA2_PAGES`](doc/reference/jinja2.md): now `*.html` pages are
considered jinja2 templates by default.
* Renamed `j2` feature to `jinja2`
* Content loading
* A `.staticsite` file in a content directory is read as directory metadata,
and can be used to provide metadata to `.j2.html` pages. See
for details.
* Static assets loaded by the theme have been moved to `static/` in the
rendered site, to avoid cluttering the rest of the contents. Referring to
them in `url_for` in templates has not changed.
* Set `asset` to true for a file in [`.staticsite` directory metadata](doc/reference/contents.md),
to force loading it as a static asset.
* Allow marking entire subdirectories as assets in
[directory metadata](doc/reference/contents.md).
* Try harder to localize timestamps as the configured site TIMEZONE.
* Added a `ssite show` command to open a directory in a browser without loading
possibly unsafe settings.
* When run without a `settings.py`, take more defaults from repo mode. This
makes running staticfile or arbitrary directories quite useful, and similar
to viewing a repository on GitLab/GitHub.
* Improved logging in case of jinja2 errors. Use --debug to see a full
stacktrace.
* Instantiate Feature classes in dependency order: this allows a feature
constructor to register hooks with another one.
* Added syndication feature (see ) to simplify generation
of RSS and Atom feeds
* Added `ssite dump_meta` to page information as available to templates
* One can now match pages by regexp and not just by glob. See
.
* Cleaned up reference documentation.
* Allow selecting a language code for rendering. See `LANGUAGES` in [settings](doc/reference/settings.md).
* Added `BUILD_COMMAND` [setting](doc/reference/settings.md).
* Removed compatibility `Feature.load_dir` method. The old `try_load_page`
method is no longer supported. Now a feature that does not load files does
not waste time during content loading.
* [New `pages` feature](doc/reference/pages.md) that allows defining a page filter in a
`pages` metadata element, and then set `page.meta.pages` to a list of the
matching pages. This can be used to simplify templates, so that with only one
page filter one can control both the syndication and the page listing aspect
of a blog page.
* [New `arrange()` template filter](doc/reference/templates.md) to do efficient sorted
sampling from a list of pages.
* `ssite edit`: when paginating results, an empty input goes to the next page
* cleanup and documented [directory index](doc/reference/dir.md) feature
* `page.meta.alias` is honored for all page types
* `page.meta.template` is honored for all page types
* Started [developers documentation](doc/reference/devel/README.md)
* Started [usage HOWTO documentation](doc/reference/howto/README.md)
* Switch to [jinja2 sandboxed environment](https://jinja.palletsprojects.com/en/2.10.x/sandbox/)
by default. Site [settings](doc/reference/settings.md) can turn it off, which is ok
because `settings.py` is a point where arbitrary code can be injected. This
means that you now only have to secure access to `settings.py`, and can be a
bit more free with allowing others to participate in the site development.
Also, you need to use `ssite show`, and *not* `ssite serve`, to preview
potentially untrusted sites: `ssite show` will not load a `settings.py`.
## Upgrade notes
### Taxonomies
* If you use taxonomies, explicitly list them in the new `TAXONOMIES`
setting.
* `item_name` in a `.taxonomy` file does not have a special meaning anymore,
and templates can still find it in the taxonomy page metadata
* `output_dir` in a `.taxonomy` file is now ignored, and the taxonomy pages
will be in a directory with the same name as the file, without extension
* `tags.html`, `tag.html`, and `tag-archive.html` templates need updating: see
the versions in `example/theme` for an updated example
* `series_tags` is now ignored
* The `series` feature is merged into `tags`: add a `series` taxonomy to keep using
the `series` metadata in pages
* You may need to update the series rendering part of your templates: see
[the series documentation](doc/reference/series.md) and the `page.html` example template
for details and an example.
* In templates, use `page.meta.pages` instead of `page.pages`
### Settings
* `PROJECT_ROOT` setting now defaults to `None` instead of `.`, and if None will
be filled using the directory where the settings file is found, or the
current directory otherwise. The resulting behaviour should be in practice
very similar to the previous `.` setting.
* `TIMEZONE` setting now defaults to the system or user timezone instead of
`UTC`
* `CONTENT` setting now defaults to `PROJECT_ROOT` instead of `content`. Set
it to `content` explicitly if you depend on the previous value
* `OUTPUT` setting now defaults to `None` instead of `web`, and `ssite build`
will ask you to set it or provide a `--output` option. Set it to `web`
explicitly if you depend on the previous value
* `SITE_NAME` setting now defaults to `None` instead of `Site name not set`,
and will be filled with the title of the toplevel index page, or the basename
of the toplevel content directory if the toplevel index page has not title
set or is autogenerated.
### Command line
* Running `ssite serve` on a random repository cloned off the internet can
expose you to arbitrary code execution if the project includes a
`.staticsite.py` settings file: use `ssite show` instead. Use `ssite serve`
for authoring your own websites, whose settings you control.
### Pages
* `.html` files are now parsed as jinja2 templates by default. If you have
bundles of HTML in your site content that you'd like copied as-is, you can
mark them as 'asset' in [`.staticsite` directory metadata](doc/reference/contents.md).
### Link stability
* `tag/archive.html` is now `tag/archive`
* Static assets loaded by themes are now moved into a `static/` directory in
the rendered website. `url_for` generates the right links for them, but if
one had hardcoded links to them in the site, or external sites linked to the
site static assets, those links may end up broken
### Templates
* Where you used `page.pages`, now use `page.meta.pages`
* Where you used `contents` for rendered page contents, now you use
`page.contents`
* Data pages now honor the `page.meta.template` metadata, and are rendered
directly by that template, with using one template for contents and one for
the page layout. If you use data pages, change your `data-$TYPE.html`
templates to extend `page.html` and render into the `page_content` block.
# New in version 1.1
* Documented and consolidated the Features feature
* Reuse existing static content in destination directory to speed up rendering
* Allow invoking feature-specific code from the command line
(`ssite site --cmd …`)
# New in version 1.0
* Refactored codebase to introduce the concept of pluggable Features. Most
staticsite features are now implemented as pluggable features, and new
features can be provided with python modules placed in the
`$THEMEDIR/features/` directory
* Implemented data pages, as yaml, toml, or json, that provide pure datasets.
`data-$type.html` jinja2 templates can be used to render their contents.
* Speed up site rebuilds by caching intermediate markdown contents
**Upgrade notes**:
* To prevent the creation of a cache directory in your `PROJECT_ROOT`, set the
new `CACHE_REBUILDS` setting to `False`.
# New in version 0.6
* Allow filtering by taxonomies in `site_pages()`
* New settings `SYSTEM_ASSETS` to list directories in `/usr/share/javascript`
to include to site assets
* Generate unique IDs in footnotes by default. Thanks DonKult!
* Implement rendering raw JSON, YAML, or TOML data files
# New in version 0.5
* Fixed markdown syntax for link targets in `example/archetypes/links.md`
# New in version 0.4
* Pages with dates in the future are considered drafts not yet to be published.
Added option --draft to include them in the rendering.
* Added `{{next_month}}` to the template variables.
* Default editor configuration appends a `+` to the command line to open the
file with the cursor at the end.
* If the archetype does not need a title or a slug, the `-t` argument to `ssite
serve` is optional and no title will be asked interactively.
* Documented how to use staticsite to blog a monthly collection of links.
# New in version 0.3
* Allow pointing to .py configuration instead of project on command line.
This means you can potentially have a farm of .py site descriptions pointing
at various other directories in the file system.
* archetypes and output directory configurable in `settings.py`. See
[settings.md](doc/reference/settings.md) for details.
* Added `--theme`, `--content`, `--archetypes` and `--output` to command line
to override the corresponding settings.
* Fixed a bug in taxonomy generation
# New in version 0.2
* Configurable site layout, using `CONTENT` and `THEME` in `settings.py`. See
[the settings reference](doc/reference/settings.md) for details.
* The example `settings.py` has been updated to use `content` for site
contents, like [Hugo](https://gohugo.io) does.
* Directory indices: if in your contents you have `dir/foo.md` without
`dir/index.md` or `dir/index.j2.html", then a directory index for dir will be
generated automatically, showing links to all site pages in that directory.
* Documentation has been expanded and split into separate files under `doc/`
* New template function `taxonomies()` that returns a list of taxonomies. See
[templates.md](doc/reference/templates.md).
* New template filter `|basename` that returns the basename of a path. See
[templates.md](doc/reference/templates.md).
staticsite-1.4.1/PKG-INFO 0000644 0001750 0001750 00000000542 13605113260 015544 0 ustar enrico enrico 0000000 0000000 Metadata-Version: 2.1
Name: staticsite
Version: 1.4.1
Summary: Static site generator
Home-page: https://github.com/spanezz/staticsite
Author: Enrico Zini
Author-email: enrico@enricozini.org
License: http://www.gnu.org/licenses/gpl-3.0.html
Description: UNKNOWN
Platform: UNKNOWN
Requires-Python: >= 3.7
Provides-Extra: fast_caching
Provides-Extra: serve
staticsite-1.4.1/README.md 0000644 0001750 0001750 00000003604 13603650051 015732 0 ustar enrico enrico 0000000 0000000 # staticsite
Static site generator.
Builds a website out of [markdown](https://en.wikipedia.org/wiki/Markdown),
[restructuredText](https://en.wikipedia.org/wiki/ReStructuredText),
and [Jinja2](https://jinja.palletsprojects.com/) pages, and
[json](https://en.wikipedia.org/wiki/JSON)/[yaml](https://en.wikipedia.org/wiki/YAML)/[toml](https://en.wikipedia.org/wiki/TOML)
datasets.
Create a blog, tag your posts, publish post series.
Live preview your website, updated as you write it.
Freely organise your contents, and turn any directory into a website.
## Get started
* [A new blog in under one minute!](doc/tutorial/blog.md)
* [See more quickstart guides](doc/tutorial/README.md)
## Add features
* [HOWTO guides](doc/howto/README.md): step by step guides for getting specific
works done with staticsite
## Get serious
* [Reference documentation](doc/reference/README.md): description of each part of
staticsite
* [Developer documentation](doc/devel/README.md): documentation for developing
staticsite itself
## Example sites
This is a list of sites using staticsite, whose sources are public, that can be
used as examples:
* : `git clone https://git.enricozini.org/site.git`
## License
> This program is free software: you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation, either version 3 of the License, or
> (at your option) any later version.
>
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> GNU General Public License for more details.
>
> You should have received a copy of the GNU General Public License
> along with this program. If not, see .
## Author
Enrico Zini
staticsite-1.4.1/coverage.sh 0000755 0001750 0001750 00000000141 13601465045 016603 0 ustar enrico enrico 0000000 0000000 #!/bin/sh
eatmydata nose2-3 -C --coverage-report html &&
sensible-browser htmlcov/index.html
staticsite-1.4.1/devel/ 0000755 0001750 0001750 00000000000 13605113260 015545 5 ustar enrico enrico 0000000 0000000 staticsite-1.4.1/devel/bench_load_content.py 0000644 0001750 0001750 00000001004 13601465045 021731 0 ustar enrico enrico 0000000 0000000 #!/usr/bin/python3
import timeit
from staticsite import Site, Settings
def setup():
settings = Settings()
settings.PROJECT_ROOT = "example"
settings.load("example/settings.py")
site = Site(settings)
site.features.load_default_features()
site.load_theme()
# Patch add_page to be a noop
site.add_page = lambda page: None
return site
val = timeit.timeit("site.load_content()", setup="site = setup()\nsite.load_content()", number=300, globals=globals())
print(f"Current: {val}")
staticsite-1.4.1/devel/bench_yaml.py 0000644 0001750 0001750 00000003205 13601465045 020227 0 ustar enrico enrico 0000000 0000000 #!/usr/bin/python3
import timeit
from staticsite.utils import yaml_codec # noqa
test_yaml = """
---
# In staticsite, a taxonomy is a group of attributes like categories or tags.
#
# Like in Hugo, you can have as many taxonomies as you want. See
# https://gohugo.io/taxonomies/overview/ for a general introduction to
# taxonomies.
#
# This file describes the taxonomy for "tags". The name of the taxonomy is
# taken from the file name.
#
# The format of the file is the same that is used for the front matter of
# posts, again same as in Hugo: https://gohugo.io/content/front-matter/
# Any toplevel metadata is used for the tag index
title: "All series"
description: "Index of all series in the site."
# template: tags.html
# Category metadata is used for each tag page
category:
# template: tag.html
template_title: "Latest posts of series {{page.name}}"
template_description: "Most recent posts of series {{page.name}}"
syndication:
template_title: "{{page.meta.site_name}}: posts of series {{page.meta.index.name}}"
template_description: "{{page.meta.site_name}}: most recent posts of series {{page.meta.index.name}}"
# Archive metadata is used for each tag archive page
archive:
# template: tag-archive.html
template_title: "Archive of posts of series {{page.name}}"
template_description: "Archive of all posts of series {{page.name}}"
"""
val = timeit.timeit("yaml_codec.loads_ruamel(test_yaml)", number=1000, globals=globals())
print(f"Ruamel: {val}")
val = timeit.timeit("yaml_codec.loads_pyyaml(test_yaml)", number=1000, globals=globals())
print(f"PyYAML: {val}")
staticsite-1.4.1/devel/profile-view 0000755 0001750 0001750 00000020035 13601465045 020112 0 ustar enrico enrico 0000000 0000000 #!/usr/bin/python3
from __future__ import annotations
from typing import Dict, List, Tuple
import argparse
import pstats
import marshal
import tempfile
import subprocess
import pprint
import sys
import os
# from pstats import SortKey
import cmd
# File name, Line number, Function or scope name
Func = Tuple[str, int, str]
# Collected profiler statistics
Stats = Dict[
# Function of scope
Func,
Tuple[
# Aggregated statistics
int, int, float, float,
# Callers
Dict[
# Caller function or scope
Func,
# Call statistics collected for this caller → callee
Tuple[int, int, float, float]
]
]
]
class Node:
"""
Node in the caller → callee graph
"""
def __init__(self, func: Func):
self.fname, self.lineno, self.scope = func
self.callees: List["Call"] = []
self.callers: List["Call"] = []
self.cc = 0
self.nc = 0
self.tt = 0.0
self.ct = 0.0
def __str__(self):
# Builtin function
if self.fname == "~" and self.lineno == 0:
return f"[builtin]:{self.scope}"
# Shorten file names from system libraries
self.shortname = self.fname
for path in sorted(sys.path, key=lambda x: -len(x)):
if not path:
continue
if self.fname.startswith(path):
return f"[sys]{self.fname[len(path):]}:{self.lineno}|{self.scope}"
# File in the local project
return f"{self.fname}:{self.lineno}|{self.scope}"
class Call:
"""
Arc in the caller → callee graph
"""
def __init__(self, caller: Node, callee: Node, cc: int, nc: int, tt: float, ct: float):
self.caller = caller
self.callee = callee
self.cc = cc
self.nc = nc
self.tt = tt
self.ct = ct
class Graph:
"""
Graph of callers and callees.
Each node in the graph represents a function, with its aggregated
statistics.
Each arc in the graph represents each collected caller → callee statistics
"""
def __init__(self, stats: Stats):
# Index of all nodes in the graph
self.nodes: Dict[Func, Node] = {}
# Total execution time
self.total_time = 0.0
# Build the graph
for callee, (cc, nc, tt, ct, callers) in stats.items():
self.total_time += tt
# Get the callee and fill its aggregated stats
ncallee = self.node(callee)
ncallee.cc = cc
ncallee.nc = nc
ncallee.tt = tt
ncallee.ct = ct
# Create caller → callee arcs
for caller, (cc, nc, tt, ct) in callers.items():
ncaller = self.node(caller)
call = Call(ncaller, ncallee, cc, nc, tt, ct)
ncallee.callers.append(call)
ncaller.callees.append(call)
def node(self, fun: Func) -> Node:
"""
Lookup or create a node
"""
res = self.nodes.get(fun)
if res is None:
res = Node(fun)
self.nodes[fun] = res
return res
@classmethod
def load(cls, pathname: str) -> "Graph":
"""
Builds a Graph from profile statistics saved on a file
"""
with open(pathname, "rb") as fd:
return cls(marshal.load(fd))
@classmethod
def from_pstats(cls, stats: pstats.Stats) -> "Graph":
"""
Builds a Graph from an existing pstats.Stats structure
"""
return cls(stats.stats)
class Menu:
# Markers
CALLER = "←"
CALLEE = "→"
NODE = "•"
def __init__(self):
self.entries = []
def add(self, marker: str, node: Node, cc: int, nc: int, tt: float, ct: float, perc: float, indent=0):
if indent == 0:
lead = ""
else:
lead = "┆ " * (indent - 1) + "├─"
self.entries.append(
(node, len(self.entries), lead + (marker + " " if marker else "") + str(node), cc, nc, tt, ct, perc))
def print(self):
flen = max(len(x[2]) for x in self.entries)
print(f" {'Function / Scope'.ljust(flen)} {'cc'.rjust(6)} {'nc'.rjust(6)} tt ct %")
for node, idx, desc, cc, nc, tt, ct, perc in self.entries:
print(f"{idx:3d}: {desc.ljust(flen)} {cc:6d} {nc:6d} {tt:7.3f} {ct:7.3f} {perc:5.1f}")
def get_node(self, pos):
return self.entries[int(pos)][0]
class Browser(cmd.Cmd):
def __init__(self, stats: pstats.Stats):
super().__init__()
self.stats = stats
self.graph = Graph.from_pstats(stats)
# Last menu shown
self.menu = None
def print_caller_table(self, calls):
for c in calls:
self.menu.add(Menu.CALLER, c.caller, c.cc, c.nc, c.tt, c.ct, c.ct * 100.0 / self.graph.total_time)
def print_callee_table(self, calls):
for c in calls:
self.menu.add(Menu.CALLEE, c.callee, c.cc, c.nc, c.tt, c.ct, c.ct * 100.0 / self.graph.total_time)
def print_node(self, node):
self.menu.add(Menu.NODE, node, node.cc, node.nc, node.tt, node.ct, node.ct * 100.0 / self.graph.total_time)
def do_calls(self, arg):
"""
Print callees and callers for the given node
"""
node = self.menu.get_node(arg)
self.menu = Menu()
self.print_caller_table(sorted(node.callers, key=lambda x: -x.ct)[:10])
self.print_node(node)
self.print_callee_table(sorted(node.callees, key=lambda x: -x.ct)[:10])
self.menu.print()
def do_index(self, arg):
"""
Show an index of relevant functions
"""
self.menu = Menu()
nodes = []
for node in self.graph.nodes.values():
if os.path.basename(node.fname) == "ssite":
if node.scope == "main":
nodes.append(node)
if os.path.basename(node.fname) == "site.py":
if node.scope in ("load", "scan_content", "load_content", "load_theme", "analyze"):
nodes.append(node)
if os.path.dirname(node.fname).endswith("staticsite/cmd"):
if node.scope == "run":
nodes.append(node)
nodes.sort(key=lambda n: -n.ct)
for node in nodes:
self.print_node(node)
self.menu.print()
def do_tree(self, arg):
"""
Show a callee tree with the top-called functions
"""
node = self.menu.get_node(arg)
self.menu = Menu()
self.menu.add(Menu.NODE, node, node.cc, node.nc, node.tt, node.ct, node.ct * 100.0 / self.graph.total_time)
def add_callees(n, depth=0):
# Max tree depth
if depth > 3:
return
# Add all callees to the menu
for c in sorted(n.callees, key=lambda x: -x.ct):
if c.ct < node.ct * 0.01:
break
self.menu.add("┬", c.callee, c.cc, c.nc, c.tt, c.ct, c.ct * 100.0 / node.ct, indent=depth)
add_callees(c.callee, depth=depth + 1)
add_callees(node, depth=1)
self.menu.print()
def do_pprint(self, arg):
"""
Pretty print the raw collected statistics
"""
with tempfile.NamedTemporaryFile("wt") as fd:
pprint.pprint(self.stats.stats, stream=fd)
fd.flush()
subprocess.run(["less", fd.name])
def do_EOF(self, arg):
"""
Quit
"""
print()
return True
def main():
parser = argparse.ArgumentParser(description="Static site generator.")
parser.add_argument("profile", nargs="?", default="profile.out",
help="cProfile output to read")
args = parser.parse_args()
stats = pstats.Stats(args.profile)
# stats.sort_stats(SortKey.CUMULATIVE).print_stats(20)
# stats.sort_stats(SortKey.TIME).print_stats(20)
# stats.sort_stats(SortKey.CUMULATIVE).print_callees(r"site.py.+\(load_content\)")
cmd = Browser(stats)
cmd.do_index("")
cmd.cmdloop()
if __name__ == "__main__":
main()
staticsite-1.4.1/doc/ 0000755 0001750 0001750 00000000000 13605113260 015213 5 ustar enrico enrico 0000000 0000000 staticsite-1.4.1/doc/devel/ 0000755 0001750 0001750 00000000000 13605113260 016312 5 ustar enrico enrico 0000000 0000000 staticsite-1.4.1/doc/devel/README.md 0000644 0001750 0001750 00000003333 13603343314 017576 0 ustar enrico enrico 0000000 0000000 # Developer documentation
## Playing with the internals
You can run `ssite shell` on an existing site, to get a python shell with the
`site` variable set to the fully built `staticsite.Site` object for the site.
## Running tests
staticsite uses pretty standard unittest-based tests. You can run them normally
with `nose2-3` or `./setup.py test`.
## Test coverage
```
nose2-3 -C --coverage-report=html
sensible-browser htmlcov/index.html
```
## Profiling
```
python3 -m cProfile -o profile.out ./ssite build …
ipython3
>>> import pstats
>>> from pstats import SortKey
>>> stats = pstats.Stats("profile.out")
>>> stats.sort_stats(SortKey.CUMULATIVE).print_stats(20)
```
You can use `devel/profile-view` to get some ready made statistics on profile
data, and explore the profile results.
You can also use [runsnakerun](http://www.vrplumber.com/programming/runsnakerun/)
(in Debian, you currently need version 2.0.5 (not yet available in buster) to
read python3 profile data).
## Linting
Just run `flake8` in the project directory.
staticsite should be flake8-clean, with a `max-line-length` of 120.
## Static type checking
```
mypy staticsite ssite
```
## Codespell
```
codespell --write-changes --skip debian/copyright *.md debian doc example staticsite tests
```
## Release checklist
* Run tests
* `nose2-3`
* `flake8`
* `mypy ssite staticsite`
* Build for debian
* `debian/rules debsrc`
* `sudo cowbuilder update`
* `sudo cowbuilder build staticsite_$version.dsc`
* `debsign staticsite_$version_source.changes`
* `dput staticsite_$version_source.changes`
* Tag release in git
* `git tag -s v$version`
* `git push --tags`
Documentation at
staticsite-1.4.1/doc/howto/ 0000755 0001750 0001750 00000000000 13605113260 016353 5 ustar enrico enrico 0000000 0000000 staticsite-1.4.1/doc/howto/README.md 0000644 0001750 0001750 00000000422 13605077140 017636 0 ustar enrico enrico 0000000 0000000 # HOWTOs
* [Add an about page](about-page.md)
* [Group blog posts in a directory](blog-posts-in-a-directory.md)
* [Tag site pages](tag-pages.md)
* [Post series](post-series.md)
* [Add an image for a post](post-image.md)
* [Social media previews](social-media-previews.md)
staticsite-1.4.1/doc/howto/about-page.md 0000644 0001750 0001750 00000002161 13603673632 020735 0 ustar enrico enrico 0000000 0000000 # Add an about page
## Write an about page
Create `about.md`:
~~~~{.md}
```yaml
nav_title: About
```
# About this site
> We have now sunk to a depth at which restatement of the obvious is the first
> duty of intelligent men. If liberty means anything at all, it means the right
> to tell people what they do not want to hear. In times of universal deceit,
> telling the truth will be a revolutionary act.
>
> (George Orwell)
~~~~
Add a [`nav` entry](../reference/metadata.md#nav) to `index.md`'s front matter:
~~~~{.md}
```yaml
site_url: https://www.example.org
template: blog.html
syndication: yes
pages: "*"
nav: [about.md] # ← Add this!
```
~~~~
Now the navigation bar at the top of every page in the site will have an
"About" link.
You can change the `nav` setting at will, to customize navigation for the
various sections of your site.
You can use [`nav_title`](../reference/metadata.md#nav_title) to provide a
shorter title for the page when shown in a navbar.
## Next steps
* [Group blog posts in a directory](blog-posts-in-a-directory.md)
* [More HOWTOs](README.md)
* [Back to main documentation](../../README.md)
staticsite-1.4.1/doc/howto/blog-posts-in-a-directory.md 0000644 0001750 0001750 00000002514 13603671317 023626 0 ustar enrico enrico 0000000 0000000 # Group blog posts in a directory
In the [blog tutorial](../tutorial/blog.md) all the posts are together at the
root of the site, and you are free to organise your site contents as you like.
Here are two examples:
## Posts in a `posts`/` directory
You can decide to write all your blog posts under a `posts/` directory. You can
then change the [`pages`](../reference/metadata.md#pages) selection accordingly
in the blog front matter:
~~~~{.md}
```yaml
site_url: https://www.example.org
template: blog.html
syndication: yes
pages: "posts/*" # ← change like this so select only pages in posts/
```
# My new blog
Welcome to my new blog.
~~~~
The `pages` selection will pick all pages inside `posts/` and all its
subdirectories.
## Posts in a directory per year
You can decide to write all your blog posts under one directory per year, like
`2020/`, `2021`, and so on.
You can then change the [`pages`](../reference/metadata.md#pages) selection
to match directories consisting of numbers, using a regular expression:
~~~~{.md}
```yaml
site_url: https://www.example.org
template: blog.html
syndication: yes
pages: "^\\d+/" # ← start with ^ to use a regular expression
```
# My new blog
Welcome to my new blog.
~~~~
## Next steps
* [Tag site pages](tag-pages.md)
* [More HOWTOs](README.md)
* [Back to main documentation](../../README.md)
staticsite-1.4.1/doc/howto/post-image.md 0000644 0001750 0001750 00000000742 13605100276 020750 0 ustar enrico enrico 0000000 0000000 # Add an image for a post
If your post is called `post.md`, add an image with the same name, like
`post.jpg` or `post.png`, and the image will appear in the post.
If the image has an [`ImageDescription` EXIF tag](../reference/images.md), the
theme may use it as an `alt` text and as an image caption.
You can run `ssite meta post.jpg` to edit the image metadata that staticsite
can use.
## Next steps
* [More HOWTOs](README.md)
* [Back to main documentation](../../README.md)
staticsite-1.4.1/doc/howto/post-series.md 0000644 0001750 0001750 00000001437 13605100267 021162 0 ustar enrico enrico 0000000 0000000 # Post series
Create a `series` [taxonomy](tag-pages.md) to group posts into sequential
series!
## Create a `series` taxonomy
Write a a `series.taxonomy` file:
```yaml
---
title: All series
description: Index of all the series of posts in this site
```
## Add pages to a series
You can now set the `tags` entry at the top of your posts to tag them:
~~~~{.md}
```yaml
series: venice2020
series_title: Venice 2020
```
# On the train to Venice
…
~~~~
`series` is just like any other taxonomy, but when the default page template
sees a category in the `series` taxonomy, it will use it to render *first*,
*last*, *previous*, and *next* navigation links.
## Next steps
* [Add an image for a post](post-image.md)
* [More HOWTOs](README.md)
* [Back to main documentation](../../README.md)
staticsite-1.4.1/doc/howto/social-media-previews.md 0000644 0001750 0001750 00000003613 13603666050 023101 0 ustar enrico enrico 0000000 0000000 # Template designed documentation
## Social media previews
[The Essential Meta Tags for Social Media](https://css-tricks.com/essential-meta-tags-social-media/)
is a good introduction for creating social media preview metadata for web pages.
In staticsite templates, this becomes:
```jinja2
{% if page.meta.description -%}
{%- endif %}
{% if page.meta.image -%}
{%- endif %}
```
Notes:
* [`og:description` should not contain HTML tags](https://stackoverflow.com/questions/7759782/can-opengraph-description-fields-contain-html)
* [`description` and `og:description` can be combined](https://stackoverflow.com/questions/6203984/combining-the-meta-description-and-open-graph-protocol-description-into-one-tag)
## Testing social media previews
**Facebook**:
* [Sharing debugger](https://developers.facebook.com/tools/debug/sharing/) (requires login)
* [Object Graph Object debugger](https://developers.facebook.com/tools/debug/og/object/) (requires login)
**Twitter**:
* [Twitter card validator](https://cards-dev.twitter.com/validator) (requires login)
**Telegram**:
* [@webpagebot](https://telegramgeeks.com/2016/03/you-can-update-link-preview-telegram/)
can be asked to (re)generate and show link previews
## Other useful links
* [Open Graph Check](https://opengraphcheck.com/)
* [Description of Open Graph types](https://stackoverflow.com/questions/8263493/ogtype-and-valid-values-constantly-being-parsed-as-ogtype-website)
## Next steps
* [More HOWTOs](README.md)
* [Back to main documentation](../../README.md)
staticsite-1.4.1/doc/howto/tag-pages.md 0000644 0001750 0001750 00000001730 13603673573 020566 0 ustar enrico enrico 0000000 0000000 # Tag site pages
You can tag site pages using one or more sets of categories. Each set of
categories is called a [taxonomy](../reference/taxonomies.md).
## Create a `tags` taxonomy
Write a a `tags.taxonomy` file:
```yaml
---
title: All tags
description: Index of all the tags used in the site
```
Here you can customize how the tag index looks like.
Each taxonomy automatically gets an index of all categories, and a little
blog-like page for each category, including RSS/Atom feeds and archive pages.
## Add the tags index to the site navbar
Change the [`nav`](about-page.md) entry to add a reference to `tags.taxonomy`:
~~~~{.md}
```yaml
nav: [tags.taxonomy, about.md]
```
~~~~
## Tag pages
You can now set the `tags` entry at the top of your posts to tag them:
~~~~{.md}
```yaml
tags: [travel, family]
```
# A day in the countryside
…
~~~~
## Next steps
* [Post series](post-series.md)
* [More HOWTOs](README.md)
* [Back to main documentation](../../README.md)
staticsite-1.4.1/doc/reference/ 0000755 0001750 0001750 00000000000 13605113260 017151 5 ustar enrico enrico 0000000 0000000 staticsite-1.4.1/doc/reference/README.md 0000644 0001750 0001750 00000001424 13605075243 020441 0 ustar enrico enrico 0000000 0000000 # Reference documentation
## Site structure
* [The Site object](site.md)
* [The Page object](page.md)
* [Site settings](settings.md)
* [Source contents](contents.md)
* [Themes](theme.md)
* [Jinja2 templates reference](templates.md)
* [Selecting site pages](page-filter.md)
* [Archetypes reference](archetypes.md)
* [Site-specific features](feature.md)
## Site contents
* [Front Matter](front-matter.md)
* [Common page metadata](metadata.md)
* [Markdown pages](markdown.md)
* [reStructuredText pages](rst.md)
* [Jinja2 pages](jinja2.md)
* [Data pages](data.md)
* [Taxonomies](taxonomies.md)
* [Images](images.md)
* [Listing subpages](pages.md)
* [RSS/Atom feed generation](syndication.md)
* [Series of pages](series.md)
* [Directory indices](dir.md)
[Back to README](../../README.md)
staticsite-1.4.1/doc/reference/archetypes.md 0000644 0001750 0001750 00000002672 13601501231 021644 0 ustar enrico enrico 0000000 0000000 # Archetypes
## Creating new pages
```bash
$ ./ssite new example
Please enter the page title: An example new page
(editor opens)
```
`staticsite` uses [Hugo-style archetypes](https://gohugo.io/content/archetypes/).
By default, `archetypes/default.md` is used as a template for new pages, and
you can use the `-a` or `--archetype` option to pick another one.
The archetype is processed via the same Jinja2 logic as the rest of the site,
plus the `title` and `slug` variables for the article. The `path` value in the
front matter is used to decide where to write the file, and is removed before
writing the page.
The editor and editor command line can also be configured, see
`global_settings.py` for details and examples.
# Archetypes tips
## Monthly collection of links
`example/archetypes/links.md` is an example of how to use archetypes to publish
a monthly collection of links:
```jinja2
+++
path = "blog/{{next_month.strftime("%Y")}}/links-{{next_month.strftime("%m")}}.md"
date = "{{next_month|datetime_format()}}"
tags = ["ssite new -a linkslinks"]
+++
# Links for {{next_month.strftime("%B %Y")}}
…
```
Use `ssite new -a links` to add a link to the collection.
The path and title of the page will be generated based on next month only, and
the page will not be published while links are being collected. When the next
month comes, the page will be published and `ssite new -a links` will start a
new page.
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/contents.md 0000644 0001750 0001750 00000006606 13601744401 021343 0 ustar enrico enrico 0000000 0000000 # site: source contents of the site
staticsite does not mandate a site structure, and generates output mirroring
how source files are organised.
This lets you free to set the structure of your website by organising pages in
directories in any way you want.
Site contents can contain any kind of resource handled by staticsite
[features](feature.md), like:
* [markdown files](markdown.md)
* [restructuredText files](rst.rst)
* [data files](data.md)
* [jinja2 templates](jinja2.md)
* [taxonomy files](taxonomies.md)
Most pages handled by staticsite features will be generated as
`pagename/index.html` instead of `pagename.html`, to build a site with clean
URLs.
Any file not handled by staticsite features will be copied as-is to the
website, allowing you to intermix freely rendered pages with static assets or
downloadable content.
## Directory metadata
If a `.staticsite` file is found in a content directory, it is parsed as
`yaml`, `json`, or `toml`, and its contents become default
[metadata](metadata.md) for all the pages in that directory, and all its
subdirectories.
Likewise, the metadata found in the index file for a directory, become default
metadata for all the pages in that directory, and all its subdirectories.
You can use this to set metadata like `site_name`, `author`, `site_url`,
`site_root`.
Also, if you set `asset` to true in `.staticsite`, the subdirectory is loaded
as static files, and not passed through site features.
A `.staticsite` or directory index file can also have these entries to control
metadata of other files:
### `dirs`
Provides extra metadata for subdirectories of the given directory.
It is equivalent to setting `site` in each of the matching subdirectories.
### `files`
Provides extra metadata for files found in the directory.
This can be used, for example, to provide metadata for `.html` pages.
File names can be given as glob expressions or regular expressions, as with
[page selection](page-filter.md). If a file matches multiple entries, it gets
all the matching metadata, with the later ones potentially overwriting the
previous ones.
### Example directory metadata
```yaml
---
files:
index.j2.html:
syndication:
filter:
path: blog/*
limit: 10
sort: "-date"
add_to:
path: blog/*
title: "Example blog feed"
dirs:
"static-*:
asset: true
```
### Content loading
Content loading happens in 3 stages:
**scanning directories**: the content directory tree is scanned looking for
`.staticsite` files, directory index files, and taxonomy files, and using them
to build initial metadata for each file and directory in the site, and a list
of known taxonomies.
Other features could hook into this stage, like [`taxonomy`](taxonomies.md)
does, to gather information that can affect page loading.
For example, the list of taxonomies built at this stage informs which tags in
[reSt](rst.rst) files are parsed as lists of strings, and directory indices can
affect which files are loads as assets instead of as normal pages.
**loading content**: every file is scanned or loaded to contribute to the site
contents. Front matter metadata is loaded and validated.
**analyzing**: once content is loaded, features can have a pass at analyzing
the loaded data to generate, for example, tag pages, or syndication pages.
At this point, the site is laid out and all pages are ready to be rendered.
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/data.md 0000644 0001750 0001750 00000001553 13601501241 020404 0 ustar enrico enrico 0000000 0000000 # Data files
Data files have a `.json`, `.yaml`, or `.toml` extension and can be rendered
with custom Jinja2 templates.
The content of the data file is parsed, and merged into the page metadata.
The jinja2 template can be chosen using the `data_type` metadata (see below).
The metadata of any page with the `data_type` metadata will be also tracked as
data. This allows to create normal pages that also add to a named dataset.
## Page metadata
The [usual metadata](metadata.md) can be used, plus the following items:
### `page.meta.data_type`
Identifies the data type. Internally, the data feature groups data pages by
type, so further features can efficiently access thematic datasets.
The `page.meta.template` metadata for data pages, when not specified, defaults
to `dir-[type].html`, or if that is missing, to `data.html`.
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/dir.md 0000644 0001750 0001750 00000001050 13601501245 020245 0 ustar enrico enrico 0000000 0000000 # Directory indices
For each directory that does not have an index page, staticsite automatically
generates one: this makes every partial url to the site a valid URL.
## Directory pages
Directory pages have these extra properties:
* `page.meta.template` defaults to `dir.html`
* `page.meta.title` is the directory name, or the site name in case the site
root is an autogenerated directory page
* `page.meta.pages` lists the pages in this directory
* `page.meta.parent` parent page in the directory hierarcny
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/feature.md 0000644 0001750 0001750 00000004451 13603344374 021144 0 ustar enrico enrico 0000000 0000000 # Site-specific features
Since version 1.0, it is possible to provide site-specific features as python
packages in the theme `features` directory.
At site load time, the `$theme/features` directory gets scanned with
[`pkgutil.iter_modules`](https://docs.python.org/3/library/pkgutil.html#pkgutil.iter_modules),
and all modules found can provide extra features in a `FEATURES` dict at module level.
The `FEATURES` dict maps feature names to subclasses of `staticsite.Feature`.
See `staticsite/feature.py` for details on the base `Feature` class.
You can add anything you want to the modules under `$theme/features`: see for
example [importlib.resources](https://docs.python.org/3/library/importlib.html#module-importlib.resources)
for how to package assets together with a feature.
This mechanism can also add site-specific command line features under the
`ssite site --cmd …` command.
See `example/theme/features/hello.py` for an annotate example feature.
Most of staticsite is now implemented through features, and you can also look
at `staticfile/features/` to take existing features as examples for custom
ones.
You can also replace an existing staticsite feature by providing a new feature
registered with the same name.
## Feature dependencies
Each feature can define a `RUN_BEFORE` or `RUN_AFTER` on other feature names,
to sequence running so that the results of a feature are guaranteed to be
available when another one runs.
For example, the `syndication` analyze pass needs to run after `taxonomy` and
`pages` have built their page lists.
staticsite provides one predefined synchronization point that can be used for
dependencies:
* `autogenerated_pages`: use it in `RUN_BEFORE` for feature that generate pages
not present in the site contents on disk. Use it in `RUN_AFTER` for features
that work on any kind of page, whether on-disk or autogenerated.
Note that dependencies may not be needed as much as they might seem: they are
useful to sort the execution of feature constructors, `load_dir_meta`,
`load_dir`, and `finalize`, but those are already separate stages. For example,
if `taxonomy` needs to run its `finalize` methods after all pages have been
loaded from disk, a dependency is not needed, since the `load_dir` stage
already happens before the `finalize` stage.
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/front-matter.md 0000644 0001750 0001750 00000002112 13601501254 022111 0 ustar enrico enrico 0000000 0000000 # Front matter
Front matter in staticsite[^1] is arbitrary key/value data stored in
[JSON](https://en.wikipedia.org/wiki/JSON),
[YAML](https://en.wikipedia.org/wiki/YAML), or
[toml](https://en.wikipedia.org/wiki/TOML) format.
It is the way used to add metadata in [markdown](markdown.md),
[data](data.md), and [jinja2](jinja2.md) pages.
If metadata starts with `---`, it is read as YAML. If it starts with `+++` it
is read as TOML. If it starts with `{`, it is read as JSON.
For documentation on possible metadata contents, see [Common page metadata](metadata.md)
## Example YAML front matter in a markdown page
```yaml
---
title: Page with metadata in YAML format
---
page contents
```
## Example JSON front matter in a Jinja2 page
```jinja2
{% block front_matter %}
{
"title": "Page with metadata in JSON format"
}
{% endblock %}
{% block content %}
...
{% endblock %}
```
## Example TOML data page
```toml
+++
title = "Page with metadata in TOML format"
```
[^1]:
Inspired from [Hugo front matter](https://gohugo.io/content/front-matter/)
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/images.md 0000644 0001750 0001750 00000003655 13604642302 020754 0 ustar enrico enrico 0000000 0000000 # Images
Files with an `image/*` mime type found in content directories are scanned for
metadata and used as image pages.
Their behaviour is similar to the one of static assets, but templates and other
staticsite facilities can make use of the metadata resolved.
## Metadata extracted from images
These are the current metadata elements filled from image data, when available:
* `page.meta.width`: image width in pixels
* `page.meta.height`: image height in pixels
* `page.meta.lat`: latitude from EXIF tags, as a signed floating point number
of degrees
* `page.meta.lon`: longitude from EXIF tags, as a signed floating point number
of degrees
* `page.meta.title`: content of the `ImageDescription` EXIF tag
* `page.meta.author`: content of the `Artist` EXIF tag
* `page.meta.image_orientation`: content of the [`ImageOrientation` EXIF tag](https://www.impulseadventure.com/photo/exif-orientation.html)
## Image associated to another page
If you have an image sharing the file name with another page (for example, an
image called `example.jpg` next to a page called `example.md`), then the page
automatically gets a `page.meta.image` value pointing to the image.
You can use this, for example, to easily provide an image for blog posts.
## Scaled versions of images
[Theme](theme.md) configurations can specify a set of scaled versions of images
to generate:
```yaml
# Scaled down widths of images that will be generated
image_sizes:
medium:
width: 600
small:
width: 480
thumbnail:
width: 128
```
Given a `image.jpg` image file, this will generate `image-medium.jpg`,
`image-small.jpg` and `image-thumbnail.jpg`.
Using this feature, the [`img_for` template function](templates.md) will
automatically generate `srcset` attributes to let the browser choose which
version to load.
Scaled versions of the image will be available in the image's [`meta.related`
metadata](metadata.md#related).
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/jinja2.md 0000644 0001750 0001750 00000002606 13603075057 020665 0 ustar enrico enrico 0000000 0000000 # Jinja2 pages
You can put [jinja2 templates](templates.md) in your site contents, and they
will be rendered as site pages.
This can be used to generate complex index pages, blog front pages, and
anything else [Jinja2](http://jinja.pocoo.org/) is able to generate.
You can set `JINJA2_PAGES` in the [site settings](settings.md) to a list of
patterns (globs or regexps as in [page filters](page-filter.md)) matching file
names to consider jinja2 templates by default. It defaults to
`["*.html", "*.j2.*"]`.
Any file with `.j2.` in their file name will be rendered as a template,
stripping `.j2.` in the destination file name.
For example, `dir/robots.j2.txt` will become `dir/robots.txt` when the site is
built.
## Front matter
If a page defines a jinja2 block called `front_matter`, the block is rendered
and parsed as front matter.
**Note**: [jinja2 renders all contents it finds before `{% extends %}`](https://jinja.palletsprojects.com/en/2.10.x/templates/#child-template).
To prevent your front matter from ending up in the rendered HTML, place the
`front_matter` block after the `{% extends %}` directive, or manage your front
matter from [`.staticfile` directory metadata](content.md).
If you want to use `template_*` entries, you can wrap the front matter around
`{% raw %}` to prevent jinja2 from rendering their contents as part of the rest
of the template.
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/markdown.md 0000644 0001750 0001750 00000007702 13605101025 021317 0 ustar enrico enrico 0000000 0000000 # Markdown pages
Markdown files have a `.md` extension and are prefixed by
[front matter metadata](front-matter.md).
The flavour of markdown is what's supported by
[python-markdown](http://pythonhosted.org/Markdown/) with the
[Extra](http://pythonhosted.org/Markdown/extensions/extra.html),
[CodeHilite](http://pythonhosted.org/Markdown/extensions/code_hilite.html)
and [Fenced Code Blocks](http://pythonhosted.org/Markdown/extensions/fenced_code_blocks.html)
extensions, and is quite close to
[GitHub Flavored Markdown](https://github.github.com/gfm/) or
[GitLab Markdown](https://docs.gitlab.com/ee/user/markdown.html).
`staticsite` adds an extra internal plugin to Python-Markdown to postprocess
the page contents to adjust internal links to guarantee that they point where
they should.
Adding a horizontal rule *using underscores* (3 or more underscores), creates a
page fold. When rendering the page inline, such as in a blog index page, or in
RSS/Atom syndication, the content from the horizontal rule onwards will not be
shown.
If you want to add a horizontal rule without introducing a page fold, use a
sequence of three or more asterisks (`***`) or dashes (`---`) instead.
## Linking to other pages
Pages can link to other pages via normal Markdown links (`[text](link)`).
Links that start with a `/` will be rooted at the top of the site contents.
Relative links are resolved relative to the location of the current page first,
and failing that relative to its parent directory, and so on until the root of
the site.
For example, if you have `blog/2016/page.md` that contains a link like
``, the link will point to the first of this
options that will be found:
1. `blog/2016/images/photo.jpg`
2. `blog/images/photo.jpg`
3. `images/photo.jpg`
This allows one to organise pages pointing to other pages or assets without needing
to worry about where they are located in the site.
You can link to other Markdown pages with the `.md` extension
([like GitHub does](https://help.github.com/articles/relative-links-in-readmes/))
or without, as if you were editing a wiki.
## Page metadata
The front matter of the post can be written in
[TOML](https://github.com/toml-lang/toml),
[YAML](https://en.wikipedia.org/wiki/YAML) or
[JSON](https://en.wikipedia.org/wiki/JSON), just like in
[Hugo](https://gohugo.io/content/front-matter/).
Use `---` delimiters to mark YAML front matter. Use `+++` delimiters to mark
TOML front matter. Use `{`…`}` delimiters to mark JSON front matter.
You can also usea [triple-backticks code blocks](https://python-markdown.github.io/extensions/fenced_code_blocks/)
first thing in the file to mark front matter, optionally specifying `yaml`,
`toml`, or `json` as the format (yaml is used as a default):
~~~~{.markdown}
```yaml
date: 2020-01-02 12:00
```
# My page
~~~~
If you want to start your markdown content with a code block, add an empty line
at the top: front matter detection only happens on the first line of the file.
See [page metadata](metadata.md) for a list of commonly used metadata.
## Extra settings
Markdown rendering makes use of these settings:
### `MARKDOWN_EXTENSIONS`
Extensions used by python-markdown. Defaults to:
```py
MARKDOWN_EXTENSIONS = [
"markdown.extensions.extra",
"markdown.extensions.codehilite",
"markdown.extensions.fenced_code",
]
```
### `MARKDOWN_EXTENSION_CONFIGS`
Configuration for markdown extensions. Defaults to:
```py
MARKDOWN_EXTENSION_CONFIGS = {
'markdown.extensions.extra': {
'markdown.extensions.footnotes': {
# See https://github.com/spanezz/staticsite/issues/13
'UNIQUE_IDS': True,
},
},
}
```
## Rendering markdown pages
Besides the usual `meta`, markdown pages have also these attributes:
* `page.contents`: the Markdown contents rendered as HTML. You may want to use
it with the [`|safe` filter](https://jinja.palletsprojects.com/en/2.10.x/templates/#safe)
to prevent double escaping
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/metadata.md 0000644 0001750 0001750 00000021723 13605100507 021260 0 ustar enrico enrico 0000000 0000000 # Common page metadata
This is a list of metadata elements that have special meaning in this site.
You can use `ssite dump_meta` to see all the content and metadata that pages
make available to templates via the `page` variable.
### `template`
Template used to render the page. Defaults to `page.html`, although specific
pages of some features can default to other template names.
Use this similarly to [Jekill's layouts](https://jekyllrb.com/docs/step-by-step/04-layouts/).
### `date`
Publication date for the page.
A python datetime object, timezone aware. If the date is in the future when
`ssite` runs, the page will be consider a draft and will be ignored. Use `ssite
--draft` to also consider draft pages.
If missing, the modification time of the file is used.
### `author`
* Inherited from directory indices.
A string with the name of the author for this page.
SITE_AUTHOR is used as a default if found in settings.
If not found, it defaults to the current user's name.
### `template_copyright`
* Inherited from directory indices.
* Template for copyright
If set instead of `copyright`, it is a jinja2 template used to generate the
copyright information.
The template context will have `page` available, with the current page. The
result of the template will not be further escaped, so you can use HTML markup
in it.
If missing, defaults to `"© {{page.meta.date.year}} {{page.meta.author}}"`
### `copyright`
* Inherited from directory indices.
A string with the copyright information for this page.
### `template_title`
* Inherited from directory indices.
* Template for title
If set instead of `title`, it is a jinja2 template used to generate the title.
The template context will have `page` available, with the current page. The
result of the template will not be further escaped, so you can use HTML markup
in it.
### `title`
* Inherited from directory indices.
The page title.
If omitted:
* the first title found in the page contents is used.
* in the case of jinaj2 template pages, the contents of `{% block title %}`,
if present, is rendered and used.
* if the page has no title, the title of directory indices above this page is
inherited.
* if still no title can be found, the site name is used as a default.
### `template_description`
* Inherited from directory indices.
* Template for description
If set instead of `description`, it is a jinja2 template used to generate the
description. The template context will have `page` available, with the current
page. The result of the template will not be further escaped, so you can use
HTML markup in it.
### `description`
* Inherited from directory indices.
The page description. If omitted, the page will have no description.
### `site_name`
* Inherited from directory indices.
Name of the site. If missing, it defaults to the title of the toplevel index
page. If missing, it defaults to the name of the content directory.
### `site_url`
* Inherited from directory indices.
Base URL for the site, used to generate an absolute URL to the page.
### `site_path`
Where a content directory appears in the site.
By default, is is the `site_path` of the parent directory, plus the directory
name.
If you are publishing the site at `/prefix` instead of the root of the domain,
override this with `/prefix` in the content root.
### `build_path`
Relative path in the build directory for the file that will be written
when this page gets rendered. For example, `blog/2016/example.md`
generates `blog/2016/example/index.html`.
If found in pages front matter, it is ignored, and is always computed at page
load time.
### `asset`
* Inherited from directory indices.
If set to True for a file (for example, by a `file:` pattern in a directory
index), the file is loaded as a static asset, regardless of whether a feature
would load it.
If set to True in a directory index, the directory and all its subdirectories
are loaded as static assets, without the interventions of features.
### `aliases`
* Inherited from directory indices.
Relative paths in the destination directory where the page should also show up.
[Like in Hugo](https://gohugo.io/extras/aliases/), this can be used to maintain
existing links when moving a page to a different location.
### `indexed`
If true, the page appears in [directory indices](dir.md) and in
[page filter results](page_filter.md).
It defaults to true at least for [Markdown](markdown.md),
[reStructuredText](rst.rst), and [data](data.md) pages.
### `draft`
If true, the page is still a draft and will not appear in the destination site,
unless draft mode is enabled.
It defaults to false, or true if `page.meta.date` is in the future.
### `data_type`
Type of data for this file.
This is used to group data of the same type together, and to choose a
`data-[data_type].html` rendering template.
### `image`
Image used for this post.
It is set to a path to an image file relative to the current page.
During the analyze phase, it is resolved to the corresponding [image page](images.md).
If not set, and an image exists with the same name as the page (besides the
extension), that image is used.
### `pages`
The `pages` metadata can use to select a set of pages shown by the current
page. Although default `page.html` template will not do anything with them,
other page templates, like `blog.html`, use this to select the pages to show.
The `pages` feature allows defining a [page filter](page-filter.md) in the
`pages` metadata element, which will be replaced with a list of matching pages.
To select pages, the `pages` metadata is set to a dictionary that select pages
in the site, with the `path`, and taxonomy names arguments similar to the
`site_pages` function in [templates](templates.md).
See [Selecting pages](page-filter.md) for details.
### `syndication`
Defines syndication for the contents of this page.
It is a structure which can contain normal metadata, plus:
* `add_to`: chooses which pages will include a link to the RSS/Atom feeds.
By default, the link is added to all syndicated pages. If this is `False`,
then no feed is added to pages. If it is a dictionary, it selects pages in
the site, similar to the `site_pages` function in [templates](templates.md).
See [Selecting pages](page-filter.md) for details.
* `archive`: if not false, an archive link will be generated next to the
page. It can be set of a dictionary of metadata to be used as defaults for
the generated archive page. It defaults to True.
Any other metadata found in the structure are used when generating pages for
the RSS/Atom feeds, so you can use `title`, `template_title`, `description`,
and so on, to personalize the feeds.
The pages that go in the feed are those listed in
[`page.meta.pages`](doc/reference/pages.md), keeping into account the
[`syndicated` and `syndication_date` page metadata](doc/reference/metadata.md).
When rendering RSS/Atom feed pages, `page.meta.pages` is replaced with the list
of syndicated pages, sorted with the most recent first.
Setting `syndication` to true turns on syndication with all defaults,
equivalent to:
```yaml
syndication:
add_to: yes
archive:
template: archive.html
```
### `syndicated`
Set to true if the page can be included in a syndication, else to false.
If not set, it defaults to the value of `indexed`.
### `syndication_date`
Syndication date for this page.
This is the date that will appear in RSS and Atom feeds, and the page will not
be syndicated before this date.
If a page is syndicated and `syndication_date` is missing, it defaults to `date`.
### `nav`
* Inherited from directory indices.
List of page paths that are used for the navbar.
### `nav_title`
Title to use when this paged is linked in a navbar.
It defaults to `page.meta.title`, or to the series name for series pages.
`nav_title` is only guaranteed to exist for pages that are used in `nav`.
### `related`
Dict of pages related to this page.
Dict values will be resolved as pages.
If there are no related pages, `page.meta.related` will be guaranteed to exist
as an empty dictionary.
Features can add to this. For example, [syndication](syndication.md) can add
`meta.related.archive`, `meta.related.rss`, and `meta.related.atom`.
### `series`
List of categories for the `series` taxonomy.
Setting this as a simple string is the same as setting it as a list of one
element.
### `tags`
List of categories for the `tags` taxonomy.
Setting this as a simple string is the same as setting it as a list of one
element.
staticsite-1.4.1/doc/reference/page-filter.md 0000644 0001750 0001750 00000002752 13603414140 021677 0 ustar enrico enrico 0000000 0000000 # Selecting site pages
Functions like `site_pages` in [templates](templages.md) or `filter`/`add_to`
in [syndication](syndication.md) allow selecting pages from the site.
These parameters can be used to choose pages:
* `path`: glob or regular expression that matches the file name in the site
contents directory. It is used as a file glob (like `"blog/*"`), unless it
starts with `^` or ends with `$`: then it is considered a regular
expression.
* `sort`: order the results according to the given metadata item. Prepend a
dash (`-`) for reverse sorting. Use `url` or `-url` to sort by the url of
the page in the website.
* `limit` is the maximum number of pages to return.
* `root` is a path limiting matching pages to those under it. You can use
`"/"` to match from the site root. By default it is the path of the
directory containing the page from which the search is made.
Any taxonomy defined in the site becomes a possible parameter for filtering,
and is a list of categories of that taxonomy: pages must have all those
categories to be selected.
Note that in many cases, you may want to omit `sort` and `limit` from
`site_pages` and page front matter, and decide sorting and limit in templates
with [the `arrange()` filter](templates.md).
## Example:
List blog articles about Debian in a template:
```jinja2
{% for page in site_pages(path="blog/*", tags=["debian"], sort="-date") %}
{{url_for(page)}}
{% endfor %}
```
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/page.md 0000644 0001750 0001750 00000003620 13604672005 020416 0 ustar enrico enrico 0000000 0000000 # Page
`Page` objects are the base for all elements in the site. Different content is
loaded with different instances of `Page`, like `Asset`, `Image`, and
`MarkdownPage`.
## `meta`
Dictionary with all the [metadata](metadata.md) collected for the page or resource.
You can inspect this using the `ssite dump_meta` command.
## `find_pages(…)`
Find resources in the site relative to the current page.
The full signature is:
```py
Page.find_pages(
path: Optional[str] = None,
limit: Optional[int] = None,
sort: Optional[str] = None,
root: Optional[str] = None,
**kw) -> List[Page]
```
See [page filter documentation](page-filter.md) for details.
## `resolve_path(target: Union[str, Page]) -> Page`
Find a page by path, relative to the current page.
If target is already a `Page`, it is returned as-is.
## `url_for(target: Union[str, "Page"], absolute=False) -> str`
Return a URL that can be used in this page to link to `target`.
Set `absolute=True` to force it to be an absolute URL.
## `html_full() -> str`
Render the full page, from the `` tag downwards.
This is used to render the page itself.
## `html_body() -> str`
Render the full body of the page, with UI elements excluding
navigation, headers, footers.
This is used when rendering the page itself, when the theme is doing the UI and
the page needs to render its contents via Markdown or reStructuredText.
## `html_inline() -> str`
Render the content of the page to be shown inline, like in a blog page.
For pages with a leading introduction, the rest of the content is not shown.
Small images are used by default.
No UI elements are used if possible.
## `html_feed() -> str`
Render the content of the page to be shown in a RSS/Atom feed.
The whole contents are shown, without UI elements. All local links are rendered
as absolute URLs
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/pages.md 0000644 0001750 0001750 00000002015 13601501267 020574 0 ustar enrico enrico 0000000 0000000 ## Subpages
The `pages` feature allows defining a [page filter](page-filter.md) in the
`pages` metadata element, which will be replaced with a list of matching pages.
To select pages, the `pages` metadata is set to a dictionaru that select pages
in the site, similar to the `site_pages` function in [templates](templates.md),
and to [`filter` in syndication](syndication.md). See [Selecting
pages](page-filter.md) for details.
## Example blog page
```jinja2
{% extends "base.html" %}
{% block front_matter %}
---
pages:
path: blog/*
limit: 10
sort: "-date"
syndication:
add_to:
path: blog/*
title: "Enrico's blog feed"
{% endblock %}
{% import 'lib/blog.html' as blog %}
{% block title %}Enrico's blog{% endblock %}
{% block nav %}
{{super()}}
Archive
{% endblock %}
{% block content %}
Last 10 blog posts
{{blog.pages(page)}}
{% endblock %}
```
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/rst.rst 0000644 0001750 0001750 00000004541 13601465045 020526 0 ustar enrico enrico 0000000 0000000 RestructuredText files
======================
RestructuredText files have a ``.rst`` extension and their metadata are taken
from docinfo information.
``staticsite`` will postprocess the RestructuredText doctree to adjust internal
links to guarantee that they point where they should.
Linking to other pages
----------------------
Pages can link to other pages via any of the normal reSt links.
Links that start with a ``/`` will be rooted at the top of the site contents.
Relative links are resolved relative to the location of the current page first,
and failing that relative to its parent directory, and so on until the root of
the site.
For example, if you have ``blog/2016/page.rst`` that contains a link to
``images/photo.jpg``, the link will point to the first of this
options that will be found:
1. ``blog/2016/images/photo.jpg``
2. ``blog/images/photo.jpg``
3. ``images/photo.jpg``
This allows organising pages pointing to other pages or assets without needing
to worry about where they are located in the site.
You can link to other Markdown or RestructuredText pages with the ``.md`` or
``.rst`` extension (`like GitHub does`__)
or without, as if you were editing a wiki.
__ https://help.github.com/articles/relative-links-in-readmes/
Page metadata
-------------
As in Sphinx_, a field list near the top of the file is parsed as front
matter and removed from the generated files.
.. _Sphinx: http://www.sphinx-doc.org/en/stable/markup/misc.html#file-wide-metadata
All `bibliographic fields`_ known to docutils are parsed according to their
respective type.
.. _`bibliographic fields`: http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#bibliographic-fields
All fields whose name matches a taxonomy defined in ``TAXONOMY_NAMES``
`settings `_ are parsed as yaml, and expected to be a list of
strings, with the set of values (e.g. tags) of the given taxonomy for the
current page.
See `page metadata `_ for a list of commonly used metadata.
Rendering reStructuredText pages
--------------------------------
Besides the usual ``meta``, reStructuredText pages have also these attributes:
* ``page.contents``: the reSt contents rendered as HTML. You may want to use
it with the [`|safe` filter](https://jinja.palletsprojects.com/en/2.10.x/templates/#safe)
to prevent double escaping
`Back to reference index `_
staticsite-1.4.1/doc/reference/series.md 0000644 0001750 0001750 00000003112 13601501274 020764 0 ustar enrico enrico 0000000 0000000 # Series of posts
Any category of any taxonomy collects an ordered list of posts, that can be
used to generate interlinked series of pages.
All posts in a category are ordered by date (see [page metadata](markdown.md)).
Given a [category page](taxonomies.md), the `.sequence(page)` method locates
the page in the sequence of pages in that category, returning a dictionary
with these values:
* `index`: position of this page in the series (starts from 1)
* `length`: number of pages in the series
* `first`: first page in the series
* `last`: last page in the series
* `prev`: previous page in the series, if available
* `next`: next page in the series, if available
* `title`: title for the series
This example template renders the position of the page in the series, choosing
as a series the first category of the page in a taxonomy called `series`:
```jinja2
{% with place = page.meta.series[0].sequence(page) %}
{{place.title}} {{place.index}}/{{place.length}}
{% endwith %}
```
## Series title
The series title is, by default, the title of the first page in the series.
If a page defines a `series_title` header, then it becomes the series title
from that page onwards. It is possible to redefine the series title during a
series, like for example a "My trip" series that later becomes "My trip:
Italy", "My trip: France", "My trip: Spain", and so on.
## Multiple series for a page
A page is part of one series for each category of each taxonomy it has.
Templates need to choose which categories are relevant for use in generating
series navigation links.
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/settings.md 0000644 0001750 0001750 00000007141 13601504042 021334 0 ustar enrico enrico 0000000 0000000 # settings.py: configuration for the site
Sites can provide a configuration file, called `settings.py` or
`.staticsite.py` by default, that is interpreted via Python similarly to what
happens in [Django](https://docs.djangoproject.com/en/1.9/topics/settings/).
Only uppercase values set in the configuration are used by staticsite, the rest
is ignored.
Default settings are defined in the module `staticsite/global_settings.py` and
overridden by `settings.py` or `.staticsite.py`.
## Common settings
* `PROJECT_ROOT`: If some settings use relative paths, they are assumed to be
rooted in this path. Defaults to the directory where the settings file is
found.
## Site contents
* `CONTENT`: Directory with the source content of the site. Defaults to
`PROJECT_ROOT`
* `THEME_PATHS`: Sequence of directory names where themes are looked up.
It defaults to `/usr/share/staticsite/themes`, and a `themes` directory next
to the `ssite` executable.
* `THEME`: Theme used to render the site, as a directory name to be looked up
in `THEME_PATHS`. For backwards compatibility, if it is a sequence of
strings, it is taken as a sequence of paths to theme directories to try in
order. Defaults to `default`.
* `SYSTEM_ASSETS`: Names of static asset directories to add from
`/usr/share/javascript`. Defaults to the empty list.
## Site-wide metadata
* `SITE_NAME`: Site name. It defaults to the title of the toplevel page.
* `SITE_AUTHOR`: default value for the [`author` metadata](metadata.md)
* `TIMEZONE`: Default timezone used for datetimes in site contents.
* `LANGUAGES`: List of dicts representing which languages to build the site
for. Currently only the first entry is used, and it should contain a `locale`
key with the locale to use to build the site. In the future this can grow
into building multiple versions of the site for different languages.
Defaults to `[{"locale": "C"}]`.
## `ssite build` settings
* `SITE_URL`: default value for the [`site_url` metadata](metadata.md).
* `SITE_ROOT`: default value for the [`site_root` metadata](metadata.md).
* `OUTPUT`: Directory where the output of `ssite build` will go. If not set,
`ssite build` will ask for it.
* `DRAFT_MODE`: If True, do not ignore pages with dates in the future. Defaults
to False, where pages with dates in the future are considered drafts and are
not included in the site.
* `CACHE_REBUILDS`: If True, store cached data to speed up rebuilds. Defaults
to True.
* `BUILD_COMMAND`: set to the name of the `ssite` command being run.
* `JINJA2_SANDBOXED`: disable jinja2 sandboxing, making it noticeably faster,
but allowing template designer to inject insecure code. Turn it on if you can
trust the authors of templates.
* `STATIC_PATH`: path where theme static assets will be placed in built site.
Override with "" to merge when with the rest of the contents.
## `ssite new` settings
* `ARCHETYPES`: Directory where [archetypes](archetypes.md) used by `ssite new`
are found
* `EDITOR`: editor command used by `ssite new` to edit new pages. Defaults to
`$EDITOR` or `sensible-editor`.
* `EDIT_COMMAND`: Command used to run the editor, as passed to
`subprocess.check_command`. Each list element is expanded with
`string.format`, with all other settings values made available to the
`format` template, plus `{name}` set to the absolute path of the file to
edit. Defaults to `["{EDITOR}", "{name}", "+"]`
## Feature specific settings
* `JINJA2_PAGES`: see [jinja2 pages documentation](doc/jinja2.md)
* `MARKDOWN_EXTENSIONS` and `MARKDOWN_EXTENSION_CONFIGS`:
see [markdown pages documentation](doc/markdown.md)
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/site.md 0000644 0001750 0001750 00000001334 13601501277 020445 0 ustar enrico enrico 0000000 0000000 # Site
The [site object](../staticsite/site.py) collects and tracks all contents of a
site.
Through it, templates and code can access:
* `settings`: the site [settings](settings.md)
* `pages`: the site pages, indexed by relative path in the built site
* `timezone`: timezone object for the default site timezone, used as a default
for naive datetime objects
* `generation_time`: datetime of the current execution of staticsite
* `theme`: [Theme](theme.md) for the site
* `features`: site [features](feature.md) indexed by name
* `content_root`: path to the root directory of site [contents](contents.md)
* `site_name`: configured site name
* `archetypes`: site [archetypes](archetypes.md)
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/syndication.md 0000644 0001750 0001750 00000004130 13603600742 022021 0 ustar enrico enrico 0000000 0000000 ## Syndication
The Syndication feature implements generation of a [RSS](https://en.wikipedia.org/wiki/RSS)
and [Atom](https://en.wikipedia.org/wiki/Atom_(Web_standard\)) feed for a page
or group of pages.
Add a `syndication` metadata to a page to declare it as the index for a group
of page. RSS and Atom feeds will appear next to the page, containing pages
selected in the `syndication` metadata.
## Syndication metadata
Example front page for a blog page:
```yaml
---
pages: blog/*
syndication: yes
template: blog.html
---
# My blog
```
See [metadata documentation](metadata.md) for a reference on the `syndication`
field.
## Syndication of taxonomies
Each category page in each taxonomy automatically defines a syndication
metadata equivalent to this:
```yaml
syndication:
add_to: no
```
This would automatically generates RSS and Atom feeds with all pages in that
category, but those feed links will only be added to the category page itself.
You can use the `syndication` metadata in your taxonomy categories to customize
titles and description in your categories feeds, like with any other page.
## Templates
See the example templates for working `syndication.rss` and `syndication.atom`
templates, that are used by the generated RSS and Atom pages.
### `syndicated_pages(page=None, limit=None)`
Templates can use the `syndicated_pages` function to list syndicated pages for
a page, sorted with the most recently syndicated first.
`page` can be a page, a path to a page, or omitted, in which case the current
page is used. `page` can also be a list of pages, which will be sorted by
syndiaction date and sampled.
`limit` is the number of pages to return, or, if omitted, all the pages are
returned.
## Syndication pages
RSS and Atom pages have these extra properties:
* `page.meta.template` defaults to `syndication.rss` or `syndication.atom`
instead of `page.html`
* `page.meta.date` is the most recent date of the pages in the feed
* `page.meta.index` is the page defining the syndication
* `page.meta.pages` is a list of all the pages included in the syndication
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/taxonomies.md 0000644 0001750 0001750 00000011502 13603633223 021664 0 ustar enrico enrico 0000000 0000000 ## Taxonomies
Files with a `.taxonomy` extension represent where that taxonomy will appear in
the built site.
For example, `dir/tags.taxonomy` will become `dir/tags/…` in the built site,
and contain an index of all categories in the taxonomy, and for each category
an index page, an archive page, and rss and atom feeds.
**Added in 1.3**: Removed again the need to list in [`TAXONOMIES` settings](settings.md)
the taxonomies used in the site.
**Added in 1.2**: Any taxonomy you use needs to be explicitly listed in
settings as a `TAXONOMIES` list of taxonomy names. staticsite prints a warning
if a `.taxonomy` file is found that is not listed in `TAXONOMIES`.
The `.taxonomy` file will be a yaml, json, or toml file, like in
[markdown](markdown.md) front matter.
The relevant fields in a taxonomy file are:
* `title`, `description`: used for the taxonomy index page
* `category`: metadata for the page generated for each category in the taxonomy
* `archive`: metadata for the page generated for each category archive
* **changed in 1.2**: `template_tags`: use `template` instead
* **changed in 1.2**: `template_tag`: use `category/template` instead
* **changed in 1.2**: `template_archive`: use `archive/template` instead
* **Removed in 1.2**: `output_dir` is now ignored, and the taxonomy pages will
be put in a directory with the same name as the file, without extension
* **Changed in 1.2**: `item_name` in a `.taxonomy` file does not have a special
meaning anymore, and templates can still find it in the taxonomy page
metadata
* **Added in 1.2**: page.meta["tags"] or other taxonomy names gets substituted,
from a list of strings, to a list of pages for the taxonomy index, which can
be used to generate links and iterate subpages in templates without the need
of specialised functions.
* **Removed in 1.2**: `series_tags` is now ignored: every category can be used
to build a series
Example:
```yaml
---
# In staticsite, a taxonomy is a group of attributes like categories or tags.
#
# Like in Hugo, you can have as many taxonomies as you want. See
# https://gohugo.io/taxonomies/overview/ for a general introduction to
# taxonomies.
#
# This file describes the taxonomy for "tags". The name of the taxonomy is
# taken from the file name.
#
# The format of the file is the same that is used for the front matter of
# posts, again same as in Hugo: https://gohugo.io/content/front-matter/
# Template for rendering the taxonomy index. Here, it's the page that shows the
# list of tags
template: taxonomy.html
category:
# Template for rendering the page for one tag. Here, it's the page that shows
# the latest pages tagged with the tag
template: blog.html
# Title used in category pages
template_title: "Latest posts for tag {{page.name}}"
# Description used in category pages
template_description: "Most recent posts with tag {{page.name}}"
syndication:
add_to: no
archive:
# Template for rendering the archive page for one tag. Here, it's the page that
# links to all the pages tagged with the tag
template_title: "Archive of posts for tag {{page.name}}"
template_description: "Archive of all posts with tag {{page.name}}"
```
### Jinja2 templates
Each taxonomy defines extra `url_for_*` functions. For example, given a *tags*
taxonomy with *tag* as singular name:
* `taxonomies()`: list of all taxonomy index pages, ordered by name
* `taxonomy(name)`: taxonomy index page for the given taxonomy
* **Removed in 1.2**: `url_for_tags()`: links to the taxonomy index.
* **Removed in 1.2**: `url_for_tag(tag)`: use `url_for(category)`
* **Removed in 1.2**: `url_for_tag_archive(tag)`: use `url_for(category.archive)`
* **Removed in 1.2**: `url_for_tag_rss(tag)`: see [the syndication feature](syndication.md)
* **Removed in 1.2**: `url_for_tag_atom(tag)`: see [the syndication feature](syndication.md)
### Taxonomy pages
Pages generated by the taxonomy feature have some extra attributes besides the
usual [meta](metadata.md), documented here.
**Taxonomy index page**:
* `name`: the taxonomy name (e.g. "tags")
* `categories`: dict mapping category names to category index pages. In
templates, the dict is sorted by category name.
* The page can be indexed by category name, returning the corresponding
category index page.
**Category index page**:
* `page.name`: the category name
* `page.meta.pages`: the pages that have this category
* `page.meta.taxonomy`: the taxonomy index page for this category
* `page.meta.archive`: the archive page for this category
**Category archive**:
* `page.name`: the category name
* `page.meta.pages`: the pages that have this category
* `page.meta.taxonomy`: the taxonomy index page for this category
* `page.meta.category`: the category index page for this category
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/templates.md 0000644 0001750 0001750 00000007506 13605101025 021475 0 ustar enrico enrico 0000000 0000000 # Jinja2 templates in staticsite
Staticsite uses [jinja2](http://jinja.pocoo.org/) as a template engine.
## Jinja2 environment
The [site contents](contents.md) and the [`theme` directory](theme.md) are both
in the Jinja2 search path, and you can `{% import %}` or `{% include %}`
anything from them.
This is a reference to the basic contents of template contexts in staticsite.
Each [feature](features.md) can provide more filters and functions to Jinja2
templates: see the documentation of the various features for details.
### Site and page
* `site` is available as the current [site object](site.md)
* `page` is available as the current page object. If present, it has at least a
`meta` member, pointing to the [metadata for the page](metadata.md).
Feature-specific pages can have extra membres, which are documented in each
feature documentation. You can use `ssite dump_meta` to see all the content that pages make available to templates.
### Site settings
Any setting defined in `settings.py` is also available to Jinja2, so you can do
for example:
```jinja2
Built with staticsite and theme {{THEME|basename}}
```
### Functions
* `url_for("path/page")`: returns the URL that links to the page or asset with
the given path.
The path is resolved relative to the current page, or to the root of the site
or content directory if it is an absolute path.
* `url_for(page)`: returns the URL that links to the given page.
* `page_for("path/page")`: returns the page with the given path.
The path is resolved relative to the current page, or to the root of the site
or content directory if it is an absolute path.
* `page_for(page)`: returns the page itself.
* `site_pages(path=None, limit=None, sort=None, root=None, **kw)`: return a
list of pages defined in the site that match the given arguments. See
[Selecting pages](page-filter.md) for details.
This is an alias to `page.find_pages()`
* `now`: the current date and time, alias to `site.generation_time`.
* `next_month`: midnight of the first day of next month. Useful in archetypes
front matter to collect content into monthly pages.
* `taxonomies()`: a list of all known taxonomies.
* `regex()`: alias to `re.compile`, which can be used to explicitly interpret
a `site_pages` argument as a regular expression
* `img_for(Union[str, Page], type=None, **attrs)`: create an `
` tag for
the given image or path to an image, with the `alt`, `src`, `srcset`,
`width`, `height` tags filled as needed. Use `type` to choose one of the
[configured scaled versions](images.md) of the image. Do not use `type` to
generate a `srcset` attribute that allows the browser to choose
automatically. You can provide extra element attributes to the `
` tag as
keyword arguments to the function.
### Filters
* `|datetime_format(format=None)` formats a datetime. Formats
supported: "rss2", "rfc822", "atom", "rfc3339", "w3ctdf",
"[iso8601](https://xkcd.com/1179/)" (default). If the format
starts with `%` it is considered a [strftime](http://strftime.org/)
format string.
* `|basename` returns the file name part of a pathname.
* `|markdown` renders the string using [markdown](markdown.md).
* `|arrange(sort, limit=None)` sorts a list of pages, and returns the first
`limit` ones. If `limit` is not specified, returns the whole sorted list of
pages. `sort` takes the same values as in [page filters](page-filter.md).
### Template loading
Referring to a template by path, looks it up in theme directories. If a
template is not found in a theme, it is looked up in the themes it extends.
Prefix a template name with `content:` to look it up in the site content
directory instead. This way you could have content pages that extend other
content pages, or a local base template in the content directory that extends
the one from the theme.
[Back to reference index](README.md)
staticsite-1.4.1/doc/reference/theme.md 0000644 0001750 0001750 00000005575 13601501304 020605 0 ustar enrico enrico 0000000 0000000 # theme: controlling the appearance of the site
Inside a theme directory there are the [Jinja2](http://jinja.pocoo.org/)
templates that control how pages are rendered, and static assets for the theme.
The theme contents are independent from the contents of the site, and it should
be possible to swap one theme for another at any point.
## Theme configuration
If a `config` file is found in the theme directory, it is parsed as `yaml`,
`json`, or `toml` data, and used as theme configuration.
Valid theme configuration entries currently are:
* `system_assets`: list of names of directories under `/usr/share/javascript`
to be added as static assets to the site
* `extends`: name or list of names of themes that this theme depends on. See
**Theme inheritance** below for details.
## Theme templates
These templates are used by default by `staticsite`:
* `dir.html` is used to render directory indices.
* `page.html` is used to render Markdown pages.
* `redirect.html` is used to render placeholder pages that redirect to the new
location where a page can now be found.
These templates are expected to be present by the Jinja2 templates
inside `content`:
* `base.html` is used for the common parts of all pages.
* `syndication.xml` contains jinja2 macros used to generate RSS2 and Atom
feeds.
* `lib/blog.html` macro library with functions to render blogs and category pages.
These templates are used by [taxonomy pages](taxonomies.md):
* `taxonomy/taxonomy.html` is used for the index of all categories in the taxonomy.
* `taxonomy/category.html` is used to generate the page for each category.
* `taxonomy/archive.html` is used to generate the archive page for each category.
See [the template documentation](templates.md) for a reference on writing
templates.
## Static assets
The contents of a `static` directory in the theme directory are added as static
assets to the site.
Other static assets are loaded from `/usr/share/javascript` as listed in the
`SYSTEM_ASSETS` [setting](settings.md) or in the `system_assets` theme
configuration.
## Theme inheritance
A theme can list dependencies on other themes via the `extends` configuration
entry.
At theme load time, the configuration of all the themes in the dependency chain
is read, and the whole tree of dependencies is flattened into a list, with the
dependencies always preceding the themes they depend on.
### Features
Features for the site are loaded from all the theme feature directories, if
present.
### Templates
Templates are looked up in the site contents, then in the main theme, then
down the theme dependency chains.
### Assets
Assets are loaded from all the `system_assets` directories configured in all
the templates in the chain, removing duplicates.
Then assets are loaded from all the `static/` directories in all the templates
in the dependency chain, from the bottom-most dependency upwards.
[Back to reference index](README.md)
staticsite-1.4.1/doc/tutorial/ 0000755 0001750 0001750 00000000000 13605113260 017056 5 ustar enrico enrico 0000000 0000000 staticsite-1.4.1/doc/tutorial/README.md 0000644 0001750 0001750 00000000134 13605075213 020340 0 ustar enrico enrico 0000000 0000000 # Tutorials
* [A new blog in under one minute](blog.md)
[Back to README](../../README.md)
staticsite-1.4.1/doc/tutorial/blog.md 0000644 0001750 0001750 00000002011 13605077601 020325 0 ustar enrico enrico 0000000 0000000 # A new blog in under one minute
Create a new blog in few simple steps:
## Step 1: create `index.md`:
~~~~{.md}
```yaml
site_url: https://www.example.org
template: blog.html
syndication: yes
pages: "*"
```
# My new blog
Welcome to my new blog.
~~~~
## Step 2: run `ssite show`
A browser will open with a preview of your blog.
## Step 3: add posts
Create `new_post.md` and type something into it: as soon as you save it,
it will automatically appear in your blog.
Throw in a `new_post.jpg` to add an image to your new blog post.
## Step 4: publish your site
Run `ssite build -o built_site`
The contents of `built_site` are ready to be published by any web server.
## Next steps
* [See more tutorials](README.md)
* [Add an about page](../howto/about-page.md)
* [Group blog posts in a directory](../howto/blog-posts-in-a-directory.md)
* [Tag site pages](../howto/tag-pages.md)
* [Post series](../howto/post-series.md)
* [Add an image for a post](../howto/post-image.md)
* [Back to main documentation](../../README.md)
staticsite-1.4.1/example/ 0000755 0001750 0001750 00000000000 13605113260 016101 5 ustar enrico enrico 0000000 0000000 staticsite-1.4.1/example/blog/ 0000755 0001750 0001750 00000000000 13605113260 017024 5 ustar enrico enrico 0000000 0000000 staticsite-1.4.1/example/blog/about.md 0000644 0001750 0001750 00000000175 13603343314 020466 0 ustar enrico enrico 0000000 0000000 # About
This is the example blog setup shipped with staticsite.
It is very basic, and it can be a starting point for more.
staticsite-1.4.1/example/blog/index.md 0000644 0001750 0001750 00000000267 13605112351 020462 0 ustar enrico enrico 0000000 0000000 ```yaml
site_url: https://www.example.org
template: blog.html
nav: [about.md]
syndication: yes
pages: "posts/*"
```
# My example blog
Hello. These are the last 10 posts of my blog.
staticsite-1.4.1/example/blog/posts/ 0000755 0001750 0001750 00000000000 13605113260 020174 5 ustar enrico enrico 0000000 0000000 staticsite-1.4.1/example/blog/posts/example.jpg 0000644 0001750 0001750 00000107453 13602426455 022355 0 ustar enrico enrico 0000000 0000000 JFIF H H jExif MM * b | ( 6 i This is an example image H H Creative Commons Attribution-Share Alike 3.0 Unported 0231 ] 0100 ASCII Image downloaded from https://commons.wikimedia.org/wiki/File:JPEG_example_flower.jpg [Photo by David Crawshaw, 2002-01-28
Image composition by David Crawshaw, 2004-09-08, GFDL
" U>ӛ3
g֛elހ !ǶX[k#ƻd 9[*IQ;ٽ 5$ɸTL"<6 +&Uǎb