kopia lustrzana https://github.com/piku/piku
build: lite cleanup of pylint results (#141)
rodzic
666f871bc9
commit
a93b471d67
79
piku.py
79
piku.py
|
@ -8,28 +8,27 @@ try:
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
exit("Piku requires Python 3.5 or above")
|
exit("Piku requires Python 3.5 or above")
|
||||||
|
|
||||||
from click import argument, command, group, get_current_context, option, secho as echo, pass_context
|
|
||||||
from collections import defaultdict, deque
|
from collections import defaultdict, deque
|
||||||
from datetime import datetime
|
|
||||||
from fcntl import fcntl, F_SETFL, F_GETFL
|
from fcntl import fcntl, F_SETFL, F_GETFL
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from hashlib import md5
|
from grp import getgrgid
|
||||||
from json import loads
|
from json import loads
|
||||||
from multiprocessing import cpu_count
|
from multiprocessing import cpu_count
|
||||||
from os import chmod, getgid, getuid, symlink, unlink, remove, stat, listdir, environ, makedirs, O_NONBLOCK
|
from os import chmod, getgid, getuid, symlink, unlink, remove, stat, listdir, environ, makedirs, O_NONBLOCK
|
||||||
from os.path import abspath, basename, dirname, exists, getmtime, join, realpath, splitext
|
from os.path import abspath, basename, dirname, exists, getmtime, join, realpath, splitext
|
||||||
|
from pwd import getpwuid
|
||||||
from re import sub
|
from re import sub
|
||||||
from shutil import copyfile, rmtree, which
|
from shutil import copyfile, rmtree, which
|
||||||
from socket import socket, AF_INET, SOCK_STREAM
|
from socket import socket, AF_INET, SOCK_STREAM
|
||||||
from sys import argv, stdin, stdout, stderr, version_info, exit
|
|
||||||
from stat import S_IRUSR, S_IWUSR, S_IXUSR
|
from stat import S_IRUSR, S_IWUSR, S_IXUSR
|
||||||
from subprocess import call, check_output, Popen, STDOUT, PIPE
|
from subprocess import call, check_output, Popen, STDOUT
|
||||||
|
from sys import argv, stdin, stdout, stderr, version_info, exit
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
from traceback import format_exc
|
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
from traceback import format_exc
|
||||||
from urllib.request import urlopen
|
from urllib.request import urlopen
|
||||||
from pwd import getpwuid
|
|
||||||
from grp import getgrgid
|
from click import argument, group, secho as echo, pass_context
|
||||||
|
|
||||||
# === Make sure we can access all system binaries ===
|
# === Make sure we can access all system binaries ===
|
||||||
|
|
||||||
|
@ -189,6 +188,7 @@ INTERNAL_NGINX_UWSGI_SETTINGS = """
|
||||||
uwsgi_param SERVER_NAME $server_name;
|
uwsgi_param SERVER_NAME $server_name;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
# === Utility functions ===
|
# === Utility functions ===
|
||||||
|
|
||||||
def sanitize_app_name(app):
|
def sanitize_app_name(app):
|
||||||
|
@ -253,13 +253,13 @@ def parse_procfile(filename):
|
||||||
workers[kind] = command
|
workers[kind] = command
|
||||||
except:
|
except:
|
||||||
echo("Warning: unrecognized Procfile entry '{}'".format(line), fg='yellow')
|
echo("Warning: unrecognized Procfile entry '{}'".format(line), fg='yellow')
|
||||||
if not len(workers):
|
if len(workers) == 0:
|
||||||
return {}
|
return {}
|
||||||
# WSGI trumps regular web workers
|
# WSGI trumps regular web workers
|
||||||
if 'wsgi' in workers or 'jwsgi' in workers:
|
if 'wsgi' in workers or 'jwsgi' in workers:
|
||||||
if 'web' in workers:
|
if 'web' in workers:
|
||||||
echo("Warning: found both 'wsgi' and 'web' workers, disabling 'web'", fg='yellow')
|
echo("Warning: found both 'wsgi' and 'web' workers, disabling 'web'", fg='yellow')
|
||||||
del(workers['web'])
|
del workers['web']
|
||||||
return workers
|
return workers
|
||||||
|
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ def parse_settings(filename, env={}):
|
||||||
|
|
||||||
with open(filename, 'r') as settings:
|
with open(filename, 'r') as settings:
|
||||||
for line in settings:
|
for line in settings:
|
||||||
if '#' == line[0] or len(line.strip()) == 0: # ignore comments and newlines
|
if line[0] == '#' or len(line.strip()) == 0: # ignore comments and newlines
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
k, v = map(lambda x: x.strip(), line.split("=", 1))
|
k, v = map(lambda x: x.strip(), line.split("=", 1))
|
||||||
|
@ -312,10 +312,13 @@ def check_requirements(binaries):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def found_app(kind):
|
def found_app(kind):
|
||||||
|
"""Helper function to output app detected"""
|
||||||
echo("-----> {} app detected.".format(kind), fg='green')
|
echo("-----> {} app detected.".format(kind), fg='green')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def do_deploy(app, deltas={}, newrev=None):
|
def do_deploy(app, deltas={}, newrev=None):
|
||||||
"""Deploy an app by resetting the work directory"""
|
"""Deploy an app by resetting the work directory"""
|
||||||
|
|
||||||
|
@ -336,11 +339,12 @@ def do_deploy(app, deltas={}, newrev=None):
|
||||||
if not exists(log_path):
|
if not exists(log_path):
|
||||||
makedirs(log_path)
|
makedirs(log_path)
|
||||||
workers = parse_procfile(procfile)
|
workers = parse_procfile(procfile)
|
||||||
if workers and len(workers):
|
if workers and len(workers) > 0:
|
||||||
settings = {}
|
settings = {}
|
||||||
if exists(join(app_path, 'requirements.txt')) and found_app("Python"):
|
if exists(join(app_path, 'requirements.txt')) and found_app("Python"):
|
||||||
settings.update(deploy_python(app, deltas))
|
settings.update(deploy_python(app, deltas))
|
||||||
elif exists(join(app_path, 'package.json')) and found_app("Node") and (check_requirements(['nodejs', 'npm']) or check_requirements(['nodeenv'])):
|
elif exists(join(app_path, 'package.json')) and found_app("Node") and (
|
||||||
|
check_requirements(['nodejs', 'npm']) or check_requirements(['nodeenv'])):
|
||||||
settings.update(deploy_node(app, deltas))
|
settings.update(deploy_node(app, deltas))
|
||||||
elif exists(join(app_path, 'pom.xml')) and found_app("Java Maven") and check_requirements(['java', 'mvn']):
|
elif exists(join(app_path, 'pom.xml')) and found_app("Java Maven") and check_requirements(['java', 'mvn']):
|
||||||
settings.update(deploy_java(app, deltas))
|
settings.update(deploy_java(app, deltas))
|
||||||
|
@ -371,6 +375,7 @@ def do_deploy(app, deltas={}, newrev=None):
|
||||||
else:
|
else:
|
||||||
echo("Error: app '{}' not found.".format(app), fg='red')
|
echo("Error: app '{}' not found.".format(app), fg='red')
|
||||||
|
|
||||||
|
|
||||||
def deploy_gradle(app, deltas={}):
|
def deploy_gradle(app, deltas={}):
|
||||||
"""Deploy a Java application using Gradle"""
|
"""Deploy a Java application using Gradle"""
|
||||||
java_path = join(ENV_ROOT, app)
|
java_path = join(ENV_ROOT, app)
|
||||||
|
@ -400,6 +405,7 @@ def deploy_gradle(app, deltas={}):
|
||||||
|
|
||||||
return spawn_app(app, deltas)
|
return spawn_app(app, deltas)
|
||||||
|
|
||||||
|
|
||||||
def deploy_java(app, deltas={}):
|
def deploy_java(app, deltas={}):
|
||||||
"""Deploy a Java application using Maven"""
|
"""Deploy a Java application using Maven"""
|
||||||
# TODO: Use jenv to isolate Java Application environments
|
# TODO: Use jenv to isolate Java Application environments
|
||||||
|
@ -431,6 +437,7 @@ def deploy_java(app, deltas={}):
|
||||||
|
|
||||||
return spawn_app(app, deltas)
|
return spawn_app(app, deltas)
|
||||||
|
|
||||||
|
|
||||||
def deploy_clojure(app, deltas={}):
|
def deploy_clojure(app, deltas={}):
|
||||||
"""Deploy a Clojure Application"""
|
"""Deploy a Clojure Application"""
|
||||||
|
|
||||||
|
@ -511,7 +518,8 @@ def deploy_node(app, deltas={}):
|
||||||
|
|
||||||
version = env.get("NODE_VERSION")
|
version = env.get("NODE_VERSION")
|
||||||
node_binary = join(virtualenv_path, "bin", "node")
|
node_binary = join(virtualenv_path, "bin", "node")
|
||||||
installed = check_output("{} -v".format(node_binary), cwd=join(APP_ROOT, app), env=env, shell=True).decode("utf8").rstrip("\n") if exists(node_binary) else ""
|
installed = check_output("{} -v".format(node_binary), cwd=join(APP_ROOT, app), env=env, shell=True).decode("utf8").rstrip(
|
||||||
|
"\n") if exists(node_binary) else ""
|
||||||
|
|
||||||
if version and check_requirements(['nodeenv']):
|
if version and check_requirements(['nodeenv']):
|
||||||
if not installed.endswith(version):
|
if not installed.endswith(version):
|
||||||
|
@ -520,7 +528,8 @@ def deploy_node(app, deltas={}):
|
||||||
echo("Warning: Can't update node with app running. Stop the app & retry.", fg='yellow')
|
echo("Warning: Can't update node with app running. Stop the app & retry.", fg='yellow')
|
||||||
else:
|
else:
|
||||||
echo("-----> Installing node version '{NODE_VERSION:s}' using nodeenv".format(**env), fg='green')
|
echo("-----> Installing node version '{NODE_VERSION:s}' using nodeenv".format(**env), fg='green')
|
||||||
call("nodeenv --prebuilt --node={NODE_VERSION:s} --clean-src --force {VIRTUAL_ENV:s}".format(**env), cwd=virtualenv_path, env=env, shell=True)
|
call("nodeenv --prebuilt --node={NODE_VERSION:s} --clean-src --force {VIRTUAL_ENV:s}".format(**env),
|
||||||
|
cwd=virtualenv_path, env=env, shell=True)
|
||||||
else:
|
else:
|
||||||
echo("-----> Node is installed at {}.".format(version))
|
echo("-----> Node is installed at {}.".format(version))
|
||||||
|
|
||||||
|
@ -664,7 +673,6 @@ def spawn_app(app, deltas={}):
|
||||||
env['NGINX_SOCKET'] = "{BIND_ADDRESS:s}:{PORT:s}".format(**env)
|
env['NGINX_SOCKET'] = "{BIND_ADDRESS:s}:{PORT:s}".format(**env)
|
||||||
echo("-----> nginx will look for app '{}' on {}".format(app, env['NGINX_SOCKET']))
|
echo("-----> nginx will look for app '{}' on {}".format(app, env['NGINX_SOCKET']))
|
||||||
|
|
||||||
|
|
||||||
domain = env['NGINX_SERVER_NAME'].split()[0]
|
domain = env['NGINX_SERVER_NAME'].split()[0]
|
||||||
key, crt = [join(NGINX_ROOT, "{}.{}".format(app, x)) for x in ['key', 'crt']]
|
key, crt = [join(NGINX_ROOT, "{}.{}".format(app, x)) for x in ['key', 'crt']]
|
||||||
if exists(join(ACME_ROOT, "acme.sh")):
|
if exists(join(ACME_ROOT, "acme.sh")):
|
||||||
|
@ -680,7 +688,8 @@ def spawn_app(app, deltas={}):
|
||||||
if not exists(key) or not exists(join(ACME_ROOT, domain, domain + ".key")):
|
if not exists(key) or not exists(join(ACME_ROOT, domain, domain + ".key")):
|
||||||
echo("-----> getting letsencrypt certificate")
|
echo("-----> getting letsencrypt certificate")
|
||||||
call('{acme:s}/acme.sh --issue -d {domain:s} -w {www:s}'.format(**locals()), shell=True)
|
call('{acme:s}/acme.sh --issue -d {domain:s} -w {www:s}'.format(**locals()), shell=True)
|
||||||
call('{acme:s}/acme.sh --install-cert -d {domain:s} --key-file {key:s} --fullchain-file {crt:s}'.format(**locals()), shell=True)
|
call('{acme:s}/acme.sh --install-cert -d {domain:s} --key-file {key:s} --fullchain-file {crt:s}'.format(
|
||||||
|
**locals()), shell=True)
|
||||||
if exists(join(ACME_ROOT, domain)) and not exists(join(ACME_WWW, app)):
|
if exists(join(ACME_ROOT, domain)) and not exists(join(ACME_WWW, app)):
|
||||||
symlink(join(ACME_ROOT, domain), join(ACME_WWW, app))
|
symlink(join(ACME_ROOT, domain), join(ACME_WWW, app))
|
||||||
else:
|
else:
|
||||||
|
@ -689,7 +698,9 @@ def spawn_app(app, deltas={}):
|
||||||
# fall back to creating self-signed certificate if acme failed
|
# fall back to creating self-signed certificate if acme failed
|
||||||
if not exists(key) or stat(crt).st_size == 0:
|
if not exists(key) or stat(crt).st_size == 0:
|
||||||
echo("-----> generating self-signed certificate")
|
echo("-----> generating self-signed certificate")
|
||||||
call('openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj "/C=US/ST=NY/L=New York/O=Piku/OU=Self-Signed/CN={domain:s}" -keyout {key:s} -out {crt:s}'.format(**locals()), shell=True)
|
call(
|
||||||
|
'openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj "/C=US/ST=NY/L=New York/O=Piku/OU=Self-Signed/CN={domain:s}" -keyout {key:s} -out {crt:s}'.format(
|
||||||
|
**locals()), shell=True)
|
||||||
|
|
||||||
# restrict access to server from CloudFlare IP addresses
|
# restrict access to server from CloudFlare IP addresses
|
||||||
acl = []
|
acl = []
|
||||||
|
@ -730,12 +741,14 @@ def spawn_app(app, deltas={}):
|
||||||
static_url, static_path = item.split(':')
|
static_url, static_path = item.split(':')
|
||||||
if static_path[0] != '/':
|
if static_path[0] != '/':
|
||||||
static_path = join(app_path, static_path)
|
static_path = join(app_path, static_path)
|
||||||
env['INTERNAL_NGINX_STATIC_MAPPINGS'] = env['INTERNAL_NGINX_STATIC_MAPPINGS'] + expandvars(INTERNAL_NGINX_STATIC_MAPPING, locals())
|
env['INTERNAL_NGINX_STATIC_MAPPINGS'] = env['INTERNAL_NGINX_STATIC_MAPPINGS'] + expandvars(
|
||||||
|
INTERNAL_NGINX_STATIC_MAPPING, locals())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
echo("Error {} in static path spec: should be /url1:path1[,/url2:path2], ignoring.".format(e))
|
echo("Error {} in static path spec: should be /url1:path1[,/url2:path2], ignoring.".format(e))
|
||||||
env['INTERNAL_NGINX_STATIC_MAPPINGS'] = ''
|
env['INTERNAL_NGINX_STATIC_MAPPINGS'] = ''
|
||||||
|
|
||||||
env['INTERNAL_NGINX_CUSTOM_CLAUSES'] = expandvars(open(join(app_path, env["NGINX_INCLUDE_FILE"])).read(), env) if env.get("NGINX_INCLUDE_FILE") else ""
|
env['INTERNAL_NGINX_CUSTOM_CLAUSES'] = expandvars(open(join(app_path, env["NGINX_INCLUDE_FILE"])).read(),
|
||||||
|
env) if env.get("NGINX_INCLUDE_FILE") else ""
|
||||||
env['INTERNAL_NGINX_PORTMAP'] = ""
|
env['INTERNAL_NGINX_PORTMAP'] = ""
|
||||||
if 'web' in workers or 'wsgi' in workers or 'jwsgi' in workers:
|
if 'web' in workers or 'wsgi' in workers or 'jwsgi' in workers:
|
||||||
env['INTERNAL_NGINX_PORTMAP'] = expandvars(NGINX_PORTMAP_FRAGMENT, env)
|
env['INTERNAL_NGINX_PORTMAP'] = expandvars(NGINX_PORTMAP_FRAGMENT, env)
|
||||||
|
@ -874,7 +887,6 @@ def spawn_worker(app, kind, command, env, ordinal=1):
|
||||||
('plugin', 'asyncio_python3'),
|
('plugin', 'asyncio_python3'),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
# If running under nginx, don't expose a port at all
|
# If running under nginx, don't expose a port at all
|
||||||
if 'NGINX_SERVER_NAME' in env:
|
if 'NGINX_SERVER_NAME' in env:
|
||||||
sock = join(NGINX_ROOT, "{}.sock".format(app))
|
sock = join(NGINX_ROOT, "{}.sock".format(app))
|
||||||
|
@ -898,7 +910,8 @@ def spawn_worker(app, kind, command, env, ordinal=1):
|
||||||
settings.append(('attach-daemon', command))
|
settings.append(('attach-daemon', command))
|
||||||
|
|
||||||
if kind in ['wsgi', 'web']:
|
if kind in ['wsgi', 'web']:
|
||||||
settings.append(('log-format','%%(addr) - %%(user) [%%(ltime)] "%%(method) %%(uri) %%(proto)" %%(status) %%(size) "%%(referer)" "%%(uagent)" %%(msecs)ms'))
|
settings.append(('log-format',
|
||||||
|
'%%(addr) - %%(user) [%%(ltime)] "%%(method) %%(uri) %%(proto)" %%(status) %%(size) "%%(referer)" "%%(uagent)" %%(msecs)ms'))
|
||||||
|
|
||||||
# remove unnecessary variables from the env in nginx.ini
|
# remove unnecessary variables from the env in nginx.ini
|
||||||
for k in ['NGINX_ACL']:
|
for k in ['NGINX_ACL']:
|
||||||
|
@ -919,10 +932,13 @@ def spawn_worker(app, kind, command, env, ordinal=1):
|
||||||
|
|
||||||
copyfile(available, enabled)
|
copyfile(available, enabled)
|
||||||
|
|
||||||
|
|
||||||
def do_restart(app):
|
def do_restart(app):
|
||||||
|
"""Restarts a deployed app"""
|
||||||
|
|
||||||
config = glob(join(UWSGI_ENABLED, '{}*.ini'.format(app)))
|
config = glob(join(UWSGI_ENABLED, '{}*.ini'.format(app)))
|
||||||
|
|
||||||
if len(config):
|
if len(config) > 0:
|
||||||
echo("Restarting app '{}'...".format(app), fg='yellow')
|
echo("Restarting app '{}'...".format(app), fg='yellow')
|
||||||
for c in config:
|
for c in config:
|
||||||
remove(c)
|
remove(c)
|
||||||
|
@ -966,9 +982,7 @@ def multi_tail(app, filenames, catch_up=20):
|
||||||
# Check for updates on every file
|
# Check for updates on every file
|
||||||
for f in filenames:
|
for f in filenames:
|
||||||
line = peek(files[f])
|
line = peek(files[f])
|
||||||
if not line:
|
if line:
|
||||||
continue
|
|
||||||
else:
|
|
||||||
updated = True
|
updated = True
|
||||||
yield "{} | {}".format(prefixes[f].ljust(longest), line)
|
yield "{} | {}".format(prefixes[f].ljust(longest), line)
|
||||||
|
|
||||||
|
@ -987,6 +1001,8 @@ def multi_tail(app, filenames, catch_up=20):
|
||||||
# === CLI commands ===
|
# === CLI commands ===
|
||||||
|
|
||||||
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
|
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
|
||||||
|
|
||||||
|
|
||||||
@group(context_settings=CONTEXT_SETTINGS)
|
@group(context_settings=CONTEXT_SETTINGS)
|
||||||
def piku():
|
def piku():
|
||||||
"""The smallest PaaS you've ever seen"""
|
"""The smallest PaaS you've ever seen"""
|
||||||
|
@ -1118,7 +1134,7 @@ def cmd_destroy(app):
|
||||||
|
|
||||||
for p in [join(x, '{}*.ini'.format(app)) for x in [UWSGI_AVAILABLE, UWSGI_ENABLED]]:
|
for p in [join(x, '{}*.ini'.format(app)) for x in [UWSGI_AVAILABLE, UWSGI_ENABLED]]:
|
||||||
g = glob(p)
|
g = glob(p)
|
||||||
if len(g):
|
if len(g) > 0:
|
||||||
for f in g:
|
for f in g:
|
||||||
echo("Removing file '{}'".format(f), fg='yellow')
|
echo("Removing file '{}'".format(f), fg='yellow')
|
||||||
remove(f)
|
remove(f)
|
||||||
|
@ -1147,7 +1163,7 @@ def cmd_logs(app, process):
|
||||||
app = exit_if_invalid(app)
|
app = exit_if_invalid(app)
|
||||||
|
|
||||||
logfiles = glob(join(LOG_ROOT, app, process + '.*.log'))
|
logfiles = glob(join(LOG_ROOT, app, process + '.*.log'))
|
||||||
if len(logfiles):
|
if len(logfiles) > 0:
|
||||||
for line in multi_tail(app, logfiles):
|
for line in multi_tail(app, logfiles):
|
||||||
echo(line.strip(), fg='white')
|
echo(line.strip(), fg='white')
|
||||||
else:
|
else:
|
||||||
|
@ -1212,6 +1228,7 @@ def cmd_run(app, cmd):
|
||||||
p = Popen(' '.join(cmd), stdin=stdin, stdout=stdout, stderr=stderr, env=environ, cwd=join(APP_ROOT, app), shell=True)
|
p = Popen(' '.join(cmd), stdin=stdin, stdout=stdout, stderr=stderr, env=environ, cwd=join(APP_ROOT, app), shell=True)
|
||||||
p.communicate()
|
p.communicate()
|
||||||
|
|
||||||
|
|
||||||
@piku.command("restart")
|
@piku.command("restart")
|
||||||
@argument('app')
|
@argument('app')
|
||||||
def cmd_restart(app):
|
def cmd_restart(app):
|
||||||
|
@ -1273,7 +1290,7 @@ def cmd_setup_ssh(public_key_file):
|
||||||
setup_authorized_keys(fingerprint, PIKU_SCRIPT, key)
|
setup_authorized_keys(fingerprint, PIKU_SCRIPT, key)
|
||||||
except Exception:
|
except Exception:
|
||||||
echo("Error: invalid public key file '{}': {}".format(key_file, format_exc()), fg='red')
|
echo("Error: invalid public key file '{}': {}".format(key_file, format_exc()), fg='red')
|
||||||
elif '-' == public_key_file:
|
elif public_key_file == '-':
|
||||||
buffer = "".join(stdin.readlines())
|
buffer = "".join(stdin.readlines())
|
||||||
with NamedTemporaryFile(mode="w") as f:
|
with NamedTemporaryFile(mode="w") as f:
|
||||||
f.write(buffer)
|
f.write(buffer)
|
||||||
|
@ -1293,7 +1310,7 @@ def cmd_stop(app):
|
||||||
app = exit_if_invalid(app)
|
app = exit_if_invalid(app)
|
||||||
config = glob(join(UWSGI_ENABLED, '{}*.ini'.format(app)))
|
config = glob(join(UWSGI_ENABLED, '{}*.ini'.format(app)))
|
||||||
|
|
||||||
if len(config):
|
if len(config) > 0:
|
||||||
echo("Stopping app '{}'...".format(app), fg='yellow')
|
echo("Stopping app '{}'...".format(app), fg='yellow')
|
||||||
for c in config:
|
for c in config:
|
||||||
remove(c)
|
remove(c)
|
||||||
|
@ -1349,7 +1366,7 @@ cat | PIKU_ROOT="{PIKU_ROOT:s}" {PIKU_SCRIPT:s} git-hook {app:s}""".format(**env
|
||||||
|
|
||||||
@piku.command("git-upload-pack", hidden=True)
|
@piku.command("git-upload-pack", hidden=True)
|
||||||
@argument('app')
|
@argument('app')
|
||||||
def cmd_git_receive_pack(app):
|
def cmd_git_upload_pack(app):
|
||||||
"""INTERNAL: Handle git upload pack for an app"""
|
"""INTERNAL: Handle git upload pack for an app"""
|
||||||
app = sanitize_app_name(app)
|
app = sanitize_app_name(app)
|
||||||
env = globals()
|
env = globals()
|
||||||
|
|
Ładowanie…
Reference in New Issue