Skip to content

Commit

Permalink
autorun support
Browse files Browse the repository at this point in the history
  • Loading branch information
jimdigriz committed Jan 21, 2025
1 parent 045d8e3 commit 6f71925
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ information.
pip install nbgitpuller
```

### Configuration

Copy `jupyter_git_pull_config.py` to one of your Jupyter configuration paths (as determined from `jupyter --paths`) and edit it to meet your needs.

## Example

This example shows how to use the [nbgitpuller link generator]
Expand Down
34 changes: 34 additions & 0 deletions jupyter_git_pull_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# May be set to a list of URLs described as Python regular expressions (using re.fullmatch())
# where it is permitted to autorun scripts from the pulled project as a pre-initialisation
# step.
#
# WARNING: Enable this only if you understand and accept the risks of AUTORUN.INF.
# ----
# c.NbGitPuller.autorun_allow = [
# r'https://github\.com/org/name\.git',
# r'https://github\.com/org-two/name-two\.git'
# ]
# ----
#
# To allow all sources (*not* recommended) use:
# ----
# c.NbGitPuller.autorun_allow = True
# ----
#
# The default is 'False' which means the autorun functionality is completely disabled
#c.NbGitPuller.autorun_allow = False

# List of scripts to search for when attempting to autorun. The first match will
# be run with a single argument of 'init' or 'update' depending on what nbgitpuller
# is doing.
# ----
# c.NbGitPuller.autorun_script = [
# '.nbgitpuller.script',
# '.different.script'
# ]
# ----
#
# The 'script' must be executable and when checked out on a 'exec' (ie. not a 'noexec') mountpoint
#
# The default is the empty list.
#c.NbGitPuller.autorun_script = []
29 changes: 29 additions & 0 deletions nbgitpuller/application.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from .version import __version__ # noqa
from .pull import GitPuller # noqa
from jupyter_server.extension.application import ExtensionApp
from traitlets import Bool, CRegExp, List, Unicode, Union
from traitlets.config import Configurable
import os


Expand All @@ -12,6 +14,33 @@ class NbGitPuller(ExtensionApp):
os.path.join(os.path.dirname(__file__), 'static')
]

autorun_allow = Union(
[Bool(), List(CRegExp())],
default_value=False,
config=True,
help="""
List of URLs described as Python regular expressions (using re.fullmatch()) where
it is permitted to autorun scripts from the pulled project as a pre-initialisation
step. Enable this only if you understand and accept the risks of AUTORUN.INF.
When set to boolean True, all URLs are allowed, whilst False (default) autorun
is disabled completely.
"""
)

autorun_script = List(
Unicode(),
default_value=[],
config=True,
help="""
List of scripts to search for when attempting to autorun. The first match will
be run with a single argument of 'init' or 'update' depending on what nbgitpuller
is doing.
Enable this only if you understand and accept the risks of AUTORUN.INF.
"""
)

def initialize_handlers(self):
from .handlers import (
SyncHandler,
Expand Down
31 changes: 31 additions & 0 deletions nbgitpuller/pull.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import re
import subprocess
import logging
import time
Expand Down Expand Up @@ -81,6 +82,9 @@ def __init__(self, git_url, repo_dir, branch, **kwargs):
elif not self.branch_exists(self.branch_name):
raise ValueError(f"Branch: {self.branch_name} -- not found in repo: {self.git_url}")

self.autorun_allow = kwargs.pop('autorun_allow', False)
self.autorun_script = kwargs.pop('autorun_script', [])

newargs = {k: v for k, v in kwargs.items() if v is not None}
super(GitPuller, self).__init__(**newargs)

Expand Down Expand Up @@ -143,6 +147,30 @@ def pull(self):
else:
yield from self.update()

def autorun(self, operation="method"):
"""
Search for and execute the autorun script.
"""

if not self.autorun_allow:
return
if not any(( re.fullmatch(pattern, self.git_url) for pattern in self.autorun_allow )):
logging.info('autorun skipped, URL does not match any rules')
return

script = next(( s for s in self.autorun_script if os.access(os.path.join(self.repo_dir, s), os.X_OK)), None)
if not script:
logging.info('autorun skipped, no matching (executable) script')
return

try:
for line in execute_cmd([ os.path.join(self.repo_dir, script), operation ], cwd=self.repo_dir, close_fds=True):
yield line
except subprocess.CalledProcessError:
m = f"Problem autorunning {script}"
logging.exception(m)
raise ValueError(m)

def initialize_repo(self):
"""
Clones repository
Expand All @@ -154,6 +182,7 @@ def initialize_repo(self):
clone_args.extend(['--branch', self.branch_name])
clone_args.extend(["--", self.git_url, self.repo_dir])
yield from execute_cmd(clone_args)
yield from self.autorun('init')
logging.info('Repo {} initialized'.format(self.repo_dir))

def reset_deleted_files(self):
Expand Down Expand Up @@ -343,6 +372,8 @@ def update(self):
yield from self.ensure_lock()
yield from self.merge()

yield from self.autorun('update')


def main():
"""
Expand Down

0 comments on commit 6f71925

Please sign in to comment.