summaryrefslogtreecommitdiff
path: root/contrib/deck.sh
blob: 1bb1690f7133e9cb4bd30c86cea42f906a05ba67 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#!/bin/bash

## Before using this script, enable sshd on the deck and setup an sshd key between the deck and your dev in sshd_config.
## This script defaults to port 22 unless otherwise specified, and cannot run without a sudo password or LAN IP.
## You will need to specify the path to the ssh key if using key connection exclusively.

## TODO: document latest changes to wiki

## Pre-parse arugments for ease of use
CLONEFOLDER=${1:-""}
INSTALLFOLDER=${2:-""}
DECKIP=${3:-""}
SSHPORT=${4:-""}
PASSWORD=${5:-""}
SSHKEYLOC=${6:-""}
LOADERBRANCH=${7:-""}
LIBRARYBRANCH=${8:-""}
TEMPLATEBRANCH=${9:-""}
LATEST=${10:-""}

## gather options into an array 
OPTIONSARRAY=("$CLONEFOLDER" "$INSTALLFOLDER" "$DECKIP" "$SSHPORT" "$PASSWORD" "$SSHKEYLOC" "$LOADERBRANCH" "$LIBRARYBRANCH" "$TEMPLATEBRANCH" "$LATEST")

## iterate through options array to check their presence
count=0
for OPTION in ${OPTIONSARRAY[@]}; do
    ! [[ "$OPTION" == "" ]] && count=$(($count+1))
    # printf "OPTION=$OPTION\n"
done

setfolder() {
    if [[ "$2" == "clone" ]]; then
        local ACTION="clone"
        local DEFAULT="git"
    elif [[ "$2" == "install" ]]; then
        local ACTION="install"
        local DEFAULT="dev"
    fi
    
    if [[ "$ACTION" == "clone" ]]; then
        printf "Enter the directory in /home/user/ to ${ACTION} to.\n"
        printf "The ${ACTION} directory would be: ${HOME}/${DEFAULT}\n"
        read -p "Enter your ${ACTION} directory: " CLONEFOLDER
        if ! [[ "$CLONEFOLDER" =~ ^[[:alnum:]]+$ ]]; then
            printf "Folder name not provided. Using default, '${DEFAULT}'.\n"
            CLONEFOLDER="${DEFAULT}"
        fi
    elif [[ "$ACTION" == "install" ]]; then
        printf "Enter the directory in /home/deck/homebrew to ${ACTION} pluginloader to.\n"
        printf "The ${ACTION} directory would be: /home/deck/homebrew/${DEFAULT}/pluginloader\n"
        printf "It is highly recommended that you use the default folder path seen above, just press enter at the next prompt.\n"
        read -p "Enter your ${ACTION} directory: " INSTALLFOLDER
        if ! [[ "$INSTALLFOLDER" =~ ^[[:alnum:]]+$ ]]; then
            printf "Folder name not provided. Using default, '${DEFAULT}'.\n"
            INSTALLFOLDER="${DEFAULT}"
        fi
    else
        printf "Folder type could not be determined, exiting\n"
        exit 1
    fi
}

checkdeckip() {
    ### check that ip is provided
    if [[ "$1" == "" ]]; then
        printf "An ip address must be provided, exiting.\n"
        exit 1
    fi

    ### check to make sure it's a potentially valid ipv4 address
    if ! [[ $1 =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        printf "A valid ip address must be provided, exiting.\n"
        exit 1
    fi
}

checksshport() {
    ### check to make sure a port was specified
    if [[ "$1" == "" ]]; then
        printf "ssh port not provided. Using default, '22'.\n"
        SSHPORT="22"
    fi

    ### check for valid ssh port
    if [[ $1 -le 0 ]]; then
        printf "A valid ssh port must be provided, exiting.\n"
        exit 1
    fi
}

checksshkey() {
    ### check if ssh key is present at location provided
    if [[ "$1" == "" ]]; then
        SSHKEYLOC="$HOME/.ssh/id_rsa"
        printf "ssh key was not provided. Defaulting to $SSHKEYLOC if it exists.\n"
    fi

    ### check if sshkey is present at location
    if ! [[ -e "$1" ]]; then
        SSHKEYLOC=""
        printf "ssh key does not exist. This script will use password authentication.\n"
    fi
}

checkpassword() {
    ### check to make sure a password for 'deck' was specified
    if [[ "$1" == "" ]]; then
        printf "Remote deck user password was not provided, exiting.\n"
        exit 1
    fi
}

clonefromto() {
    # printf "repo=$1\n"
    # printf "outdir=$2\n"
    # printf "branch=$3\n"
    printf "Repository: $1\n"
    git clone $1 $2 &> '/dev/null'
    CODE=$?
    # printf "CODE=${CODE}"
    if [[ $CODE -eq 128 ]]; then
        cd $2
        git fetch --all &> '/dev/null'
    fi
    if [[ -z $3 ]]; then
        printf "Enter the desired branch for repository "$1" :\n"
        local OUT="$(git branch -r | sed '/\/HEAD/d')"
        # $OUT="$($OUT > )"
        printf "$OUT\nbranch: "
        read BRANCH
    else
        printf "on branch: $3\n"
        BRANCH="$3"
    fi
    if ! [[ -z ${BRANCH} ]]; then
        git checkout $BRANCH &> '/dev/null'
    fi
    if [[ ${LATEST} == "true" ]]; then
        git pull --all
    elif [[ ${LATEST} == "true" ]]; then
        printf "Assuming user not pulling latest commits.\n"
    else
        printf "Pull latest commits? (y/N): "
        read PULL
        case ${PULL:0:1} in
            y|Y )
                printf "Pulling latest commits.\n"
                git pull --all
            ;;
            * )
                printf "Not pulling latest commits.\n"
            ;;
        esac
        if ! [[ "$PULL" =~ ^[[:alnum:]]+$ ]]; then
            printf "Assuming user not pulling latest commits.\n"
        fi
    fi
}

pnpmtransbundle() {
    cd $1
    if [[ "$2" == "library" ]]; then
        npm install --quiet &> '/dev/null'
        npm run build --quiet &> '/dev/null'
        sudo npm link --quiet &> '/dev/null'
    elif [[ "$2" == "frontend" ]]; then
        pnpm i &> '/dev/null'
        pnpm run build &> '/dev/null'
    elif [[ "$2" == "template" ]]; then
        pnpm i &> '/dev/null'
        pnpm run build &> '/dev/null'
    fi
}

printf "Installing Steam Deck Plugin Loader contributor/developer (for Steam Deck)...\n"

printf "THIS SCRIPT ASSUMES YOU ARE RUNNING IT ON A PC, NOT THE DECK!
Not planning to contribute to or develop for PluginLoader?
If so, you should not be using this script.\n
If you have a release/nightly installed this script will disable it.\n"

printf "This script requires you to have nodejs installed. (If nodejs doesn't bundle npm on your OS/distro, then npm is required as well).\n"

if ! [[ $count -gt 0 ]] ; then
    read -p "Press any key to continue"
fi

## User chooses preffered clone & install directories

if [[ "$CLONEFOLDER" == "" ]]; then
    setfolder "$CLONEFOLDER" "clone"
fi

if [[ "$INSTALLFOLDER" == "" ]]; then
    setfolder "$INSTALLFOLDER" "install"
fi

CLONEDIR="$HOME/$CLONEFOLDER"
INSTALLDIR="/home/deck/homebrew/$INSTALLFOLDER"

## Input ip address, port, password and sshkey

### DECKIP already been parsed?
if [[ "$DECKIP" == "" ]]; then
    ### get ip address of deck from user
    read -p "Enter the ip address of your Steam Deck: " DECKIP
fi

### validate DECKIP
checkdeckip "$DECKIP"

### SSHPORT already been parsed?
if [[ "$SSHPORT" == "" ]]; then
    ### get ssh port from user
    read -p "Enter the ssh port of your Steam Deck: " SSHPORT
fi

### validate SSHPORT
checksshport "$SSHPORT"

### PASSWORD already been parsed?
if [[ "$PASSWORD" == "" ]]; then
    ### prompt the user for their deck's password
    printf "Enter the password for the Steam Deck user 'deck' : "
    read -s PASSWORD
    printf "\n"
fi

### validate PASSWORD
checkpassword "$PASSWORD"

### SSHKEYLOC already been parsed?
if [[ "$SSHKEYLOC" == "" ]]; then
    ### prompt the user for their ssh key
    read -p "Enter the directory for your ssh key, for ease of connection : " SSHKEYLOC
fi

### validate SSHKEYLOC
checksshkey "$SSHKEYLOC"

if [[ "$SSHKEYLOC" == "" ]]; then
    IDENINVOC=""
else
    IDENINVOC="-i ${SSHKEYLOC}"
fi

## Create folder structure

printf "\nCloning git repositories.\n"

mkdir -p ${CLONEDIR} &> '/dev/null'

### remove folders just in case
# rm -r ${CLONEDIR}/pluginloader
# rm -r ${CLONEDIR}/pluginlibrary
# rm -r ${CLONEDIR}/plugintemplate

clonefromto "https://github.com/SteamDeckHomebrew/PluginLoader" ${CLONEDIR}/pluginloader "$LOADERBRANCH" 

clonefromto "https://github.com/SteamDeckHomebrew/decky-frontend-lib" ${CLONEDIR}/pluginlibrary "$LIBRARYBRANCH"

clonefromto "https://github.com/SteamDeckHomebrew/decky-plugin-template" ${CLONEDIR}/plugintemplate "$TEMPLATEBRANCH"

## install python dependencies to deck

printf "\nInstalling python dependencies.\n"

rsync -azp --rsh="ssh -p $SSHPORT $IDENINVOC" ${CLONEDIR}/pluginloader/requirements.txt deck@${DECKIP}:${INSTALLDIR}/pluginloader/requirements.txt &> '/dev/null'

ssh deck@${DECKIP} -p ${SSHPORT} ${IDENINVOC} "python -m ensurepip && python -m pip install --upgrade pip && python -m pip install --upgrade setuptools && python -m pip install -r $INSTALLDIR/pluginloader/requirements.txt" &> '/dev/null'

## Transpile and bundle typescript

sudo npm install -g pnpm &> '/dev/null'

type pnpm &> '/dev/null'

PNPMLIVES=$?

if ! [[ "$PNPMLIVES" -eq 0 ]]; then
    printf "pnpm does not appear to be installed, exiting.\n"
    exit 1
fi

[ "$UID" -eq 0 ] || printf "Input password to install typscript compiler.\n"

printf "Transpiling and bundling typescript.\n"

pnpmtransbundle ${CLONEDIR}/pluginlibrary/ "library"

pnpmtransbundle ${CLONEDIR}/pluginloader/frontend "frontend"

pnpmtransbundle ${CLONEDIR}/plugintemplate "template"

## Transfer relevant files to deck

printf "Copying relevant files to install directory\n\n"

ssh deck@${DECKIP} -p ${SSHPORT} ${IDENINVOC} "mkdir -p $INSTALLDIR/pluginloader && mkdir -p $INSTALLDIR/plugins" &> '/dev/null'

### copy files for PluginLoader
rsync -avzp --rsh="ssh -p $SSHPORT $IDENINVOC" --exclude='.git/' --exclude='.github/' --exclude='.vscode/' --exclude='frontend/' --exclude='dist/' --exclude='contrib/' --exclude='*.log' --exclude='requirements.txt' --exclude='backend/__pycache__/' --exclude='.gitignore' --delete ${CLONEDIR}/pluginloader/* deck@${DECKIP}:${INSTALLDIR}/pluginloader &> '/dev/null'

if ! [[ $? -eq 0 ]]; then
    printf "Error occurred when copying $CLONEDIR/pluginloader/ to $INSTALLDIR/pluginloader/\n"
    exit 1
fi

### copy files for plugin template
rsync -avzp --rsh="ssh -p $SSHPORT $IDENINVOC" --exclude='.git/' --exclude='.github/' --exclude='.vscode/' --exclude='node_modules/' --exclude='src/' --exclude='*.log' --exclude='.gitignore' --exclude='pnpm-lock.yaml' --exclude='package.json' --exclude='rollup.config.js' --exclude='tsconfig.json' --delete ${CLONEDIR}/plugintemplate deck@${DECKIP}:${INSTALLDIR}/plugins &> '/dev/null'
if ! [[ $? -eq 0 ]]; then
    printf "Error occurred when copying $CLONEDIR/plugintemplate to $INSTALLDIR/plugins\n"
    exit 1
fi

## TODO: direct contributors to wiki for this info?

printf "Run these commands to deploy your local changes to the deck:\n"
printf "'rsync -avzp --mkpath --rsh=""\"ssh -p $SSHPORT $IDENINVOC\""" --exclude='.git/' --exclude='.github/' --exclude='.vscode/' --exclude='frontend/' --exclude='dist/' --exclude='contrib/' --exclude='*.log' --exclude='requirements.txt' --exclude='backend/__pycache__/' --exclude='.gitignore' --delete $CLONEDIR/pluginloader/* deck@$DECKIP:$INSTALLDIR/pluginloader/'\n"

printf "'rsync -avzp --mkpath --rsh=""\"ssh -p $SSHPORT $IDENINVOC\""" --exclude='.git/' --exclude='.github/' --exclude='.vscode/' --exclude='node_modules/' --exclude='src/' --exclude='*.log' --exclude='.gitignore' --exclude='package-lock.json' --delete $CLONEDIR/pluginname deck@$DECKIP:$INSTALLDIR/plugins'\n"

printf "Run in console or in a script this command to run your development version:\n'ssh deck@$DECKIP -p $SSHPORT $IDENINVOC 'export PLUGIN_PATH=$INSTALLDIR/plugins; export CHOWN_PLUGIN_PATH=0; echo 'steam' | sudo -SE python3 $INSTALLDIR/pluginloader/backend/main.py'\n"

## Disable Releases versions if they exist

### ssh into deck and disable PluginLoader release/nightly service
printf "Connecting via ssh to disable any PluginLoader release versions.\n"
printf "Script will exit after this. All done!\n"

ssh deck@${DECKIP} -p ${SSHPORT} ${IDENINVOC} "printf $PASSWORD | sudo -S systemctl disable --now plugin_loader; echo $?"