This commit is contained in:
2022-05-17 01:56:44 +03:00
commit 3a9b8c8468
117 changed files with 7175 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
tmp/*
chromedriver*
*.apk
+93
View File
@@ -0,0 +1,93 @@
FROM golang:1.17 as go
COPY tmp/devtools /devtools
RUN \
apt-get update && \
apt-get install -y upx-ucl libx11-dev && \
cd /devtools && \
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" && \
upx /devtools/devtools
FROM ubuntu:18.04
ARG APPIUM_VERSION="1.8.1"
RUN \
apt update && \
apt remove -y libcurl4 && \
apt install -y apt-transport-https ca-certificates tzdata locales libcurl4 curl gnupg && \
curl --silent --location https://deb.nodesource.com/setup_12.x | bash - && \
apt install -y --no-install-recommends \
curl \
iproute2 \
nodejs \
openjdk-8-jdk-headless \
unzip \
xvfb \
libpulse0 \
libxcomposite1 \
libxcursor1 \
libxi6 \
libasound2 \
fluxbox \
x11vnc \
feh \
wmctrl \
libglib2.0-0 && \
apt-get clean && \
rm -Rf /tmp/* && rm -Rf /var/lib/apt/lists/*
RUN cd / && npm install --prefix ./opt/ appium@$APPIUM_VERSION
COPY android.conf /etc/ld.so.conf.d/
COPY fluxbox/aerokube /usr/share/fluxbox/styles/
COPY fluxbox/init /root/.fluxbox/
COPY fluxbox/aerokube.png /usr/share/images/fluxbox/
COPY --from=go /devtools/devtools /usr/bin/
# Android SDK
ENV ANDROID_HOME /opt/android-sdk-linux
ENV PATH /opt/android-sdk-linux/platform-tools:/opt/android-sdk-linux/tools:/opt/android-sdk-linux/tools/bin:/opt/android-sdk-linux/emulator:$PATH
ENV LD_LIBRARY_PATH ${ANDROID_HOME}/emulator/lib64:${ANDROID_HOME}/emulator/lib64/gles_swiftshader:${ANDROID_HOME}/emulator/lib64/qt/lib:${ANDROID_HOME}/emulator/lib64/vulkan:${LD_LIBRARY_PATH}
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64
ARG ANDROID_DEVICE=""
ARG REPLACE_IMG="y"
ARG AVD_NAME="android6.0-1"
ARG BUILD_TOOLS="build-tools;23.0.1"
ARG PLATFORM="android-23"
ARG EMULATOR_IMAGE="system-images;android-23;default;x86"
ARG EMULATOR_IMAGE_TYPE="default"
ARG ANDROID_ABI="x86"
ARG SDCARD_SIZE="500"
ARG USERDATA_SIZE="500"
RUN \
curl -o sdk-tools.zip https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip && \
mkdir -p /opt/android-sdk-linux /root/.config/Android\ Open\ Source\ Project/ && \
unzip -q sdk-tools.zip -d /opt/android-sdk-linux && \
rm sdk-tools.zip && \
yes | sdkmanager --licenses
RUN \
sdkmanager "emulator" "tools" "platform-tools" "$BUILD_TOOLS" "platforms;$PLATFORM" "$EMULATOR_IMAGE" && \
mksdcard "$SDCARD_SIZE"M sdcard.img && \
echo "no" | ( \
([ -n "$ANDROID_DEVICE" ] && avdmanager create avd -n "$AVD_NAME" -k "$EMULATOR_IMAGE" --abi "$ANDROID_ABI" --device "$ANDROID_DEVICE" --sdcard /sdcard.img ) || \
avdmanager create avd -n "$AVD_NAME" -k "$EMULATOR_IMAGE" --abi "$ANDROID_ABI" --sdcard /sdcard.img \
) && \
ldconfig && \
( \
resize2fs /root/.android/avd/$AVD_NAME.avd/userdata.img "$USERDATA_SIZE"M || \
/opt/android-sdk-linux/emulator/qemu-img resize -f raw /root/.android/avd/$AVD_NAME.avd/userdata.img "$USERDATA_SIZE"M \
) && \
([ -z "$REPLACE_IMG" ] || mv /root/.android/avd/$AVD_NAME.avd/userdata.img /root/.android/avd/$AVD_NAME.avd/userdata-qemu.img ) && \
rm /opt/android-sdk-linux/system-images/$PLATFORM/$EMULATOR_IMAGE_TYPE/"$ANDROID_ABI"/userdata.img
COPY ["Emulator.conf", "/root/.config/Android Open Source Project/Emulator.conf"]
COPY emulator-snapshot.sh tmp/chromedriver* *.apk /usr/bin/
# Entrypoint
COPY tmp/entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
+2
View File
@@ -0,0 +1,2 @@
[General]
showNestedWarning=false
+2
View File
@@ -0,0 +1,2 @@
/opt/android-sdk-linux/emulator/lib64
/opt/android-sdk-linux/emulator/lib64/gles_swiftshader
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
MAX_ATTEMPTS=5
adb root
adb devices | grep emulator | cut -f1 | while read id; do
apks=(/usr/bin/*.apk)
for apk in "${apks[@]}"; do
if [ -r "$apk" ]; then
for i in `seq 1 ${MAX_ATTEMPTS}`; do
echo "Installing $apk (attempt #$i of $MAX_ATTEMPTS)"
adb -s "$id" install -r "$apk" && break || sleep 15 && echo "Retrying to install $apk"
done
fi
done
adb -s "$id" emu kill -2 || true
done
rm -f /tmp/.X99-lock || true
+88
View File
@@ -0,0 +1,88 @@
#!/bin/bash
CHROMEDRIVER_PORT=9515
BOOTSTRAP_PORT=4725
EMULATOR=emulator-5554
APPIUM_ARGS=${APPIUM_ARGS:-""}
EMULATOR_ARGS=${EMULATOR_ARGS:-""}
PORT=${PORT:-"4444"}
DISPLAY_NUM=99
export DISPLAY=":$DISPLAY_NUM"
SCREEN_RESOLUTION=${SCREEN_RESOLUTION:-"1920x1080x24"}
SKIN=${SKIN:-"1080x1920"}
STOP=""
VERBOSE=${VERBOSE:-""}
if [ -z "$VERBOSE" ]; then
if [ -z "$APPIUM_ARGS" ]; then
APPIUM_ARGS="--log-level error"
fi
else
EMULATOR_ARGS="$EMULATOR_ARGS -verbose"
fi
clean() {
STOP="yes"
if [ -n "$APPIUM_PID" ]; then
kill -TERM "$APPIUM_PID"
fi
if [ -n "$EMULATOR_PID" ]; then
kill -TERM "$EMULATOR_PID"
fi
if [ -n "$X11VNC_PID" ]; then
kill -TERM "$X11VNC_PID"
fi
if [ -n "$DEVTOOLS_PID" ]; then
kill -TERM "$DEVTOOLS_PID"
fi
if [ -n "$XVFB_PID" ]; then
kill -TERM "$XVFB_PID"
fi
}
trap clean SIGINT SIGTERM
/usr/bin/xvfb-run -e /dev/stdout -l -n "$DISPLAY_NUM" -s "-ac -screen 0 $SCREEN_RESOLUTION -noreset -listen tcp" /usr/bin/fluxbox -display "$DISPLAY" -log /tmp/fluxbox.log 2>/dev/null &
XVFB_PID=$!
retcode=1
until [ $retcode -eq 0 ] || [ -n "$STOP" ]; do
DISPLAY="$DISPLAY" wmctrl -m >/dev/null 2>&1
retcode=$?
if [ $retcode -ne 0 ]; then
echo Waiting X server...
sleep 0.1
fi
done
if [ -n "$STOP" ]; then exit 0; fi
if [ "$ENABLE_VNC" != "true" ] && [ "$ENABLE_VIDEO" != "true" ]; then
EMULATOR_ARGS="$EMULATOR_ARGS -no-window"
fi
ANDROID_AVD_HOME=/root/.android/avd DISPLAY="$DISPLAY" /opt/android-sdk-linux/emulator/emulator ${EMULATOR_ARGS} -writable-system -no-boot-anim -no-audio -no-jni -avd @AVD_NAME@ -sdcard /sdcard.img -skin "$SKIN" -skindir /opt/android-sdk-linux/platforms/@PLATFORM@/skins/ -gpu swiftshader_indirect -ranchu -qemu -enable-kvm &
EMULATOR_PID=$!
if [ "$ENABLE_VNC" == "true" ]; then
x11vnc -display "$DISPLAY" -passwd selenoid -shared -forever -loop500 -rfbport 5900 -rfbportv6 5900 -logfile /tmp/x11vnc.log &
X11VNC_PID=$!
fi
while [ "$(adb shell getprop sys.boot_completed | tr -d '\r')" != "1" ] && [ -z "$STOP" ] ; do sleep 1; done
if [ -n "$STOP" ]; then exit 0; fi
DEFAULT_CAPABILITIES='"androidNaturalOrientation": true, "deviceName": "android", "platformName": "Android", "noReset": true, "udid":"'$EMULATOR'"'
if [ -n "@CHROME_MOBILE@" ]; then
while ip addr | grep inet | grep -q tentative > /dev/null; do sleep 0.1; done
DEFAULT_CAPABILITIES=$DEFAULT_CAPABILITIES', "chromedriverPort": '$CHROMEDRIVER_PORT
/usr/bin/devtools --android &
DEVTOOLS_PID=$!
fi
if [ -x "/usr/bin/chromedriver" ]; then
DEFAULT_CAPABILITIES=$DEFAULT_CAPABILITIES',"chromedriverExecutable": "/usr/bin/chromedriver"'
fi
/opt/node_modules/.bin/appium -a 0.0.0.0 -p "$PORT" -bp "$BOOTSTRAP_PORT" --log-timestamp --log-no-colors --command-timeout 90 --no-reset ${APPIUM_ARGS} --default-capabilities "{$DEFAULT_CAPABILITIES}" &
APPIUM_PID=$!
wait
+175
View File
@@ -0,0 +1,175 @@
###############################################################################
#
# name: aerokube (based on ubuntu_light)
# made: paultag
# date: 16-10-2010
# http://pault.ag/
#
############################################################## BACKGROUND ######
# background: flat
# background.color: #2c001e
# background.colorTo: #2c001e
background: fullscreen
background.pixmap: /usr/share/images/fluxbox/aerokube.png
############################################################## FONTS ##########
menu.frame.font: Ubuntu-10:bold
menu.title.font: Ubuntu-12:bold
toolbar.clock.font: Ubuntu-10:bold
toolbar.workspace.font: Ubuntu-12:bold
toolbar.iconbar.focused.font: Ubuntu-10:bold
toolbar.iconbar.unfocused.font: Ubuntu-10
window.font: Ubuntu-10
############################################################## MENU ###########
menu.bevelWidth: 1
#menu.itemHeight: 35
#menu.titleHeight: 21
menu.borderColor: #525252
menu.borderWidth: 1
menu.bullet: Triangle
menu.bullet.position: Right
menu.frame.underlineColor: #ffffff
menu.title: flat gradient rectangle
menu.title.justify: center
menu.title.color: #FFFFFF
menu.title.colorTo: #FFFFFF
menu.title.textColor: #333333
menu.frame: flat gradient crossdiagonal
menu.frame.justify: left
menu.frame.color: #FFFFFF
menu.frame.colorTo: #FFFFFF
menu.frame.textColor: #333333
menu.frame.disableColor: #aea79f
menu.hilite: flat gradient rectangle
menu.hilite.color: #aea79f
menu.hilite.colorTo: #aea79f
menu.hilite.textColor: #000000
############################################################## TOOLBAR ########
toolbar.bevelWidth: 0
toolbar.borderWidth: 1
toolbar.borderColor: #aea79f
toolbar.height: 20
toolbar.justify: center
toolbar: flat gradient rectangle
toolbar.pixmap:
toolbar.color: #aea79f
toolbar.colorTo: #aea79f
toolbar.clock: parentrelative
toolbar.clock.justify: center
toolbar.clock.color: #
toolbar.clock.colorTo: #
toolbar.clock.textColor: #333333
toolbar.workspace: parentrelative
toolbar.workspace.justify: Center
toolbar.workspace.color: #
toolbar.workspace.colorTo: #
toolbar.workspace.textColor: #333333
toolbar.button: parentrelative
toolbar.button.color: #333333
toolbar.button.colorTo: #333333
toolbar.button.picColor: #333333
toolbar.button.pressed: parentrelative
toolbar.button.pressed.color: #aea79f
toolbar.button.pressed.colorTo: #aea79f
toolbar.button.pressed.picColor: #000000
toolbar.iconbar.borderWidth: 1
toolbar.iconbar.borderColor: #333333
toolbar.iconbar.empty: parentrelative
toolbar.iconbar.empty.color: #
toolbar.iconbar.empty.colorTo: #
toolbar.iconbar.focused.borderWidth: 1
toolbar.iconbar.focused.borderColor: #333333
toolbar.iconbar.focused: flat gradient rectangle
toolbar.iconbar.focused.color: #FFFFFF
toolbar.iconbar.focused.colorTo: #FFFFFF
toolbar.iconbar.focused.textColor: #333333
toolbar.iconbar.focused.justify: center
toolbar.iconbar.unfocused.borderWidth: 1
toolbar.iconbar.unfocused.borderColor: #525252
toolbar.iconbar.unfocused: flat gradient rectangle
toolbar.iconbar.unfocused.color: #aea79f
toolbar.iconbar.unfocused.colorTo: #aea79f
toolbar.iconbar.unfocused.textColor: #444444
toolbar.iconbar.unfocused.justify: center
############################################################## WINDOW #########
window.roundCorners: TopRight TopLeft
window.bevelWidth: 4
window.shade: false
window.borderWidth: 1
window.borderColor: #333333
window.justify: Center
window.title.height: 21
window.title.focus: flat gradient rectangle
window.title.focus.color: #000000
window.title.focus.colorTo: #333333
window.title.unfocus: flat gradient rectangle
window.title.unfocus.color: #111111
window.title.unfocus.colorTo: #444444
window.label.focus: parentrelative
window.label.focus.color: #
window.label.focus.colorTo: #
window.label.focus.textColor: #FFFFFF
window.label.unfocus: parentrelative
window.label.unfocus.color: #
window.label.unfocus.colorTo: #
window.label.unfocus.textColor: #aea79f
window.button.focus: parentrelative
window.button.focus.color: #
window.button.focus.colorTo: #
window.button.focus.picColor: #FFFFFF
window.button.unfocus: parentrelative
window.button.unfocus.Color: #
window.button.unfocus.ColorTo: #
window.button.unfocus.picColor: #888888
window.button.pressed: parentrelative
window.button.pressed.color: #
window.button.pressed.colorTo: #
window.button.pressed.picColor: #000000
window.handle.focus: flat
window.handle.focus.color: #1f1f1f
window.handle.focus.colorTo: #1f1f1f
window.handle.unfocus: lat
window.handle.unfocus.color: #1f1f1f
window.handle.unfocus.colorTo: #1f1f1f
window.handleWidth: 2
window.grip.focus: flat
window.grip.focus.color: #525252
window.grip.focus.colorTo: #525252
window.grip.unfocus: flat
window.grip.unfocus.color: #1f1f1f
window.grip.unfocus.colorTo: #1f1f1f
###############################################################################
# EOF
Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

+7
View File
@@ -0,0 +1,7 @@
session.menuFile: ~/.fluxbox/menu
session.keyFile: ~/.fluxbox/keys
session.styleFile: /usr/share/fluxbox/styles/aerokube
session.configVersion: 13
session.screen0.strftimeFormat: %d %b, %a %02k:%M:%S
session.screen0.toolbar.visible: false
session.screen0.toolbar.tools:
+251
View File
@@ -0,0 +1,251 @@
#!/bin/bash
set -e
die(){
echo "$1"
return 1
}
require_command(){
if [ -z "$(command -v $1)" ]; then
die "$1 command required for this script to run"
fi
}
request_answer(){
prompt=$1
default_value=$2
if [ -n "$default_value" ]; then
prompt="$prompt [$default_value]"
fi
read -r -p "$prompt " value
if [ -z "$value" ] && [ -n "$default_value" ]; then
value="$default_value"
fi
echo "$value"
}
validate_android_version(){
version="$1"
type=${2:-"default"}
abi=${3:-"x86"}
avd_name="android$version-1"
build_tools="build-tools;29.0.2"
replace_img="y"
case "$version" in
4.4)
platform="android-19"
emulator_image="system-images;android-19;$type;$abi"
;;
5.0)
platform="android-21"
emulator_image="system-images;android-21;$type;$abi"
;;
5.1)
platform="android-22"
emulator_image="system-images;android-22;$type;$abi"
;;
6.0)
platform="android-23"
emulator_image="system-images;android-23;$type;$abi"
;;
7.0)
platform="android-24"
emulator_image="system-images;android-24;$type;$abi"
;;
7.1)
platform="android-25"
emulator_image="system-images;android-25;$type;$abi"
;;
8.0)
platform="android-26"
emulator_image="system-images;android-26;$type;$abi"
;;
8.1)
platform="android-27"
emulator_image="system-images;android-27;$type;$abi"
;;
9.0)
platform="android-28"
emulator_image="system-images;android-28;$type;$abi"
replace_img=""
;;
10.0)
platform="android-29"
emulator_image="system-images;android-29;$type;$abi"
replace_img=""
;;
11.0)
platform="android-30"
emulator_image="system-images;android-30;$type;$abi"
replace_img=""
;;
12.0)
platform="android-31"
emulator_image="system-images;android-31;$type;$abi"
replace_img=""
;;
*)
echo "Unsupported Android version"
false
;;
esac
}
validate_android_image_type(){
type="$1"
case "$type" in
"default" | "google_apis" | "google_apis_playstore" | "android-wear" | "android-tv" )
;;
*)
echo "Unsupported Android image type"
false
;;
esac
}
validate_android_abi(){
abi="$1"
case "$abi" in
"armeabi-v7a" | "arm64-v8a" | "x86" | "x86_64" )
;;
*)
echo "Unsupported Application Binary Interface"
false
;;
esac
}
download_chromedriver() {
pushd "$TMP_DIR"
wget -O chromedriver.zip http://chromedriver.storage.googleapis.com/$1/chromedriver_linux64.zip
unzip chromedriver.zip
rm chromedriver.zip
popd
}
test_image(){
tests_dir=../../selenoid-container-tests/
if [ -d "$tests_dir" ]; then
echo "Running test suite on image."
docker rm -f selenium || true
docker run -d --privileged --name selenium -p 4445:4444 $1
echo "Waiting for image to start..."
sleep 20
pushd "$tests_dir"
mvn clean test -Dgrid.connection.url="http://localhost:4445/wd/hub" -Dgrid.browser.name=chrome || true
popd
docker rm -f selenium || true
else
echo "Skipping tests as $tests_dir does not exist."
fi
}
require_command "docker"
require_command "sed"
require_command "true"
require_command "false"
require_command "wget"
require_command "unzip"
require_command "cut"
TMP_DIR="android/tmp"
rm -Rf ./"$TMP_DIR" || true
mkdir -p "$TMP_DIR"
cp android/entrypoint.sh "$TMP_DIR/entrypoint.sh"
cp -r ../static/chrome/devtools "$TMP_DIR/devtools"
appium_version=$(request_answer "Specify Appium version:" "1.18.1")
until [ "$?" -ne 0 ]; do
android_image_type=$(request_answer "Specify Android image type (possible values: \"default\", \"google_apis\", \"google_apis_playstore\", \"android-tv\", \"android-wear\"):" "default")
if validate_android_image_type "$android_image_type"; then
break
fi
done
until [ "$?" -ne 0 ]; do
android_abi=$(request_answer "Specify Application Binary Interface (possible values: \"armeabi-v7a\", \"arm64-v8a\", \"x86\", \"x86_64\"):" "x86")
if validate_android_abi "$android_abi"; then
break
fi
done
until [ "$?" -ne 0 ]; do
android_version=$(request_answer "Specify Android version:" "8.1")
if validate_android_version "$android_version" "$android_image_type" "$android_abi"; then
break
fi
done
IFS=';' read -ra emulator_image_info <<< "$emulator_image"
emulator_image_type=${emulator_image_info[2]}
sed -i.bak "s|@AVD_NAME@|$avd_name|g" "$TMP_DIR/entrypoint.sh"
sed -i.bak "s|@PLATFORM@|$platform|g" "$TMP_DIR/entrypoint.sh"
android_device=$(request_answer "Specify device preset name if needed (e.g. \"Nexus 4\"):")
sdcard_size=$(request_answer "Specify SD card size, Mb:" 500)
userdata_size=$(request_answer "Specify userdata.img size, Mb:" 500)
image_name="android"
default_tag="$android_version"
chrome_mobile=$(request_answer "Are you building a Chrome Mobile image (for mobile web testing):" "n")
if [ "y" == "$chrome_mobile" ]; then
sed -i.bak 's|@CHROME_MOBILE@|yes|g' "$TMP_DIR/entrypoint.sh"
image_name="chrome-mobile"
else
sed -i.bak 's|@CHROME_MOBILE@||g' "$TMP_DIR/entrypoint.sh"
fi
chromedriver_version=$(request_answer "Specify Chromedriver version if needed (required for Chrome Mobile):")
if [ -n "$chromedriver_version" ]; then
chrome_major_version="$(cut -d'.' -f1 <<<${chromedriver_version})"
chrome_minor_version="$(cut -d'.' -f2 <<<${chromedriver_version})"
if [ -n "$chrome_major_version" ] && [ -n "$chrome_minor_version" ]; then
default_tag="$chrome_major_version.$chrome_minor_version"
fi
fi
tag=$(request_answer "Specify image tag:" "selenoid/$image_name:$default_tag")
need_quickboot=$(request_answer "Add Android quick boot snapshot?" "y")
if [ -n "$chromedriver_version" ]; then
download_chromedriver "$chromedriver_version"
fi
rm -Rf *.bak || true
set -x
tmp_tag="$tag"_tmp
docker build -t "$tmp_tag" \
--build-arg APPIUM_VERSION="$appium_version" \
--build-arg ANDROID_DEVICE="$android_device" \
--build-arg REPLACE_IMG="$replace_img" \
--build-arg AVD_NAME="$avd_name" \
--build-arg BUILD_TOOLS="$build_tools" \
--build-arg PLATFORM="$platform" \
--build-arg EMULATOR_IMAGE="$emulator_image" \
--build-arg EMULATOR_IMAGE_TYPE="$emulator_image_type" \
--build-arg ANDROID_ABI="$android_abi" \
--build-arg SDCARD_SIZE="$sdcard_size" \
--build-arg USERDATA_SIZE="$userdata_size" android
if [ "$need_quickboot" == "y" ]; then
id=$(docker run -e CHROME_MOBILE="$chrome_mobile" -d --privileged "$tmp_tag")
sleep 60
docker exec "$id" "/usr/bin/emulator-snapshot.sh"
sleep 30 # Wait for snapshot to save
docker commit "$id" "$tag"
docker rm -f "$id" || true
else
docker tag "$tmp_tag" "$tag"
fi
docker rmi -f "$tmp_tag" || true
set +x
if [ "y" == "$chrome_mobile" ]; then
test_image "$tag"
fi
read -r -p "Push?" yn
if [ "$yn" == "y" ]; then
docker push "$tag"
fi
+121
View File
@@ -0,0 +1,121 @@
package main
import (
"context"
"flag"
"fmt"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"os/signal"
"strings"
"syscall"
"time"
)
var (
listen string
gracePeriod time.Duration
target string
queue = make(chan struct{}, 1)
)
func init() {
flag.StringVar(&listen, "listen", ":4444", "host and port to listen to")
flag.DurationVar(&gracePeriod, "grace-period", 300*time.Second, "graceful shutdown period")
flag.StringVar(&target, "target", "http://localhost:4723", "target proxy url")
flag.Parse()
}
func signalContext() (context.Context, context.CancelFunc) {
ctx, cancel := context.WithCancel(context.Background())
go func() {
defer cancel()
stop := make(chan os.Signal)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
<-stop
}()
return ctx, cancel
}
func main() {
ctx, cancel := signalContext()
defer cancel()
err := mainCtx(ctx)
if err != nil {
log.Fatal(err)
}
}
func mux(ctx context.Context, u *url.URL) http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/wd/hub/session", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
select {
case <-r.Context().Done():
return
case <-ctx.Done():
http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
return
case queue <- struct{}{}:
}
(&httputil.ReverseProxy{
Director: func(r *http.Request) {
r.URL.Scheme, r.URL.Host = u.Scheme, u.Host
},
ModifyResponse: func(resp *http.Response) error {
if resp.StatusCode != http.StatusOK {
<-queue
}
return nil
},
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
<-queue
log.Printf("proxy to %s: %v", u.String(), err)
http.Error(w, http.StatusText(http.StatusBadGateway), http.StatusBadGateway)
},
}).ServeHTTP(w, r)
}))
mux.HandleFunc("/wd/hub/session/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
(&httputil.ReverseProxy{
Director: func(r *http.Request) {
r.URL.Scheme, r.URL.Host = u.Scheme, u.Host
},
}).ServeHTTP(w, r)
fragments := strings.Split(r.URL.Path, "/")
if r.Method == http.MethodDelete && len(fragments) == 5 {
<-queue
}
}))
return mux
}
func mainCtx(ctx context.Context) error {
target, err := url.Parse(target)
if err != nil {
return fmt.Errorf("parse target url: %v", err)
}
server := &http.Server{
Addr: listen,
Handler: mux(ctx, target),
}
e := make(chan error)
go func() {
e <- server.ListenAndServe()
}()
select {
case err := <-e:
return err
case <-ctx.Done():
}
log.Printf("starting graceful shutdown in %v]", gracePeriod)
shCtx, cancel := context.WithTimeout(context.Background(), gracePeriod)
defer cancel()
if err := server.Shutdown(shCtx); err != nil {
return fmt.Errorf("graceful shutdown: %v", err)
}
log.Printf("stopped")
return nil
}
+79
View File
@@ -0,0 +1,79 @@
FROM golang:1.17 as go
COPY xseld /xseld
COPY fileserver /fileserver
RUN \
apt-get update && \
apt-get install -y upx-ucl libx11-dev && \
cd /xseld && \
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" && \
upx /xseld/xseld && \
cd /fileserver && \
go test -race && \
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" && \
upx /fileserver/fileserver
FROM ubuntu:20.04
RUN \
apt update && \
apt remove -y libcurl4 && \
apt install -y apt-transport-https ca-certificates tzdata locales libcurl4 curl gnupg && \
DEBIAN_FRONTEND=noninteractive apt -y upgrade && \
echo ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true | debconf-set-selections && \
echo 'UTC' | tee /etc/timezone && \
dpkg-reconfigure -f noninteractive tzdata && \
echo "gtk-cursor-blink=0" > /root/.gtkrc-2.0 && \
apt update && \
apt install -y ttf-mscorefonts-installer \
ttf-dejavu-core \
fontconfig \
fontconfig-config \
fonts-dejavu-core \
fonts-liberation \
fonts-ubuntu-font-family-console \
fonts-wqy-zenhei \
fonts-thai-tlwg-ttf \
fonts-ipafont-mincho \
fonts-sahadeva \
fonts-noto-unhinted \
fonts-noto-color-emoji \
libfontconfig1 \
libfontenc1 \
libfreetype6 \
libxfont2 \
libxft2 \
libnss3-tools \
xfonts-base \
xfonts-encodings \
xfonts-utils \
flashplugin-installer \
xvfb \
pulseaudio \
fluxbox \
x11vnc \
feh \
wmctrl \
libnss-wrapper \
xsel && \
mkdir -p /var/lib/locales/supported.d/ && grep UTF-8 /usr/share/i18n/SUPPORTED > /var/lib/locales/supported.d/all && \
locale-gen && update-locale && \
fc-cache -f -v && \
adduser --system --home /home/selenium --uid 4096 \
--ingroup root --disabled-password --shell /bin/bash selenium && \
mkdir -p /home/selenium/Downloads && \
mkdir -p /home/selenium/.fluxbox && \
chgrp -R 0 /home/selenium && \
chmod -R g=u /home/selenium && \
ln -sf /bin/true /usr/bin/xdg-open && \
apt-get clean && \
rm -Rf /tmp/* && rm -Rf /var/lib/apt/lists/*
COPY fluxbox /usr/share/fluxbox/styles/
COPY --chown=selenium:root fluxbox /home/selenium/.fluxbox/
COPY aerokube.png /usr/share/images/fluxbox/
COPY --from=go /fileserver/fileserver /usr/bin/
COPY --from=go /xseld/xseld /usr/bin/
Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

+5
View File
@@ -0,0 +1,5 @@
module fileserver
go 1.17
require github.com/aandryashin/matchers v0.0.0-20161126170413-435295ea180e
+2
View File
@@ -0,0 +1,2 @@
github.com/aandryashin/matchers v0.0.0-20161126170413-435295ea180e h1:ogUKYFNcdYUIBSLibE4+EjbTJazoHr5JsWWx21Lpn8c=
github.com/aandryashin/matchers v0.0.0-20161126170413-435295ea180e/go.mod h1:cbmYNkm9xeQlNoWEPtOUcvNok2gSD7ErMnYkRW+eHi8=
+84
View File
@@ -0,0 +1,84 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"sort"
"strings"
)
func main() {
dir, err := downloadsDir()
if err != nil {
log.Fatal(err)
}
log.Fatal(http.ListenAndServe(":8080", mux(dir)))
}
func downloadsDir() (string, error) {
homeDir := os.Getenv("HOME")
if homeDir == "" {
homeDir = "/home/selenium"
}
dir := filepath.Join(homeDir, "Downloads")
err := os.MkdirAll(dir, 0755)
if err != nil {
return "", fmt.Errorf("failed to create downloads dir: %v", err)
}
return dir, nil
}
const jsonParam = "json"
func mux(dir string) http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodDelete {
deleteFileIfExists(w, r, dir)
return
}
if _, ok := r.URL.Query()[jsonParam]; ok {
listFilesAsJson(w, dir)
return
}
http.FileServer(http.Dir(dir)).ServeHTTP(w, r)
})
return mux
}
func listFilesAsJson(w http.ResponseWriter, dir string) {
files, err := ioutil.ReadDir(dir)
sort.Slice(files, func(i, j int) bool {
return files[i].ModTime().After(files[j].ModTime())
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
ret := []string{}
for _, f := range files {
ret = append(ret, f.Name())
}
w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(ret)
}
func deleteFileIfExists(w http.ResponseWriter, r *http.Request, dir string) {
fileName := strings.TrimPrefix(r.URL.Path, "/")
filePath := filepath.Join(dir, fileName)
_, err := os.Stat(filePath)
if err != nil {
http.Error(w, fmt.Sprintf("Unknown file %s", fileName), http.StatusNotFound)
return
}
err = os.Remove(filePath)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to delete file %s: %v", fileName, err), http.StatusInternalServerError)
return
}
}
+58
View File
@@ -0,0 +1,58 @@
package main
import (
. "github.com/aandryashin/matchers"
. "github.com/aandryashin/matchers/httpresp"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
)
var (
dir string
srv *httptest.Server
)
func init() {
dir, _ = ioutil.TempDir("", "fileserver")
srv = httptest.NewServer(mux(dir))
}
func withUrl(path string) string {
return srv.URL + path
}
func TestDownloadAndRemoveFile(t *testing.T) {
tempFile, _ := ioutil.TempFile(dir, "fileserver")
ioutil.WriteFile(tempFile.Name(), []byte("test-data"), 0644)
tempFileName := filepath.Base(tempFile.Name())
resp, err := http.Get(withUrl("/" + tempFileName))
AssertThat(t, err, Is{nil})
AssertThat(t, resp, Code{200})
_, err = os.Stat(tempFile.Name())
AssertThat(t, err, Is{nil})
rsp, err := http.Get(withUrl("/?json"))
AssertThat(t, err, Is{nil})
AssertThat(t, rsp, Code{http.StatusOK})
var files []string
AssertThat(t, rsp, IsJson{&files})
AssertThat(t, files, EqualTo{[]string{tempFileName}})
req, _ := http.NewRequest(http.MethodDelete, withUrl("/" + tempFileName), nil)
resp, err = http.DefaultClient.Do(req)
AssertThat(t, err, Is{nil})
AssertThat(t, resp, Code{200})
_, err = os.Stat(tempFile.Name())
AssertThat(t, err, Not{nil})
}
func TestRemoveMissingFile(t *testing.T) {
req, _ := http.NewRequest(http.MethodDelete, withUrl("/missing-file"), nil)
resp, err := http.DefaultClient.Do(req)
AssertThat(t, err, Is{nil})
AssertThat(t, resp, Code{404})
}
+175
View File
@@ -0,0 +1,175 @@
###############################################################################
#
# name: aerokube (based on ubuntu_light)
# made: paultag
# date: 16-10-2010
# http://pault.ag/
#
############################################################## BACKGROUND ######
# background: flat
# background.color: #2c001e
# background.colorTo: #2c001e
background: fullscreen
background.pixmap: /usr/share/images/fluxbox/aerokube.png
############################################################## FONTS ##########
menu.frame.font: Ubuntu-10:bold
menu.title.font: Ubuntu-12:bold
toolbar.clock.font: Ubuntu-10:bold
toolbar.workspace.font: Ubuntu-12:bold
toolbar.iconbar.focused.font: Ubuntu-10:bold
toolbar.iconbar.unfocused.font: Ubuntu-10
window.font: Ubuntu-10
############################################################## MENU ###########
menu.bevelWidth: 1
#menu.itemHeight: 35
#menu.titleHeight: 21
menu.borderColor: #525252
menu.borderWidth: 1
menu.bullet: Triangle
menu.bullet.position: Right
menu.frame.underlineColor: #ffffff
menu.title: flat gradient rectangle
menu.title.justify: center
menu.title.color: #FFFFFF
menu.title.colorTo: #FFFFFF
menu.title.textColor: #333333
menu.frame: flat gradient crossdiagonal
menu.frame.justify: left
menu.frame.color: #FFFFFF
menu.frame.colorTo: #FFFFFF
menu.frame.textColor: #333333
menu.frame.disableColor: #aea79f
menu.hilite: flat gradient rectangle
menu.hilite.color: #aea79f
menu.hilite.colorTo: #aea79f
menu.hilite.textColor: #000000
############################################################## TOOLBAR ########
toolbar.bevelWidth: 0
toolbar.borderWidth: 1
toolbar.borderColor: #aea79f
toolbar.height: 20
toolbar.justify: center
toolbar: flat gradient rectangle
toolbar.pixmap:
toolbar.color: #aea79f
toolbar.colorTo: #aea79f
toolbar.clock: parentrelative
toolbar.clock.justify: center
toolbar.clock.color: #
toolbar.clock.colorTo: #
toolbar.clock.textColor: #333333
toolbar.workspace: parentrelative
toolbar.workspace.justify: Center
toolbar.workspace.color: #
toolbar.workspace.colorTo: #
toolbar.workspace.textColor: #333333
toolbar.button: parentrelative
toolbar.button.color: #333333
toolbar.button.colorTo: #333333
toolbar.button.picColor: #333333
toolbar.button.pressed: parentrelative
toolbar.button.pressed.color: #aea79f
toolbar.button.pressed.colorTo: #aea79f
toolbar.button.pressed.picColor: #000000
toolbar.iconbar.borderWidth: 1
toolbar.iconbar.borderColor: #333333
toolbar.iconbar.empty: parentrelative
toolbar.iconbar.empty.color: #
toolbar.iconbar.empty.colorTo: #
toolbar.iconbar.focused.borderWidth: 1
toolbar.iconbar.focused.borderColor: #333333
toolbar.iconbar.focused: flat gradient rectangle
toolbar.iconbar.focused.color: #FFFFFF
toolbar.iconbar.focused.colorTo: #FFFFFF
toolbar.iconbar.focused.textColor: #333333
toolbar.iconbar.focused.justify: center
toolbar.iconbar.unfocused.borderWidth: 1
toolbar.iconbar.unfocused.borderColor: #525252
toolbar.iconbar.unfocused: flat gradient rectangle
toolbar.iconbar.unfocused.color: #aea79f
toolbar.iconbar.unfocused.colorTo: #aea79f
toolbar.iconbar.unfocused.textColor: #444444
toolbar.iconbar.unfocused.justify: center
############################################################## WINDOW #########
window.roundCorners: TopRight TopLeft
window.bevelWidth: 4
window.shade: false
window.borderWidth: 1
window.borderColor: #333333
window.justify: Center
window.title.height: 21
window.title.focus: flat gradient rectangle
window.title.focus.color: #000000
window.title.focus.colorTo: #333333
window.title.unfocus: flat gradient rectangle
window.title.unfocus.color: #111111
window.title.unfocus.colorTo: #444444
window.label.focus: parentrelative
window.label.focus.color: #
window.label.focus.colorTo: #
window.label.focus.textColor: #FFFFFF
window.label.unfocus: parentrelative
window.label.unfocus.color: #
window.label.unfocus.colorTo: #
window.label.unfocus.textColor: #aea79f
window.button.focus: parentrelative
window.button.focus.color: #
window.button.focus.colorTo: #
window.button.focus.picColor: #FFFFFF
window.button.unfocus: parentrelative
window.button.unfocus.Color: #
window.button.unfocus.ColorTo: #
window.button.unfocus.picColor: #888888
window.button.pressed: parentrelative
window.button.pressed.color: #
window.button.pressed.colorTo: #
window.button.pressed.picColor: #000000
window.handle.focus: flat
window.handle.focus.color: #1f1f1f
window.handle.focus.colorTo: #1f1f1f
window.handle.unfocus: lat
window.handle.unfocus.color: #1f1f1f
window.handle.unfocus.colorTo: #1f1f1f
window.handleWidth: 2
window.grip.focus: flat
window.grip.focus.color: #525252
window.grip.focus.colorTo: #525252
window.grip.unfocus: flat
window.grip.unfocus.color: #1f1f1f
window.grip.unfocus.colorTo: #1f1f1f
###############################################################################
# EOF
+7
View File
@@ -0,0 +1,7 @@
session.menuFile: ~/.fluxbox/menu
session.keyFile: ~/.fluxbox/keys
session.styleFile: /usr/share/fluxbox/styles/aerokube
session.configVersion: 13
session.screen0.strftimeFormat: %d %b, %a %02k:%M:%S
session.screen0.toolbar.visible: false
session.screen0.toolbar.tools:
+3
View File
@@ -0,0 +1,3 @@
module xseld
go 1.17
+44
View File
@@ -0,0 +1,44 @@
package main
import (
"io"
"log"
"net/http"
"os/exec"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
cmd := exec.Command("xsel", "-b")
switch r.Method {
case http.MethodGet:
cmd.Args = append(cmd.Args, "-o")
stdout, err := cmd.StdoutPipe()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
go io.Copy(w, stdout)
case http.MethodPost:
cmd.Args = append(cmd.Args, "-i")
stdin, err := cmd.StdinPipe()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
go func() {
defer stdin.Close()
io.Copy(stdin, r.Body)
}()
default:
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
err := cmd.Run()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})
log.Fatal(http.ListenAndServe(":9090", nil))
}
+28
View File
@@ -0,0 +1,28 @@
FROM golang:1.17 as go
COPY choose /choose
COPY rproxy /rproxy
RUN \
apt-get update && \
apt-get install -y upx-ucl && \
cd /choose && \
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" && \
upx /choose/choose && \
cd /rproxy && \
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" && \
upx /rproxy/rproxy
FROM ubuntu:18.04
COPY --from=go /choose/choose /usr/local/bin/
COPY --from=go /rproxy/rproxy /usr/local/bin/
RUN \
apt update && \
apt -y install xvfb x11-utils x11vnc tigervnc-common tigervnc-viewer
COPY entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
+16
View File
@@ -0,0 +1,16 @@
#browsers.json
```
"MicrosoftEdge": {
"default": "77",
"versions": {
"77": {
"image": "selenoid/external-host:1.0.0",
"port": "4444",
"path": "/",
"env": ["URLS=[\"http://172.17.0.1:4444/\"]","VNC_PASSWORD=longpassword","SCREEN_RESOLUTION=1921x1080x24"]
}
}
}
```
+30
View File
@@ -0,0 +1,30 @@
package main
import (
"os"
"time"
"fmt"
"encoding/json"
"math/rand"
)
var (
s rand.Source
r *rand.Rand
)
func init() {
s = rand.NewSource(time.Now().Unix())
r = rand.New(s)
}
func main() {
var hosts []string
if err := json.Unmarshal([]byte(os.Getenv("URLS")), &hosts); err != nil {
fmt.Printf("unmarshal json: %v", err)
os.Exit(1)
}
if l := len(hosts); l > 0 {
fmt.Println(hosts[r.Intn(l)])
}
}
+51
View File
@@ -0,0 +1,51 @@
#!/bin/bash
SCREEN_RESOLUTION=${SCREEN_RESOLUTION:-"1920x1080x24"}
DISPLAY_NUM=99
URLS=${URLS:-'["http://172.17.0.1:4444/"]'}
VNC_PASSWORD=${VNC_PASSWORD:-"password"}
export URLS
export VNC_PASSWORD
export DISPLAY=":$DISPLAY_NUM"
clean() {
if [ -n "$XVFB_PID" ]; then
kill -TERM "$XVFB_PID"
fi
if [ -n "$X11VNC_PID" ]; then
kill -TERM "$X11VNC_PID"
fi
if [ -n "$RPROXY_PID" ]; then
kill -TERM "$RPROXY_PID"
fi
}
trap clean SIGINT SIGTERM
URL=$(choose $URL)
HOST=$(echo $URL | sed -e 's@\(.*\)://@@' -e 's@[:/]\(.*\)$@@')
/bin/bash -c 'echo -e "$VNC_PASSWORD\n$VNC_PASSWORD\nn\n" | vncpasswd file.passwd'>/dev/null
xvfb-run -l -n $DISPLAY_NUM -s "-ac -screen 0 $SCREEN_RESOLUTION -noreset -listen tcp" \
vncviewer passwd=file.passwd $HOST &
XVFB_PID=$!
retcode=1
until [ $retcode -eq 0 ]; do
xdpyinfo -display $DISPLAY >/dev/null 2>&1
retcode=$?
if [ $retcode -ne 0 ]; then
echo Waiting xvfb...
sleep 1
fi
done
x11vnc -display $DISPLAY -passwd selenoid -shared -forever -loop500 -rfbport 5900 -rfbportv6 5900 -logfile /dev/null &
X11VNC_PID=$!
rproxy $URL &
RPROXY_PID=$!
wait
+17
View File
@@ -0,0 +1,17 @@
package main
import (
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
)
func main() {
u, err := url.Parse(os.Args[1])
if err != nil {
log.Fatalf("parse url: %v", err)
}
log.Fatal(http.ListenAndServe(":4444", httputil.NewSingleHostReverseProxy(u)))
}
+16
View File
@@ -0,0 +1,16 @@
FROM browsers/base:7.3.6
RUN \
curl -s https://deb.opera.com/archive.key | apt-key add - && \
echo 'deb https://deb.opera.com/opera/ stable non-free' >> /etc/apt/sources.list.d/opera.list && \
apt-get update && \
apt-get -y install opera=12.16.1860 openjdk-8-jre-headless && \
rm -Rf /tmp/* && rm -Rf /var/lib/apt/lists/*
COPY selenium-server-standalone.jar /usr/share/selenium/
COPY entrypoint.sh /
USER selenium
EXPOSE 4444
ENTRYPOINT ["/entrypoint.sh"]
+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
SCREEN_RESOLUTION=${SCREEN_RESOLUTION:-"1920x1080x24"}
ENABLE_WINDOW_MANAGER=${ENABLE_WINDOW_MANAGER:-""}
DISPLAY_NUM=99
export DISPLAY=":$DISPLAY_NUM"
clean() {
if [ -n "$FILESERVER_PID" ]; then
kill -TERM "$FILESERVER_PID"
fi
if [ -n "$XSELD_PID" ]; then
kill -TERM "$XSELD_PID"
fi
if [ -n "$XVFB_PID" ]; then
kill -TERM "$XVFB_PID"
fi
if [ -n "$SELENIUM_PID" ]; then
kill -TERM "$SELENIUM_PID"
fi
if [ -n "$X11VNC_PID" ]; then
kill -TERM "$X11VNC_PID"
fi
}
trap clean SIGINT SIGTERM
/usr/bin/fileserver &
FILESERVER_PID=$!
DISPLAY="$DISPLAY" /usr/bin/xseld &
XSELD_PID=$!
/usr/bin/xvfb-run -l -n "$DISPLAY_NUM" -s "-ac -screen 0 $SCREEN_RESOLUTION -noreset -listen tcp" /usr/bin/fluxbox -display "$DISPLAY" -log /tmp/fluxbox.log 2>/dev/null &
XVFB_PID=$!
retcode=1
until [ $retcode -eq 0 ]; do
DISPLAY="$DISPLAY" wmctrl -m >/dev/null 2>&1
retcode=$?
if [ $retcode -ne 0 ]; then
echo Waiting X server...
sleep 0.1
fi
done
if [ "$ENABLE_VNC" == "true" ]; then
x11vnc -display "$DISPLAY" -passwd selenoid -shared -forever -loop500 -rfbport 5900 -rfbportv6 5900 -logfile /tmp/x11vnc.log &
X11VNC_PID=$!
fi
/usr/bin/java -Xmx256m -Djava.security.egd=file:/dev/./urandom -jar /usr/share/selenium/selenium-server-standalone.jar -port 4444 -browserTimeout 120 &
SELENIUM_PID=$!
wait
+3
View File
@@ -0,0 +1,3 @@
FROM wernight/phantomjs:2.1.1
EXPOSE 4444
CMD ["/usr/local/bin/phantomjs", "--webdriver=4444"]
+10
View File
@@ -0,0 +1,10 @@
# Rebuilding Debian Packages
1. Download package from APT-repository:
```
$ apt-get download google-chrome-stable=48.0.2564.109-1+suffix0
```
2. Rebuild package to new owner using script:
```
$ rebuild-deb.sh -f google-chrome-stable=48.0.2564.109-1+suffix0_amd64.deb -r 'suffix0' -a 'aerokube0'
```
+94
View File
@@ -0,0 +1,94 @@
#!/bin/bash
set -e
usage()
{
cat << EOF
usage: $0 options
OPTIONS:
-h Show this message
-f Filename
-r Remove version postfix
-a Add version postfix
EOF
}
filename=''
remove_postfix=''
add_postfix=''
while getopts 'f:r:a:' OPTION
do
case $OPTION in
h)
usage
exit 1
;;
f)
filename=$OPTARG
;;
r)
remove_postfix=$OPTARG
;;
a)
add_postfix=$OPTARG
;;
?)
usage
exit
;;
esac
done
if [ -z "$filename" ]; then
usage
exit 1
fi
set -x
cp "$filename" .
spackage=$(echo "$filename" | awk -F '/' '{print $NF}')
package=$(echo "$spackage" | awk -F '_' '{print $1}')
version=$(echo "$spackage" | awk -F '_' '{print $2}')
rm -Rf "$package" control changelog
# Set variables
export DH_ALWAYS_EXCLUDE="CVS:.svn:.git"
# Extract package content
dpkg-deb -x $spackage $package/
# Extract package control
dpkg-deb -e $spackage $package/DEBIAN
# Extract package changelog
changelog=$(find $package/usr/share/doc -name 'changelog*.gz' 2>/dev/null| head -n 1)
if [ -n "$changelog" -a -f "$changelog" ]; then
rm -f "$changelog"
fi
old_version=$version
if [ -n "$remove_postfix" ]; then
version=$(echo $version | sed -e "s|+$remove_postfix||g")
old_version=$version"+"$remove_postfix
fi
new_version=$version
if [ -n "$add_postfix" ]; then
new_version=$new_version"+"$add_postfix
fi
dch --create --force-distribution --distribution unstable --package "$package" --newversion "$new_version" -c changelog 'Package rebuilt'
# Fix control
section=$(awk '/Section:/ {print $NF}' $package/DEBIAN/control 2>/dev/null || echo 'misc')
priority=$(awk '/Priority:/ {print $NF}' $package/DEBIAN/control 2>/dev/null || echo 'extra')
echo "$(echo $spackage | sed "s/$old_version/$new_version/") $section $priority" > files
echo "Source: $package" > control
grep -iv "Source:" $package/DEBIAN/control >> control
cp control $package/DEBIAN/control
# Build package
sed -i "s/$old_version/$new_version/g" $package/DEBIAN/control
dpkg-deb -b $package/ ./
# Remove source package
rm -f "./$spackage"
+76
View File
@@ -0,0 +1,76 @@
# Contributor: Anton Dzyk <anton.dzyk@yandex.ru>
# Maintainer: Ivan Krutov <vania-pooh@aerokube.com>
pkgname=ffmpeg-x11grab
pkgsource=ffmpeg
pkgver=4.3
pkgrel=1
pkgdesc="FFMPEG version optimized for x11grab to x264"
url="https://ffmpeg.org"
arch="all"
license="LGPL-2.1-or-later GPL-2.0-or-later"
makedepends="gnutls-dev lame-dev libvorbis-dev xvidcore-dev zlib-dev libvdpau-dev
imlib2-dev x264-dev libtheora-dev coreutils bzip2-dev perl-dev libvpx-dev
libvpx-dev sdl2-dev libxfixes-dev libva-dev v4l-utils-dev yasm opus-dev libass-dev pulseaudio-dev"
source="https://ffmpeg.org/releases/ffmpeg-$pkgver.tar.xz
0001-libavutil-clean-up-unused-FF_SYMVER-macro.patch
"
builddir="$srcdir/$pkgsource-$pkgver"
build() {
local _dbg="--disable-debug"
local _asm=""
[ -n "$DEBUG" ] && _dbg="--enable-debug"
case "$CARCH" in
x86 | arm*) _asm="--disable-asm" ;;
esac
cd "$builddir"
./configure \
--prefix=/usr \
--enable-avfilter \
--enable-gpl \
--enable-libx264 \
--enable-libpulse \
--enable-static \
--enable-small \
--disable-ffplay \
--disable-ffprobe \
--disable-doc \
--disable-htmlpages \
--disable-manpages \
--disable-podpages \
--disable-txtpages \
--disable-w32threads \
--disable-alsa \
--disable-audiotoolbox \
--disable-cuda \
--disable-cuvid \
--disable-d3d11va \
--disable-dxva2 \
--disable-nvenc \
--disable-vaapi \
--disable-vdpau \
--disable-videotoolbox \
--disable-librtmp \
--disable-devices \
--enable-indev=xcbgrab \
--enable-indev=pulse \
$_asm $_dbg
make
}
package() {
cd "$builddir"
make DESTDIR="$pkgdir" install
}
libs() {
pkgdesc="Libraries for ffmpeg"
replaces="ffmpeg"
mkdir -p "$subpkgdir"/usr
mv "$pkgdir"/usr/lib "$subpkgdir"/usr
}
sha512sums="f031eb6c4423887af323ab7d1f431234d4e30993a52db45dccf427b41eb442a3bd020dcbc13e83cbf813fad0f36c849cb651203570148387c864507aa19f313a ffmpeg-4.3.tar.xz
1047a23eda51b576ac200d5106a1cd318d1d5291643b3a69e025c0a7b6f3dbc9f6eb0e1e6faa231b7e38c8dd4e49a54f7431f87a93664da35825cc2e9e8aedf4 0001-libavutil-clean-up-unused-FF_SYMVER-macro.patch"
+21
View File
@@ -0,0 +1,21 @@
FROM alpine:3.12
RUN apk add -U alpine-sdk && adduser -g "" -D -G abuild selenoid
USER selenoid
RUN git clone git://git.alpinelinux.org/aports /home/selenoid/aports
ADD APKBUILD /home/selenoid/aports/community/ffmpeg/
RUN cd /home/selenoid/aports/community/ffmpeg/ && \
abuild checksum && \
abuild unpack && \
abuild deps && \
abuild build
USER root
FROM alpine:3.12
RUN apk add -U x264-libs sdl2 libxcb libbz2 xset pulseaudio-utils && \
rm -rf /var/cache/apk/*
COPY --from=0 /home/selenoid/aports/community/ffmpeg/src/ffmpeg-4.3/ffmpeg /usr/bin/ffmpeg
COPY entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
+42
View File
@@ -0,0 +1,42 @@
#!/bin/sh
VIDEO_SIZE=${VIDEO_SIZE:-"1920x1080"}
BROWSER_CONTAINER_NAME=${BROWSER_CONTAINER_NAME:-"browser"}
DISPLAY=${DISPLAY:-"99"}
FILE_NAME=${FILE_NAME:-"video.mp4"}
FRAME_RATE=${FRAME_RATE:-"12"}
CODEC=${CODEC:-"libx264"}
PRESET=${PRESET:-""}
if [ "$CODEC" == "libx264" -a -n "$PRESET" ]; then
PRESET="-preset $PRESET"
fi
INPUT_OPTIONS=${INPUT_OPTIONS:-""}
HIDE_CURSOR=${HIDE_CURSOR:-""}
if [ -n "$HIDE_CURSOR" ]; then
INPUT_OPTIONS="$INPUT_OPTIONS -draw_mouse 0"
fi
retcode=1
max_attempts=300
attempts=0
echo 'Waiting for display to open...'
until [ $retcode -eq 0 -o $attempts -eq $max_attempts ]; do
xset -display ${BROWSER_CONTAINER_NAME}:${DISPLAY} b off > /dev/null 2>&1
retcode=$?
if [ $retcode -ne 0 ]; then
echo 'Sleeping before next attempt...'
sleep 0.1
fi
attempts=$((attempts+1))
done
mkdir -p ~/.config/pulse
echo -n 'gIvST5iz2S0J1+JlXC1lD3HWvg61vDTV1xbmiGxZnjB6E3psXsjWUVQS4SRrch6rygQgtpw7qmghDFTaekt8qWiCjGvB0LNzQbvhfs1SFYDMakmIXuoqYoWFqTJ+GOXYByxpgCMylMKwpOoANEDePUCj36nwGaJNTNSjL8WBv+Bf3rJXqWnJ/43a0hUhmBBt28Dhiz6Yqowa83Y4iDRNJbxih6rB1vRNDKqRr/J9XJV+dOlM0dI+K6Vf5Ag+2LGZ3rc5sPVqgHgKK0mcNcsn+yCmO+XLQHD1K+QgL8RITs7nNeF1ikYPVgEYnc0CGzHTMvFR7JLgwL2gTXulCdwPbg=='| base64 -d>~/.config/pulse/cookie
export PULSE_SERVER=${BROWSER_CONTAINER_NAME}
if pactl info >/dev/null 2>&1; then
exec ffmpeg -f pulse -i default -y -f x11grab -video_size ${VIDEO_SIZE} -r ${FRAME_RATE} ${INPUT_OPTIONS} -i ${BROWSER_CONTAINER_NAME}:${DISPLAY} -codec:v ${CODEC} ${PRESET} -pix_fmt yuv420p -filter:v "pad=ceil(iw/2)*2:ceil(ih/2)*2" "/data/$FILE_NAME"
else
exec ffmpeg -y -f x11grab -video_size ${VIDEO_SIZE} -r ${FRAME_RATE} ${INPUT_OPTIONS} -i ${BROWSER_CONTAINER_NAME}:${DISPLAY} -codec:v ${CODEC} ${PRESET} -pix_fmt yuv420p -filter:v "pad=ceil(iw/2)*2:ceil(ih/2)*2" "/data/$FILE_NAME"
fi