Merge pull request #1579 from MasterRoot24/gentoo-chroot
91
spk/gentoo-chroot/Makefile
Normal file
@ -0,0 +1,91 @@
|
||||
SPK_NAME = gentoo-chroot
|
||||
SPK_VERS = 13.0
|
||||
SPK_REV = 1
|
||||
SPK_ICON = src/gentoo.png
|
||||
DSM_UI_DIR = app
|
||||
|
||||
DEPENDS =
|
||||
WHEELS = pyextdirect==0.3.1 flask Werkzeug Jinja2 itsdangerous
|
||||
SPK_DEPENDS = "python>=2.7.6-8"
|
||||
|
||||
MAINTAINER = "SynoCommunity"
|
||||
DESCRIPTION = "Gentoo is a free operating system based on either Linux or FreeBSD that can be automatically optimized and customized for just about any application or need. Gentoo Chroot allows you to install the Gentoo OS inside your DiskStation, alongside DSM. This package is intended for advanced users only."
|
||||
RELOAD_UI = yes
|
||||
DISPLAY_NAME = "Gentoo Chroot"
|
||||
CHANGELOG =
|
||||
|
||||
HOMEPAGE = "http://www.gentoo.org/"
|
||||
LICENSE =
|
||||
HELPURL = "3rdparty/gentoo-chroot/help/enu/index.html"
|
||||
SUPPORTURL = "http://www.gentoo.org/main/en/support.xml"
|
||||
|
||||
INSTALLER_SCRIPT = src/installer.sh
|
||||
SSS_SCRIPT = src/dsm-control.sh
|
||||
|
||||
INSTALL_PREFIX = /usr/local/$(SPK_NAME)
|
||||
|
||||
COPY_TARGET = nop
|
||||
POST_STRIP_TARGET = gentoo-chroot_extra_install
|
||||
|
||||
GENTOO_ARCH =
|
||||
ifeq ($(findstring $(ARCH),88f6281),$(ARCH))
|
||||
GENTOO_CPU = arm
|
||||
GENTOO_ARCH = armv7a
|
||||
endif
|
||||
ifeq ($(findstring $(ARCH),armada370 armadaxp armada375 alpine),$(ARCH))
|
||||
GENTOO_CPU = arm
|
||||
GENTOO_ARCH = armv7a_hardfp
|
||||
endif
|
||||
ifeq ($(findstring $(ARCH),bromolow cedarview evansport x86 avoton x64),$(ARCH))
|
||||
GENTOO_CPU = x86
|
||||
GENTOO_ARCH = i686
|
||||
endif
|
||||
ifeq ($(findstring $(ARCH),qoriq),$(ARCH))
|
||||
GENTOO_CPU = ppc
|
||||
GENTOO_ARCH = ppc
|
||||
endif
|
||||
ifeq ($(strip $(GENTOO_ARCH)),)
|
||||
$(error Arch $(ARCH) not supported)
|
||||
endif
|
||||
|
||||
GENTOO_STAGE3 := $(shell curl -s http://distfiles.gentoo.org/releases/$(GENTOO_CPU)/autobuilds/latest-stage3-$(GENTOO_ARCH).txt | sed '/^\#/d' | awk '{print $$1}')
|
||||
GENTOO_STAGE3_URL := http://distfiles.gentoo.org/releases/$(GENTOO_CPU)/autobuilds/$(GENTOO_STAGE3)
|
||||
GENTOO_STAGE3_FILE := $(shell basename $(GENTOO_STAGE3))
|
||||
|
||||
include ../../mk/spksrc.spk.mk
|
||||
|
||||
.PHONY: gentoo-chroot_extra_install
|
||||
gentoo-chroot_extra_install:
|
||||
install -m 755 -d ${STAGING_DIR}/share/wheelhouse
|
||||
install -m 644 ${WORK_DIR}/wheelhouse/* ${STAGING_DIR}/share/wheelhouse/
|
||||
wget -nv -c -O $(WORK_DIR)/$(GENTOO_STAGE3_FILE) $(GENTOO_STAGE3_URL)
|
||||
install -m 755 -d $(STAGING_DIR)/var
|
||||
install -m 755 -d $(STAGING_DIR)/var/chroottarget
|
||||
tar xjpf $(WORK_DIR)/$(GENTOO_STAGE3_FILE) -C $(STAGING_DIR)/var/chroottarget --exclude './dev/*'
|
||||
install -m 755 -d $(STAGING_DIR)/etc
|
||||
install -m 644 src/mounts $(STAGING_DIR)/etc/mounts
|
||||
install -m 755 -d $(STAGING_DIR)/app
|
||||
install -m 755 -d $(STAGING_DIR)/app/help
|
||||
install -m 755 -d $(STAGING_DIR)/app/help/enu
|
||||
install -m 644 src/app/help/enu/index.html $(STAGING_DIR)/app/help/enu/index.html
|
||||
install -m 644 src/app/config $(STAGING_DIR)/app/config
|
||||
install -m 644 src/app/style.css $(STAGING_DIR)/app/style.css
|
||||
install -m 644 src/app/gentoo-chroot.js $(STAGING_DIR)/app/gentoo-chroot.js
|
||||
install -m 755 src/app/setup.py $(STAGING_DIR)/app/setup.py
|
||||
install -m 755 src/app/start.py $(STAGING_DIR)/app/start.py
|
||||
install -m 755 src/app/stop.py $(STAGING_DIR)/app/stop.py
|
||||
install -m 755 src/app/gentoo-chroot.cgi.py $(STAGING_DIR)/app/gentoo-chroot.cgi
|
||||
install -m 755 -d $(STAGING_DIR)/app/application
|
||||
install -m 644 src/app/application/* $(STAGING_DIR)/app/application/
|
||||
install -m 755 -d $(STAGING_DIR)/app/texts
|
||||
for language in enu; do \
|
||||
install -m 755 -d $(STAGING_DIR)/app/texts/$${language}; \
|
||||
install -m 644 src/app/texts/$${language}/strings $(STAGING_DIR)/app/texts/$${language}/strings; \
|
||||
done
|
||||
install -m 755 -d $(STAGING_DIR)/app/images
|
||||
install -m 644 src/app/images/*.png $(STAGING_DIR)/app/images/
|
||||
for size in 16 24 32 48 72; do \
|
||||
convert $(SPK_ICON) -thumbnail $${size}x$${size} \
|
||||
$(STAGING_DIR)/app/images/$(SPK_NAME)-$${size}.png ; \
|
||||
done
|
||||
|
0
spk/gentoo-chroot/PLIST
Normal file
0
spk/gentoo-chroot/src/app/application/__init__.py
Normal file
66
spk/gentoo-chroot/src/app/application/auth.py
Normal file
@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from collections import namedtuple
|
||||
from flask import abort, request
|
||||
from functools import wraps, partial
|
||||
from subprocess import check_output
|
||||
import grp
|
||||
import os
|
||||
import pwd
|
||||
|
||||
|
||||
__all__ = ['authenticate', 'requires_auth']
|
||||
|
||||
|
||||
def authenticate():
|
||||
"""Authenticate a user using Synology's authenticate.cgi
|
||||
|
||||
If the user is authenticated, returns a nametuple with the
|
||||
username and its groups, if not returns None. For example::
|
||||
|
||||
>>> authenticate()
|
||||
User(name='admin', groups=['administrators'])
|
||||
|
||||
:rtype: namedtuple or None
|
||||
|
||||
"""
|
||||
User = namedtuple('User', ['name', 'groups'])
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
user = check_output(['/usr/syno/synoman/webman/modules/authenticate.cgi'], stderr=devnull).strip()
|
||||
if not user:
|
||||
return None
|
||||
groups = [g.gr_name for g in grp.getgrall() if user in g.gr_mem]
|
||||
groups.append(grp.getgrgid(pwd.getpwnam(user).pw_gid).gr_name)
|
||||
return User(user, set(groups))
|
||||
|
||||
|
||||
def requires_auth(f=None, groups=None, users=None):
|
||||
"""Require a user to be authenticated. If he is not, this aborts
|
||||
on 403.
|
||||
|
||||
The condition to be authorized is for the user to be authenticated
|
||||
and in one of the listed groups (if any) or one of the listed users
|
||||
(if any)
|
||||
|
||||
:param function f: the decorated function
|
||||
:param list groups: groups whitelist
|
||||
:param list users: users whitelist
|
||||
|
||||
"""
|
||||
if f is None:
|
||||
return partial(requires_auth, groups=groups, users=users)
|
||||
|
||||
@wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
user = authenticate()
|
||||
if user is None: # Not authenticated
|
||||
abort(403)
|
||||
# A user is authorized if he is in the groups whitelist or the users whitelist
|
||||
authorized = False
|
||||
if groups is not None and len(set(groups) & user.groups) > 0: # Authorized group
|
||||
authorized = True
|
||||
if users is not None and user.name in users: # Authorized user
|
||||
authorized = True
|
||||
if not authorized:
|
||||
abort(403)
|
||||
return f(*args, **kwargs)
|
||||
return decorated
|
5
spk/gentoo-chroot/src/app/application/config.py
Normal file
@ -0,0 +1,5 @@
|
||||
__all__ = ['env_path', 'chroottarget', 'installed']
|
||||
|
||||
env_path = '/usr/local/gentoo-chroot/bin:/usr/local/gentoo-chroot/env/bin:/usr/local/python/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/syno/sbin:/usr/syno/bin'
|
||||
chroottarget = '/usr/local/gentoo-chroot/var/chroottarget/'
|
||||
installed = '/usr/local/gentoo-chroot/var/installed'
|
44
spk/gentoo-chroot/src/app/application/db.py
Normal file
@ -0,0 +1,44 @@
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy import Column, Integer, String
|
||||
from sqlalchemy.engine import create_engine
|
||||
from sqlalchemy.orm.session import sessionmaker
|
||||
import subprocess
|
||||
import os
|
||||
from config import *
|
||||
|
||||
|
||||
__all__ = ['Base', 'engine', 'Session', 'Service', 'setup']
|
||||
|
||||
|
||||
Base = declarative_base()
|
||||
engine = create_engine('sqlite:////usr/local/gentoo-chroot/var/gentoo-chroot.db', echo=False)
|
||||
Session = sessionmaker(bind=engine)
|
||||
|
||||
|
||||
class Service(Base):
|
||||
__tablename__ = 'services'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String)
|
||||
launch_script = Column(String)
|
||||
status_command = Column(String)
|
||||
|
||||
def start(self):
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
status = not subprocess.call(['chroot', chroottarget, '/bin/bash', '-c', self.launch_script + ' start'], stdin=devnull, stdout=devnull, stderr=devnull, env={'PATH': env_path})
|
||||
return status
|
||||
|
||||
def stop(self):
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
status = not subprocess.call(['chroot', chroottarget, '/bin/bash', '-c', self.launch_script + ' stop'], stdin=devnull, stdout=devnull, stderr=devnull, env={'PATH': env_path})
|
||||
return status
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
status = not subprocess.call(['chroot', chroottarget, '/bin/bash', '-c', self.status_command], stdin=devnull, stdout=devnull, stderr=devnull, env={'PATH': env_path})
|
||||
return status
|
||||
|
||||
|
||||
def setup():
|
||||
Base.metadata.create_all(engine)
|
117
spk/gentoo-chroot/src/app/application/direct.py
Normal file
@ -0,0 +1,117 @@
|
||||
from pyextdirect.configuration import create_configuration, expose, LOAD, STORE_READ, STORE_CUD
|
||||
from pyextdirect.router import Router
|
||||
import os
|
||||
import subprocess
|
||||
from config import *
|
||||
from db import *
|
||||
|
||||
|
||||
__all__ = ['Base', 'Services', 'Overview']
|
||||
|
||||
|
||||
Base = create_configuration()
|
||||
|
||||
|
||||
class Services(Base):
|
||||
def __init__(self):
|
||||
self.session = Session()
|
||||
|
||||
@expose(kind=STORE_CUD)
|
||||
def create(self, data):
|
||||
results = []
|
||||
for record in data:
|
||||
service = Service(name=record['name'], launch_script=record['launch_script'], status_command=record['status_command'])
|
||||
self.session.add(service)
|
||||
self.session.commit()
|
||||
results.append({'id': service.id, 'name': service.name, 'launch_script': service.launch_script,
|
||||
'status_command': service.status_command, 'status': service.status})
|
||||
return results
|
||||
|
||||
@expose(kind=STORE_READ)
|
||||
def read(self):
|
||||
results = []
|
||||
for service in self.session.query(Service).all():
|
||||
results.append({'id': service.id, 'name': service.name, 'launch_script': service.launch_script,
|
||||
'status_command': service.status_command, 'status': service.status})
|
||||
return results
|
||||
|
||||
@expose(kind=STORE_CUD)
|
||||
def update(self, data):
|
||||
results = []
|
||||
for record in data:
|
||||
service = self.session.query(Service).get(record['id'])
|
||||
service.name = record['name']
|
||||
service.launch_script = record['launch_script']
|
||||
service.status_command = record['status_command']
|
||||
results.append({'id': service.id, 'name': service.name, 'launch_script': service.launch_script,
|
||||
'status_command': service.status_command, 'status': service.status})
|
||||
self.session.commit()
|
||||
return results
|
||||
|
||||
@expose(kind=STORE_CUD)
|
||||
def destroy(self, data):
|
||||
results = []
|
||||
for service_id in data:
|
||||
service = self.session.query(Service).get(service_id)
|
||||
self.session.delete(service)
|
||||
results.append({'id': service.id, 'name': service.name, 'launch_script': service.launch_script,
|
||||
'status_command': service.status_command, 'status': service.status})
|
||||
self.session.commit()
|
||||
return [r['id'] for r in results]
|
||||
|
||||
@expose
|
||||
def start(self, service_id):
|
||||
service = self.session.query(Service).get(service_id)
|
||||
return service.start()
|
||||
|
||||
@expose
|
||||
def stop(self, service_id):
|
||||
service = self.session.query(Service).get(service_id)
|
||||
return service.stop()
|
||||
|
||||
def stop_all(self):
|
||||
for service in self.session.query(Service).all():
|
||||
if service.status:
|
||||
service.stop()
|
||||
|
||||
def start_all(self):
|
||||
for service in self.session.query(Service).all():
|
||||
if not service.status:
|
||||
service.start()
|
||||
|
||||
class Overview(Base):
|
||||
def __init__(self):
|
||||
self.session = Session()
|
||||
|
||||
@expose(kind=LOAD)
|
||||
def load(self):
|
||||
result = {'installed': 'installed' if self.is_installed() else 'installing',
|
||||
'running_services': self.running_services(),
|
||||
'updates': self.updates_count()}
|
||||
return result
|
||||
|
||||
@expose
|
||||
def updates_count(self):
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
updates_count = int(subprocess.check_output(['chroot', chroottarget, '/bin/bash', '-c', 'emerge --update --deep @world --pretend --quiet | grep "U" | wc -l'], stdin=devnull, stderr=devnull, env={'PATH': env_path}))
|
||||
return updates_count
|
||||
|
||||
@expose
|
||||
def do_refresh(self):
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
status = not subprocess.call(['chroot', chroottarget, '/bin/bash', '-c', 'emerge --sync --quiet'], stdin=devnull, stdout=devnull, stderr=devnull, env={'PATH': env_path})
|
||||
if status:
|
||||
return self.updates_count()
|
||||
return status
|
||||
|
||||
@expose
|
||||
def do_update(self):
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
status = not subprocess.call(['chroot', chroottarget, '/bin/bash', '-c', 'emerge --update --deep @world --quiet'], stdin=devnull, stdout=devnull, stderr=devnull, env={'PATH': env_path})
|
||||
return status
|
||||
|
||||
def is_installed(self):
|
||||
return os.path.exists(installed)
|
||||
|
||||
def running_services(self):
|
||||
return len([service for service in self.session.query(Service).all() if service.status == 1])
|
31
spk/gentoo-chroot/src/app/config
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"gentoo-chroot.js": {
|
||||
"SYNOCOMMUNITY.GentooChroot.AppInstance": {
|
||||
"type": "app",
|
||||
"title": "app:app_name",
|
||||
"version": "0.1",
|
||||
"icon": "images/gentoo-chroot-{0}.png",
|
||||
"texts": "texts",
|
||||
"allowMultiInstance": false,
|
||||
"allUsers": false,
|
||||
"appWindow": "SYNOCOMMUNITY.GentooChroot.AppWindow",
|
||||
"depend": ["SYNOCOMMUNITY.GentooChroot.AppWindow"]
|
||||
},
|
||||
"SYNOCOMMUNITY.GentooChroot.AppWindow": {
|
||||
"type": "lib",
|
||||
"title": "app:app_name",
|
||||
"icon": "images/gentoo-chroot-{0}.png",
|
||||
"texts": "texts",
|
||||
"depend": ["SYNOCOMMUNITY.GentooChroot.ListView", "SYNOCOMMUNITY.GentooChroot.MainCardPanel"]
|
||||
},
|
||||
"SYNOCOMMUNITY.GentooChroot.ListView": [],
|
||||
"SYNOCOMMUNITY.GentooChroot.MainCardPanel": {
|
||||
"depend": ["SYNOCOMMUNITY.GentooChroot.PanelOverview", "SYNOCOMMUNITY.GentooChroot.PanelServices"]
|
||||
},
|
||||
"SYNOCOMMUNITY.GentooChroot.PanelOverview": [],
|
||||
"SYNOCOMMUNITY.GentooChroot.PanelServices": {
|
||||
"depend": ["SYNOCOMMUNITY.GentooChroot.ServiceEditorWindow"]
|
||||
},
|
||||
"SYNOCOMMUNITY.GentooChroot.ServiceEditorWindow": []
|
||||
}
|
||||
}
|
38
spk/gentoo-chroot/src/app/gentoo-chroot.cgi.py
Normal file
@ -0,0 +1,38 @@
|
||||
#!/usr/local/gentoo-chroot/env/bin/python
|
||||
from application.auth import requires_auth
|
||||
from application.direct import Base, Overview
|
||||
from flask import Flask, request, Response
|
||||
from pyextdirect.api import create_api
|
||||
from pyextdirect.router import Router
|
||||
from wsgiref.handlers import CGIHandler
|
||||
import json
|
||||
|
||||
|
||||
app = Flask('gentoo-chroot')
|
||||
|
||||
|
||||
@app.route('/direct/router', methods=['POST'])
|
||||
@requires_auth(groups=['administrators'])
|
||||
def route():
|
||||
router = Router(Base)
|
||||
return Response(router.route(request.json or dict((k, v[0] if len(v) == 1 else v) for k, v in request.form.to_dict(False).iteritems())), mimetype='application/json')
|
||||
|
||||
|
||||
@app.route('/direct/poller', methods=['GET'])
|
||||
@requires_auth(groups=['administrators'])
|
||||
def poll():
|
||||
overview = Overview()
|
||||
event = {'type': 'event', 'name': 'status', 'data': {
|
||||
'installed': 'installed' if overview.is_installed() else 'installing',
|
||||
'running_services': overview.running_services()}}
|
||||
return Response(json.dumps(event), mimetype='application/json')
|
||||
|
||||
|
||||
@app.route('/direct/api')
|
||||
@requires_auth(groups=['administrators'])
|
||||
def api():
|
||||
return create_api(Base)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
CGIHandler().run(app)
|
814
spk/gentoo-chroot/src/app/gentoo-chroot.js
Normal file
@ -0,0 +1,814 @@
|
||||
// Namespace
|
||||
Ext.ns("SYNOCOMMUNITY.GentooChroot");
|
||||
|
||||
// Translator
|
||||
_V = function (category, element) {
|
||||
return _TT("SYNOCOMMUNITY.GentooChroot.AppInstance", category, element)
|
||||
}
|
||||
|
||||
// Direct API
|
||||
Ext.Direct.addProvider({
|
||||
"url": "3rdparty/gentoo-chroot/gentoo-chroot.cgi/direct/router",
|
||||
"namespace": "SYNOCOMMUNITY.GentooChroot.Remote",
|
||||
"type": "remoting",
|
||||
"actions": {
|
||||
"Overview": [{
|
||||
"name": "load",
|
||||
"len": 0
|
||||
}, {
|
||||
"name": "updates_count",
|
||||
"len": 0
|
||||
}, {
|
||||
"name": "do_refresh",
|
||||
"len": 0
|
||||
}, {
|
||||
"name": "do_update",
|
||||
"len": 0
|
||||
}],
|
||||
"Services": [{
|
||||
"name": "save",
|
||||
"len": 5
|
||||
}, {
|
||||
"name": "read",
|
||||
"len": 0
|
||||
}, {
|
||||
"name": "create",
|
||||
"len": 1
|
||||
}, {
|
||||
"name": "update",
|
||||
"len": 1
|
||||
}, {
|
||||
"name": "destroy",
|
||||
"len": 1
|
||||
}, {
|
||||
"name": "start",
|
||||
"len": 1
|
||||
}, {
|
||||
"name": "stop",
|
||||
"len": 1
|
||||
}]
|
||||
}
|
||||
});
|
||||
SYNOCOMMUNITY.GentooChroot.Poller = new Ext.direct.PollingProvider({
|
||||
'type': 'polling',
|
||||
'url': '3rdparty/gentoo-chroot/gentoo-chroot.cgi/direct/poller',
|
||||
'interval': 10000
|
||||
});
|
||||
Ext.Direct.addProvider(SYNOCOMMUNITY.GentooChroot.Poller);
|
||||
SYNOCOMMUNITY.GentooChroot.Poller.disconnect();
|
||||
|
||||
// Const
|
||||
SYNOCOMMUNITY.GentooChroot.DEFAULT_HEIGHT = 300;
|
||||
SYNOCOMMUNITY.GentooChroot.MAIN_WIDTH = 800;
|
||||
SYNOCOMMUNITY.GentooChroot.LIST_WIDTH = 210;
|
||||
|
||||
// Application
|
||||
SYNOCOMMUNITY.GentooChroot.AppInstance = Ext.extend(SYNO.SDS.AppInstance, {
|
||||
appWindowName: "SYNOCOMMUNITY.GentooChroot.AppWindow",
|
||||
constructor: function () {
|
||||
SYNOCOMMUNITY.GentooChroot.AppInstance.superclass.constructor.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
|
||||
// Main window
|
||||
SYNOCOMMUNITY.GentooChroot.AppWindow = Ext.extend(SYNO.SDS.AppWindow, {
|
||||
appInstance: null,
|
||||
mainPanel: null,
|
||||
constructor: function (config) {
|
||||
this.appInstance = config.appInstance;
|
||||
this.mainPanel = new SYNOCOMMUNITY.GentooChroot.MainPanel({
|
||||
owner: this
|
||||
});
|
||||
config = Ext.apply({
|
||||
resizable: true,
|
||||
maximizable: true,
|
||||
minimizable: true,
|
||||
width: SYNOCOMMUNITY.GentooChroot.MAIN_WIDTH,
|
||||
height: SYNOCOMMUNITY.GentooChroot.DEFAULT_HEIGHT,
|
||||
layout: "fit",
|
||||
border: false,
|
||||
cls: "synocommunity-gentoochroot",
|
||||
items: [this.mainPanel]
|
||||
}, config);
|
||||
SYNOCOMMUNITY.GentooChroot.AppWindow.superclass.constructor.call(this, config);
|
||||
},
|
||||
onOpen: function (a) {
|
||||
SYNOCOMMUNITY.GentooChroot.AppWindow.superclass.onOpen.call(this, a);
|
||||
this.mainPanel.onActivate();
|
||||
},
|
||||
onRequest: function (a) {
|
||||
SYNOCOMMUNITY.GentooChroot.AppWindow.superclass.onRequest.call(this, a);
|
||||
},
|
||||
onClose: function () {
|
||||
if (SYNOCOMMUNITY.GentooChroot.AppWindow.superclass.onClose.apply(this, arguments)) {
|
||||
this.doClose();
|
||||
this.mainPanel.onDeactivate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
setStatus: function (status) {
|
||||
status = status || {};
|
||||
var toolbar = this.mainPanel.cardPanel.layout.activeItem.getFooterToolbar();
|
||||
if (toolbar && Ext.isFunction(toolbar.setStatus)) {
|
||||
toolbar.setStatus(status)
|
||||
} else {
|
||||
this.getMsgBox().alert("Message", status.text)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Main panel
|
||||
SYNOCOMMUNITY.GentooChroot.MainPanel = Ext.extend(Ext.Panel, {
|
||||
listPanel: null,
|
||||
cardPanel: null,
|
||||
constructor: function (config) {
|
||||
this.owner = config.owner;
|
||||
var a = new SYNOCOMMUNITY.GentooChroot.ListView({
|
||||
module: this
|
||||
});
|
||||
this.listPanel = new Ext.Panel({
|
||||
region: "west",
|
||||
width: SYNOCOMMUNITY.GentooChroot.LIST_WIDTH,
|
||||
height: SYNOCOMMUNITY.GentooChroot.DEFAULT_HEIGHT,
|
||||
cls: "synocommunity-gentoochroot-list",
|
||||
items: [a],
|
||||
listeners: {
|
||||
scope: this,
|
||||
activate: this.onActivate,
|
||||
deactivate: this.onDeactivate
|
||||
},
|
||||
onActivate: function (panel) {
|
||||
a.onActivate()
|
||||
}
|
||||
});
|
||||
this.listView = a;
|
||||
this.curHeight = SYNOCOMMUNITY.GentooChroot.DEFAULT_HEIGHT;
|
||||
this.cardPanel = new SYNOCOMMUNITY.GentooChroot.MainCardPanel({
|
||||
module: this,
|
||||
owner: config.owner,
|
||||
itemId: "grid",
|
||||
region: "center"
|
||||
});
|
||||
this.id_panel = [
|
||||
["overview", this.cardPanel.PanelOverview],
|
||||
["services", this.cardPanel.PanelServices]
|
||||
];
|
||||
SYNOCOMMUNITY.GentooChroot.MainPanel.superclass.constructor.call(this, {
|
||||
border: false,
|
||||
layout: "border",
|
||||
height: SYNOCOMMUNITY.GentooChroot.DEFAULT_HEIGHT,
|
||||
monitorResize: true,
|
||||
items: [this.listPanel, this.cardPanel]
|
||||
});
|
||||
},
|
||||
onActivate: function (panel) {
|
||||
if (!this.isVisible()) {
|
||||
return
|
||||
}
|
||||
this.listPanel.onActivate(panel);
|
||||
this.cardPanel.onActivate(panel);
|
||||
},
|
||||
onDeactivate: function (panel) {
|
||||
if (!this.rendered) {
|
||||
return
|
||||
}
|
||||
this.cardPanel.onDeactivate(panel);
|
||||
},
|
||||
doSwitchPanel: function (id_panel) {
|
||||
var c = this.cardPanel.getLayout();
|
||||
c.setActiveItem(id_panel);
|
||||
var b;
|
||||
for (b = 0; b < this.id_panel.length; b++) {
|
||||
var a = this.id_panel[b][1];
|
||||
if (id_panel === this.id_panel[b][0]) {
|
||||
a.onActivate();
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
getPanelHeight: function (id_panel) {
|
||||
return SYNOCOMMUNITY.GentooChroot.DEFAULT_HEIGHT
|
||||
},
|
||||
isPanelDirty: function (c) {
|
||||
var b;
|
||||
for (b = 0; b < this.id_panel.length; b++) {
|
||||
if (c === this.id_panel[b][0]) {
|
||||
var a = this.id_panel[b][1];
|
||||
if ("undefined" === typeof a.checkDirty) {
|
||||
return false
|
||||
}
|
||||
if (true == a.checkDirty()) {
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
panelDeactivate: function (c) {
|
||||
for (var b = 0; b < this.id_panel.length; b++) {
|
||||
if (c === this.id_panel[b][0]) {
|
||||
var a = this.id_panel[b][1];
|
||||
if ("undefined" === typeof a.onDeactivate) {
|
||||
return
|
||||
}
|
||||
a.onDeactivate();
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
},
|
||||
switchPanel: function (f) {
|
||||
var c = this.cardPanel.getLayout();
|
||||
var b = c.activeItem.itemId;
|
||||
if (f === b) {
|
||||
return
|
||||
}
|
||||
if (Ext.isIE) {
|
||||
this.doSwitchPanel(f);
|
||||
return
|
||||
}
|
||||
var a = this.getPanelHeight(f);
|
||||
if (this.curHeight == a) {
|
||||
this.doSwitchPanel(f);
|
||||
return
|
||||
}
|
||||
this.owner.el.disableShadow();
|
||||
var d = this.owner.body;
|
||||
var e = function () {
|
||||
d.clearOpacity();
|
||||
this.owner.getEl().setHeight("auto");
|
||||
d.setHeight("auto");
|
||||
this.owner.setHeight(a);
|
||||
this.owner.el.enableShadow();
|
||||
this.owner.syncShadow();
|
||||
this.doSwitchPanel(f)
|
||||
};
|
||||
d.shift({
|
||||
height: a - 54,
|
||||
duration: 0.3,
|
||||
opacity: 0.1,
|
||||
scope: this,
|
||||
callback: e
|
||||
});
|
||||
this.curHeight = a
|
||||
}
|
||||
});
|
||||
|
||||
// List view
|
||||
SYNOCOMMUNITY.GentooChroot.ListView = Ext.extend(Ext.list.ListView, {
|
||||
constructor: function (config) {
|
||||
var store = new Ext.data.JsonStore({
|
||||
data: {
|
||||
items: [{
|
||||
title: _V("ui", "console"),
|
||||
id: "console_title"
|
||||
}, {
|
||||
title: _V("ui", "overview"),
|
||||
id: "overview"
|
||||
}, {
|
||||
title: _V("ui", "services"),
|
||||
id: "services"
|
||||
}]
|
||||
},
|
||||
autoLoad: true,
|
||||
root: "items",
|
||||
fields: ["title", "id"]
|
||||
});
|
||||
config = Ext.apply({
|
||||
cls: "synocommunity-gentoochroot-list",
|
||||
padding: 10,
|
||||
split: false,
|
||||
trackOver: false,
|
||||
hideHeaders: true,
|
||||
singleSelect: true,
|
||||
store: store,
|
||||
columns: [{
|
||||
dataIndex: "title",
|
||||
cls: "synocommunity-gentoochroot-list-column",
|
||||
sortable: false,
|
||||
tpl: '<div class="synocommunity-gentoochroot-list-{id}">{title}</div>'
|
||||
}],
|
||||
listeners: {
|
||||
scope: this,
|
||||
beforeclick: this.onBeforeClick,
|
||||
selectionchange: this.onListSelect,
|
||||
activate: this.onActivate,
|
||||
mouseenter: {
|
||||
fn: function (d, e, g) {
|
||||
var f = Ext.get(g);
|
||||
if (f.hasClass(this.selectedClass)) {
|
||||
f.removeClass(this.overClass)
|
||||
}
|
||||
var h = d.getRecord(g).get("id");
|
||||
if (h === "console_title") {
|
||||
f.removeClass(this.overClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, config);
|
||||
this.addEvents("onbeforeclick");
|
||||
SYNOCOMMUNITY.GentooChroot.ListView.superclass.constructor.call(this, config)
|
||||
},
|
||||
onBeforeClick: function (c, d, f, b) {
|
||||
var g = c.getRecord(f);
|
||||
var h = g.get("id");
|
||||
if (h === "console_title") {
|
||||
return false
|
||||
}
|
||||
if (false == this.fireEvent("onbeforeclick", this, d, f, b)) {
|
||||
return false
|
||||
}
|
||||
var e = this.module.cardPanel.getLayout();
|
||||
var a = e.activeItem.itemId;
|
||||
if (h === a) {
|
||||
return false
|
||||
}
|
||||
if (this.module.isPanelDirty(a)) {
|
||||
this.module.cardPanel.owner.getMsgBox().confirm(_T("app", "app_name"), _T("common", "confirm_lostchange"), function (i) {
|
||||
if ("yes" === i) {
|
||||
this.module.panelDeactivate(a);
|
||||
this.select(d)
|
||||
}
|
||||
}, this);
|
||||
return false
|
||||
}
|
||||
this.module.panelDeactivate(a);
|
||||
return true
|
||||
},
|
||||
onListSelect: function (b, a) {
|
||||
var c = this.getRecord(a[0]);
|
||||
this.module.switchPanel(c.get("id"))
|
||||
},
|
||||
onActivate: function (panel) {
|
||||
var a = this.getSelectedRecords()[0];
|
||||
if (!a) {
|
||||
this.select(1)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Card panel
|
||||
SYNOCOMMUNITY.GentooChroot.MainCardPanel = Ext.extend(Ext.Panel, {
|
||||
PanelOverview: null,
|
||||
constructor: function (config) {
|
||||
this.owner = config.owner;
|
||||
this.module = config.module;
|
||||
this.PanelOverview = new SYNOCOMMUNITY.GentooChroot.PanelOverview({
|
||||
owner: this.owner
|
||||
});
|
||||
this.PanelServices = new SYNOCOMMUNITY.GentooChroot.PanelServices({
|
||||
owner: this.owner
|
||||
});
|
||||
config = Ext.apply({
|
||||
activeItem: 0,
|
||||
layout: "card",
|
||||
items: [this.PanelOverview, this.PanelServices],
|
||||
border: false,
|
||||
listeners: {
|
||||
scope: this,
|
||||
activate: this.onActivate,
|
||||
deactivate: this.onDeactivate
|
||||
}
|
||||
}, config);
|
||||
SYNOCOMMUNITY.GentooChroot.MainCardPanel.superclass.constructor.call(this, config)
|
||||
},
|
||||
onActivate: function (panel) {
|
||||
if (this.PanelOverview) {
|
||||
this.PanelOverview.onActivate();
|
||||
}
|
||||
},
|
||||
onDeactivate: function (panel) {
|
||||
this.PanelOverview.onDeactivate();
|
||||
}
|
||||
});
|
||||
|
||||
// FormPanel base
|
||||
SYNOCOMMUNITY.GentooChroot.FormPanel = Ext.extend(Ext.FormPanel, {
|
||||
constructor: function (config) {
|
||||
config = Ext.apply({
|
||||
owner: null,
|
||||
items: [],
|
||||
padding: "20px 30px 2px 30px",
|
||||
border: false,
|
||||
header: false,
|
||||
trackResetOnLoad: true,
|
||||
monitorValid: true,
|
||||
fbar: {
|
||||
xtype: "statusbar",
|
||||
defaultText: " ",
|
||||
statusAlign: "left",
|
||||
buttonAlign: "left",
|
||||
hideMode: "visibility",
|
||||
items: [{
|
||||
text: _T("common", "commit"),
|
||||
ctCls: "syno-sds-cp-btn",
|
||||
scope: this,
|
||||
handler: this.onApply
|
||||
}, {
|
||||
text: _T("common", "reset"),
|
||||
ctCls: "syno-sds-cp-btn",
|
||||
scope: this,
|
||||
handler: this.onReset
|
||||
}]
|
||||
}
|
||||
}, config);
|
||||
SYNO.LayoutConfig.fill(config);
|
||||
SYNOCOMMUNITY.GentooChroot.FormPanel.superclass.constructor.call(this, config);
|
||||
if (!this.owner instanceof SYNO.SDS.BaseWindow) {
|
||||
throw Error("please set the owner window of form");
|
||||
}
|
||||
},
|
||||
onActivate: Ext.emptyFn,
|
||||
onDeactivate: Ext.emptyFn,
|
||||
onApply: function () {
|
||||
if (!this.getForm().isDirty()) {
|
||||
this.owner.setStatusError({
|
||||
text: _T("error", "nochange_subject"),
|
||||
clear: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!this.getForm().isValid()) {
|
||||
this.owner.setStatusError({
|
||||
text: _T("common", "forminvalid"),
|
||||
clear: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
onReset: function () {
|
||||
if (!this.getForm().isDirty()) {
|
||||
this.getForm().reset();
|
||||
return;
|
||||
}
|
||||
this.owner.getMsgBox().confirm(this.title, _T("common", "confirm_lostchange"), function (response) {
|
||||
if ("yes" === response) {
|
||||
this.getForm().reset();
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
});
|
||||
|
||||
// Overview panel
|
||||
SYNOCOMMUNITY.GentooChroot.PanelOverview = Ext.extend(SYNOCOMMUNITY.GentooChroot.FormPanel, {
|
||||
constructor: function (config) {
|
||||
this.owner = config.owner;
|
||||
this.loaded = false;
|
||||
config = Ext.apply({
|
||||
itemId: "overview",
|
||||
fbar: {
|
||||
xtype: "statusbar",
|
||||
defaultText: " ",
|
||||
statusAlign: "left",
|
||||
buttonAlign: "left",
|
||||
hideMode: "visibility",
|
||||
items: []
|
||||
},
|
||||
items: [{
|
||||
xtype: "fieldset",
|
||||
labelWidth: 130,
|
||||
title: _V("ui", "information"),
|
||||
defaultType: "displayfield",
|
||||
items: [{
|
||||
fieldLabel: _V("ui", "status"),
|
||||
name: "install_status",
|
||||
value: ""
|
||||
}, {
|
||||
fieldLabel: _V("ui", "running_services"),
|
||||
name: "running_services",
|
||||
value: ""
|
||||
}]
|
||||
}, {
|
||||
xtype: "fieldset",
|
||||
labelWidth: 130,
|
||||
title: "Portage",
|
||||
items: [{
|
||||
xtype: "compositefield",
|
||||
fieldLabel: _V("ui", "available_updates"),
|
||||
items: [{
|
||||
xtype: "displayfield",
|
||||
name: "updates",
|
||||
width: 60,
|
||||
value: ""
|
||||
}, {
|
||||
xtype: "button",
|
||||
id: "synocommunity-gentoochroot-do_refresh",
|
||||
text: _V("ui", "do_refresh"),
|
||||
handler: this.onClickRefreshUpdates,
|
||||
scope: this
|
||||
}, {
|
||||
xtype: "button",
|
||||
id: "synocommunity-gentoochroot-do_update",
|
||||
text: _V("ui", "do_update"),
|
||||
handler: this.onClickUpdate,
|
||||
scope: this
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
api: {
|
||||
load: SYNOCOMMUNITY.GentooChroot.Remote.Overview.load
|
||||
}
|
||||
}, config);
|
||||
SYNO.LayoutConfig.fill(config);
|
||||
SYNOCOMMUNITY.GentooChroot.PanelOverview.superclass.constructor.call(this, config);
|
||||
},
|
||||
onClickRefreshUpdates: function (button, event) {
|
||||
button.disable();
|
||||
Ext.getCmp("synocommunity-gentoochroot-do_update").disable();
|
||||
SYNOCOMMUNITY.GentooChroot.Remote.Overview.do_refresh(function (provider, response) {
|
||||
if (response.result !== false) {
|
||||
this.getForm().findField("updates").setValue(response.result);
|
||||
this.owner.setStatusOK({
|
||||
text: response.result + " " + _V("ui", "updates_available")
|
||||
});
|
||||
} else {
|
||||
this.owner.setStatusError({
|
||||
text: _V("ui", "cannot_update"),
|
||||
clear: true
|
||||
});
|
||||
}
|
||||
button.enable();
|
||||
Ext.getCmp("synocommunity-gentoochroot-do_update").enable();
|
||||
}, this);
|
||||
},
|
||||
onClickUpdate: function (button, event) {
|
||||
button.disable();
|
||||
Ext.getCmp("synocommunity-gentoochroot-do_refresh").disable();
|
||||
SYNOCOMMUNITY.GentooChroot.Remote.Overview.do_update(function (provider, response) {
|
||||
if (response.result) {
|
||||
this.getForm().findField("updates").setValue(0);
|
||||
this.owner.setStatusOK({
|
||||
text: _V("ui", "update_successful")
|
||||
});
|
||||
} else {
|
||||
this.owner.setStatusError({
|
||||
text: _V("ui", "cannot_update"),
|
||||
clear: true
|
||||
});
|
||||
}
|
||||
button.enable();
|
||||
Ext.getCmp("synocommunity-gentoochroot-do_refresh").enable();
|
||||
}, this);
|
||||
},
|
||||
onStatus: function (response) {
|
||||
this.getForm().findField("install_status").setValue(_V("ui", response.data.installed));
|
||||
this.getForm().findField("running_services").setValue(response.data.running_services);
|
||||
if (response.data.installed == "installing") {
|
||||
Ext.getCmp("synocommunity-gentoochroot-do_refresh").disable();
|
||||
Ext.getCmp("synocommunity-gentoochroot-do_update").disable();
|
||||
} else {
|
||||
Ext.getCmp("synocommunity-gentoochroot-do_refresh").enable();
|
||||
Ext.getCmp("synocommunity-gentoochroot-do_update").enable();
|
||||
}
|
||||
},
|
||||
onActivate: function () {
|
||||
Ext.Direct.on("status", this.onStatus, this);
|
||||
if (!this.loaded) {
|
||||
this.loaded = true;
|
||||
this.getEl().mask(_T("common", "loading"), "x-mask-loading");
|
||||
this.load({
|
||||
scope: this,
|
||||
success: function (form, action) {
|
||||
this.getForm().findField("install_status").setValue(_V("ui", action.result.data.installed));
|
||||
if (action.result.data.updates > 0) {
|
||||
this.owner.setStatusOK({
|
||||
text: action.result.data.updates + " " + _V("ui", "updates_available")
|
||||
});
|
||||
}
|
||||
if (action.result.data.installed == "installing") {
|
||||
Ext.getCmp("synocommunity-gentoochroot-do_refresh").disable();
|
||||
Ext.getCmp("synocommunity-gentoochroot-do_update").disable();
|
||||
}
|
||||
this.getEl().unmask();
|
||||
SYNOCOMMUNITY.GentooChroot.Poller.connect();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
SYNOCOMMUNITY.GentooChroot.Poller.connect();
|
||||
}
|
||||
},
|
||||
onDeactivate: function () {
|
||||
Ext.Direct.un("status", this.onStatus, this);
|
||||
SYNOCOMMUNITY.GentooChroot.Poller.disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
// Services panel
|
||||
SYNOCOMMUNITY.GentooChroot.PanelServices = Ext.extend(Ext.grid.GridPanel, {
|
||||
constructor: function (config) {
|
||||
this.owner = config.owner;
|
||||
this.loaded = false;
|
||||
this.store = new Ext.data.DirectStore({
|
||||
autoSave: false,
|
||||
fields: ["id", "name", "launch_script", "status_command", "status"],
|
||||
api: {
|
||||
read: SYNOCOMMUNITY.GentooChroot.Remote.Services.read,
|
||||
create: SYNOCOMMUNITY.GentooChroot.Remote.Services.create,
|
||||
update: SYNOCOMMUNITY.GentooChroot.Remote.Services.update,
|
||||
destroy: SYNOCOMMUNITY.GentooChroot.Remote.Services.destroy
|
||||
},
|
||||
idProperty: "id",
|
||||
root: "data",
|
||||
writer: new Ext.data.JsonWriter({
|
||||
encode: false,
|
||||
listful: true,
|
||||
writeAllFields: true
|
||||
})
|
||||
});
|
||||
config = Ext.apply({
|
||||
itemId: "services",
|
||||
border: false,
|
||||
store: this.store,
|
||||
loadMask: true,
|
||||
tbar: {
|
||||
items: [{
|
||||
text: _V("ui", "add"),
|
||||
itemId: "add",
|
||||
scope: this,
|
||||
handler: this.onClickAdd
|
||||
}, {
|
||||
text: _V("ui", "edit"),
|
||||
itemId: "edit",
|
||||
scope: this,
|
||||
handler: this.onClickEdit
|
||||
}, {
|
||||
text: _V("ui", "delete"),
|
||||
itemId: "delete",
|
||||
scope: this,
|
||||
handler: this.onClickDelete
|
||||
}, {
|
||||
text: _V("ui", "start"),
|
||||
itemId: "start",
|
||||
scope: this,
|
||||
handler: this.onClickStart
|
||||
}, {
|
||||
text: _V("ui", "stop"),
|
||||
itemId: "stop",
|
||||
scope: this,
|
||||
handler: this.onClickStop
|
||||
}, {
|
||||
text: _V("ui", "refresh"),
|
||||
itemId: "refresh",
|
||||
scope: this,
|
||||
handler: this.onClickRefresh
|
||||
}]
|
||||
},
|
||||
columns: [{
|
||||
header: _V("ui", "name"),
|
||||
sortable: true,
|
||||
width: 35,
|
||||
dataIndex: "name"
|
||||
}, {
|
||||
header: _V("ui", "launch_script"),
|
||||
width: 45,
|
||||
dataIndex: "launch_script"
|
||||
}, {
|
||||
header: _V("ui", "status_command"),
|
||||
dataIndex: "status_command"
|
||||
}, {
|
||||
header: _V("ui", "status"),
|
||||
width: 25,
|
||||
dataIndex: "status",
|
||||
renderer: function (value, metaData, record, rowIndex, colIndex, store) {
|
||||
if (value) {
|
||||
return _V("ui", "running");
|
||||
}
|
||||
return _V("ui", "not_running");
|
||||
}
|
||||
}]
|
||||
}, config);
|
||||
SYNOCOMMUNITY.GentooChroot.PanelServices.superclass.constructor.call(this, config);
|
||||
},
|
||||
onActivate: function () {
|
||||
if (!this.loaded) {
|
||||
this.store.load();
|
||||
this.loaded = true;
|
||||
}
|
||||
},
|
||||
onClickAdd: function () {
|
||||
var editor = new SYNOCOMMUNITY.GentooChroot.ServiceEditorWindow({}, this.store);
|
||||
editor.open()
|
||||
},
|
||||
onClickEdit: function () {
|
||||
var editor = new SYNOCOMMUNITY.GentooChroot.ServiceEditorWindow({}, this.store, this.getSelectionModel().getSelected());
|
||||
editor.open()
|
||||
},
|
||||
onClickDelete: function () {
|
||||
var records = this.getSelectionModel().getSelections();
|
||||
if (records.length != 0) {
|
||||
this.store.remove(this.getSelectionModel().getSelections());
|
||||
this.store.save();
|
||||
}
|
||||
},
|
||||
onClickStart: function () {
|
||||
this.getSelectionModel().each(function (record) {
|
||||
SYNOCOMMUNITY.GentooChroot.Remote.Services.start(record.id, function (provider, response) {
|
||||
if (response.result) {
|
||||
record.set("status", true);
|
||||
record.commit();
|
||||
}
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
onClickStop: function () {
|
||||
this.getSelectionModel().each(function (record) {
|
||||
SYNOCOMMUNITY.GentooChroot.Remote.Services.stop(record.id, function (provider, response) {
|
||||
if (response.result) {
|
||||
record.set("status", false);
|
||||
record.commit();
|
||||
}
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
onClickRefresh: function () {
|
||||
this.store.load();
|
||||
}
|
||||
});
|
||||
|
||||
// Service window
|
||||
SYNOCOMMUNITY.GentooChroot.ServiceEditorWindow = Ext.extend(SYNO.SDS.ModalWindow, {
|
||||
title: _V("ui", "service"),
|
||||
constructor: function (config, store, record) {
|
||||
this.store = store;
|
||||
this.record = record;
|
||||
this.panel = new SYNOCOMMUNITY.GentooChroot.PanelServiceEditor({}, record);
|
||||
config = Ext.apply(config, {
|
||||
width: 550,
|
||||
height: 210,
|
||||
resizable: false,
|
||||
layout: "fit",
|
||||
items: [this.panel],
|
||||
buttons: [{
|
||||
text: _T("common", "apply"),
|
||||
scope: this,
|
||||
handler: this.onClickApply
|
||||
}, {
|
||||
text: _T("common", "close"),
|
||||
scope: this,
|
||||
handler: this.onClickClose
|
||||
}]
|
||||
})
|
||||
SYNOCOMMUNITY.GentooChroot.ServiceEditorWindow.superclass.constructor.call(this, config);
|
||||
},
|
||||
onClickApply: function () {
|
||||
if (this.record === undefined) {
|
||||
var record = new this.store.recordType({
|
||||
name: this.panel.getForm().findField("name").getValue(),
|
||||
launch_script: this.panel.getForm().findField("launch_script").getValue(),
|
||||
status_command: this.panel.getForm().findField("status_command").getValue()
|
||||
});
|
||||
this.store.add(record);
|
||||
} else {
|
||||
this.record.beginEdit();
|
||||
this.record.set("name", this.panel.getForm().findField("name").getValue());
|
||||
this.record.set("launch_script", this.panel.getForm().findField("launch_script").getValue());
|
||||
this.record.set("status_command", this.panel.getForm().findField("status_command").getValue());
|
||||
this.record.endEdit();
|
||||
}
|
||||
this.store.save();
|
||||
this.close();
|
||||
},
|
||||
onClickClose: function () {
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
|
||||
// Service panel
|
||||
SYNOCOMMUNITY.GentooChroot.PanelServiceEditor = Ext.extend(SYNOCOMMUNITY.GentooChroot.FormPanel, {
|
||||
constructor: function (config, record) {
|
||||
this.record = record;
|
||||
config = Ext.apply({
|
||||
itemId: "service",
|
||||
padding: "15px 15px 2px 15px",
|
||||
defaultType: "textfield",
|
||||
labelWidth: 130,
|
||||
fbar: null,
|
||||
defaults: {
|
||||
anchor: "-20"
|
||||
},
|
||||
items: [{
|
||||
fieldLabel: _V("ui", "name"),
|
||||
name: "name"
|
||||
}, {
|
||||
fieldLabel: _V("ui", "launch_script"),
|
||||
name: "launch_script"
|
||||
}, {
|
||||
fieldLabel: _V("ui", "status_command"),
|
||||
name: "status_command"
|
||||
}]
|
||||
}, config);
|
||||
SYNOCOMMUNITY.GentooChroot.PanelServiceEditor.superclass.constructor.call(this, config);
|
||||
if (this.record !== undefined) {
|
||||
this.loadRecord();
|
||||
}
|
||||
},
|
||||
loadRecord: function () {
|
||||
this.getForm().findField("name").setValue(this.record.data.name);
|
||||
this.getForm().findField("launch_script").setValue(this.record.data.launch_script);
|
||||
this.getForm().findField("status_command").setValue(this.record.data.status_command);
|
||||
}
|
||||
});
|
47
spk/gentoo-chroot/src/app/help/enu/index.html
Normal file
@ -0,0 +1,47 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Help - Gentoo Chroot</title>
|
||||
<link href="/webman/help/help.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Gentoo Chroot</h1>
|
||||
<p><a href="http://www.gentoo.org/">Gentoo</a> is a free operating system based on either Linux or FreeBSD that can be automatically optimized and customized for just about any application or need. Gentoo Chroot allows you to install the Gentoo OS inside your DiskStation, alongside DSM. <em>This package is intended for advanced users only</em>.</p>
|
||||
<h2>Installation</h2>
|
||||
<p>Once the <em>package</em> installation has finished in the Package Center, the installation of the <em>chroot environment</em> continues in the background. Open <b>Gentoo Chroot</b> from the <b>Main Menu</b> of DSM and you can see its status under <b>Overview</b> in the left pane. When the installation finishes, the status will automatically change to <b>Installed</b>.</p>
|
||||
<h3>Initial Setup</h3>
|
||||
<p>Due to the custom nature of Gentoo, this package installs a very minimal Gentoo installation to your DiskStation and leaves the setup and configuration up to you.</p>
|
||||
<p>As soon as the status of the <em>chroot environment</em> is <b>Installed</b>, you can begin configuring your new installation of Gentoo. To do so, connect to the DiskStation through SSH (root user) and use the following commands:</p>
|
||||
<ol>
|
||||
<li><code>/var/packages/gentoo-chroot/scripts/start-stop-status start</code></li>
|
||||
<li><code>/var/packages/gentoo-chroot/scripts/start-stop-status chroot</code></li>
|
||||
<li><code>env-update</code></li>
|
||||
<li><code>source /etc/profile</code></li>
|
||||
<li><code>export PS1="(chroot) $PS1"</code></li>
|
||||
</ol>
|
||||
<p>Unless you know what you are doing, it is <em>strongly</em> recommended that you to continue the setup of your installation of Gentoo by following from the relevant section of the official Gentoo handbook: <a href="http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=1&chap=6#doc_chap2">here</a>.</p>
|
||||
<h2>App Usage</h2>
|
||||
<h3>Overview</h3>
|
||||
<p>From the Gentoo Chroot app, you can monitor how many services are running, perform update operations and manage services.</p>
|
||||
<h3>Updates</h3>
|
||||
<p>Gentoo uses <a href="http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=2&chap=1">Portage</a> to handle package updates.</p>
|
||||
<p>Again, due to the custom nature of Gentoo, usually it's best to perform package updates via the command-line interface to Portage: <code><a href="http://dev.gentoo.org/~zmedico/portage/doc/man/emerge.1.html">emerge</a></code>. As <code>emerge</code> generally provides a greater amount of control over the packages that are installed and updated in your installation of Gentoo, wherever possible it's advisable to update your Gentoo installation manually using via the command-line.</p>
|
||||
<p>If you just want to quickly check for available updates for Gentoo, simply click <b>Update</b> and Portage will sync with the package tree, then inform you of how many updates are available.</p>
|
||||
<p>Whilst it's generally better to update Gentoo via the command-line, you can perform a quick update by simply clicking <b>Update</b>.</p>
|
||||
<h3>Services</h3>
|
||||
<p>Gentoo Chroot allows you to manage the packages you installed in the chroot directly from DSM.</p>
|
||||
<p>Under <b>Services</b> in the left pane, you can manage services that you manually installed previously in the chroot: start and stop them easily.</p>
|
||||
<h4>Configuration</h4>
|
||||
<ol>
|
||||
<li>Manually install in the chroot the service you chose.</li>
|
||||
<li>Configure it by editing the correct configuration files.</li>
|
||||
<li>In the interface, click on <b>Add</b> and fill the form. The <b>Launch script</b> will be launched with the <code>start</code> argument to start the service and <code>stop</code> to stop it. The <b>Status command</b> should return exit code <code>0</code> (success) if the service is started, or <code>>0</code> (error) if it is stopped.</li>
|
||||
</ol>
|
||||
<h4>Example: SSH Server</h4>
|
||||
<ol>
|
||||
<li>Edit the configuration file: <code>/etc/ssh/sshd_config</code>.</li>
|
||||
<li>Change the port number and other things if necessary.</li>
|
||||
<li>Click on <b>Add</b> and put the name <code>SSHD</code>, the launch script <code>rc-service sshd</code> and the status command <code>rc-service sshd status</code>.</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
BIN
spk/gentoo-chroot/src/app/images/accept.png
Normal file
After Width: | Height: | Size: 781 B |
BIN
spk/gentoo-chroot/src/app/images/delete.png
Normal file
After Width: | Height: | Size: 715 B |
BIN
spk/gentoo-chroot/src/app/images/gentoo-chroot-16.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
spk/gentoo-chroot/src/app/images/gentoo-chroot-24.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
spk/gentoo-chroot/src/app/images/gentoo-chroot-32.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
spk/gentoo-chroot/src/app/images/gentoo-chroot-48.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
spk/gentoo-chroot/src/app/images/list_item_active.png
Normal file
After Width: | Height: | Size: 386 B |
BIN
spk/gentoo-chroot/src/app/images/list_item_hover.png
Normal file
After Width: | Height: | Size: 379 B |
BIN
spk/gentoo-chroot/src/app/images/overview.png
Normal file
After Width: | Height: | Size: 524 B |
BIN
spk/gentoo-chroot/src/app/images/pencil.png
Normal file
After Width: | Height: | Size: 450 B |
BIN
spk/gentoo-chroot/src/app/images/services.png
Normal file
After Width: | Height: | Size: 718 B |
BIN
spk/gentoo-chroot/src/app/images/synocommunity.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
6
spk/gentoo-chroot/src/app/setup.py
Normal file
@ -0,0 +1,6 @@
|
||||
#!/usr/local/gentoo-chroot/env/bin/python
|
||||
from application.db import setup
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
setup()
|
7
spk/gentoo-chroot/src/app/start.py
Normal file
@ -0,0 +1,7 @@
|
||||
#!/usr/local/gentoo-chroot/env/bin/python
|
||||
from application.direct import Services
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
services = Services()
|
||||
services.start_all()
|
7
spk/gentoo-chroot/src/app/stop.py
Normal file
@ -0,0 +1,7 @@
|
||||
#!/usr/local/gentoo-chroot/env/bin/python
|
||||
from application.direct import Services
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
services = Services()
|
||||
services.stop_all()
|
60
spk/gentoo-chroot/src/app/style.css
Normal file
@ -0,0 +1,60 @@
|
||||
/* List view customized style */
|
||||
.synocommunity-gentoochroot-list {
|
||||
background-color: #E1ECFA !important;
|
||||
}
|
||||
|
||||
.synocommunity-gentoochroot-list .x-list-selected {
|
||||
background-image: url(images/list_item_active.png);
|
||||
background-position: right top;
|
||||
color: #FFF;
|
||||
}
|
||||
.synocommunity-gentoochroot-list .x-list-over {
|
||||
background-image: url(images/list_item_hover.png);
|
||||
background-position: right top;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.synocommunity-gentoochroot-list-column div {
|
||||
background-repeat: no-repeat;
|
||||
padding-left: 20px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.synocommunity-gentoochroot .synocommunity-gentoochroot-list .x-panel-body {
|
||||
background-color: #E1ECFA;
|
||||
background-image: url(images/synocommunity.png);
|
||||
background-position: center bottom;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
/* List view icons */
|
||||
.synocommunity-gentoochroot-list-overview {
|
||||
background-image: url(images/overview.png);
|
||||
margin-left: 16px;
|
||||
}
|
||||
.synocommunity-gentoochroot-list-services {
|
||||
background-image: url(images/services.png);
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
/* Titles */
|
||||
.synocommunity-gentoochroot-list-column div.synocommunity-gentoochroot-list-console_title {
|
||||
margin-top: 8px;
|
||||
padding-left: 0;
|
||||
color: #003C66 !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.x-list-over .synocommunity-gentoochroot-list-column div.synocommunity-gentoochroot-list-console_title {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.synocommunity-gentoochroot-compositefield-button {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ext-ie8 .synocommunity-gentoochroot .x-toolbar-cell .x-form-field-trigger-wrap .x-form-trigger {
|
||||
right: auto
|
||||
}
|
36
spk/gentoo-chroot/src/app/texts/enu/strings
Normal file
@ -0,0 +1,36 @@
|
||||
[app]
|
||||
app_name = "Gentoo Chroot"
|
||||
description = "Management UI for Gentoo Chroot"
|
||||
|
||||
[help]
|
||||
description = "SynoCommunity Gentoo Chroot"
|
||||
|
||||
[ui]
|
||||
console = "Console"
|
||||
overview = "Overview"
|
||||
services = "Services"
|
||||
service = "Service"
|
||||
information = "Information"
|
||||
status = "Status"
|
||||
running_services = "Running services"
|
||||
installed = "Installed"
|
||||
installing = "Installing"
|
||||
available_updates = "Available Update(s)"
|
||||
do_refresh = "Refresh"
|
||||
updates_available = "update(s) available"
|
||||
cannot_refresh = "Error occurred whilst updating the Portage tree"
|
||||
do_update = "Update"
|
||||
cannot_update = "Error occurred during update"
|
||||
update_successful = "Update successful"
|
||||
name = "Name"
|
||||
launch_script = "Launch script"
|
||||
status_command = "Status command"
|
||||
actions = "Actions"
|
||||
start = "Start"
|
||||
stop = "Stop"
|
||||
add = "Add"
|
||||
edit = "Edit"
|
||||
delete = "Delete"
|
||||
refresh = "Refresh"
|
||||
running = "Started"
|
||||
not_running = "Stopped"
|
126
spk/gentoo-chroot/src/dsm-control.sh
Executable file
@ -0,0 +1,126 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Package
|
||||
PACKAGE="gentoo-chroot"
|
||||
DNAME="Gentoo Chroot"
|
||||
|
||||
# Others
|
||||
INSTALL_DIR="/usr/local/${PACKAGE}"
|
||||
PATH="${INSTALL_DIR}/bin:${PATH}"
|
||||
CHROOTTARGET=`realpath ${INSTALL_DIR}/var/chroottarget`
|
||||
|
||||
start_daemon ()
|
||||
{
|
||||
# Mount if install is finished
|
||||
if [ -f ${INSTALL_DIR}/var/installed ]; then
|
||||
# Make sure we don't mount twice
|
||||
grep -q "${CHROOTTARGET}/proc " /proc/mounts || mount -t proc proc ${CHROOTTARGET}/proc
|
||||
grep -q "${CHROOTTARGET}/sys " /proc/mounts || mount -t sysfs sys ${CHROOTTARGET}/sys
|
||||
grep -q "${CHROOTTARGET}/dev " /proc/mounts || mount -o bind /dev ${CHROOTTARGET}/dev
|
||||
grep -q "${CHROOTTARGET}/dev/pts " /proc/mounts || mount -o bind /dev/pts ${CHROOTTARGET}/dev/pts
|
||||
test -d "${CHROOTTARGET}/dev/fd" || ln -s '../proc/self/fd' ${CHROOTTARGET}/dev/fd
|
||||
grep -q "${CHROOTTARGET}/tmp " /proc/mounts || mount -t tmpfs /tmp ${CHROOTTARGET}/tmp
|
||||
|
||||
# Mount user specified directories, if specified
|
||||
if [ -f ${INSTALL_DIR}/etc/mounts ]; then
|
||||
if [ `sed -e 's/#.*$//g' -e '/^$/d' ${INSTALL_DIR}/etc/mounts | wc -l` != 0 ]; then
|
||||
sed -e 's/#.*$//g' -e '/^$/d' ${INSTALL_DIR}/etc/mounts | while read mount; do
|
||||
SRC=$(echo $mount | awk '{ print $1 }')
|
||||
DST=$(echo $mount | awk '{ print $2 }' | cut -c 2-)
|
||||
grep -q "${CHROOTTARGET}/${DST} " /proc/mounts || mount -o bind $SRC ${CHROOTTARGET}/${DST}
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start all services
|
||||
${INSTALL_DIR}/app/start.py
|
||||
fi
|
||||
}
|
||||
|
||||
stop_daemon ()
|
||||
{
|
||||
# Stop running services
|
||||
${INSTALL_DIR}/app/stop.py
|
||||
|
||||
# Unmount
|
||||
test -L ${CHROOTTARGET}/dev/fd && rm ${CHROOTTARGET}/dev/fd
|
||||
for mount in `grep ${CHROOTTARGET} /proc/mounts | awk '{ print $2 }'`; do umount -l $mount; done
|
||||
|
||||
}
|
||||
|
||||
daemon_status ()
|
||||
{
|
||||
`grep -q "${CHROOTTARGET}/proc " /proc/mounts` && `grep -q "${CHROOTTARGET}/sys " /proc/mounts` && `grep -q "${CHROOTTARGET}/dev " /proc/mounts` && `grep -q "${CHROOTTARGET}/dev/pts " /proc/mounts` && `grep -q "${CHROOTTARGET}/tmp " /proc/mounts` && `test -d "${CHROOTTARGET}/dev/fd"`
|
||||
}
|
||||
|
||||
|
||||
case $1 in
|
||||
start)
|
||||
if daemon_status; then
|
||||
echo ${DNAME} is already running
|
||||
exit 0
|
||||
else
|
||||
echo Starting ${DNAME} ...
|
||||
start_daemon
|
||||
exit $?
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
if daemon_status; then
|
||||
echo Stopping ${DNAME} ...
|
||||
stop_daemon
|
||||
exit 0
|
||||
else
|
||||
echo ${DNAME} is not running
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
restart)
|
||||
if daemon_status; then
|
||||
echo Stopping ${DNAME} ... && \
|
||||
stop_daemon && \
|
||||
echo Starting ${DNAME} ... && \
|
||||
start_daemon && \
|
||||
exit 0
|
||||
else
|
||||
echo ${DNAME} is not running
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
if daemon_status; then
|
||||
echo ${DNAME} is running
|
||||
exit 0
|
||||
else
|
||||
echo ${DNAME} is not running
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
chroot)
|
||||
if daemon_status; then
|
||||
echo Entering chroot...
|
||||
chroot ${CHROOTTARGET}/ /bin/bash
|
||||
else
|
||||
echo WARNING: ${DNAME} is not running
|
||||
echo WARNING: The chroot environment will not have access to /proc, /dev, /sys or /tmp which could cause problems!
|
||||
echo Entering chroot...
|
||||
chroot ${CHROOTTARGET}/ /bin/bash
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
log)
|
||||
if [ -f ${CHROOTTARGET}/var/log/syslog ]; then
|
||||
echo ${CHROOTTARGET}/var/log/syslog
|
||||
exit 0
|
||||
elif [ -f ${CHROOTTARGET}/var/log/messages ]; then
|
||||
echo ${CHROOTTARGET}/var/log/messages
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "You must provide an argument to this script; either 'start', 'stop', 'restart', 'status' or 'chroot'"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
BIN
spk/gentoo-chroot/src/gentoo.png
Normal file
After Width: | Height: | Size: 1.1 MiB |
82
spk/gentoo-chroot/src/installer.sh
Executable file
@ -0,0 +1,82 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Package
|
||||
PACKAGE="gentoo-chroot"
|
||||
DNAME="Gentoo Chroot"
|
||||
|
||||
# Others
|
||||
INSTALL_DIR="/usr/local/${PACKAGE}"
|
||||
PYTHON_DIR="/usr/local/python"
|
||||
CHROOTTARGET="${INSTALL_DIR}/var/chroottarget"
|
||||
PATH="${INSTALL_DIR}/bin:${INSTALL_DIR}/env/bin:${PYTHON_DIR}/bin:${PATH}"
|
||||
CHROOT_PATH="/usr/local/bin:/usr/bin:/bin"
|
||||
VIRTUALENV="${PYTHON_DIR}/bin/virtualenv"
|
||||
TMP_DIR="${SYNOPKG_PKGDEST}/../../@tmp"
|
||||
|
||||
preinst ()
|
||||
{
|
||||
exit 0
|
||||
}
|
||||
|
||||
postinst ()
|
||||
{
|
||||
# Link
|
||||
ln -s ${SYNOPKG_PKGDEST} ${INSTALL_DIR}
|
||||
|
||||
# Create a Python virtualenv
|
||||
${VIRTUALENV} --system-site-packages ${INSTALL_DIR}/env > /dev/null
|
||||
|
||||
# Install the wheels/requirements
|
||||
${INSTALL_DIR}/env/bin/pip install --use-wheel --no-deps --no-index -U --force-reinstall -f ${INSTALL_DIR}/share/wheelhouse -r ${INSTALL_DIR}/share/wheelhouse/requirements.txt > /dev/null 2>&1
|
||||
|
||||
# Setup the database
|
||||
${INSTALL_DIR}/env/bin/python ${INSTALL_DIR}/app/setup.py
|
||||
|
||||
# Configure the chroot environment
|
||||
if [ "${SYNOPKG_PKG_STATUS}" != "UPGRADE" ]; then
|
||||
cp /etc/hosts /etc/resolv.conf ${CHROOTTARGET}/etc/
|
||||
echo 'hostname="'`hostname -s`'"' > ${CHROOTTARGET}/etc/conf.d/hostname
|
||||
touch ${CHROOTTARGET}/run/openrc/softlevel
|
||||
touch ${CHROOTTARGET}/var/run/utmp
|
||||
touch ${CHROOTTARGET}/var/log/wtmp
|
||||
touch ${INSTALL_DIR}/var/installed
|
||||
fi
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
preuninst ()
|
||||
{
|
||||
exit 0
|
||||
}
|
||||
|
||||
postuninst ()
|
||||
{
|
||||
# Remove link
|
||||
rm -f ${INSTALL_DIR}
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
preupgrade ()
|
||||
{
|
||||
# Save some stuff
|
||||
rm -fr ${TMP_DIR}/${PACKAGE}
|
||||
mkdir -p ${TMP_DIR}/${PACKAGE}
|
||||
mv ${INSTALL_DIR}/etc ${TMP_DIR}/${PACKAGE}/
|
||||
mv ${INSTALL_DIR}/var ${TMP_DIR}/${PACKAGE}/
|
||||
exit 0
|
||||
}
|
||||
|
||||
postupgrade ()
|
||||
{
|
||||
# Restore some stuff
|
||||
rm -fr ${INSTALL_DIR}/etc
|
||||
rm -fr ${INSTALL_DIR}/var
|
||||
mv ${TMP_DIR}/${PACKAGE}/etc ${INSTALL_DIR}/
|
||||
mv ${TMP_DIR}/${PACKAGE}/var ${INSTALL_DIR}/
|
||||
rm -fr ${TMP_DIR}/${PACKAGE}
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
5
spk/gentoo-chroot/src/mounts
Normal file
@ -0,0 +1,5 @@
|
||||
# Enter any custom mounts below.
|
||||
|
||||
# Use the following format:
|
||||
# /path/to/host/dir /path/inside/chroot
|
||||
|