Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
__pycache__/
*.py[cod]
*$py.class

.idea/
# C extensions
*.so

Expand Down
21 changes: 18 additions & 3 deletions CHANGELOGS.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
# CHANGELOGS

## 1.1.0

* Bulk refactors and code documentation
* New commands for `static.py` files
* `--serve` for livewatch changes
* `--watch` for watch specific files and folders.
* `--port` especiffy serve port

## 1.0.0

* Back to namespace method for write templates names
* Example: `html5up/massively` instead of just `massively`
* Template assets are not included in the library to minimize the size of the library, they were moved to a [separate repository](https://github.com/jamstackpy/jamstack-templates).
* Example: `html5up/massively` instead of just `massively`
* Template assets are not included in the library to minimize the size of the library, they were moved to
a [separate repository](https://github.com/jamstackpy/jamstack-templates).

## 0.1.0

* Improve **Plain** template
* Add new templates (massively, phantom)
* When creating a project, instead of writing the template like this: **html5up/massively**, you can use the name directly, i.e. **massively**
* When creating a project, instead of writing the template like this: **html5up/massively**, you can use the name
directly, i.e. **massively**
* The assets of each template are now included in the library

## 0.0.4

* Add README.md info

## 0.0.3

* Add plain template

## 0.0.1

* Initial release
33 changes: 24 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

![](https://img.shields.io/pypi/v/jamstack)

Also known as Jamstackpy, is a tool that allows you to create static websites using the power of **Python** hand in hand with the [Flask](https://github.com/pallets/flask) library. Its operation is based on templates which are rendered with the powerful Jinja engine generating your website with all its dependencies.
Also known as Jamstackpy, is a tool that allows you to create static websites using the power of **Python** hand in hand
with the [Flask](https://github.com/pallets/flask) library. Its operation is based on templates which are rendered with
the powerful Jinja engine generating your website with all its dependencies.

## Installation

Expand All @@ -15,22 +17,22 @@ python -m pip install jamstack
## Create basic project

```bash
jamstack plain <foldername> # or jamstack plain . --existing
jamstack plain <foldername>
```

## Templates

Jamstack has templates available courtesy of [html5up](https://html5up.net).

| Template | Command | Tutorial |
| ------------------------------------------ | ----------------- | ------------------------------------------------------------ |
| [Massively](https://html5up.net/massively) | html5up/massively | |
| Template | Command | Tutorial |
|--------------------------------------------|-------------------|--------------------------------------------------------------------------|
| [Massively](https://html5up.net/massively) | html5up/massively | |
| [Phantom](https://html5up.net/phantom) | html5up/phantom | [**HERE**](https://github.com/jamstackpy/jamstack/wiki/Phantom-template) |

The syntax is as follows:

```bash
jamstack t <template> <foldername>
jamstack t <template_command> <project_folder_name>
```

Use the `--existing` flag if you want the project to be created in an existing folder
Expand All @@ -39,7 +41,9 @@ Use the `--existing` flag if you want the project to be created in an existing f
jamstack t html5up/massively myproject --existing
```

By default, projects are created without the assets (stylesheets, images, etc...) to download them, you must pass the `--jamdo` option to the `static.py` file of the respective project.
By default, projects based in templates are created without the assets (stylesheets, images, etc...) to download them,
you must pass
the `--jamdo` option to the `static.py` file of the respective project.

## Build

Expand All @@ -51,10 +55,21 @@ python static.py

Your site will be generated in the **dist/** folder.

Alternatively you can use the `--server` flag if you want to start livewatch.
## Other project command-line options

| Argument | Description |
|-----------|---------------------------------------------------------------------------|
| `--serve` | Optional. Start project livewatch (autoreload when files change). |
| `--watch` | Optional. Specify files and folders to watch. Must be separated by comma. |
| `--port` | Optional. Specify server port. |

## Sites using jamstack

- [DeliciousPy Telegram Channel](https://deliciouspy.github.io/)
- [The Flask Community Work Group](https://flaskcwg.github.io/)
- [A Personal Site](https://compileralchemy.github.io/)
- [Abdur-Rahmaan Janhangeer](https://compileralchemy.github.io/)

# TODO

- [ ] Replace `python static.py --serve/--jamdo` by something like `jamstack --serve/--jamdo`
- [ ] Remove Flask as Main requirement and just use Jinja
4 changes: 2 additions & 2 deletions jamstack/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version_info = (1, 0, 0)
__version__ = ".".join([str(v) for v in version_info])
version_info = (1, 1, 0)
__version__ = ".".join(map(str, version_info))
22 changes: 7 additions & 15 deletions jamstack/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,43 @@
from pathlib import Path

import click

from jamstack.api.file import trycopytree

package_folder = Path(__file__).parent.absolute()
sites_path = os.path.join(package_folder, 'sites')


@click.group(help="<Jamstack cli/>")
@click.group(help="Jamstack command line interface")
def cli():
pass


@click.command(help="<Empty, plain repo />")
@click.command(help="Create an empty, plain repository")
@click.argument('project_name')
@click.option('--existing/--not-existing', default=False)
def plain(project_name, existing):
path = '.'

dirs_exist_ok = False
if existing is True:
dirs_exist_ok = True
trycopytree(
os.path.join(sites_path, 'plain'),
os.path.join(path, project_name),
dirs_exist_ok=dirs_exist_ok
existing
)


@click.command(help="<Repo by templates />")
@click.command(help="Create a repository from a template")
@click.argument('template')
@click.argument('project_name')
@click.option('--existing/--not-existing', default=False)
def t(template, project_name, existing):
path = '.'

namespace = template.split('/')[0]
project = template.split('/')[1]

dirs_exist_ok = False
if existing is True:
dirs_exist_ok = True
namespace, project = template.split('/')

trycopytree(
os.path.join(sites_path, namespace, project),
os.path.join(path, project_name),
dirs_exist_ok=dirs_exist_ok
existing
)


Expand Down
98 changes: 61 additions & 37 deletions jamstack/api/file.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,33 @@
import logging
import os
import shutil
import uuid

# from werkzeug.utils import secure_filename


def trycopytree(source, dest, verbose=False, dirs_exist_ok=False):
def trycopytree(source, dest, dirs_exist_ok):
"""
Recursive copy of folder
Copy a file or directory from source to dest.

Parameters
----------
source: str
source folder path
source file or directory path
dest: str
destination folder path

destination file or directory path
dirs_exist_ok:
especifies if the project folder already exist
Returns
-------
None
"""
try:
shutil.copytree(source, dest, dirs_exist_ok=dirs_exist_ok)
if verbose:
print("done copying {} to {}".format(source, dest))
except Exception as e:
print(e)


def trycopy(source, dest, verbose=False):
"""
Non-ecursive copy of folder

Parameters
----------
source: str
source folder path
dest: str
destination folder path

Returns
-------
None
"""
try:
shutil.copy(source, dest)
if verbose:
print("done copying {} to {}".format(source, dest))
os.mkdir(os.path.join(dest, 'dist')) # Maybe place in static.py?
print('Project created successfully! :)')
except FileExistsError:
print('Project folder already exist! Use --existing if you want to override it.')
except Exception as e:
print(e)
logging.exception(e)


def trymkdir(path, verbose=False):
Expand All @@ -59,6 +38,8 @@ def trymkdir(path, verbose=False):
----------
path: str
path with folder already in
verbose: bool, optional
If True, print debug information. Default is False.

Returns
-------
Expand All @@ -69,7 +50,7 @@ def trymkdir(path, verbose=False):
if verbose:
print("created dir at", path)
except Exception as e:
print(e)
logging.exception(e)


def trymkfile(path, content, verbose=False):
Expand All @@ -82,20 +63,22 @@ def trymkfile(path, content, verbose=False):
path to create file with filename included
content: str
file content
verbose: bool, optional
If True, print debug information. Default is False.

Returns
-------
None
"""
try:
with open(path, "w+") as f:
with open(path, "x") as f:
f.write(content)
if verbose:
print("file created at {}".format(path))
print("with content:")
print(content)
except Exception as e:
print(e)
logging.exception(e)


def absdiroffile(filepath):
Expand All @@ -117,19 +100,60 @@ def absdiroffile(filepath):


def get_folders(path):
"""
Get a list of directories in the given path.

Parameters
----------
path: str
Path to search for directories.

Returns
-------
list
List of directories in the given path.
"""
dirs = [d for d in os.listdir(
path) if os.path.isdir(os.path.join(path, d))]
return dirs


def unique_filename(fname):
"""
Generate a unique filename by prepending a UUID to the given filename.

Parameters
----------
fname: str
Original filename.

Returns
-------
str
Unique filename with prepended UUID.
"""
prepended = str(uuid.uuid4()).replace("-", "_")[:10]
return "{}_{}".format(prepended, fname)


def delete_file(path):
os.remove(path)
"""
Delete the file at the given path.

Parameters
----------
path: str
Path of the file to delete.

Returns
-------
None
"""
try:
os.remove(path)
logging.info("File deleted: {}".format(path))
except Exception as e:
logging.exception(e)

# def unique_sec_filename(filename):
# return unique_filename(secure_filename(filename))
Loading