File indexing completed on 2024-05-05 04:38:45
0001 #!/bin/sh 0002 0003 # SPDX-FileCopyrightText: 2011 David Nolden <david.nolden.kdevelop@art-master.de> 0004 # 0005 # SPDX-License-Identifier: LGPL-2.0-or-later 0006 0007 _shell=$(ps -cp $$ -o command="") 0008 0009 # Since this runs as a replacement for the init-files, we need to chain in the 'real' rcs. 0010 # We ignore profile, login & logout rcs, as we want no login shells. 0011 case $_shell in 0012 zsh) 0013 alias shopt=':' 0014 test -f "$OLD_ZDOTDIR/.zshenv" && . "$OLD_ZDOTDIR/.zshenv" 0015 test -f "$OLD_ZDOTDIR/.zshrc" && . "$OLD_ZDOTDIR/.zshrc" 0016 ;; #zsh still also sources the systemwide rcs when called with $ZDOTDIR set. 0017 bash) 0018 test -f ~/.bash_profile && source ~/.bash_profile 0019 test -f /etc/bash.bashrc && source /etc/bash.bashrc 0020 test -f ~/.bashrc && source ~/.bashrc 0021 ;; 0022 esac 0023 0024 if ! [ "$APPLICATION_HOST" ]; then 0025 export APPLICATION_HOST=$(hostname) 0026 fi 0027 0028 if ! [ "$KDEV_SHELL_ENVIRONMENT_ID" ]; then 0029 export KDEV_SHELL_ENVIRONMENT_ID="default" 0030 fi 0031 0032 if ! [ "$KDEV_DBUS_ID" ]; then 0033 echo "The required environment variable KDEV_DBUS_ID is not set. This variable defines the dbus id of the application instance which is supposed to be attached." 0034 exit 5 0035 fi 0036 0037 # Eventually, if we are forwarding to another host, and kdevplatform_shell_environment.sh 0038 # has been located through "which kdevplatform_shell_environment.sh", then we need to update KDEV_BASEDIR. 0039 if ! [ -e "$KDEV_BASEDIR/kdevplatform_shell_environment.sh" ]; then 0040 KDEV_BASEDIR=$(dirname $(which kdevplatform_shell_environment.sh)) 0041 fi 0042 0043 if ! [ -e "$KDEV_BASEDIR/kdev_dbus_socket_transformer" ]; then 0044 echo "The $KDEV_BASEDIR/kdev_dbus_socket_transformer utility is missing, controlling the application across ssh is not possible" 0045 fi 0046 0047 # Takes a list of tools, and prints a warning of one of them is not available in the path 0048 function checkToolsInPath { 0049 for TOOL in $@; do 0050 command -v $TOOL &> /dev/null || echo "The utility $TOOL is not in your path, the shell integration will not work properly." 0051 done 0052 } 0053 0054 # Check if all required tools are there (on the host machine) 0055 checkToolsInPath sed ls cut dirname mktemp basename readlink hostname 0056 0057 # special handling for qdbus variants 0058 _qdbus=qdbus-qt5 0059 if ! command -v $_qdbus &> /dev/null; then 0060 _qdbus=qdbus 0061 if ! command -v $_qdbus &> /dev/null; then 0062 echo "The utility qdbus (or qdbus-qt5) is not in your path, the shell integration will not work properly." 0063 fi 0064 fi 0065 0066 if ! [ "$KDEV_SSH_FORWARD_CHAIN" ]; then 0067 # Check for additional utilities that are required on the client machine 0068 checkToolsInPath kioclient5 0069 fi 0070 0071 # Queries the session name from the running application instance 0072 function getSessionName { 0073 echo "$($_qdbus $KDEV_DBUS_ID /org/kdevelop/SessionController org.kdevelop.SessionController.sessionName)" 0074 } 0075 0076 function getSessionDir { 0077 echo "$($_qdbus $KDEV_DBUS_ID /org/kdevelop/SessionController org.kdevelop.SessionController.sessionDir)" 0078 } 0079 0080 function getCurrentShellEnvPath { 0081 local ENV_ID=$KDEV_SHELL_ENVIRONMENT_ID 0082 if [ "$1" ]; then 0083 ENV_ID=$1 0084 fi 0085 0086 echo "$(getSessionDir)/${ENV_ID}.sh" 0087 } 0088 0089 function help! { 0090 echo "You are controlling the $APPLICATION session '$(getSessionName)'" 0091 echo "" 0092 if [[ "$1" == "" ]]; then 0093 echo "Standard commands:" 0094 echo "raise! - Raise the window." 0095 echo "sync! - Synchronize the working directory with the currently open document. See \"help! sync\"" 0096 echo "open! [file] ... - Open the file(s) within the attached application. See \"help! open\"" 0097 echo "eopen! [file] ... - Open the file(s) within an external application using kde-open." 0098 echo "create! [file] [[text]] - Create and open a new file." 0099 echo "search! [pattern] [[locations]] ... - Search for the given pattern here or at the optionally given location(s)." 0100 echo "dsearch! [pattern] [[locations]] ... - Same as search, but starts the search instantly instead of showing the dialog (using previous settings)." 0101 echo "ssh! [ssh arguments] - Connect to a remote host via ssh, keeping the control-connection alive. See \"help! remote\"" 0102 echo "" 0103 echo "help! - Show help." 0104 echo "help! open - Show extended help about file opening commands." 0105 echo "help! sync - Show extended help about path synchronization commands." 0106 echo "help! remote - Show extended help about remote shell-integration through ssh." 0107 echo "help! env - Show extended help about the environment." 0108 echo "" 0109 echo "Most commands can be abbreviated by the first character(s), eg. r! instead of raise!, and se! instead of search!." 0110 fi 0111 0112 if [[ "$1" == "open" ]]; then 0113 echo "Extended opening:" 0114 echo "The open! command can also be used to open files in specific tool-view configurations, by adding split-separators:" 0115 echo "- Files around the / separator will be arranged horizontally by split-view." 0116 echo "- Files around the - separator will be arranged vertically by split-view." 0117 echo "- Parens [ ... ] can be used to disambiguate the hierarchy (there must be spaces between filename and paren)." 0118 echo "- If a file is missing around a separator, the currently active view is inserted into the position." 0119 echo "" 0120 echo "Examples:" 0121 echo "open! file1 / file2 - The active view is split horizontally." 0122 echo " file1 is opened in the left view, and file2 in the right view." 0123 echo "open! file1 / [ file2 - file3 ] - The active view is split horizontally, and the right split-view is split vertically." 0124 echo " file1 is opened in the left view, file2 in the right upper view, and file3 in the right lower view." 0125 echo "open! / file1 - The active view is split horizontally." 0126 echo " - The active document is kept in the left split-view, and file1 is opened in the right split-view." 0127 echo "" 0128 echo "Short forms: o! = open!, eo! = eopen!, c! = create!" 0129 fi 0130 0131 if [[ "$1" == "sync" ]]; then 0132 echo "Extended syncing:" 0133 echo "sync! [[project-name]] - If no project-name is given, then the sync! command synchronizes to the currently active document." 0134 echo " If no document is active, then it synchronizes to the currently selected item in the project tree-view." 0135 echo " If a case-insensitive project name prefix is given, then it synchronizes to the base folder of the matching project." 0136 echo "syncsel! - Synchronizes to the currently selected item in the project tree-view, independently of the active document." 0137 echo "project! [[project-name]] - Map from a path within the build directory to the corresponding path in the source directory." 0138 echo " If we're already in the source directory, map to the root of the surrounding project." 0139 echo "bdir! [[project-name]] - Map from a path within the source directory to the corresponding path in the build directory." 0140 echo " If we're already in the build directory, map to the root of the build directory." 0141 echo "" 0142 echo "Short forms: s! = sync!, ss! = syncsel!, p! = project!, b! = bdir!" 0143 fi 0144 0145 if [[ "$1" == "remote" ]]; then 0146 echo "Extended remote commands:" 0147 echo "ssh! [ssh arguments] - Connect to a remote host via ssh, keeping the control-connection alive." 0148 echo " - The whole dbus environment is forwarded, KDevelop needs to be installed on both sides." 0149 echo "ssw! [ssh arguments] - Like ssh!, but preserves the current working directory." 0150 echo "exec! [cmd] [args] [file] . .. - Execute the given command on the client machine, referencing any number of local files on the host machine." 0151 echo " - The file paths will be re-encoded as fish:// urls if required." 0152 echo "cexec! [cmd] [args] [file] . .. - Execute the given command on the client machine, referencing any number of local files on the host machine." 0153 echo " - The files will be COPIED to the client machine if required." 0154 echo "copytohost! [client path] [host path] - Copy a file/directory through the fish protocol from the client machine th the host machine." 0155 echo "copytoclient! [host path] [client path]- Copy a file/directory through the fish protocol from the host machine to the client machine." 0156 echo "" 0157 echo "Short forms: e! = exec!, ce! = cexec!, cth! = copytohost!, ctc! = copytoclient!" 0158 fi 0159 0160 if [[ "$1" == "env" ]]; then 0161 echo "Environment management:" 0162 echo "The environment can be used to store session-specific macros and generally manipulate the shell environment" 0163 echo "for embedded shell sessions. The environment is sourced into the shell when the shell is initialized, and" 0164 echo "whenever setenv! is called." 0165 echo "" 0166 echo "env! - List all available shell environment-ids for this session." 0167 echo "setenv! [id] - Set the shell environmnet-id for this session to the given id, or update the current one." 0168 echo "editenv! [id] - Edit the current shell environment or the one with the optionally given id." 0169 echo "showenv! [id] - Show the current shell environment or the one with the optionally given id." 0170 echo "" 0171 echo "Short forms: sev! = setenv!, ee! = editenv!, shenv! = showenv!" 0172 fi 0173 echo "" 0174 } 0175 0176 # Short versions of the commands: 0177 0178 function r! { 0179 raise! $@ 0180 } 0181 0182 function s! { 0183 sync! $@ 0184 } 0185 0186 function ss! { 0187 syncsel! 0188 } 0189 0190 function syncsel! { 0191 sync! '[selection]' 0192 } 0193 0194 function p! { 0195 if [ "$@" ]; then 0196 s! $@ 0197 fi 0198 project! 0199 } 0200 0201 function b! { 0202 if [ "$@" ]; then 0203 s! $@ 0204 fi 0205 bdir! 0206 } 0207 0208 function o! { 0209 open! $@ 0210 } 0211 0212 function eo! { 0213 eopen! $@ 0214 } 0215 0216 function e! { 0217 exec! $@ 0218 } 0219 0220 function ce! { 0221 cexec! $@ 0222 } 0223 0224 function c! { 0225 create! $@ 0226 } 0227 0228 function se! { 0229 search! $@ 0230 } 0231 0232 function ds! { 0233 dsearch! $@ 0234 } 0235 0236 function h! { 0237 help! $@ 0238 } 0239 0240 function cth! { 0241 copytohost! $@ 0242 } 0243 0244 function ctc! { 0245 copytoclient! $@ 0246 } 0247 0248 function sev! { 0249 setenv! $@ 0250 } 0251 0252 function ee! { 0253 editenv! $@ 0254 } 0255 0256 function shev! { 0257 showenv! $@ 0258 } 0259 0260 # Internals: 0261 0262 # Opens a document in internally in the application 0263 function openDocument { 0264 RESULT=$($_qdbus $KDEV_DBUS_ID /org/kdevelop/DocumentController org.kdevelop.DocumentController.openDocumentSimple $1) 0265 if [[ "$RESULT" != "true" ]]; then 0266 echo "Failed to open $1" 0267 fi 0268 } 0269 0270 # Opens a document in internally in the application 0271 function openDocuments { 0272 if [[ $_shell == "zsh" ]]; then 0273 arr=(${=1}) 0274 else 0275 arr=("$1") 0276 fi 0277 RESULT=$($_qdbus $KDEV_DBUS_ID /org/kdevelop/DocumentController org.kdevelop.DocumentController.openDocumentsSimple "(" $arr ")") 0278 if [[ "$RESULT" != "true" ]]; then 0279 echo "Failed to open $1" 0280 fi 0281 } 0282 0283 # Executes a command on the client machine using the custom-script integration. 0284 # First argument: The full command. Second argument: The working directory. 0285 function executeInApp { 0286 local CMD="$1" 0287 local WD=$2 0288 if ! [ "$WD" ]; then 0289 WD=$(pwd) 0290 fi 0291 RESULT=$($_qdbus $KDEV_DBUS_ID /org/kdevelop/ExternalScriptPlugin org.kdevelop.ExternalScriptPlugin.executeCommand "$CMD" "$WD") 0292 if [[ "$RESULT" != "true" ]]; then 0293 echo "Execution failed" 0294 fi 0295 } 0296 0297 # First argument: The full command. Second argument: The working directory. 0298 # Executes the command silently and synchronously, and returns the output 0299 function executeInAppSync { 0300 local CMD=$1 0301 local WD=$2 0302 if ! [ "$WD" ]; then 0303 WD=$(pwd) 0304 fi 0305 RESULT=$($_qdbus $KDEV_DBUS_ID /org/kdevelop/ExternalScriptPlugin org.kdevelop.ExternalScriptPlugin.executeCommandSync "$CMD" "$WD") 0306 echo "$RESULT" 0307 } 0308 0309 # Getter functions: 0310 0311 function getActiveDocument { 0312 $_qdbus $KDEV_DBUS_ID /org/kdevelop/DocumentController org.kdevelop.DocumentController.activeDocumentPath $@ 0313 } 0314 0315 function getOpenDocuments { 0316 $_qdbus $KDEV_DBUS_ID /org/kdevelop/DocumentController org.kdevelop.DocumentController.activeDocumentPaths 0317 } 0318 0319 function raise! { 0320 $_qdbus $KDEV_DBUS_ID /kdevelop/MainWindow org.kdevelop.MainWindow.ensureVisible 0321 } 0322 0323 function bdir! { 0324 TARG=$($_qdbus $KDEV_DBUS_ID /org/kdevelop/ProjectController org.kdevelop.ProjectController.mapSourceBuild "$(pwd)" false) 0325 if [ "$TARG" ]; then 0326 cd $TARG 0327 else 0328 echo "Got no path" 0329 fi 0330 } 0331 0332 function project! { 0333 TARG=$($_qdbus $KDEV_DBUS_ID /org/kdevelop/ProjectController org.kdevelop.ProjectController.mapSourceBuild "$(pwd)" true) 0334 if [ "$TARG" ]; then 0335 cd $TARG 0336 else 0337 echo "Got no path" 0338 fi 0339 } 0340 0341 0342 # Main functions: 0343 0344 function raise! { 0345 $_qdbus $KDEV_DBUS_ID /kdevelop/MainWindow org.kdevelop.MainWindow.ensureVisible 0346 } 0347 0348 function sync! { 0349 local P=$(getActiveDocument $@) 0350 if [ "$P" ]; then 0351 0352 if [[ "$P" == fish://* ]]; then 0353 # This regular expression filters the user@host:port out of fish:///user@host:port/path/... 0354 LOGIN=$(echo $P | sed "s/fish\:\/\/*\([^\/]*\)\(\/.*\)/\1/") 0355 P_ON_HOST=$(echo $P | sed "s/fish\:\/\/*\([^\/]*\)\(\/.*\)/\2/") 0356 if [[ "$KDEV_SSH_FORWARD_CHAIN" == "$LOGIN" ]]; then 0357 P="$P_ON_HOST" 0358 else 0359 if [[ "$KDEV_SSH_FORWARD_CHAIN" == "" ]]; then 0360 # Try to ssh to the host machine 0361 # We need to split away the optional ":port" suffix, because the ssh command does not allow that syntax 0362 HOST=$(echo $LOGIN | cut --delimiter=':' -f 1) 0363 0364 CMD="ssh!" 0365 0366 if [[ "$LOGIN" == *:* ]]; then 0367 # If there is a port, extract it 0368 PORT=$(echo $LOGIN | cut --delimiter=':' -f 2) 0369 CMD="$CMD -p $PORT" 0370 fi 0371 0372 CMD="$CMD $HOST" 0373 # Execute the ssh command 0374 echo "Executing $CMD" 0375 KDEV_WORKING_DIR="$(dirname $P_ON_HOST)" 0376 $CMD 0377 return 0378 else 0379 echo "Cannot synchronize the working directory, because the host-names do not match (app: $LOGIN, shell: $KDEV_SSH_FORWARD_CHAIN)" 0380 return 0381 fi 0382 fi 0383 0384 elif [[ "$P" == file://* ]]; then 0385 P=$(echo $P | sed 's$^file://$$') 0386 0387 elif [ "$KDEV_SSH_FORWARD_CHAIN" ]; then 0388 # This session is being forwarded to another machine, but the current document is not 0389 # However, we won't complain, because it's possible that the machines share the same file-system 0390 if [[ $(isEqualFileOnHostAndClient $P) != "yes" ]]; then 0391 echo "Cannot synchronize the working directory, because the file systems do not match" 0392 return 0393 fi 0394 fi 0395 0396 [ -d "$P" ] || P=$(dirname "$P") 0397 cd "$P" 0398 else 0399 echo "Got no path" 0400 fi 0401 } 0402 0403 # Take a path, and returns "yes" if the equal file is available on the host and the client 0404 # The check is performed by comparing inode-numbers 0405 function isEqualFileOnHostAndClient { 0406 function trimWhiteSpace() { 0407 echo $1 0408 } 0409 0410 FILE=$1 0411 INODE_HOST=$(trimWhiteSpace $(ls --color=never -i $FILE | cut -d' ' -f1)) 0412 INODE_CLIENT=$(trimWhiteSpace $(executeInAppSync "ls --color=never -i $FILE | cut -d' ' -f1" "$(dirname $FILE)")) 0413 if [[ "$INODE_HOST" == "$INODE_CLIENT" ]]; then 0414 echo "yes" 0415 else 0416 echo "" 0417 fi 0418 } 0419 0420 # Takes a relative file, returns an absolute file/url that should be valid on the client. 0421 function mapFileToClient { 0422 local RELATIVE_FILE=$1 0423 FILE=$(readlink -f $RELATIVE_FILE) 0424 if ! [ -e "$FILE" ]; then 0425 # Try opening the file anyway, it might be an url or something else we don't understand here 0426 FILE=$RELATIVE_FILE 0427 else 0428 # We are referencing an absolute file, available on the file-system. 0429 0430 if [ "$KDEV_SSH_FORWARD_CHAIN" ]; then 0431 # If we are forwarding, map it to the client somehow. 0432 if [[ "$(isEqualFileOnHostAndClient "$FILE")" != "yes" ]]; then 0433 # We can eventually map the file using the fish protocol 0434 FISH_HOST=$KDEV_SSH_FORWARD_CHAIN 0435 if [[ "$FISH_HOST" == *\,* ]]; then 0436 # Extracts everything before the first comma 0437 FISH_HOST=$(echo $FISH_HOST | sed 's/\([^,]*\),\(.*\)/\1/') 0438 echo "ssh chain is too long: $KDEV_SSH_FORWARD_CHAIN mapping anyway using $FISH_HOST" 1>&2 0439 fi 0440 # Theoretically, we can only map through fish if the forward-chains contains no comma, which means that 0441 # we forward only once. Try anyway, there might be the same filesystem on the whole forward-chain. 0442 FILE="fish://$FISH_HOST$FILE" 0443 fi 0444 fi 0445 fi 0446 echo $FILE 0447 } 0448 0449 function open! { 0450 NEWFILES="" 0451 for RELATIVE_FILE; do 0452 if [[ "$RELATIVE_FILE" == "/" || "$RELATIVE_FILE" == "-" ]]; then 0453 FILE=$RELATIVE_FILE 0454 else 0455 FILE=$(mapFileToClient $RELATIVE_FILE) 0456 fi 0457 NEWFILES="$NEWFILES $FILE" 0458 done 0459 0460 openDocuments "$NEWFILES" 0461 } 0462 0463 function eopen! { 0464 for RELATIVE_FILE; do 0465 FILE=$(mapFileToClient $RELATIVE_FILE) 0466 executeInApp "kde-open5 $FILE" 0467 done 0468 } 0469 0470 function exec! { 0471 ARGS="" 0472 for RELATIVE_FILE; do 0473 if [[ "$ARGS" == "" ]]; then 0474 # Do not transform the command-name 0475 ARGS=$RELATIVE_FILE 0476 else 0477 FILE=$(mapFileToClient $RELATIVE_FILE) 0478 ARGS=$ARGS" "$FILE 0479 fi 0480 done 0481 echo "Executing: " $ARGS 0482 executeInApp "$ARGS" 0483 } 0484 0485 function copytohost! { 0486 executeInApp "kioclient5 copy $1 $(mapFileToClient $2)" 0487 } 0488 0489 function copytoclient! { 0490 executeInApp "kioclient5 copy $(mapFileToClient $1) $2" 0491 } 0492 0493 function cexec! { 0494 ARGS="" 0495 PREFIX="" 0496 TMP=1 0497 for RELATIVE_FILE; do 0498 if [[ "$ARGS" == "" ]]; then 0499 # Do not transform the command-name 0500 ARGS=$RELATIVE_FILE 0501 else 0502 FILE=$(mapFileToClient $RELATIVE_FILE) 0503 0504 if [[ "$FILE" == fish://* ]]; then 0505 # Add a prefix to copy the file into a temporary file 0506 # Keep the baseline as suffix, so that applications can easily recognize the mimetype 0507 PREFIX+="FILE$TMP=\$(mktemp).$(basename $FILE); kioclient5 copy $FILE \$FILE$TMP;" 0508 # Use the temporary variable instead of the name 0509 FILE="\$FILE$TMP" 0510 TMP=$(($TMP+1)) 0511 fi 0512 0513 ARGS=$ARGS" "$FILE 0514 fi 0515 done 0516 echo "Executing: " $ARGS 0517 executeInApp "$PREFIX $ARGS" 0518 } 0519 0520 function create! { 0521 FILE=$(readlink -f $1) 0522 if ! [ "$FILE" ]; then 0523 echo "Error: Bad arguments." 0524 return 1 0525 fi 0526 if [ -e "$FILE" ]; then 0527 echo "The file $FILE already exists" 0528 return 2 0529 fi 0530 echo $2 > $FILE 0531 0532 openDocument $(mapFileToClient $FILE) 0533 } 0534 0535 function search! { 0536 PATTERN=$1 0537 0538 # if ! [ "$PATTERN" ]; then 0539 # echo "Error: No pattern given." 0540 # return 1 0541 # fi 0542 0543 LOCATION=$2 0544 0545 if ! [ "$LOCATION" ]; then 0546 LOCATION="." 0547 fi 0548 0549 LOCATION=$(mapFileToClient $LOCATION) 0550 0551 for LOC in $*; do 0552 if [[ "$LOC" == "$1" ]]; then 0553 continue; 0554 fi 0555 if [[ "$LOC" == "$2" ]]; then 0556 continue; 0557 fi 0558 LOCATION="$LOCATION;$(mapFileToClient $LOC)" 0559 done 0560 0561 $_qdbus $KDEV_DBUS_ID /org/kdevelop/GrepViewPlugin org.kdevelop.GrepViewPlugin.startSearch "$PATTERN" "$LOCATION" true 0562 } 0563 0564 function dsearch! { 0565 PATTERN=$1 0566 0567 if ! [ "$PATTERN" ]; then 0568 echo "Error: No pattern given." 0569 return 1 0570 fi 0571 0572 LOCATION=$2 0573 0574 if ! [ "$LOCATION" ]; then 0575 LOCATION="." 0576 fi 0577 0578 LOCATION=$(mapFileToClient $LOCATION) 0579 0580 for LOC in $*; do 0581 if [[ "$LOC" == "$1" ]]; then 0582 continue; 0583 fi 0584 if [[ "$LOC" == "$2" ]]; then 0585 continue; 0586 fi 0587 LOCATION="$LOCATION;$(mapFileToClient $LOC)" 0588 done 0589 0590 $_qdbus $KDEV_DBUS_ID /org/kdevelop/GrepViewPlugin org.kdevelop.GrepViewPlugin.startSearch "$PATTERN" "$LOCATION" false 0591 } 0592 0593 ##### SSH DBUS FORWARDING -------------------------------------------------------------------------------------------------------------------- 0594 0595 DBUS_SOCKET_TRANSFORMER=$KDEV_BASEDIR/kdev_dbus_socket_transformer 0596 0597 # We need this, to make sure that our forwarding-loops won't get out of control 0598 # This configures the shell to kill background jobs when it is terminated 0599 shopt -s huponexit 0600 0601 export DBUS_ABSTRACT_SOCKET_TARGET_BASE_PATH=/tmp/dbus-forwarded-$USER-$APPLICATION_HOST 0602 0603 export DBUS_FORWARDING_TCP_LOCAL_PORT=9000 0604 export DBUS_FORWARDING_TCP_MAX_LOCAL_PORT=10000 0605 export DBUS_ABSTRACT_SOCKET_TARGET_INDEX=1 0606 export DBUS_ABSTRACT_SOCKET_MAX_TARGET_INDEX=1000 0607 0608 function getPortFromSSHCommand { 0609 # The port is given to ssh exclusively in the format "-p PORT" 0610 # This regular expression extracts the "4821" from "ssh -q bla1 -p 4821 bla2" 0611 local ARGS=$@ 0612 local RET=$(echo "$@" | sed "s/.*-p \+\([0-9]*\).*/\1/") 0613 if [[ "$ARGS" == "$RET" ]]; then 0614 # There was no match 0615 echo "" 0616 else 0617 echo ":$RET" 0618 fi 0619 } 0620 0621 function getLoginFromSSHCommand { 0622 # The login name can be given to ssh in the format "-l NAME" 0623 # This regular expression extracts the "NAME" from "ssh -q bla1 -l NAME bla2" 0624 local ARGS=$@ 0625 local RET=$(echo "$ARGS" | sed "s/.*-l \+\([a-z,A-Z,_,0-9]*\).*/\1/") 0626 if [[ "$RET" == "$ARGS" || "$RET" == "" ]]; then 0627 # There was no match 0628 echo "" 0629 else 0630 echo "$RET@" 0631 fi 0632 } 0633 0634 function getHostFromSSHCommand { 0635 # This regular expression extracts the "bla2" from "echo "ssh -q bla1 -p 4821 bla2" 0636 # Specifically, it finds the first argument which is not preceded by a "-x" parameter kind specification. 0637 0638 local CLEANED="" 0639 local NEWCLEANED="$@" 0640 0641 while [[ "$NEWCLEANED" != "$CLEANED" ]]; do 0642 CLEANED="$NEWCLEANED" 0643 # This expression removes one "-x ARG" parameter 0644 NEWCLEANED="$(echo $CLEANED | sed "s/\(.*\)\(-[a-z,A-Z] \+[a-z,0-9]*\)\ \(.*\)/\1\3/")" 0645 done 0646 0647 # After cleaning, the result should only consist of the host-name followed by an optional command. 0648 # Select the host-name, by extracting the first column. 0649 echo $CLEANED | cut --delimiter=" " -f 1 0650 } 0651 0652 function getSSHForwardOptionsFromCommand { 0653 0654 HOST="$(getLoginFromSSHCommand "$@")$(getHostFromSSHCommand "$@")$(getPortFromSSHCommand "$@")" 0655 0656 if [ "$KDEV_SSH_FORWARD_CHAIN" ]; then 0657 # We are already forwarding, so we deal with a chain of multiple ssh commands. 0658 # We still record it, although it's not sure if we can use it somehow. 0659 echo "KDEV_SSH_FORWARD_CHAIN=\"$KDEV_SSH_FORWARD_CHAIN,$HOST\""; 0660 else 0661 echo "KDEV_SSH_FORWARD_CHAIN=$HOST" 0662 fi 0663 } 0664 0665 function getDBusAbstractSocketSuffix { 0666 # From something like DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-wYmSkVH7FE,guid=b214dad39e0292a4299778d64d761a5b 0667 # extract the /tmp/dbus-wYmSkVH7FE 0668 echo $DBUS_SESSION_BUS_ADDRESS | sed 's/unix\:abstract\=.*\(,guid\=.*\)/\1/' 0669 } 0670 0671 function keepForwardingDBusToTCPSocket { 0672 while ! $KDEV_BASEDIR/kdev_dbus_socket_transformer $DBUS_FORWARDING_TCP_LOCAL_PORT --bind-only; do 0673 if (($DBUS_FORWARDING_TCP_LOCAL_PORT<$DBUS_FORWARDING_TCP_MAX_LOCAL_PORT)); then 0674 export DBUS_FORWARDING_TCP_LOCAL_PORT=$(($DBUS_FORWARDING_TCP_LOCAL_PORT+1)) 0675 # echo "Increased local port to " $DBUS_FORWARDING_TCP_LOCAL_PORT; 0676 else 0677 echo "Failed to allocate a local TCP port"; 0678 return 1; 0679 fi 0680 done 0681 0682 $KDEV_BASEDIR/kdev_dbus_socket_transformer $DBUS_FORWARDING_TCP_LOCAL_PORT& 0683 return 0; 0684 } 0685 0686 function keepForwardingDBusFromTCPSocket { 0687 0688 while ! $KDEV_BASEDIR/kdev_dbus_socket_transformer $FORWARD_DBUS_FROM_PORT ${DBUS_ABSTRACT_SOCKET_TARGET_BASE_PATH}-${DBUS_ABSTRACT_SOCKET_TARGET_INDEX} --bind-only; do 0689 if ((${DBUS_ABSTRACT_SOCKET_TARGET_INDEX}<${DBUS_ABSTRACT_SOCKET_MAX_TARGET_INDEX})); then 0690 export DBUS_ABSTRACT_SOCKET_TARGET_INDEX=$(($DBUS_ABSTRACT_SOCKET_TARGET_INDEX+1)) 0691 else 0692 echo "Failed to allocate a local path for the abstract dbus socket"; 0693 return 1; 0694 fi 0695 done 0696 0697 local PATH=${DBUS_ABSTRACT_SOCKET_TARGET_BASE_PATH}-${DBUS_ABSTRACT_SOCKET_TARGET_INDEX} 0698 export DBUS_SESSION_BUS_ADDRESS=unix:abstract=$PATH${DBUS_SOCKET_SUFFIX} 0699 $KDEV_BASEDIR/kdev_dbus_socket_transformer $FORWARD_DBUS_FROM_PORT $PATH& 0700 } 0701 0702 function ssh! { 0703 keepForwardingDBusToTCPSocket # Start the dbus forwarding subprocess 0704 DBUS_FORWARDING_TCP_TARGET_PORT=$((5000+($RANDOM%50000))) 0705 0706 ssh $@ -t -R localhost:$DBUS_FORWARDING_TCP_TARGET_PORT:localhost:$DBUS_FORWARDING_TCP_LOCAL_PORT \ 0707 " APPLICATION=$APPLICATION \ 0708 KDEV_BASEDIR=$KDEV_BASEDIR \ 0709 KDEV_DBUS_ID=$KDEV_DBUS_ID \ 0710 FORWARD_DBUS_FROM_PORT=$DBUS_FORWARDING_TCP_TARGET_PORT \ 0711 APPLICATION_HOST=$APPLICATION_HOST \ 0712 KDEV_WORKING_DIR=$KDEV_WORKING_DIR \ 0713 KDEV_SHELL_ENVIRONMENT_ID=$KDEV_SHELL_ENVIRONMENT_ID \ 0714 DBUS_SOCKET_SUFFIX=$(getDBusAbstractSocketSuffix) \ 0715 $(getSSHForwardOptionsFromCommand "$@") \ 0716 bash --init-file \ 0717 \$(if [ -e \"$KDEV_BASEDIR/kdevplatform_shell_environment.sh\" ]; \ 0718 then echo \"$KDEV_BASEDIR/kdevplatform_shell_environment.sh\"; \ 0719 elif [ -e \"$(which kdevplatform_shell_environment.sh)\" ]; then 0720 echo \"$(which kdevplatform_shell_environment.sh)\"; \ 0721 else \ 0722 echo \"~/.kdevplatform_shell_environment.sh\"; \ 0723 fi) \ 0724 -i" 0725 0726 0727 0728 if [ "$FORWARD_DBUS_FROM_PORT" ]; then 0729 # We created the 2nd subprocess 0730 kill %2 # Stop the dbus forwarding subprocess 0731 else 0732 # We created the 1st subprocess 0733 kill %1 # Stop the dbus forwarding subprocess 0734 fi 0735 } 0736 0737 # A version of ssh! that preserves the current working directory 0738 function ssw! { 0739 KDEV_WORKING_DIR=$(pwd) 0740 ssh! $@ 0741 } 0742 0743 function env! { 0744 FILES="$(executeInAppSync "ls $(getSessionDir)/*.sh" "")" 0745 for FILE in $FILES; do 0746 FILE=$(basename $FILE) 0747 ID=${FILE%.sh} # This ugly construct strips away the .sh suffix 0748 if [[ "$ID" == "$KDEV_SHELL_ENVIRONMENT_ID" ]]; then 0749 echo "$ID [current]" 0750 else 0751 echo "$ID" 0752 fi 0753 done 0754 } 0755 0756 function editenv! { 0757 local ENV_ID=$KDEV_SHELL_ENVIRONMENT_ID 0758 if [ "$1" ]; then 0759 ENV_ID=$1 0760 fi 0761 # If the environment-file doesn't exist yet, create it 0762 executeInAppSync "if ! [ -e $(getCurrentShellEnvPath $ENV_ID) ]; then touch $(getCurrentShellEnvPath $ENV_ID); fi" "" 0763 # Open it 0764 openDocument "$(getCurrentShellEnvPath $ENV_ID)" 0765 } 0766 0767 function setenv! { 0768 if [ "$1" ]; then 0769 KDEV_SHELL_ENVIRONMENT_ID=$1 0770 fi 0771 0772 # Execute the contents of the shell-environment 0773 # note: keep compatible with FreeBSD: https://bugs.kde.org/show_bug.cgi?id=311186 0774 local TEMP=$(mktemp /tmp/$USER-XXXXXXXX) 0775 RESULT=$(executeInAppSync "cat \"$(getCurrentShellEnvPath)\"" "") 0776 echo "$RESULT" >| $TEMP 0777 if ! [ "$RESULT" ]; then 0778 # If the environment shell file doesn't exist, create it 0779 executeInAppSync "if ! [ -e $(getCurrentShellEnvPath) ]; then touch $(getCurrentShellEnvPath); fi" "" 0780 fi 0781 source $TEMP 0782 rm -f $TEMP 0783 } 0784 0785 function showenv! { 0786 local ENV_ID=$KDEV_SHELL_ENVIRONMENT_ID 0787 if [ "$1" ]; then 0788 ENV_ID=$1 0789 fi 0790 0791 echo "Environment $ENV_ID:" 0792 0793 # Execute the contents of the shell-environment 0794 echo $(executeInAppSync "cat \"$(getCurrentShellEnvPath $ENV_ID)\"" "") 0795 } 0796 0797 if [ "$FORWARD_DBUS_FROM_PORT" ]; then 0798 # Start the target-side dbus forwarding, transforming from the ssh pipe to the abstract unix domain socket 0799 export DBUS_SESSION_BUS_ADDRESS=unix:abstract=${DBUS_ABSTRACT_SOCKET_TARGET_BASE_PATH}-${DBUS_ABSTRACT_SOCKET_TARGET_INDEX}${DBUS_SOCKET_SUFFIX} 0800 keepForwardingDBusFromTCPSocket 0801 fi 0802 0803 setenv! 0804 0805 ##### INITIALIZATION -------------------------------------------------------------------------------------------------------------------- 0806 0807 # Mark that this session is attached, by prepending a '!' character 0808 PS1="!$PS1" 0809 0810 echo "You are controlling the $APPLICATION session '$(getSessionName)'. Type help! for more information." 0811 0812 if [ "$KDEV_WORKING_DIR" ]; then 0813 cd $KDEV_WORKING_DIR 0814 fi