Skip to content
Draft
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
7 changes: 1 addition & 6 deletions docs/chefops.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ This listing shows the `ricecooker` command line interface (CLI) arguments:

usage: sushichef.py [-h] [--token TOKEN] [-u] [-v] [--quiet] [--warn]
[--debug] [--compress] [--thumbnails]
[--resume] [--step {CONSTRUCT_CHANNEL, CREATE_TREE,
DOWNLOAD_FILES, GET_FILE_DIFF,
START_UPLOAD, UPLOAD_CHANNEL}]
[--deploy] [--publish]

required arguments:
Expand All @@ -26,8 +23,6 @@ This listing shows the `ricecooker` command line interface (CLI) arguments:
-v, --verbose Verbose mode (default).
--compress Compress videos using ffmpeg -crf=32 -b:a 32k mono.
--thumbnails Automatically generate thumbnails for content nodes.
--resume Resume chef session from a specified step.
--step {INIT, ... Step to resume progress from (must be used with --resume flag)
--update Force re-download of files (skip .ricecookerfilecache/ check)
--sample SIZE Upload a sample of SIZE nodes from the channel.
--deploy Immediately deploy changes to channel's main tree.
Expand Down Expand Up @@ -55,7 +50,7 @@ This is required if you suspect the files on the source website have been update
Note that some chef scripts implement their own caching mechanism, so you need
to disable those caches as well if you want to make sure you're getting new content.
Use the commands `rm -rf .webcache` to clear the webcache if it is present,
and `rm -rf .ricecookerfilecache/* storage/* restore/*` to clean all ricecooker
and `rm -rf .ricecookerfilecache/* storage/*` to clean all ricecooker
directories and start from scratch.


Expand Down
4 changes: 2 additions & 2 deletions docs/developer/design_cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ There are three types of arguments involved in a chef run:

- `args` (dict): command line args as parsed by the sushi chef class and its parents
- SushiChef: the `SushiChef.__init__` method configures argparse for the following:
- `compress`, `download_attempts`, `prompt`, `publish`, `resume`,
`stage`, `step`, `thumbnails`, `token`, `update`, `verbose`, `warn`
- `compress`, `download_attempts`, `prompt`, `publish`,
`stage`, `thumbnails`, `token`, `update`, `verbose`, `warn`
- MySushiChef: the chef's `__init__` method can define additional cli args

- `options` (dict): additional [OPTIONS...] passed at the end of the command line
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorial/gettingstarted.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ If the command succeeds, you should see something like this printed in your term

.. parsed-literal::

In SushiChef.run method. args={'command': 'uploadchannel', 'token': '<your-access-token>', 'update': False, 'resume': False, 'stage': True, 'publish': False} options={}
In SushiChef.run method. args={'command': 'uploadchannel', 'token': '<your-access-token>', 'update': False, 'stage': True, 'publish': False} options={}
Logged in with username you@yourdomain.org
Ricecooker v0.6.42 is up-to-date.

Expand Down
13 changes: 0 additions & 13 deletions ricecooker/chefs.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from .commands import uploadchannel_wrapper
from .exceptions import InvalidUsageException
from .exceptions import raise_for_invalid_channel
from .managers.progress import Status
from .utils.downloader import get_archive_filename
from .utils.jsontrees import build_tree_from_json
from .utils.jsontrees import get_channel_node_from_json
Expand Down Expand Up @@ -142,18 +141,6 @@ def __init__(self, *args, **kwargs):
default=3,
help="Maximum number of times to retry downloading files.",
)
parser.add_argument(
"--resume",
action="store_true",
help="Resume chef session from a specified step.",
)
allsteps = [step.name.upper() for step in Status]
parser.add_argument(
"--step",
choices=allsteps,
default="LAST",
help="Step to resume progress from (use with the --resume).",
)
parser.add_argument(
"--prompt",
action="store_true",
Expand Down
108 changes: 27 additions & 81 deletions ricecooker/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
from . import __version__
from . import config
from .classes.nodes import ChannelNode
from .managers.progress import RestoreManager
from .managers.progress import Status
from .managers.tree import ChannelManager
from .utils.slack import send_slack_notification

Expand All @@ -33,8 +31,6 @@ def uploadchannel( # noqa: C901
update=False,
thumbnails=False,
download_attempts=3,
resume=False,
step=Status.LAST.name,
token="#",
prompt=False,
publish=False,
Expand All @@ -49,8 +45,6 @@ def uploadchannel( # noqa: C901
update (bool): indicates whether to re-download files (optional)
thumbnails (bool): indicates whether to automatically derive thumbnails from content (optional)
download_attempts (int): number of times to retry downloading files (optional)
resume (bool): indicates whether to resume last session automatically (optional)
step (str): step to resume process from (optional)
token (str): content server authorization token
prompt (bool): indicates whether to prompt user to open channel when done (optional)
publish (bool): indicates whether to automatically publish channel (optional)
Expand Down Expand Up @@ -79,9 +73,6 @@ def uploadchannel( # noqa: C901

config.DOWNLOAD_SESSION.auth = chef.auth

# Get domain to upload to
config.init_file_mapping_store()

if not command == "dryrun":
# Authenticate user and check current Ricecooker version
username, token = authenticate_user(token)
Expand All @@ -96,62 +87,35 @@ def uploadchannel( # noqa: C901

config.LOGGER.info("\n\n***** Starting channel build process *****\n\n")

# Set up progress tracker
config.PROGRESS_MANAGER = RestoreManager()
if (
not resume or not config.PROGRESS_MANAGER.check_for_session()
) and step.upper() != Status.DONE.name:
config.PROGRESS_MANAGER.init_session()
else:
if resume or prompt_yes_or_no(
"Previous session detected. Would you like to resume your last session?"
):
config.LOGGER.info("Resuming your last session...")
step = Status.LAST.name if step is None else step
config.PROGRESS_MANAGER = config.PROGRESS_MANAGER.load_progress(
step.upper()
)
else:
config.PROGRESS_MANAGER.init_session()

if hasattr(chef, "download_content"):
chef.download_content()

# TODO load csv if exists
metadata_dict = chef.load_channel_metadata_from_csv()

# Construct channel if it hasn't been constructed already
if config.PROGRESS_MANAGER.get_status_val() <= Status.CONSTRUCT_CHANNEL.value:
config.LOGGER.info("Calling construct_channel... ")
channel = chef.construct_channel(**kwargs)
if "sample" in kwargs and kwargs["sample"]:
channel = select_sample_nodes(channel, size=kwargs["sample"])
config.PROGRESS_MANAGER.set_channel(channel)
channel = config.PROGRESS_MANAGER.channel
# Construct channel
config.LOGGER.info("Calling construct_channel... ")
channel = chef.construct_channel(**kwargs)
if "sample" in kwargs and kwargs["sample"]:
channel = select_sample_nodes(channel, size=kwargs["sample"])

# Set initial tree if it hasn't been set already
if config.PROGRESS_MANAGER.get_status_val() <= Status.CREATE_TREE.value:
config.PROGRESS_MANAGER.set_tree(create_initial_tree(channel))
tree = config.PROGRESS_MANAGER.tree
# Set initial tree
tree = create_initial_tree(channel)

# Early permission check: Try creating the channel before downloading/uploading files
# This will fail fast if the user lacks edit permissions
# Fixes issues #95 and #434 by avoiding wasted downloads/uploads
if (
config.PROGRESS_MANAGER.get_status_val() <= Status.CREATE_TREE.value
and command != "dryrun"
):
if command != "dryrun":
config.LOGGER.info("Checking channel permissions...")
try:
tree.root_id, tree.channel_id = tree.add_channel()
except Exception:
sys.exit(1)

# Download files if they haven't been downloaded already
if config.PROGRESS_MANAGER.get_status_val() <= Status.DOWNLOAD_FILES.value:
config.LOGGER.info("")
config.LOGGER.info("Downloading files...")
config.PROGRESS_MANAGER.set_files(*process_tree_files(tree))
# Download files
config.LOGGER.info("")
config.LOGGER.info("Downloading files...")
files_to_diff = process_tree_files(tree)

# Apply any modifications to chef
chef.apply_modifications(channel, metadata_dict)
Expand All @@ -164,43 +128,26 @@ def uploadchannel( # noqa: C901
config.LOGGER.info("Command is dryrun so we are not uploading channel.")
return

# Set download manager in case steps were skipped
files_to_diff = config.PROGRESS_MANAGER.files_downloaded
config.FAILED_FILES = config.PROGRESS_MANAGER.files_failed
# Get file diff
config.LOGGER.info("")
config.LOGGER.info("Getting file diff...")
file_diff = get_file_diff(tree, files_to_diff)

# Get file diff if it hasn't been generated already
if config.PROGRESS_MANAGER.get_status_val() <= Status.GET_FILE_DIFF.value:
config.LOGGER.info("")
config.LOGGER.info("Getting file diff...")
config.PROGRESS_MANAGER.set_diff(get_file_diff(tree, files_to_diff))
file_diff = config.PROGRESS_MANAGER.file_diff
# Upload files
config.LOGGER.info("")
config.LOGGER.info("Uploading files...")
upload_files(tree, file_diff)

# Set which files have already been uploaded
tree.uploaded_files = config.PROGRESS_MANAGER.files_uploaded

# Upload files if they haven't been uploaded already
if config.PROGRESS_MANAGER.get_status_val() <= Status.UPLOADING_FILES.value:
config.LOGGER.info("")
config.LOGGER.info("Uploading files...")
config.PROGRESS_MANAGER.set_uploaded(upload_files(tree, file_diff))

# Create channel on Kolibri Studio if it hasn't been created already
if config.PROGRESS_MANAGER.get_status_val() <= Status.UPLOAD_CHANNEL.value:
config.LOGGER.info("")
config.LOGGER.info("Creating channel...")
config.PROGRESS_MANAGER.set_channel_created(*create_tree(tree))
channel_link = config.PROGRESS_MANAGER.channel_link
channel_id = config.PROGRESS_MANAGER.channel_id
# Create channel on Kolibri Studio
config.LOGGER.info("")
config.LOGGER.info("Creating channel...")
channel_link, channel_id = create_tree(tree)

# Publish tree if flag is set to True
if (
config.PUBLISH
and config.PROGRESS_MANAGER.get_status_val() <= Status.PUBLISH_CHANNEL.value
):
if config.PUBLISH:
config.LOGGER.info("")
config.LOGGER.info("Publishing channel...")
publish_tree(tree, channel_id)
config.PROGRESS_MANAGER.set_published()

# Open link on web browser (if specified) and return new link
config.LOGGER.info("\n\nDONE: Channel created at {0}\n".format(channel_link))
Expand All @@ -211,7 +158,6 @@ def uploadchannel( # noqa: C901
if config.SLACK_WEBHOOK_URL:
send_slack_notification(tree.channel, channel_link)

config.PROGRESS_MANAGER.set_done()
return channel_link


Expand Down Expand Up @@ -292,13 +238,13 @@ def process_tree_files(tree):
"""process_tree_files: Download files from nodes
Args:
tree (ChannelManager): manager to handle communication to Kolibri Studio
Returns: None
Returns: list of files to check against Kolibri Studio
"""
# Fill in values necessary for next steps
config.LOGGER.info("Processing content...")
files_to_diff = tree.process_tree()
tree.check_for_files_failed()
return files_to_diff, config.FAILED_FILES
return files_to_diff


def get_file_diff(tree, files_to_diff):
Expand Down
31 changes: 1 addition & 30 deletions ricecooker/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"""

import atexit
import hashlib
import logging.config
import os
import shutil
Expand All @@ -19,7 +18,6 @@
VIDEO_HEIGHT = None
THUMBNAILS = False
PUBLISH = False
PROGRESS_MANAGER = None
SUSHI_BAR_CLIENT = None
FILE_PIPELINE = None
STAGE = False
Expand Down Expand Up @@ -140,15 +138,14 @@ def setup_logging(level=logging.INFO, main_log=None, error_log=None, add_loggers
setup_logging()


# Domain and file store location for uploading to production Studio server
# Domain for uploading to production Studio server
DEFAULT_DOMAIN = "https://api.studio.learningequality.org"
DOMAIN_ENV = os.getenv("STUDIO_URL", None)
if DOMAIN_ENV is None: # check old ENV varable for backward compatibility
DOMAIN_ENV = os.getenv("CONTENTWORKSHOP_URL", None)
DOMAIN = DOMAIN_ENV if DOMAIN_ENV else DEFAULT_DOMAIN
if DOMAIN.endswith("/"):
DOMAIN = DOMAIN.rstrip("/")
FILE_STORE_LOCATION = hashlib.md5(DOMAIN.encode("utf-8")).hexdigest()

try:
TASK_THREADS = int(os.environ.get("TASK_THREADS"))
Expand Down Expand Up @@ -192,9 +189,6 @@ def setup_logging(level=logging.INFO, main_log=None, error_log=None, add_loggers
"RICECOOKER_STORAGE", os.path.join(CURRENT_CWD, "storage")
)

# Folder to store progress tracking information
RESTORE_DIRECTORY = "restore"

# Session for communicating to Kolibri Studio
SESSION = requests.Session()

Expand Down Expand Up @@ -389,29 +383,6 @@ def authentication_url():
return AUTHENTICATION_URL.format(domain=DOMAIN)


def init_file_mapping_store():
"""init_file_mapping_store: creates log to keep track of downloaded files
Args: None
Returns: None
"""
# Make storage directory for restore files if it doesn't already exist
path = os.path.join(RESTORE_DIRECTORY, FILE_STORE_LOCATION)
if not os.path.exists(path):
os.makedirs(path)


def get_restore_path(filename):
"""get_restore_path: returns path to directory for restoration points
Args:
filename (str): Name of file to store
Returns: string path to file
"""
path = os.path.join(RESTORE_DIRECTORY, FILE_STORE_LOCATION)
if not os.path.exists(path):
os.makedirs(path)
return os.path.join(path, filename + ".pickle")


def check_version_url():
"""check_version_url: returns url to check ricecooker version
Args: None
Expand Down
Loading
Loading