Bring up to date with cockpit starter kit
This encompasses a number of changes to the build process.
This commit is contained in:
parent
a0fffde59d
commit
235f110ec7
32 changed files with 533 additions and 1172 deletions
4
.babelrc
4
.babelrc
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"presets": ["@babel/env",
|
|
||||||
"@babel/preset-react"]
|
|
||||||
}
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
node_modules/*
|
node_modules/*
|
||||||
|
pkg/lib/*
|
||||||
|
|
|
||||||
108
.eslintrc.json
108
.eslintrc.json
|
|
@ -1,67 +1,51 @@
|
||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"es6": true
|
"es6": true
|
||||||
},
|
|
||||||
"extends": ["eslint:recommended", "standard", "standard-react"],
|
|
||||||
"parser": "@babel/eslint-parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": "7",
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"jsx": true
|
|
||||||
},
|
},
|
||||||
"sourceType": "module"
|
"extends": ["eslint:recommended", "standard", "standard-jsx", "react-app"],
|
||||||
},
|
"parserOptions": {
|
||||||
"plugins": ["flowtype", "react", "react-hooks"],
|
"ecmaVersion": "7",
|
||||||
"rules": {
|
"ecmaFeatures": {
|
||||||
"indent": [
|
"jsx": true
|
||||||
"error",
|
},
|
||||||
4,
|
"sourceType": "module"
|
||||||
{
|
},
|
||||||
"ObjectExpression": "first",
|
"plugins": ["flowtype", "react", "react-hooks"],
|
||||||
"CallExpression": { "arguments": "first" },
|
"rules": {
|
||||||
"MemberExpression": 2,
|
"indent": ["error", 4,
|
||||||
"ignoredNodes": ["JSXAttribute"]
|
{
|
||||||
}
|
"ObjectExpression": "first",
|
||||||
],
|
"CallExpression": {"arguments": "first"},
|
||||||
"newline-per-chained-call": ["error", { "ignoreChainWithDepth": 2 }],
|
"MemberExpression": 2,
|
||||||
"lines-between-class-members": [
|
"ignoredNodes": [ "JSXAttribute" ]
|
||||||
"error",
|
}],
|
||||||
"always",
|
"newline-per-chained-call": ["error", { "ignoreChainWithDepth": 2 }],
|
||||||
{ "exceptAfterSingleLine": true }
|
"no-var": "error",
|
||||||
],
|
"lines-between-class-members": ["error", "always", { "exceptAfterSingleLine": true }],
|
||||||
"prefer-promise-reject-errors": ["error", { "allowEmptyReject": true }],
|
"prefer-promise-reject-errors": ["error", { "allowEmptyReject": true }],
|
||||||
"react/jsx-indent": ["error", 4],
|
"react/jsx-indent": ["error", 4],
|
||||||
"semi": ["error", "always", { "omitLastInOneLineBlock": true }],
|
"semi": ["error", "always", { "omitLastInOneLineBlock": true }],
|
||||||
|
|
||||||
"react-hooks/rules-of-hooks": "error",
|
"react-hooks/rules-of-hooks": "error",
|
||||||
"react-hooks/exhaustive-deps": "error",
|
"react-hooks/exhaustive-deps": "error",
|
||||||
|
|
||||||
"camelcase": "off",
|
"camelcase": "off",
|
||||||
"comma-dangle": "off",
|
"comma-dangle": "off",
|
||||||
"curly": "off",
|
"curly": "off",
|
||||||
"jsx-quotes": "off",
|
"jsx-quotes": "off",
|
||||||
"key-spacing": "off",
|
"key-spacing": "off",
|
||||||
"new-cap": "off",
|
"no-console": "off",
|
||||||
"no-console": "off",
|
"quotes": "off",
|
||||||
"prefer-const": "off",
|
"react/jsx-curly-spacing": "off",
|
||||||
"quotes": "off",
|
"react/jsx-indent-props": "off",
|
||||||
"react/jsx-closing-bracket-location": "off",
|
"react/prop-types": "off",
|
||||||
"react/jsx-curly-spacing": "off",
|
"space-before-function-paren": "off",
|
||||||
"react/jsx-indent-props": "off",
|
"standard/no-callback-literal": "off"
|
||||||
"react/jsx-handler-names": "off",
|
},
|
||||||
"react/prop-types": "off",
|
"globals": {
|
||||||
"space-before-function-paren": "off",
|
"require": false,
|
||||||
"standard/no-callback-literal": "off",
|
"module": false
|
||||||
|
}
|
||||||
"eqeqeq": "off",
|
|
||||||
"import/no-webpack-loader-syntax": "off",
|
|
||||||
"object-property-newline": "off",
|
|
||||||
"react/jsx-no-bind": "off"
|
|
||||||
},
|
|
||||||
"globals": {
|
|
||||||
"require": false,
|
|
||||||
"module": false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -4,15 +4,16 @@
|
||||||
*.rpm
|
*.rpm
|
||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
lib/
|
|
||||||
/*.spec
|
/*.spec
|
||||||
/.vagrant
|
/.vagrant
|
||||||
package-lock.json
|
package-lock.json
|
||||||
Test*FAIL*
|
Test*FAIL*
|
||||||
bots/
|
/bots
|
||||||
test/common/
|
test/common/
|
||||||
test/images/
|
test/images/
|
||||||
|
pkg
|
||||||
*.pot
|
*.pot
|
||||||
POTFILES*
|
POTFILES*
|
||||||
tmp/
|
tmp/
|
||||||
.mypy_cache
|
/po/LINGUAS
|
||||||
|
/tools
|
||||||
|
|
|
||||||
38
.stylelintrc.json
Normal file
38
.stylelintrc.json
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"extends": "stylelint-config-standard-scss",
|
||||||
|
"rules": {
|
||||||
|
"declaration-colon-newline-after": null,
|
||||||
|
"selector-list-comma-newline-after": null,
|
||||||
|
|
||||||
|
"at-rule-empty-line-before": null,
|
||||||
|
"declaration-colon-space-before": null,
|
||||||
|
"declaration-empty-line-before": null,
|
||||||
|
"custom-property-empty-line-before": null,
|
||||||
|
"comment-empty-line-before": null,
|
||||||
|
"scss/double-slash-comment-empty-line-before": null,
|
||||||
|
"scss/dollar-variable-colon-space-after": null,
|
||||||
|
|
||||||
|
"custom-property-pattern": null,
|
||||||
|
"declaration-block-no-duplicate-properties": null,
|
||||||
|
"declaration-block-no-redundant-longhand-properties": null,
|
||||||
|
"declaration-block-no-shorthand-property-overrides": null,
|
||||||
|
"declaration-block-single-line-max-declarations": null,
|
||||||
|
"font-family-no-duplicate-names": null,
|
||||||
|
"function-url-quotes": null,
|
||||||
|
"indentation": null,
|
||||||
|
"keyframes-name-pattern": null,
|
||||||
|
"max-line-length": null,
|
||||||
|
"no-descending-specificity": null,
|
||||||
|
"no-duplicate-selectors": null,
|
||||||
|
"scss/at-extend-no-missing-placeholder": null,
|
||||||
|
"scss/at-import-partial-extension": null,
|
||||||
|
"scss/at-mixin-pattern": null,
|
||||||
|
"scss/comment-no-empty": null,
|
||||||
|
"scss/dollar-variable-pattern": null,
|
||||||
|
"scss/double-slash-comment-whitespace-inside": null,
|
||||||
|
"scss/no-global-function-names": null,
|
||||||
|
"scss/operator-no-unspaced": null,
|
||||||
|
"selector-class-pattern": null,
|
||||||
|
"selector-id-pattern": null
|
||||||
|
}
|
||||||
|
}
|
||||||
13
.tasks
13
.tasks
|
|
@ -1,13 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# When run automated, randomize to minimize stampeding herd
|
|
||||||
if [ -t 0 ]; then
|
|
||||||
chance=10
|
|
||||||
else
|
|
||||||
chance=$(shuf -i 0-10 -n 1)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $chance -gt 9 ]; then
|
|
||||||
# Open issues for things that need doing on a regular basis
|
|
||||||
bots/npm-trigger
|
|
||||||
fi
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
dist: trusty
|
|
||||||
sudo: false
|
|
||||||
language: node_js
|
|
||||||
node_js:
|
|
||||||
- "8"
|
|
||||||
script:
|
|
||||||
- npm install
|
|
||||||
- npm run build
|
|
||||||
17
Dockerfile
17
Dockerfile
|
|
@ -1,17 +0,0 @@
|
||||||
FROM fedora:35
|
|
||||||
|
|
||||||
COPY . cockpit-session-recording
|
|
||||||
|
|
||||||
RUN sudo dnf -y install \
|
|
||||||
git \
|
|
||||||
gnupg \
|
|
||||||
intltool \
|
|
||||||
libappstream-glib \
|
|
||||||
make \
|
|
||||||
npm \
|
|
||||||
rpm-build \
|
|
||||||
rpmdevtools \
|
|
||||||
rsync \
|
|
||||||
tar
|
|
||||||
|
|
||||||
RUN cd cockpit-session-recording && make rpm
|
|
||||||
221
Makefile
221
Makefile
|
|
@ -3,24 +3,45 @@ PACKAGE_NAME := $(shell awk '/"name":/ {gsub(/[",]/, "", $$2); print $$2}' packa
|
||||||
RPM_NAME := cockpit-$(PACKAGE_NAME)
|
RPM_NAME := cockpit-$(PACKAGE_NAME)
|
||||||
VERSION := $(shell T=$$(git describe 2>/dev/null) || T=1; echo $$T | tr '-' '.')
|
VERSION := $(shell T=$$(git describe 2>/dev/null) || T=1; echo $$T | tr '-' '.')
|
||||||
ifeq ($(TEST_OS),)
|
ifeq ($(TEST_OS),)
|
||||||
TEST_OS = rhel-x
|
TEST_OS = centos-8-stream
|
||||||
endif
|
endif
|
||||||
export TEST_OS
|
export TEST_OS
|
||||||
TARFILE=cockpit-$(PACKAGE_NAME)-$(VERSION).tar.xz
|
TARFILE=$(RPM_NAME)-$(VERSION).tar.xz
|
||||||
|
NODE_CACHE=$(RPM_NAME)-node-$(VERSION).tar.xz
|
||||||
SPEC=$(RPM_NAME).spec
|
SPEC=$(RPM_NAME).spec
|
||||||
# rpmspec -q behaves differently in Fedora ≥ 37
|
PREFIX ?= /usr/local
|
||||||
RPMQUERY=$(shell rpmspec -D"VERSION $(VERSION)" -q --srpm $(SPEC).in).rpm
|
APPSTREAMFILE=org.cockpit-project.$(PACKAGE_NAME).metainfo.xml
|
||||||
SRPMFILE=$(subst noarch,src,$(RPMQUERY))
|
|
||||||
RPMFILE=$(subst src,noarch,$(RPMQUERY))
|
|
||||||
VM_IMAGE=$(CURDIR)/test/images/$(TEST_OS)
|
VM_IMAGE=$(CURDIR)/test/images/$(TEST_OS)
|
||||||
# stamp file to check if/when npm install ran
|
# stamp file to check for node_modules/
|
||||||
NODE_MODULES_TEST=package-lock.json
|
NODE_MODULES_TEST=package-lock.json
|
||||||
# one example file in dist/ from webpack to check if that already ran
|
# one example file in dist/ from bundler to check if that already ran
|
||||||
WEBPACK_TEST=dist/manifest.json
|
DIST_TEST=dist/manifest.json
|
||||||
# one example file in src/lib to check if it was already checked out
|
# one example file in pkg/lib to check if it was already checked out
|
||||||
LIB_TEST=src/lib/cockpit-po-plugin.js
|
COCKPIT_REPO_STAMP=pkg/lib/cockpit-po-plugin.js
|
||||||
|
# common arguments for tar, mostly to make the generated tarballs reproducible
|
||||||
|
TAR_ARGS = --sort=name --mtime "@$(shell git show --no-patch --format='%at')" --mode=go=rX,u+rw,a-s --numeric-owner --owner=0 --group=0
|
||||||
|
|
||||||
all: $(WEBPACK_TEST)
|
all: $(DIST_TEST)
|
||||||
|
|
||||||
|
# checkout common files from Cockpit repository required to build this project;
|
||||||
|
# this has no API stability guarantee, so check out a stable tag when you start
|
||||||
|
# a new project, use the latest release, and update it from time to time
|
||||||
|
COCKPIT_REPO_FILES = \
|
||||||
|
pkg/lib \
|
||||||
|
test/common \
|
||||||
|
tools/git-utils.sh \
|
||||||
|
tools/make-bots \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
COCKPIT_REPO_URL = https://github.com/cockpit-project/cockpit.git
|
||||||
|
COCKPIT_REPO_COMMIT = 6073b2703acd68e216bd9dbc116c30d2d7a9701c # 288.1 + esbuild plugin updates
|
||||||
|
|
||||||
|
$(COCKPIT_REPO_FILES): $(COCKPIT_REPO_STAMP)
|
||||||
|
COCKPIT_REPO_TREE = '$(strip $(COCKPIT_REPO_COMMIT))^{tree}'
|
||||||
|
$(COCKPIT_REPO_STAMP): Makefile
|
||||||
|
@git rev-list --quiet --objects $(COCKPIT_REPO_TREE) -- 2>/dev/null || \
|
||||||
|
git fetch --no-tags --no-write-fetch-head --depth=1 $(COCKPIT_REPO_URL) $(COCKPIT_REPO_COMMIT)
|
||||||
|
git archive $(COCKPIT_REPO_TREE) -- $(COCKPIT_REPO_FILES) | tar x
|
||||||
|
|
||||||
#
|
#
|
||||||
# i18n
|
# i18n
|
||||||
|
|
@ -28,95 +49,98 @@ all: $(WEBPACK_TEST)
|
||||||
|
|
||||||
LINGUAS=$(basename $(notdir $(wildcard po/*.po)))
|
LINGUAS=$(basename $(notdir $(wildcard po/*.po)))
|
||||||
|
|
||||||
po/POTFILES.js.in:
|
po/$(PACKAGE_NAME).js.pot:
|
||||||
mkdir -p $(dir $@)
|
xgettext --default-domain=$(PACKAGE_NAME) --output=$@ --language=C --keyword= \
|
||||||
find src/ -name '*.js' -o -name '*.jsx' > $@
|
--keyword=_:1,1t --keyword=_:1c,2,2t --keyword=C_:1c,2 \
|
||||||
|
|
||||||
po/$(PACKAGE_NAME).js.pot: po/POTFILES.js.in
|
|
||||||
xgettext --default-domain=cockpit --output=$@ --language=C --keyword= \
|
|
||||||
--keyword=_:1,1t --keyword=_:1c,2,1t --keyword=C_:1c,2 \
|
|
||||||
--keyword=N_ --keyword=NC_:1c,2 \
|
--keyword=N_ --keyword=NC_:1c,2 \
|
||||||
--keyword=gettext:1,1t --keyword=gettext:1c,2,2t \
|
--keyword=gettext:1,1t --keyword=gettext:1c,2,2t \
|
||||||
--keyword=ngettext:1,2,3t --keyword=ngettext:1c,2,3,4t \
|
--keyword=ngettext:1,2,3t --keyword=ngettext:1c,2,3,4t \
|
||||||
--keyword=gettextCatalog.getString:1,3c --keyword=gettextCatalog.getPlural:2,3,4c \
|
--keyword=gettextCatalog.getString:1,3c --keyword=gettextCatalog.getPlural:2,3,4c \
|
||||||
--from-code=UTF-8 --files-from=$^
|
--from-code=UTF-8 $$(find src/ -name '*.js' -o -name '*.jsx')
|
||||||
|
|
||||||
po/POTFILES.html.in:
|
po/$(PACKAGE_NAME).html.pot: $(NODE_MODULES_TEST) $(COCKPIT_REPO_STAMP)
|
||||||
mkdir -p $(dir $@)
|
pkg/lib/html2po.js -o $@ $$(find src -name '*.html')
|
||||||
find src -name '*.html' > $@
|
|
||||||
|
|
||||||
po/$(PACKAGE_NAME).html.pot: po/POTFILES.html.in
|
po/$(PACKAGE_NAME).manifest.pot: $(NODE_MODULES_TEST) $(COCKPIT_REPO_STAMP)
|
||||||
po/html2po -f $^ -o $@
|
pkg/lib/manifest2po.js src/manifest.json -o $@
|
||||||
|
|
||||||
po/$(PACKAGE_NAME).manifest.pot:
|
po/$(PACKAGE_NAME).metainfo.pot: $(APPSTREAMFILE)
|
||||||
po/manifest2po src/manifest.json -o $@
|
xgettext --default-domain=$(PACKAGE_NAME) --output=$@ $<
|
||||||
|
|
||||||
po/$(PACKAGE_NAME).pot: po/$(PACKAGE_NAME).html.pot po/$(PACKAGE_NAME).js.pot po/$(PACKAGE_NAME).manifest.pot
|
po/$(PACKAGE_NAME).pot: po/$(PACKAGE_NAME).html.pot po/$(PACKAGE_NAME).js.pot po/$(PACKAGE_NAME).manifest.pot po/$(PACKAGE_NAME).metainfo.pot
|
||||||
msgcat --sort-output --output-file=$@ $^
|
msgcat --sort-output --output-file=$@ $^
|
||||||
|
|
||||||
# Update translations against current PO template
|
po/LINGUAS:
|
||||||
update-po: po/$(PACKAGE_NAME).pot
|
echo $(LINGUAS) | tr ' ' '\n' > $@
|
||||||
for lang in $(LINGUAS); do \
|
|
||||||
msgmerge --output-file=po/$$lang.po po/$$lang.po $<; \
|
|
||||||
done
|
|
||||||
|
|
||||||
dist/po.%.js: po/%.po $(NODE_MODULES_TEST)
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
po/po2json -m po/po.empty.js -o $@.js.tmp $<
|
|
||||||
mv $@.js.tmp $@
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Build/Install/dist
|
# Build/Install/dist
|
||||||
#
|
#
|
||||||
|
|
||||||
%.spec: %.spec.in
|
$(SPEC): packaging/$(SPEC).in $(NODE_MODULES_TEST)
|
||||||
sed -e 's/%{VERSION}/$(VERSION)/g' $< > $@
|
provides=$$(npm ls --omit dev --package-lock-only --depth=Infinity | grep -Eo '[^[:space:]]+@[^[:space:]]+' | sort -u | sed 's/^/Provides: bundled(npm(/; s/\(.*\)@/\1)) = /'); \
|
||||||
|
awk -v p="$$provides" '{gsub(/%{VERSION}/, "$(VERSION)"); gsub(/%{NPM_PROVIDES}/, p)}1' $< > $@
|
||||||
|
|
||||||
$(WEBPACK_TEST): $(NODE_MODULES_TEST) $(LIB_TEST) $(shell find src/ -type f) package.json webpack.config.js $(patsubst %,dist/po.%.js,$(LINGUAS))
|
$(DIST_TEST): $(NODE_MODULES_TEST) $(COCKPIT_REPO_STAMP) $(shell find src/ -type f) package.json build.js
|
||||||
NODE_ENV=$(NODE_ENV) node_modules/.bin/webpack
|
NODE_ENV=$(NODE_ENV) ./build.js
|
||||||
|
|
||||||
watch:
|
watch:
|
||||||
NODE_ENV=$(NODE_ENV) node_modules/.bin/webpack --watch
|
NODE_ENV=$(NODE_ENV) npm run watch
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf dist/
|
rm -rf dist/
|
||||||
[ ! -e cockpit-$(PACKAGE_NAME).spec.in ] || rm -f cockpit-$(PACKAGE_NAME).spec
|
rm -f $(SPEC)
|
||||||
|
rm -f po/LINGUAS
|
||||||
|
|
||||||
install: $(WEBPACK_TEST)
|
install: $(DIST_TEST) po/LINGUAS
|
||||||
mkdir -p $(DESTDIR)/usr/share/cockpit/$(PACKAGE_NAME)
|
mkdir -p $(DESTDIR)$(PREFIX)/share/cockpit/$(PACKAGE_NAME)
|
||||||
cp -r dist/* $(DESTDIR)/usr/share/cockpit/$(PACKAGE_NAME)
|
cp -r dist/* $(DESTDIR)$(PREFIX)/share/cockpit/$(PACKAGE_NAME)
|
||||||
mkdir -p $(DESTDIR)/usr/share/metainfo/
|
mkdir -p $(DESTDIR)$(PREFIX)/share/metainfo/
|
||||||
cp org.cockpit-project.$(PACKAGE_NAME).metainfo.xml $(DESTDIR)/usr/share/metainfo/
|
msgfmt --xml -d po \
|
||||||
|
--template $(APPSTREAMFILE) \
|
||||||
|
-o $(DESTDIR)$(PREFIX)/share/metainfo/$(APPSTREAMFILE)
|
||||||
|
|
||||||
# this requires a built source tree and avoids having to install anything system-wide
|
# this requires a built source tree and avoids having to install anything system-wide
|
||||||
devel-install: $(WEBPACK_TEST)
|
devel-install: $(DIST_TEST)
|
||||||
mkdir -p ~/.local/share/cockpit
|
mkdir -p ~/.local/share/cockpit
|
||||||
ln -s `pwd`/dist ~/.local/share/cockpit/$(PACKAGE_NAME)
|
ln -s `pwd`/dist ~/.local/share/cockpit/$(PACKAGE_NAME)
|
||||||
|
|
||||||
dist: $(TARFILE)
|
# assumes that there was symlink set up using the above devel-install target,
|
||||||
|
# and removes it
|
||||||
|
devel-uninstall:
|
||||||
|
rm -f ~/.local/share/cockpit/$(PACKAGE_NAME)
|
||||||
|
|
||||||
# when building a distribution tarball, call webpack with a 'production' environment
|
print-version:
|
||||||
|
@echo "$(VERSION)"
|
||||||
|
|
||||||
|
dist: $(TARFILE)
|
||||||
|
@ls -1 $(TARFILE)
|
||||||
|
|
||||||
|
# when building a distribution tarball, call bundler with a 'production' environment
|
||||||
# we don't ship node_modules for license and compactness reasons; we ship a
|
# we don't ship node_modules for license and compactness reasons; we ship a
|
||||||
# pre-built dist/ (so it's not necessary) and ship packge-lock.json (so that
|
# pre-built dist/ (so it's not necessary) and ship package-lock.json (so that
|
||||||
# node_modules/ can be reconstructed if necessary)
|
# node_modules/ can be reconstructed if necessary)
|
||||||
$(TARFILE): export NODE_ENV=production
|
$(TARFILE): export NODE_ENV=production
|
||||||
$(TARFILE): $(WEBPACK_TEST) cockpit-$(PACKAGE_NAME).spec
|
$(TARFILE): $(DIST_TEST) $(SPEC)
|
||||||
if type appstream-util >/dev/null 2>&1; then appstream-util validate-relax --nonet *.metainfo.xml; fi
|
if type appstream-util >/dev/null 2>&1; then appstream-util validate-relax --nonet *.metainfo.xml; fi
|
||||||
touch -r package.json $(NODE_MODULES_TEST)
|
tar --xz $(TAR_ARGS) -cf $(TARFILE) --transform 's,^,$(RPM_NAME)/,' \
|
||||||
touch dist/*
|
--exclude packaging/$(SPEC).in --exclude node_modules \
|
||||||
tar --xz -cf cockpit-$(PACKAGE_NAME)-$(VERSION).tar.xz --transform 's,^,cockpit-$(PACKAGE_NAME)/,' \
|
$$(git ls-files) $(COCKPIT_REPO_FILES) $(NODE_MODULES_TEST) $(SPEC) dist/
|
||||||
--exclude cockpit-$(PACKAGE_NAME).spec.in --exclude node_modules \
|
|
||||||
$$(git ls-files) src/lib package-lock.json cockpit-$(PACKAGE_NAME).spec dist/
|
|
||||||
|
|
||||||
srpm: $(TARFILE) cockpit-$(PACKAGE_NAME).spec
|
$(NODE_CACHE): $(NODE_MODULES_TEST)
|
||||||
|
tar --xz $(TAR_ARGS) -cf $@ node_modules
|
||||||
|
|
||||||
|
node-cache: $(NODE_CACHE)
|
||||||
|
|
||||||
|
# convenience target for developers
|
||||||
|
srpm: $(TARFILE) $(NODE_CACHE) $(SPEC)
|
||||||
rpmbuild -bs \
|
rpmbuild -bs \
|
||||||
--define "_sourcedir `pwd`" \
|
--define "_sourcedir `pwd`" \
|
||||||
--define "_srcrpmdir `pwd`" \
|
--define "_srcrpmdir `pwd`" \
|
||||||
cockpit-$(PACKAGE_NAME).spec
|
$(SPEC)
|
||||||
|
|
||||||
rpm: $(RPMFILE)
|
# convenience target for developers
|
||||||
|
rpm: $(TARFILE) $(NODE_CACHE) $(SPEC)
|
||||||
$(RPMFILE): $(TARFILE) cockpit-$(PACKAGE_NAME).spec
|
|
||||||
mkdir -p "`pwd`/output"
|
mkdir -p "`pwd`/output"
|
||||||
mkdir -p "`pwd`/rpmbuild"
|
mkdir -p "`pwd`/rpmbuild"
|
||||||
rpmbuild -bb \
|
rpmbuild -bb \
|
||||||
|
|
@ -126,55 +150,58 @@ $(RPMFILE): $(TARFILE) cockpit-$(PACKAGE_NAME).spec
|
||||||
--define "_srcrpmdir `pwd`" \
|
--define "_srcrpmdir `pwd`" \
|
||||||
--define "_rpmdir `pwd`/output" \
|
--define "_rpmdir `pwd`/output" \
|
||||||
--define "_buildrootdir `pwd`/build" \
|
--define "_buildrootdir `pwd`/build" \
|
||||||
cockpit-$(PACKAGE_NAME).spec
|
$(SPEC)
|
||||||
find `pwd`/output -name '*.rpm' -printf '%f\n' -exec mv {} . \;
|
find `pwd`/output -name '*.rpm' -printf '%f\n' -exec mv {} . \;
|
||||||
rm -r "`pwd`/rpmbuild"
|
rm -r "`pwd`/rpmbuild"
|
||||||
rm -r "`pwd`/output" "`pwd`/build"
|
rm -r "`pwd`/output" "`pwd`/build"
|
||||||
# sanity check
|
|
||||||
test -e "$(RPMFILE)"
|
|
||||||
|
|
||||||
# build a VM with locally built rpm installed
|
ifeq ("$(TEST_SCENARIO)","pybridge")
|
||||||
$(VM_IMAGE): $(RPMFILE) bots
|
COCKPIT_PYBRIDGE_REF = main
|
||||||
rm -f $(VM_IMAGE) $(VM_IMAGE).qcow2
|
COCKPIT_WHEEL = cockpit-0-py3-none-any.whl
|
||||||
bots/image-customize -v -i `pwd`/$(RPMFILE) -s $(CURDIR)/test/vm.install $(TEST_OS)
|
|
||||||
bots/image-customize -v -u ./test/files/1.journal:/var/log/journal/1.journal $(TEST_OS)
|
$(COCKPIT_WHEEL):
|
||||||
bots/image-customize -v -u ./test/files/binary-rec.journal:/var/log/journal/binary-rec.journal $(TEST_OS)
|
pip wheel git+https://github.com/cockpit-project/cockpit.git@${COCKPIT_PYBRIDGE_REF}
|
||||||
|
|
||||||
|
VM_DEPENDS = $(COCKPIT_WHEEL)
|
||||||
|
VM_CUSTOMIZE_FLAGS = --install $(COCKPIT_WHEEL)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# build a VM with locally built distro pkgs installed
|
||||||
|
# disable networking, VM images have mock/pbuilder with the common build dependencies pre-installed
|
||||||
|
$(VM_IMAGE): $(TARFILE) $(NODE_CACHE) bots test/vm.install $(VM_DEPENDS)
|
||||||
|
bots/image-customize --fresh \
|
||||||
|
$(VM_CUSTOMIZE_FLAGS) \
|
||||||
|
--upload $(NODE_CACHE):/var/tmp/ --build $(TARFILE) \
|
||||||
|
--upload ./test/files/1.journal:/var/log/journal/1.journal \
|
||||||
|
--upload ./test/files/binary-rec.journal:/var/log/journal/binary-rec.journal \
|
||||||
|
--script $(CURDIR)/test/vm.install $(TEST_OS)
|
||||||
|
|
||||||
# convenience target for the above
|
# convenience target for the above
|
||||||
vm: $(VM_IMAGE)
|
vm: $(VM_IMAGE)
|
||||||
echo $(VM_IMAGE)
|
@echo $(VM_IMAGE)
|
||||||
|
|
||||||
|
# convenience target to print the filename of the test image
|
||||||
|
print-vm:
|
||||||
|
@echo $(VM_IMAGE)
|
||||||
|
|
||||||
|
# convenience target to setup all the bits needed for the integration tests
|
||||||
|
# without actually running them
|
||||||
|
prepare-check: $(NODE_MODULES_TEST) $(VM_IMAGE) test/common
|
||||||
|
|
||||||
# run the browser integration tests; skip check for SELinux denials
|
# run the browser integration tests; skip check for SELinux denials
|
||||||
# this will run all tests/check-* and format them as TAP
|
# this will run all tests/check-* and format them as TAP
|
||||||
check: $(NODE_MODULES_TEST) $(VM_IMAGE) test/common
|
check: prepare-check
|
||||||
TEST_AUDIT_NO_SELINUX=1 test/common/run-tests
|
TEST_AUDIT_NO_SELINUX=1 test/common/run-tests ${RUN_TESTS_OPTIONS}
|
||||||
|
|
||||||
# checkout Cockpit's bots for standard test VM images and API to launch them
|
# checkout Cockpit's bots for standard test VM images and API to launch them
|
||||||
# must be from master, as only that has current and existing images; but testvm.py API is stable
|
bots: tools/make-bots
|
||||||
# support CI testing against a bots change
|
tools/make-bots
|
||||||
bots:
|
|
||||||
git clone --quiet --reference-if-able $${XDG_CACHE_HOME:-$$HOME/.cache}/cockpit-project/bots https://github.com/cockpit-project/bots.git
|
|
||||||
if [ -n "$$COCKPIT_BOTS_REF" ]; then git -C bots fetch --quiet --depth=1 origin "$$COCKPIT_BOTS_REF"; git -C bots checkout --quiet FETCH_HEAD; fi
|
|
||||||
@echo "checked out bots/ ref $$(git -C bots rev-parse HEAD)"
|
|
||||||
|
|
||||||
# checkout Cockpit's test API; this has no API stability guarantee, so check out a stable tag
|
|
||||||
# when you start a new project, use the latest release, and update it from time to time
|
|
||||||
test/common:
|
|
||||||
git fetch --depth=1 https://github.com/cockpit-project/cockpit.git 267
|
|
||||||
git checkout --force FETCH_HEAD -- test/common
|
|
||||||
git reset test/common
|
|
||||||
|
|
||||||
# checkout Cockpit's PF/React/build library; again this has no API stability guarantee, so check out a stable tag
|
|
||||||
$(LIB_TEST):
|
|
||||||
git clone -b 256 --depth=1 https://github.com/cockpit-project/cockpit.git tmp/cockpit
|
|
||||||
mv tmp/cockpit/pkg/lib src/
|
|
||||||
rm -rf tmp/cockpit
|
|
||||||
|
|
||||||
$(NODE_MODULES_TEST): package.json
|
$(NODE_MODULES_TEST): package.json
|
||||||
# if it exists already, npm install won't update it; force that so that we always get up-to-date packages
|
# if it exists already, npm install won't update it; force that so that we always get up-to-date packages
|
||||||
rm -f package-lock.json
|
rm -f package-lock.json
|
||||||
# unset NODE_ENV, skips devDependencies otherwise
|
# unset NODE_ENV, skips devDependencies otherwise
|
||||||
env -u NODE_ENV npm install
|
env -u NODE_ENV npm install --ignore-scripts
|
||||||
env -u NODE_ENV npm prune
|
env -u NODE_ENV npm prune
|
||||||
|
|
||||||
.PHONY: all clean install devel-install dist srpm rpm check vm update-po
|
.PHONY: all clean install devel-install devel-uninstall print-version dist node-cache rpm prepare-check check vm print-vm
|
||||||
|
|
|
||||||
89
README.md
89
README.md
|
|
@ -17,6 +17,9 @@ GitHub Organization:
|
||||||
* [scribery.github.io](http://scribery.github.io/)
|
* [scribery.github.io](http://scribery.github.io/)
|
||||||
* [Scribery](https://github.com/Scribery)
|
* [Scribery](https://github.com/Scribery)
|
||||||
|
|
||||||
|
This project is based on the [Cockpit Starter Kit](https://github.com/cockpit-project/starter-kit).
|
||||||
|
See [Starter Kit Intro](http://cockpit-project.org/blog/cockpit-starter-kit.html) for details.
|
||||||
|
|
||||||
# Getting and building the source
|
# Getting and building the source
|
||||||
|
|
||||||
Make sure you have `npm` available (usually from your distribution package).
|
Make sure you have `npm` available (usually from your distribution package).
|
||||||
|
|
@ -30,15 +33,17 @@ make
|
||||||
|
|
||||||
# Installing
|
# Installing
|
||||||
|
|
||||||
`make install` compiles and installs the package in `/usr/share/cockpit/`. The
|
`make install` compiles and installs the package in `/usr/local/share/cockpit/`. The
|
||||||
convenience targets `srpm` and `rpm` build the source and binary rpms,
|
convenience targets `srpm` and `rpm` build the source and binary rpms,
|
||||||
respectively. Both of these make use of the `dist-gzip` target, which is used
|
respectively. Both of these make use of the `dist` target, which is used
|
||||||
to generate the distribution tarball. In `production` mode, source files are
|
to generate the distribution tarball. In `production` mode, source files are
|
||||||
automatically minified and compressed. Set `NODE_ENV=production` if you want to
|
automatically minified and compressed. Set `NODE_ENV=production` if you want to
|
||||||
duplicate this behavior.
|
duplicate this behavior.
|
||||||
|
|
||||||
For development, you usually want to run your module straight out of the git
|
For development, you usually want to run your module straight out of the git
|
||||||
tree. To do that, link that to the location were `cockpit-bridge` looks for packages:
|
tree. To do that, run `make devel-install`, which links your checkout to the
|
||||||
|
location were cockpit-bridge looks for packages. If you prefer to do
|
||||||
|
this manually:
|
||||||
|
|
||||||
```
|
```
|
||||||
mkdir -p ~/.local/share/cockpit
|
mkdir -p ~/.local/share/cockpit
|
||||||
|
|
@ -48,12 +53,39 @@ ln -s `pwd`/dist ~/.local/share/cockpit/session-recording
|
||||||
After changing the code and running `make` again, reload the Cockpit page in
|
After changing the code and running `make` again, reload the Cockpit page in
|
||||||
your browser.
|
your browser.
|
||||||
|
|
||||||
|
You can also use
|
||||||
|
[watch mode](https://esbuild.github.io/api/#watch) to
|
||||||
|
automatically update the bundle on every code change with
|
||||||
|
|
||||||
|
$ npm run watch
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
$ make watch
|
||||||
|
|
||||||
|
When developing against a virtual machine, watch mode can also automatically upload
|
||||||
|
the code changes by setting the `RSYNC` environment variable to
|
||||||
|
the remote hostname.
|
||||||
|
|
||||||
|
$ RSYNC=c make watch
|
||||||
|
|
||||||
|
When developing against a remote host as a normal user, `RSYNC_DEVEL` can be
|
||||||
|
set to upload code changes to `~/.local/share/cockpit/` instead of
|
||||||
|
`/usr/local`.
|
||||||
|
|
||||||
|
$ RSYNC_DEVEL=example.com make watch
|
||||||
|
|
||||||
|
To "uninstall" the locally installed version, run `make devel-uninstall`, or
|
||||||
|
remove manually the symlink:
|
||||||
|
|
||||||
|
rm ~/.local/share/cockpit/starter-kit
|
||||||
|
|
||||||
# Running eslint
|
# Running eslint
|
||||||
|
|
||||||
Cockpit Starter Kit uses [ESLint](https://eslint.org/) to automatically check
|
Cockpit Starter Kit uses [ESLint](https://eslint.org/) to automatically check
|
||||||
JavaScript code style in `.jsx` and `.es6` files.
|
JavaScript code style in `.js` and `.jsx` files.
|
||||||
|
|
||||||
The linter is executed within every build as a webpack preloader.
|
eslint is executed within every build.
|
||||||
|
|
||||||
For developer convenience, the ESLint can be started explicitly by:
|
For developer convenience, the ESLint can be started explicitly by:
|
||||||
|
|
||||||
|
|
@ -65,6 +97,49 @@ Violations of some rules can be fixed automatically by:
|
||||||
|
|
||||||
Rules configuration can be found in the `.eslintrc.json` file.
|
Rules configuration can be found in the `.eslintrc.json` file.
|
||||||
|
|
||||||
# Credits
|
## Running stylelint
|
||||||
|
|
||||||
Cockpit-session-recording is based on [starter-kit](http://cockpit-project.org/blog/cockpit-starter-kit.html).
|
Cockpit uses [Stylelint](https://stylelint.io/) to automatically check CSS code
|
||||||
|
style in `.css` and `scss` files.
|
||||||
|
|
||||||
|
styleint is executed within every build.
|
||||||
|
|
||||||
|
For developer convenience, the Stylelint can be started explicitly by:
|
||||||
|
|
||||||
|
$ npm run stylelint
|
||||||
|
|
||||||
|
Violations of some rules can be fixed automatically by:
|
||||||
|
|
||||||
|
$ npm run stylelint:fix
|
||||||
|
|
||||||
|
Rules configuration can be found in the `.stylelintrc.json` file.
|
||||||
|
|
||||||
|
During fast iterative development, you can also choose to not run eslint/stylelint.
|
||||||
|
This speeds up the build and avoids build failures due to e. g. ill-formatted
|
||||||
|
css or other issues:
|
||||||
|
|
||||||
|
$ make LINT=0
|
||||||
|
|
||||||
|
# Running tests locally
|
||||||
|
|
||||||
|
Run `make check` to build an RPM, install it into a standard Cockpit test VM
|
||||||
|
(centos-8-stream by default), and run the test/check-application integration test on
|
||||||
|
it. This uses Cockpit's Chrome DevTools Protocol based browser tests, through a
|
||||||
|
Python API abstraction. Note that this API is not guaranteed to be stable, so
|
||||||
|
if you run into failures and don't want to adjust tests, consider checking out
|
||||||
|
Cockpit's test/common from a tag instead of main (see the `test/common`
|
||||||
|
target in `Makefile`).
|
||||||
|
|
||||||
|
After the test VM is prepared, you can manually run the test without rebuilding
|
||||||
|
the VM, possibly with extra options for tracing and halting on test failures
|
||||||
|
(for interactive debugging):
|
||||||
|
|
||||||
|
TEST_OS=centos-8-stream test/check-application -tvs
|
||||||
|
|
||||||
|
It is possible to setup the test environment without running the tests:
|
||||||
|
|
||||||
|
TEST_OS=centos-8-stream make prepare-check
|
||||||
|
|
||||||
|
You can also run the test against a different Cockpit image, for example:
|
||||||
|
|
||||||
|
TEST_OS=fedora-34 make check
|
||||||
|
|
|
||||||
30
Vagrantfile
vendored
30
Vagrantfile
vendored
|
|
@ -1,30 +0,0 @@
|
||||||
Vagrant.configure(2) do |config|
|
|
||||||
config.vm.box = "fedora/28-cloud-base"
|
|
||||||
config.vm.network "forwarded_port", guest: 9090, host: 9090
|
|
||||||
|
|
||||||
if Dir.glob("dist/*").length == 0
|
|
||||||
config.vm.post_up_message = "NOTE: Distribution directory is empty. Run `make` to see your module show up in cockpit"
|
|
||||||
end
|
|
||||||
|
|
||||||
config.vm.synced_folder ".", "/vagrant", disabled: true
|
|
||||||
config.vm.synced_folder "dist/", "/usr/local/share/cockpit/" + File.basename(Dir.pwd), type: "rsync", create: true
|
|
||||||
|
|
||||||
config.vm.provider "libvirt" do |libvirt|
|
|
||||||
libvirt.memory = 1024
|
|
||||||
end
|
|
||||||
|
|
||||||
config.vm.provider "virtualbox" do |virtualbox|
|
|
||||||
virtualbox.memory = 1024
|
|
||||||
end
|
|
||||||
|
|
||||||
config.vm.provision "shell", inline: <<-EOF
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
sudo dnf install -y cockpit
|
|
||||||
|
|
||||||
printf "[WebService]\nAllowUnencrypted=true\n" > /etc/cockpit/cockpit.conf
|
|
||||||
|
|
||||||
systemctl enable cockpit.socket
|
|
||||||
systemctl start cockpit.socket
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
136
build.js
Executable file
136
build.js
Executable file
|
|
@ -0,0 +1,136 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import os from 'node:os';
|
||||||
|
|
||||||
|
import copy from 'esbuild-plugin-copy';
|
||||||
|
|
||||||
|
import { cleanPlugin } from './pkg/lib/esbuild-cleanup-plugin.js';
|
||||||
|
import { cockpitCompressPlugin } from './pkg/lib/esbuild-compress-plugin.js';
|
||||||
|
import { cockpitPoEsbuildPlugin } from './pkg/lib/cockpit-po-plugin.js';
|
||||||
|
import { cockpitRsyncEsbuildPlugin } from './pkg/lib/cockpit-rsync-plugin.js';
|
||||||
|
import { esbuildStylesPlugins } from './pkg/lib/esbuild-common.js';
|
||||||
|
import { eslintPlugin } from './pkg/lib/esbuild-eslint-plugin.js';
|
||||||
|
import { stylelintPlugin } from './pkg/lib/esbuild-stylelint-plugin.js';
|
||||||
|
|
||||||
|
const useWasm = os.arch() !== 'x64';
|
||||||
|
const esbuild = (await import(useWasm ? 'esbuild-wasm' : 'esbuild')).default;
|
||||||
|
|
||||||
|
const production = process.env.NODE_ENV === 'production';
|
||||||
|
const watchMode = process.env.ESBUILD_WATCH === "true";
|
||||||
|
// linters dominate the build time, so disable them for production builds by default, but enable in watch mode
|
||||||
|
const lint = process.env.LINT ? (process.env.LINT !== 0) : (watchMode || !production);
|
||||||
|
// List of directories to use when using import statements
|
||||||
|
const nodePaths = ['pkg/lib'];
|
||||||
|
const outdir = 'dist';
|
||||||
|
|
||||||
|
// Obtain package name from package.json
|
||||||
|
const packageJson = JSON.parse(fs.readFileSync('package.json'));
|
||||||
|
|
||||||
|
function notifyEndPlugin() {
|
||||||
|
return {
|
||||||
|
name: 'notify-end',
|
||||||
|
setup(build) {
|
||||||
|
let startTime;
|
||||||
|
|
||||||
|
build.onStart(() => {
|
||||||
|
startTime = new Date();
|
||||||
|
});
|
||||||
|
|
||||||
|
build.onEnd(() => {
|
||||||
|
const endTime = new Date();
|
||||||
|
const timeStamp = endTime.toTimeString().split(' ')[0];
|
||||||
|
console.log(`${timeStamp}: Build finished in ${endTime - startTime} ms`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const cwd = process.cwd();
|
||||||
|
|
||||||
|
// similar to fs.watch(), but recursively watches all subdirectories
|
||||||
|
function watch_dirs(dir, on_change) {
|
||||||
|
const callback = (ev, dir, fname) => {
|
||||||
|
// only listen for "change" events, as renames are noisy
|
||||||
|
// ignore hidden files
|
||||||
|
const isHidden = /^\./.test(fname);
|
||||||
|
if (ev !== "change" || isHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
on_change(path.join(dir, fname));
|
||||||
|
};
|
||||||
|
|
||||||
|
fs.watch(dir, {}, (ev, path) => callback(ev, dir, path));
|
||||||
|
|
||||||
|
// watch all subdirectories in dir
|
||||||
|
const d = fs.opendirSync(dir);
|
||||||
|
let dirent;
|
||||||
|
|
||||||
|
while ((dirent = d.readSync()) !== null) {
|
||||||
|
if (dirent.isDirectory())
|
||||||
|
watch_dirs(path.join(dir, dirent.name), on_change);
|
||||||
|
}
|
||||||
|
d.closeSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
const context = await esbuild.context({
|
||||||
|
...!production ? { sourcemap: "linked" } : {},
|
||||||
|
bundle: true,
|
||||||
|
entryPoints: ['./src/index.js'],
|
||||||
|
external: ['*.woff', '*.woff2', '*.jpg', '*.svg', '../../assets*'], // Allow external font files which live in ../../static/fonts
|
||||||
|
legalComments: 'external', // Move all legal comments to a .LEGAL.txt file
|
||||||
|
loader: { ".js": "jsx" },
|
||||||
|
minify: production,
|
||||||
|
nodePaths,
|
||||||
|
outdir,
|
||||||
|
target: ['es2020'],
|
||||||
|
plugins: [
|
||||||
|
cleanPlugin(),
|
||||||
|
...lint
|
||||||
|
? [
|
||||||
|
stylelintPlugin({ filter: new RegExp(cwd + '\/src\/.*\.(css?|scss?)$') }),
|
||||||
|
eslintPlugin({ filter: new RegExp(cwd + '\/src\/.*\.(jsx?|js?)$') })
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
// Esbuild will only copy assets that are explicitly imported and used
|
||||||
|
// in the code. This is a problem for index.html and manifest.json which are not imported
|
||||||
|
copy({
|
||||||
|
assets: [
|
||||||
|
{ from: ['./src/manifest.json'], to: ['./manifest.json'] },
|
||||||
|
{ from: ['./src/index.html'], to: ['./index.html'] },
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
...esbuildStylesPlugins,
|
||||||
|
cockpitPoEsbuildPlugin(),
|
||||||
|
...production ? [cockpitCompressPlugin()] : [],
|
||||||
|
cockpitRsyncEsbuildPlugin({ dest: packageJson.name }),
|
||||||
|
notifyEndPlugin(),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await context.rebuild();
|
||||||
|
} catch (e) {
|
||||||
|
if (!watchMode)
|
||||||
|
process.exit(1);
|
||||||
|
// ignore errors in watch mode
|
||||||
|
}
|
||||||
|
|
||||||
|
if (watchMode) {
|
||||||
|
const on_change = async path => {
|
||||||
|
console.log("change detected:", path);
|
||||||
|
await context.cancel();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await context.rebuild();
|
||||||
|
} catch (e) {} // ignore in watch mode
|
||||||
|
};
|
||||||
|
|
||||||
|
watch_dirs('src', on_change);
|
||||||
|
|
||||||
|
// wait forever until Control-C
|
||||||
|
await new Promise(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
context.dispose();
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
# This is a script run to release welder-web through Cockpituous:
|
|
||||||
# https://github.com/cockpit-project/cockpituous/tree/master/release
|
|
||||||
|
|
||||||
# Anything that start with 'job' may run in a way that it SIGSTOP's
|
|
||||||
# itself when preliminary preparition and then gets a SIGCONT in
|
|
||||||
# order to complete its work.
|
|
||||||
#
|
|
||||||
# Check cockpituous documentation for available release targets.
|
|
||||||
|
|
||||||
RELEASE_SOURCE="_release/source"
|
|
||||||
RELEASE_SPEC="cockpit-session-recording.spec"
|
|
||||||
RELEASE_SRPM="_release/srpm"
|
|
||||||
|
|
||||||
job release-source
|
|
||||||
job release-srpm -V
|
|
||||||
|
|
||||||
# Once you have a Fedora package and add the https://pagure.io/user/cockpit
|
|
||||||
# user to your project's maintainers, you can also upload to Fedora automatically:
|
|
||||||
|
|
||||||
## Authenticate for pushing into Fedora dist-git (works in Cockpituous release container)
|
|
||||||
# cat ~/.fedora-password | kinit cockpit@FEDORAPROJECT.ORG
|
|
||||||
## Do fedora builds for the tag, using tarball
|
|
||||||
# job release-koji -k master
|
|
||||||
# job release-koji f29
|
|
||||||
# job release-bodhi F29
|
|
||||||
|
|
||||||
# These are likely the first of your release targets; but run them after Fedora uploads,
|
|
||||||
# so that failures there will fail the release early, before publishing on GitHub
|
|
||||||
|
|
||||||
# job release-github
|
|
||||||
# job release-copr @myorg/myrepo
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<component type="addon">
|
<component type="addon">
|
||||||
<id>org.cockpit-project.session-recording</id>
|
<id>org.cockpit_project.session-recording</id>
|
||||||
<metadata_license>CC0-1.0</metadata_license>
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
<name>Session Recording</name>
|
<name>Session Recording</name>
|
||||||
<summary>
|
<summary>Session Recording module for Cockpit</summary>
|
||||||
Session Recording module for Cockpit
|
|
||||||
</summary>
|
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
Provides Session Recording module for Cockpit. Provides list of recorded by tlog terminal sessions from Journal.
|
Provides Session Recoridng moduel for Cockpit. Provides list of recorded by tlog terminal sessions from Journal.
|
||||||
Allows to play them in a player with various controls. Shows correlated logs which happened during session.
|
Allows to play them in a player with various controls. Shows correlated logs which happened during session.
|
||||||
</p>
|
</p>
|
||||||
</description>
|
</description>
|
||||||
<extends>org.cockpit_project.cockpit</extends>
|
<extends>org.cockpit_project.cockpit</extends>
|
||||||
<launchable type="cockpit-manifest">session-recording</launchable>
|
<launchable type="cockpit-manifest">session-recording</launchable>
|
||||||
|
<url type="homepage">https://github.com/Scribery/cockpit-session-recording</url>
|
||||||
|
<url type="bugtracker">https://github.com/Scribery/cockpit-session-recording/issues</url>
|
||||||
|
<update_contact>cockpit-devel_AT_lists.fedorahosted.org</update_contact>
|
||||||
</component>
|
</component>
|
||||||
|
|
|
||||||
76
package.json
76
package.json
|
|
@ -1,65 +1,51 @@
|
||||||
{
|
{
|
||||||
"name": "session-recording",
|
"name": "session-recording",
|
||||||
"version": "0.1.0",
|
|
||||||
"description": "Module for Cockpit which provides session recording configuration and playback",
|
"description": "Module for Cockpit which provides session recording configuration and playback",
|
||||||
|
"type": "module",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"repository": "git@github.com:Scribery/cockpit-session-recording.git",
|
"repository": "git@github.com:Scribery/cockpit-session-recording.git",
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "LGPL-2.1",
|
"license": "LGPL-2.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"watch": "webpack --watch",
|
"watch": "ESBUILD_WATCH='true' ./build.js",
|
||||||
"build": "webpack",
|
"build": "./build.js",
|
||||||
"eslint": "eslint --ext .js --ext .jsx src/",
|
"eslint": "eslint --ext .js --ext .jsx src/",
|
||||||
"eslint:fix": "eslint --fix --ext .js --ext .jsx src/"
|
"eslint:fix": "eslint --fix --ext .js --ext .jsx src/",
|
||||||
|
"stylelint": "stylelint src/*{.css,scss}",
|
||||||
|
"stylelint:fix": "stylelint --fix src/*{.css,scss}"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.20.12",
|
"argparse": "^2.0.1",
|
||||||
"@babel/eslint-parser": "^7.19.1",
|
"chrome-remote-interface": "^0.32.1",
|
||||||
"@babel/preset-env": "^7.20.2",
|
"esbuild": "^0.17.15",
|
||||||
"@babel/preset-react": "^7.0.0",
|
"esbuild-plugin-copy": "^2.1.1",
|
||||||
"babel-loader": "^9.1.2",
|
"esbuild-plugin-replace": "^1.3.0",
|
||||||
"chrome-remote-interface": "^0.32.0",
|
"esbuild-sass-plugin": "^2.8.0",
|
||||||
"compression-webpack-plugin": "^10.0.0",
|
"esbuild-wasm": "^0.17.16",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"eslint": "^8.13.0",
|
||||||
"css-loader": "^6.7.3",
|
"eslint-config-react-app": "^7.0.0",
|
||||||
"eslint": "^8.31.0",
|
"eslint-config-standard": "^17.0.0-1",
|
||||||
"eslint-config-standard": "^17.0.0",
|
"eslint-config-standard-jsx": "^11.0.0-1",
|
||||||
"eslint-config-standard-react": "^9.2.0",
|
|
||||||
"eslint-plugin-flowtype": "^8.0.3",
|
"eslint-plugin-flowtype": "^8.0.3",
|
||||||
"eslint-plugin-import": "^2.27.4",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.0.0",
|
||||||
"eslint-plugin-react": "^7.14.3",
|
"eslint-plugin-react": "^7.29.4",
|
||||||
"eslint-plugin-react-hooks": "^4.2.0",
|
"eslint-plugin-react-hooks": "^4.4.0",
|
||||||
"eslint-plugin-standard": "^4.1.0",
|
|
||||||
"eslint-webpack-plugin": "^3.2.0",
|
|
||||||
"htmlparser": "^1.7.7",
|
"htmlparser": "^1.7.7",
|
||||||
"jed": "^1.1.1",
|
"jed": "^1.1.1",
|
||||||
"mini-css-extract-plugin": "^2.7.2",
|
|
||||||
"po2json": "^1.0.0-alpha",
|
"po2json": "^1.0.0-alpha",
|
||||||
"sass": "^1.57.1",
|
"qunit": "^2.9.3",
|
||||||
"sass-loader": "^13.2.0",
|
"sass": "^1.61.0",
|
||||||
"sizzle": "^2.3.9",
|
"sizzle": "^2.3.3",
|
||||||
"stdio": "^2.1.1",
|
"stylelint": "^14.9.1",
|
||||||
"string-replace-loader": "^3.1.0",
|
"stylelint-config-standard-scss": "^5.0.0",
|
||||||
"webpack": "^5.75.0",
|
"stylelint-formatter-pretty": "^3.2.0"
|
||||||
"webpack-cli": "^5.0.1"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@patternfly/patternfly": "4.132.2",
|
"@patternfly/patternfly": "4.224.4",
|
||||||
"@patternfly/react-core": "4.152.4",
|
"@patternfly/react-core": "4.276.9",
|
||||||
"@patternfly/react-icons": "^4.19.8",
|
"react": "17.0.2",
|
||||||
"@patternfly/react-table": "4.29.58",
|
"react-dom": "17.0.2"
|
||||||
"buffer": "^6.0.3",
|
|
||||||
"comment-json": "^4.2.3",
|
|
||||||
"core-js": "3.27.1",
|
|
||||||
"date-fns": "2.29.3",
|
|
||||||
"ini": "^3.0.1",
|
|
||||||
"jquery": "3.6.3",
|
|
||||||
"raw-loader": "^4.0.2",
|
|
||||||
"react": "16.13.1",
|
|
||||||
"react-dom": "16.13.1",
|
|
||||||
"throttle-debounce": "5.0.0",
|
|
||||||
"xterm": "^3.14.5"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,26 +7,37 @@ URL: https://github.com/Scribery/%{name}
|
||||||
Source: https://github.com/Scribery/%{name}/releases/download/%{version}/%{name}-%{version}.tar.xz
|
Source: https://github.com/Scribery/%{name}/releases/download/%{version}/%{name}-%{version}.tar.xz
|
||||||
|
|
||||||
BuildArch: noarch
|
BuildArch: noarch
|
||||||
BuildRequires: libappstream-glib
|
BuildRequires: nodejs
|
||||||
BuildRequires: make
|
BuildRequires: make
|
||||||
|
BuildRequires: libappstream-glib
|
||||||
|
BuildRequires: gettext
|
||||||
|
%if 0%{?rhel} && 0%{?rhel} <= 8
|
||||||
|
BuildRequires: libappstream-glib-devel
|
||||||
|
%endif
|
||||||
|
|
||||||
Requires: cockpit-system
|
Requires: cockpit-system
|
||||||
Requires: tlog
|
Requires: tlog
|
||||||
|
|
||||||
|
%{NPM_PROVIDES}
|
||||||
|
|
||||||
%description
|
%description
|
||||||
Cockpit module providing session recording configuration and playback.
|
Cockpit module providing session recording configuration and playback.
|
||||||
This module allows viewing and playback of journal-stored terminal session
|
This module allows viewing and playback of journal-stored terminal session
|
||||||
recordings generated by the tlog component.
|
recordings generated by the tlog component.
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup -qn cockpit-session-recording
|
%setup -q -n %{name}
|
||||||
|
|
||||||
|
%build
|
||||||
|
# Nothing to build
|
||||||
|
|
||||||
%install
|
%install
|
||||||
%make_install
|
%make_install PREFIX=/usr
|
||||||
appstream-util validate-relax --nonet %{buildroot}/%{_datadir}/metainfo/*
|
appstream-util validate-relax --nonet %{buildroot}/%{_datadir}/metainfo/*
|
||||||
|
|
||||||
%files
|
%files
|
||||||
%{_datadir}/cockpit/session-recording
|
%{_datadir}/cockpit/*
|
||||||
%{_datadir}/metainfo/org.cockpit-project.session-recording.metainfo.xml
|
%{_datadir}/metainfo/*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Wed Jan 13 2021 Justin Stephenson <jstephen@redhat.com> - 7-1
|
* Wed Jan 13 2021 Justin Stephenson <jstephen@redhat.com> - 7-1
|
||||||
15
po/de.po
15
po/de.po
|
|
@ -4,27 +4,20 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: starter-kit 1.0\n"
|
"Project-Id-Version: starter-kit 1.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2018-08-29 00:14+0200\n"
|
"POT-Creation-Date: 2022-03-09 16:09+0100\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: \n"
|
"Language: de\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=n != 1\n"
|
||||||
|
|
||||||
#: src/index.html:20
|
#: src/app.jsx:43
|
||||||
msgid "Cockpit Starter Kit"
|
|
||||||
msgstr "Cockpit Bausatz"
|
|
||||||
|
|
||||||
#: src/app.jsx:42
|
|
||||||
msgid "Running on $0"
|
msgid "Running on $0"
|
||||||
msgstr "Läuft auf $0"
|
msgstr "Läuft auf $0"
|
||||||
|
|
||||||
#: src/manifest.json
|
|
||||||
msgid "Starter Kit"
|
|
||||||
msgstr "Bausatz"
|
|
||||||
|
|
||||||
#: src/app.jsx:29
|
#: src/app.jsx:29
|
||||||
msgid "Unknown"
|
msgid "Unknown"
|
||||||
msgstr "Unbekannt"
|
msgstr "Unbekannt"
|
||||||
|
|
|
||||||
264
po/html2po
264
po/html2po
|
|
@ -1,264 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Extracts translatable strings from HTML files in the following forms:
|
|
||||||
*
|
|
||||||
* <tag translate>String</tag>
|
|
||||||
* <tag translate context="value">String</tag>
|
|
||||||
* <tag translate="...">String</tag>
|
|
||||||
* <tag translate-attr attr="String"></tag>
|
|
||||||
*
|
|
||||||
* Supports the following Glade compatible forms:
|
|
||||||
*
|
|
||||||
* <tag translatable="yes">String</tag>
|
|
||||||
* <tag translatable="yes" context="value">String</tag>
|
|
||||||
*
|
|
||||||
* Supports the following angular-gettext compatible forms:
|
|
||||||
*
|
|
||||||
* <translate>String</translate>
|
|
||||||
* <tag translate-plural="Plural">Singular</tag>
|
|
||||||
*
|
|
||||||
* Note that some of the use of the translated may not support all the strings
|
|
||||||
* depending on the code actually using these strings to translate the HTML.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
function fatal(message, code) {
|
|
||||||
console.log((filename || "html2po") + ": " + message);
|
|
||||||
process.exit(code || 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function usage() {
|
|
||||||
console.log("usage: html2po input output");
|
|
||||||
process.exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
var fs, htmlparser, path, stdio;
|
|
||||||
|
|
||||||
try {
|
|
||||||
fs = require('fs');
|
|
||||||
path = require('path');
|
|
||||||
htmlparser = require('htmlparser');
|
|
||||||
stdio = require('stdio');
|
|
||||||
} catch (ex) {
|
|
||||||
fatal(ex.message, 127); /* missing looks for this */
|
|
||||||
}
|
|
||||||
|
|
||||||
var opts = stdio.getopt({
|
|
||||||
directory: { key: "d", args: 1, description: "Base directory for input files" },
|
|
||||||
output: { key: "o", args: 1, description: "Output file" },
|
|
||||||
from: { key: "f", args: 1, description: "File containing list of input files" },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!opts.from && opts.args.length < 1) {
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
var input = opts.args;
|
|
||||||
var entries = { };
|
|
||||||
|
|
||||||
/* Filename being parsed and offset of line number */
|
|
||||||
var filename = null;
|
|
||||||
var offsets = 0;
|
|
||||||
|
|
||||||
/* The HTML parser we're using */
|
|
||||||
var handler = new htmlparser.DefaultHandler(function(error, dom) {
|
|
||||||
if (error)
|
|
||||||
fatal(error);
|
|
||||||
else
|
|
||||||
walk(dom);
|
|
||||||
});
|
|
||||||
|
|
||||||
prepare();
|
|
||||||
|
|
||||||
/* Decide what input files to process */
|
|
||||||
function prepare() {
|
|
||||||
if (opts.from) {
|
|
||||||
fs.readFile(opts.from, { encoding: "utf-8"}, function(err, data) {
|
|
||||||
if (err)
|
|
||||||
fatal(err.message);
|
|
||||||
input = data.split("\n").filter(function(value) {
|
|
||||||
return !!value;
|
|
||||||
}).concat(input);
|
|
||||||
step();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
step();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now process each file in turn */
|
|
||||||
function step() {
|
|
||||||
filename = input.shift();
|
|
||||||
if (filename === undefined) {
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Qualify the filename if necessary */
|
|
||||||
var full = filename;
|
|
||||||
if (opts.directory)
|
|
||||||
full = path.join(opts.directory, filename);
|
|
||||||
|
|
||||||
fs.readFile(full, { encoding: "utf-8"}, function(err, data) {
|
|
||||||
if (err)
|
|
||||||
fatal(err.message);
|
|
||||||
|
|
||||||
var parser = new htmlparser.Parser(handler, { includeLocation: true });
|
|
||||||
parser.parseComplete(data);
|
|
||||||
step();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Process an array of nodes */
|
|
||||||
function walk(children) {
|
|
||||||
if (!children)
|
|
||||||
return;
|
|
||||||
|
|
||||||
children.forEach(function(child) {
|
|
||||||
var line = (child.location || { }).line || 0;
|
|
||||||
var offset = line - 1;
|
|
||||||
|
|
||||||
/* Scripts get their text processed as HTML */
|
|
||||||
if (child.type == 'script' && child.children) {
|
|
||||||
var parser = new htmlparser.Parser(handler, { includeLocation: true });
|
|
||||||
|
|
||||||
/* Make note of how far into the outer HTML file we are */
|
|
||||||
offsets += offset;
|
|
||||||
|
|
||||||
child.children.forEach(function(node) {
|
|
||||||
parser.parseChunk(node.raw);
|
|
||||||
});
|
|
||||||
parser.done();
|
|
||||||
|
|
||||||
offsets -= offset;
|
|
||||||
|
|
||||||
/* Tags get extracted as usual */
|
|
||||||
} else if (child.type == 'tag') {
|
|
||||||
tag(child);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Process a single loaded tag */
|
|
||||||
function tag(node) {
|
|
||||||
|
|
||||||
var tasks, line, entry;
|
|
||||||
var attrs = node.attribs || { };
|
|
||||||
var nest = true;
|
|
||||||
|
|
||||||
/* Extract translate strings */
|
|
||||||
if ("translate" in attrs || "translatable" in attrs) {
|
|
||||||
tasks = (attrs["translate"] || attrs["translatable"] || "yes").split(" ");
|
|
||||||
|
|
||||||
/* Calculate the line location taking into account nested parsing */
|
|
||||||
line = (node.location || { })["line"] || 0;
|
|
||||||
line += offsets;
|
|
||||||
|
|
||||||
entry = {
|
|
||||||
msgctxt: attrs['translate-context'] || attrs['context'],
|
|
||||||
msgid_plural: attrs['translate-plural'],
|
|
||||||
locations: [ filename + ":" + line ]
|
|
||||||
};
|
|
||||||
|
|
||||||
/* For each thing listed */
|
|
||||||
tasks.forEach(function(task) {
|
|
||||||
var copy = Object.assign({}, entry);
|
|
||||||
|
|
||||||
/* The element text itself */
|
|
||||||
if (task == "yes" || task == "translate") {
|
|
||||||
copy.msgid = extract(node.children);
|
|
||||||
nest = false;
|
|
||||||
|
|
||||||
/* An attribute */
|
|
||||||
} else if (task) {
|
|
||||||
copy.msgid = attrs[task];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy.msgid)
|
|
||||||
push(copy);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Walk through all the children */
|
|
||||||
if (nest)
|
|
||||||
walk(node.children);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Push an entry onto the list */
|
|
||||||
function push(entry) {
|
|
||||||
var key = entry.msgid + "\0" + entry.msgid_plural + "\0" + entry.msgctxt;
|
|
||||||
var prev = entries[key];
|
|
||||||
if (prev) {
|
|
||||||
prev.locations = prev.locations.concat(entry.locations);
|
|
||||||
} else {
|
|
||||||
entries[key] = entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Extract the given text */
|
|
||||||
function extract(children) {
|
|
||||||
if (!children)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var i, len, node, str = [];
|
|
||||||
children.forEach(function(node) {
|
|
||||||
if (node.type == 'tag' && node.children)
|
|
||||||
str.push(extract(node.children))
|
|
||||||
else if (node.type == 'text' && node.data)
|
|
||||||
str.push(node.data);
|
|
||||||
});
|
|
||||||
|
|
||||||
return str.join("");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Escape a string for inclusion in po file */
|
|
||||||
function escape(string) {
|
|
||||||
var bs = string.split('\\').join('\\\\').split('"').join('\\"');
|
|
||||||
return bs.split("\n").map(function(line) {
|
|
||||||
return '"' + line + '"';
|
|
||||||
}).join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finish by writing out the strings */
|
|
||||||
function finish() {
|
|
||||||
var result = [
|
|
||||||
'msgid ""',
|
|
||||||
'msgstr ""',
|
|
||||||
'"Project-Id-Version: PACKAGE_VERSION\\n"',
|
|
||||||
'"MIME-Version: 1.0\\n"',
|
|
||||||
'"Content-Type: text/plain; charset=UTF-8\\n"',
|
|
||||||
'"Content-Transfer-Encoding: 8bit\\n"',
|
|
||||||
'"X-Generator: Cockpit html2po\\n"',
|
|
||||||
'',
|
|
||||||
];
|
|
||||||
|
|
||||||
var msgid, entry;
|
|
||||||
for (msgid in entries) {
|
|
||||||
entry = entries[msgid];
|
|
||||||
result.push('#: ' + entry.locations.join(" "));
|
|
||||||
if (entry.msgctxt)
|
|
||||||
result.push('msgctxt ' + escape(entry.msgctxt));
|
|
||||||
result.push('msgid ' + escape(entry.msgid));
|
|
||||||
if (entry.msgid_plural) {
|
|
||||||
result.push('msgid_plural ' + escape(entry.msgid_plural));
|
|
||||||
result.push('msgstr[0] ""');
|
|
||||||
result.push('msgstr[1] ""');
|
|
||||||
} else {
|
|
||||||
result.push('msgstr ""');
|
|
||||||
}
|
|
||||||
result.push('');
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = result.join('\n');
|
|
||||||
if (!opts.output) {
|
|
||||||
process.stdout.write(data);
|
|
||||||
process.exit(0);
|
|
||||||
} else {
|
|
||||||
fs.writeFile(opts.output, data, function(err) {
|
|
||||||
if (err)
|
|
||||||
fatal(err.message);
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
185
po/manifest2po
185
po/manifest2po
|
|
@ -1,185 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Extracts translatable strings from manifest.json files.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
function fatal(message, code) {
|
|
||||||
console.log((filename || "manifest2po") + ": " + message);
|
|
||||||
process.exit(code || 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function usage() {
|
|
||||||
console.log("usage: manifest2po [-o output] input...");
|
|
||||||
process.exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
var fs, path, stdio;
|
|
||||||
|
|
||||||
try {
|
|
||||||
fs = require('fs');
|
|
||||||
path = require('path');
|
|
||||||
stdio = require('stdio');
|
|
||||||
} catch (ex) {
|
|
||||||
fatal(ex.message, 127); /* missing looks for this */
|
|
||||||
}
|
|
||||||
|
|
||||||
var opts = stdio.getopt({
|
|
||||||
directory: { key: "d", args: 1, description: "Base directory for input files" },
|
|
||||||
output: { key: "o", args: 1, description: "Output file" },
|
|
||||||
from: { key: "f", args: 1, description: "File containing list of input files" },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!opts.from && opts.args.length < 1) {
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
var input = opts.args;
|
|
||||||
var entries = { };
|
|
||||||
|
|
||||||
/* Filename being parsed */
|
|
||||||
var filename = null;
|
|
||||||
|
|
||||||
prepare();
|
|
||||||
|
|
||||||
/* Decide what input files to process */
|
|
||||||
function prepare() {
|
|
||||||
if (opts.from) {
|
|
||||||
fs.readFile(opts.from, { encoding: "utf-8"}, function(err, data) {
|
|
||||||
if (err)
|
|
||||||
fatal(err.message);
|
|
||||||
input = data.split("\n").filter(function(value) {
|
|
||||||
return !!value;
|
|
||||||
}).concat(input);
|
|
||||||
step();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
step();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now process each file in turn */
|
|
||||||
function step() {
|
|
||||||
filename = input.shift();
|
|
||||||
if (filename === undefined) {
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path.basename(filename) != "manifest.json")
|
|
||||||
return step();
|
|
||||||
|
|
||||||
fs.readFile(filename, { encoding: "utf-8"}, function(err, data) {
|
|
||||||
if (err)
|
|
||||||
fatal(err.message);
|
|
||||||
|
|
||||||
process_manifest(JSON.parse(data));
|
|
||||||
|
|
||||||
return step();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function process_manifest(manifest) {
|
|
||||||
if (manifest.menu)
|
|
||||||
process_menu(manifest.menu);
|
|
||||||
if (manifest.tools)
|
|
||||||
process_menu(manifest.tools);
|
|
||||||
}
|
|
||||||
|
|
||||||
function process_keywords(keywords) {
|
|
||||||
keywords.forEach(v => {
|
|
||||||
v.matches.forEach(keyword =>
|
|
||||||
push({
|
|
||||||
msgid: keyword,
|
|
||||||
locations: [ filename ]
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function process_docs(docs) {
|
|
||||||
docs.forEach(doc => {
|
|
||||||
push({
|
|
||||||
msgid: doc.label,
|
|
||||||
locations: [ filename ]
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function process_menu(menu) {
|
|
||||||
for (var m in menu) {
|
|
||||||
if (menu[m].label) {
|
|
||||||
push({
|
|
||||||
msgid: menu[m].label,
|
|
||||||
locations: [ filename ]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (menu[m].keywords)
|
|
||||||
process_keywords(menu[m].keywords);
|
|
||||||
if (menu[m].docs)
|
|
||||||
process_docs(menu[m].docs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Push an entry onto the list */
|
|
||||||
function push(entry) {
|
|
||||||
var key = entry.msgid + "\0" + entry.msgid_plural + "\0" + entry.msgctxt;
|
|
||||||
var prev = entries[key];
|
|
||||||
if (prev) {
|
|
||||||
prev.locations = prev.locations.concat(entry.locations);
|
|
||||||
} else {
|
|
||||||
entries[key] = entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Escape a string for inclusion in po file */
|
|
||||||
function escape(string) {
|
|
||||||
var bs = string.split('\\').join('\\\\').split('"').join('\\"');
|
|
||||||
return bs.split("\n").map(function(line) {
|
|
||||||
return '"' + line + '"';
|
|
||||||
}).join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finish by writing out the strings */
|
|
||||||
function finish() {
|
|
||||||
var result = [
|
|
||||||
'msgid ""',
|
|
||||||
'msgstr ""',
|
|
||||||
'"Project-Id-Version: PACKAGE_VERSION\\n"',
|
|
||||||
'"MIME-Version: 1.0\\n"',
|
|
||||||
'"Content-Type: text/plain; charset=UTF-8\\n"',
|
|
||||||
'"Content-Transfer-Encoding: 8bit\\n"',
|
|
||||||
'"X-Generator: Cockpit manifest2po\\n"',
|
|
||||||
'',
|
|
||||||
];
|
|
||||||
|
|
||||||
var msgid, entry;
|
|
||||||
for (msgid in entries) {
|
|
||||||
entry = entries[msgid];
|
|
||||||
result.push('#: ' + entry.locations.join(" "));
|
|
||||||
if (entry.msgctxt)
|
|
||||||
result.push('msgctxt ' + escape(entry.msgctxt));
|
|
||||||
result.push('msgid ' + escape(entry.msgid));
|
|
||||||
if (entry.msgid_plural) {
|
|
||||||
result.push('msgid_plural ' + escape(entry.msgid_plural));
|
|
||||||
result.push('msgstr[0] ""');
|
|
||||||
result.push('msgstr[1] ""');
|
|
||||||
} else {
|
|
||||||
result.push('msgstr ""');
|
|
||||||
}
|
|
||||||
result.push('');
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = result.join('\n');
|
|
||||||
if (!opts.output) {
|
|
||||||
process.stdout.write(data);
|
|
||||||
process.exit(0);
|
|
||||||
} else {
|
|
||||||
fs.writeFile(opts.output, data, function(err) {
|
|
||||||
if (err)
|
|
||||||
fatal(err.message);
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
(function (root, data) {
|
|
||||||
var loaded, module;
|
|
||||||
|
|
||||||
/* Load into Cockpit locale */
|
|
||||||
if (typeof cockpit === 'object') {
|
|
||||||
cockpit.locale(data)
|
|
||||||
loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!loaded)
|
|
||||||
root.po = data;
|
|
||||||
|
|
||||||
/* The syntax of this line is important by po2json */
|
|
||||||
}(this, {"":{"language":"en"}}));
|
|
||||||
127
po/po2json
127
po/po2json
|
|
@ -1,127 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
function fatal(message, code) {
|
|
||||||
console.log((filename || "html2po") + ": " + message);
|
|
||||||
process.exit(code || 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function usage() {
|
|
||||||
console.log("usage: po2json [--module=template.js] input output");
|
|
||||||
process.exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
var fs, po2json, Jed, stdio;
|
|
||||||
|
|
||||||
try {
|
|
||||||
fs = require('fs');
|
|
||||||
po2json = require('po2json');
|
|
||||||
Jed = require('jed');
|
|
||||||
stdio = require('stdio');
|
|
||||||
} catch(ex) {
|
|
||||||
fatal(ex.message, 127); /* missing looks for this */
|
|
||||||
}
|
|
||||||
|
|
||||||
var argi = 2;
|
|
||||||
var filename = null;
|
|
||||||
|
|
||||||
var opts = stdio.getopt({
|
|
||||||
module: { key: "m", args: 1, description: "Module template to include" },
|
|
||||||
output: { key: "o", args: 1, description: "Output file" },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (opts.args.length != 1) {
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
parse();
|
|
||||||
|
|
||||||
function prepareHeader(header) {
|
|
||||||
var body, statement, plurals = header["plural-forms"], ret = null;
|
|
||||||
if (plurals) {
|
|
||||||
try {
|
|
||||||
/* Check that the plural forms isn't being sneaky since we build a function here */
|
|
||||||
Jed.PF.parse(plurals);
|
|
||||||
} catch(ex) {
|
|
||||||
fatal("bad plural forms: " + ex.message, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A function for the front end */
|
|
||||||
statement = header["plural-forms"];
|
|
||||||
if (statement[statement.length - 1] != ';')
|
|
||||||
statement += ';';
|
|
||||||
ret = 'function(n) {\nvar nplurals, plural;\n' + statement + '\nreturn plural;\n}';
|
|
||||||
|
|
||||||
/* Added back in later */
|
|
||||||
delete header["plural-forms"];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We don't need to be transferring this */
|
|
||||||
delete header["project-id-version"];
|
|
||||||
delete header["report-msgid-bugs-to"];
|
|
||||||
delete header["pot-creation-date"];
|
|
||||||
delete header["po-revision-date"];
|
|
||||||
delete header["last-translator"];
|
|
||||||
delete header["language-team"];
|
|
||||||
delete header["mime-version"];
|
|
||||||
delete header["content-type"];
|
|
||||||
delete header["content-transfer-encoding"];
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse and process the po data */
|
|
||||||
function parse() {
|
|
||||||
filename = opts.args[0];
|
|
||||||
po2json.parseFile(opts.args[0], { "fuzzy": true }, function(err, jsonData) {
|
|
||||||
var plurals, pos;
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
fatal(err.message);
|
|
||||||
|
|
||||||
var header = jsonData[""];
|
|
||||||
if (header)
|
|
||||||
plurals = prepareHeader(header);
|
|
||||||
|
|
||||||
var data = JSON.stringify(jsonData, null, 1);
|
|
||||||
|
|
||||||
/* We know the brace in is the location to insert our function */
|
|
||||||
if (plurals) {
|
|
||||||
pos = data.indexOf('{', 1);
|
|
||||||
data = data.substr(0, pos + 1) + "'plural-forms':" + String(plurals) + "," + data.substr(pos + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data == JSON.stringify({}))
|
|
||||||
finish("");
|
|
||||||
else
|
|
||||||
wrap(data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wrap the data if desired */
|
|
||||||
function wrap(data) {
|
|
||||||
if (opts.module) {
|
|
||||||
filename = opts.module;
|
|
||||||
fs.readFile(opts.module, { encoding: "utf-8" }, function(err, template) {
|
|
||||||
if (err)
|
|
||||||
fatal(err.message);
|
|
||||||
data = template.replace('{"":{"language":"en"}}', data);
|
|
||||||
finish(data);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
finish(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write it out */
|
|
||||||
function finish(data) {
|
|
||||||
if (opts.output) {
|
|
||||||
fs.writeFile(opts.output, data, function(err) {
|
|
||||||
if (err)
|
|
||||||
fatal(err.message);
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
process.stdout.write(data);
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
import cockpit from 'cockpit';
|
import cockpit from 'cockpit';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './app.scss';
|
|
||||||
import View from "./recordings.jsx";
|
import View from "./recordings.jsx";
|
||||||
|
|
||||||
const _ = cockpit.gettext;
|
const _ = cockpit.gettext;
|
||||||
|
|
@ -29,10 +28,9 @@ export class Application extends React.Component {
|
||||||
super();
|
super();
|
||||||
this.state = { hostname: _("Unknown") };
|
this.state = { hostname: _("Unknown") };
|
||||||
|
|
||||||
cockpit.file('/etc/hostname').read()
|
cockpit.file('/etc/hostname').watch(content => {
|
||||||
.done((content) => {
|
this.setState({ hostname: content.trim() });
|
||||||
this.setState({ hostname: content.trim() });
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<!--
|
<!--
|
||||||
This file is part of Cockpit.
|
|
||||||
|
|
||||||
Copyright (C) 2017 Red Hat, Inc.
|
Copyright (C) 2017 Red Hat, Inc.
|
||||||
|
|
||||||
Cockpit is free software; you can redistribute it and/or modify it
|
Cockpit is free software; you can redistribute it and/or modify it
|
||||||
|
|
@ -15,25 +13,22 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
along with this package; If not, see <http://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
<html>
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title translate>Session Recording</title>
|
<title translate>Cockpit Session Recording</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<link rel="stylesheet" href="index.css">
|
<link rel="stylesheet" href="index.css">
|
||||||
|
|
||||||
<script type="text/javascript" src="../base1/cockpit.js"></script>
|
|
||||||
<script type="text/javascript" src="po.js"></script>
|
|
||||||
<script type="text/javascript" src="index.js"></script>
|
<script type="text/javascript" src="index.js"></script>
|
||||||
|
<script type="text/javascript" src="po.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="pf-m-redhat-form">
|
<body class="pf-m-redhat-font">
|
||||||
<div class="ct-page-fill" id="app"></div>
|
<div id="app"></div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
13
src/index.js
13
src/index.js
|
|
@ -17,12 +17,11 @@
|
||||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "./lib/patternfly/patternfly-4-cockpit.scss";
|
import "cockpit-dark-theme";
|
||||||
|
import "patternfly/patternfly-4-cockpit.scss";
|
||||||
import "core-js/stable";
|
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { Application } from './app.jsx';
|
import { Application } from './app.jsx';
|
||||||
/*
|
/*
|
||||||
* PF4 overrides need to come after the JSX components imports because
|
* PF4 overrides need to come after the JSX components imports because
|
||||||
|
|
@ -31,8 +30,10 @@ import { Application } from './app.jsx';
|
||||||
* out of the dist/index.js and since it will maintain the order of the imported CSS,
|
* out of the dist/index.js and since it will maintain the order of the imported CSS,
|
||||||
* the overrides will be correctly in the end of our stylesheet.
|
* the overrides will be correctly in the end of our stylesheet.
|
||||||
*/
|
*/
|
||||||
import "./lib/patternfly/patternfly-4-overrides.scss";
|
import "patternfly/patternfly-4-overrides.scss";
|
||||||
|
import './app.scss';
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
ReactDOM.render(React.createElement(Application, {}), document.getElementById('app'));
|
const root = createRoot(document.getElementById('app'));
|
||||||
|
root.render(<Application />);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "session-recording",
|
"name": "session-recording",
|
||||||
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"cockpit": "122"
|
"cockpit": "137"
|
||||||
},
|
},
|
||||||
|
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|
|
||||||
|
|
@ -67,15 +67,15 @@
|
||||||
|
|
||||||
.search-wrap {
|
.search-wrap {
|
||||||
min-height: 25px;
|
min-height: 25px;
|
||||||
display:block;
|
display: block;
|
||||||
clear:both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
.session_time {
|
.session_time {
|
||||||
margin-right:5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pf-c-progress__indicator:after {
|
.pf-c-progress__indicator::after {
|
||||||
content: "";
|
content: "";
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
|
|
|
||||||
|
|
@ -623,7 +623,7 @@ const PacketBuffer = class {
|
||||||
|
|
||||||
function SearchEntry(props) {
|
function SearchEntry(props) {
|
||||||
return (
|
return (
|
||||||
<span className="search-result"><a onClick={(e) => props.fastForwardToTS(props.pos, e)}>{formatDuration(props.pos)}</a></span>
|
<span className="search-result"><a href="#search-result" onClick={(e) => props.fastForwardToTS(props.pos, e)}>{formatDuration(props.pos)}</a></span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,12 @@ import configparser
|
||||||
TEST_DIR = os.path.dirname(__file__)
|
TEST_DIR = os.path.dirname(__file__)
|
||||||
sys.path.append(os.path.join(TEST_DIR, "common"))
|
sys.path.append(os.path.join(TEST_DIR, "common"))
|
||||||
sys.path.append(os.path.join(os.path.dirname(TEST_DIR), "bots/machine"))
|
sys.path.append(os.path.join(os.path.dirname(TEST_DIR), "bots/machine"))
|
||||||
from testlib import *
|
import testlib
|
||||||
|
|
||||||
# Test with pre-recorded journal files
|
# Nondestructive tests all run in the same running VM. This allows them to run in Packit, Fedora, and RHEL dist-git gating
|
||||||
class TestApplication(MachineCase):
|
# They must not permanently change any file or configuration on the system in a way that influences other tests.
|
||||||
|
@testlib.nondestructive
|
||||||
|
class TestApplication(testlib.MachineCase):
|
||||||
def _login(self, loc="/session-recording", wait="#app"):
|
def _login(self, loc="/session-recording", wait="#app"):
|
||||||
self.login_and_go(loc)
|
self.login_and_go(loc)
|
||||||
b = self.browser
|
b = self.browser
|
||||||
|
|
@ -408,4 +410,4 @@ class TestApplication(MachineCase):
|
||||||
b.wait_present("#app")
|
b.wait_present("#app")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_main()
|
testlib.test_main()
|
||||||
|
|
|
||||||
1
test/reference-image
Normal file
1
test/reference-image
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
fedora-36
|
||||||
8
test/run
8
test/run
|
|
@ -4,5 +4,11 @@ set -eu
|
||||||
# This is the expected entry point for Cockpit CI; will be called without
|
# This is the expected entry point for Cockpit CI; will be called without
|
||||||
# arguments but with an appropriate $TEST_OS, and optionally $TEST_SCENARIO
|
# arguments but with an appropriate $TEST_OS, and optionally $TEST_SCENARIO
|
||||||
|
|
||||||
[ -z "${TEST_SCENARIO:-}" ] || export TEST_BROWSER="$TEST_SCENARIO"
|
TEST_SCENARIO="${TEST_SCENARIO:-}"
|
||||||
|
[ "${TEST_SCENARIO}" = "${TEST_SCENARIO##firefox}" ] || export TEST_BROWSER=firefox
|
||||||
|
export RUN_TESTS_OPTIONS=--track-naughties
|
||||||
|
|
||||||
|
# linters are off by default for production builds, but we want to run them in CI
|
||||||
|
export LINT=1
|
||||||
|
|
||||||
make check
|
make check
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# image-customize script to enable cockpit in test VMs
|
# image-customize script to prepare a bots VM for testing this application
|
||||||
# The application RPM will be installed separately
|
# The application package will be installed separately
|
||||||
set -eu
|
set -eux
|
||||||
|
|
||||||
# don't force https:// (self-signed cert)
|
# don't force https:// (self-signed cert)
|
||||||
printf "[WebService]\\nAllowUnencrypted=true\\n" > /etc/cockpit/cockpit.conf
|
printf "[WebService]\\nAllowUnencrypted=true\\n" > /etc/cockpit/cockpit.conf
|
||||||
|
|
@ -11,5 +11,5 @@ if type firewall-cmd >/dev/null 2>&1; then
|
||||||
fi
|
fi
|
||||||
systemctl enable cockpit.socket
|
systemctl enable cockpit.socket
|
||||||
|
|
||||||
# HACK: See https://github.com/cockpit-project/cockpit/issues/14133
|
# needed for testAppMenu
|
||||||
mkdir -p /usr/share/cockpit/packagekit
|
dnf install -y cockpit-packagekit
|
||||||
|
|
|
||||||
|
|
@ -1,202 +0,0 @@
|
||||||
const path = require("path");
|
|
||||||
const copy = require("copy-webpack-plugin");
|
|
||||||
const extract = require("mini-css-extract-plugin");
|
|
||||||
const fs = require("fs");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const CompressionPlugin = require("compression-webpack-plugin");
|
|
||||||
const ESLintPlugin = require('eslint-webpack-plugin');
|
|
||||||
|
|
||||||
var externals = {
|
|
||||||
cockpit: "cockpit",
|
|
||||||
};
|
|
||||||
|
|
||||||
/* These can be overridden, typically from the Makefile.am */
|
|
||||||
const srcdir = (process.env.SRCDIR || __dirname) + path.sep + "src";
|
|
||||||
const builddir = process.env.SRCDIR || __dirname;
|
|
||||||
const distdir = builddir + path.sep + "dist";
|
|
||||||
const section = process.env.ONLYDIR || null;
|
|
||||||
const libdir = path.resolve(srcdir, "lib")
|
|
||||||
// absolute path disables recursive module resolution, so build a relative one
|
|
||||||
const nodedir = path.relative(process.cwd(), path.resolve((process.env.SRCDIR || __dirname), "node_modules"));
|
|
||||||
|
|
||||||
/* A standard nodejs and webpack pattern */
|
|
||||||
var production = process.env.NODE_ENV === "production";
|
|
||||||
|
|
||||||
var info = {
|
|
||||||
entries: {
|
|
||||||
index: [
|
|
||||||
"./index.js",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
files: [
|
|
||||||
"index.html",
|
|
||||||
"manifest.json"
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
var output = {
|
|
||||||
path: distdir,
|
|
||||||
filename: "[name].js",
|
|
||||||
sourceMapFilename: "[file].map",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Non-JS files which are copied verbatim to dist/
|
|
||||||
const copy_files = [
|
|
||||||
"./src/index.html",
|
|
||||||
"./src/manifest.json",
|
|
||||||
];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note that we're avoiding the use of path.join as webpack and nodejs
|
|
||||||
* want relative paths that start with ./ explicitly.
|
|
||||||
*
|
|
||||||
* In addition we mimic the VPATH style functionality of GNU Makefile
|
|
||||||
* where we first check builddir, and then srcdir.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function vpath(/* ... */) {
|
|
||||||
var filename = Array.prototype.join.call(arguments, path.sep);
|
|
||||||
var expanded = builddir + path.sep + filename;
|
|
||||||
if (fs.existsSync(expanded)) return expanded;
|
|
||||||
expanded = srcdir + path.sep + filename;
|
|
||||||
return expanded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Qualify all the paths in entries */
|
|
||||||
Object.keys(info.entries).forEach(function (key) {
|
|
||||||
if (section && key.indexOf(section) !== 0) {
|
|
||||||
delete info.entries[key];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.entries[key] = info.entries[key].map(function (value) {
|
|
||||||
if (value.indexOf("/") === -1) return value;
|
|
||||||
else return vpath(value);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/* Qualify all the paths in files listed */
|
|
||||||
var files = [];
|
|
||||||
info.files.forEach(function (value) {
|
|
||||||
if (!section || value.indexOf(section) === 0)
|
|
||||||
files.push({ from: vpath("src", value), to: value });
|
|
||||||
});
|
|
||||||
info.files = files;
|
|
||||||
|
|
||||||
const plugins = [
|
|
||||||
new copy({ patterns: copy_files }),
|
|
||||||
new extract({filename: "[name].css"}),
|
|
||||||
new ESLintPlugin({ extensions: ["js", "jsx"], exclude: ["spec", "node_modules", "src/lib"] }),
|
|
||||||
];
|
|
||||||
|
|
||||||
/* Only minimize when in production mode */
|
|
||||||
if (production) {
|
|
||||||
plugins.unshift(
|
|
||||||
new CompressionPlugin({
|
|
||||||
test: /\.(css|js|html)$/,
|
|
||||||
deleteOriginalAssets: true,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
var babel_loader = {
|
|
||||||
loader: "babel-loader",
|
|
||||||
options: {
|
|
||||||
presets: [
|
|
||||||
[
|
|
||||||
"@babel/env",
|
|
||||||
{
|
|
||||||
targets: {
|
|
||||||
chrome: "57",
|
|
||||||
firefox: "52",
|
|
||||||
safari: "10.3",
|
|
||||||
edge: "16",
|
|
||||||
opera: "44",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"@babel/preset-react",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mode: production ? "production" : "development",
|
|
||||||
resolve: {
|
|
||||||
modules: [libdir, nodedir],
|
|
||||||
},
|
|
||||||
entry: info.entries,
|
|
||||||
externals: externals,
|
|
||||||
output: output,
|
|
||||||
devtool: "source-map",
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: babel_loader,
|
|
||||||
test: /\.(js|jsx)$/,
|
|
||||||
},
|
|
||||||
/* HACK: remove unwanted fonts from PatternFly's css */
|
|
||||||
{
|
|
||||||
test: /patternfly-4-cockpit.scss$/,
|
|
||||||
use: [
|
|
||||||
extract.loader,
|
|
||||||
{
|
|
||||||
loader: "css-loader",
|
|
||||||
options: {
|
|
||||||
sourceMap: true,
|
|
||||||
url: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: "string-replace-loader",
|
|
||||||
options: {
|
|
||||||
multiple: [
|
|
||||||
{
|
|
||||||
search: /src:url\("patternfly-icons-fake-path\/pficon[^}]*/g,
|
|
||||||
replace: "src:url('fonts/patternfly.woff')format('woff');",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
search: /@font-face[^}]*patternfly-fonts-fake-path[^}]*}/g,
|
|
||||||
replace: "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: !production,
|
|
||||||
sassOptions: {
|
|
||||||
outputStyle: production ? 'compressed' : undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.s?css$/,
|
|
||||||
exclude: /patternfly-4-cockpit.scss/,
|
|
||||||
use: [
|
|
||||||
extract.loader,
|
|
||||||
{
|
|
||||||
loader: "css-loader",
|
|
||||||
options: {
|
|
||||||
sourceMap: true,
|
|
||||||
url: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: !production,
|
|
||||||
sassOptions: {
|
|
||||||
outputStyle: production ? 'compressed' : undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
plugins: plugins,
|
|
||||||
};
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue