├── doc ├── .nvimlog └── Repos.md ├── .github └── workflows │ └── shell.yml ├── LICENSE ├── readme.org └── src └── shade /doc/.nvimlog: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/Repos.md: -------------------------------------------------------------------------------- 1 | # Repository config 2 | 3 | To configure custom repositories, edit '${prefix}/repos' (where ${prefix} is ~/.shade for a local install, and /opt/shade for a global install). Afterwards, run `shade update --local` or `shade update --global`, again depending on the prefix. 4 | -------------------------------------------------------------------------------- /.github/workflows/shell.yml: -------------------------------------------------------------------------------- 1 | on: [push] 2 | 3 | name: 'Trigger: Push action' 4 | 5 | jobs: 6 | shellcheck: 7 | name: Shellcheck 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - name: Run ShellCheck 12 | uses: ludeeus/action-shellcheck@master 13 | with: 14 | scandir: ./src 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Matei Cotocel, mTvare6 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /readme.org: -------------------------------------------------------------------------------- 1 | * Shade package manager 2 | 3 | Shade is a simple package manager, mostly for Linux, that is written in shell. 4 | 5 | * Table of contents 6 | #+begin_quote 7 | - [[Installation]] 8 | - [[Usage]] 9 | - [[Why another package manager?]] 10 | - [[Contributing and support]] 11 | #+end_quote 12 | 13 | ** Installation 14 | 15 | - Download and move =src/shade= to a directory in your path. 16 | - Run =shade init --local= if you want to use shade just for yourself, or =shade init --global= if you want package installed with shade to be available for everyone 17 | - Add =~/.shade/bin= (if you installed locally) and =/opt/shade/bin= (if you installed globally) to your =$PATH= 18 | 19 | ** Usage 20 | 21 | Shade has quite a few commands available for use. 22 | 23 | - =help=: Shows a message describing the different commands 24 | - =init=: Initializes the directories for shade to work 25 | - =install=: Installs the specified packages 26 | - =uninstall=: Uninstalls the specified packages 27 | - =reinstall=: Reinstalls the specified packages 28 | - =query=: Searches for packages matching query 29 | - =list=: Lists installed packages 30 | - =update=: Updates buildscripts 31 | 32 | 33 | ** Why another package manager? 34 | 35 | Shade has a few advantages over other packages managers 36 | 37 | - Shade buildscripts are written in shell, so you don't need shade to build packages, making buildscripts extremely flexible 38 | - Shade is written in shell, so it is portable and can run on macOS, BSD, and even WSL (although without support) 39 | - Shade is also easily extensible, as you can edit it without needing to recompile 40 | - Shade is fairly fast, since it doesn't do too many things 41 | 42 | ** Contributing and support 43 | 44 | If you have a question, you can open an issue, join our [[https://matrix.to/#/!QFHcZFQVmhZjDjYMYR:matrix.org?via=matrix.org][Matrix room]], or ask in Github Discussions. 45 | If you want to contribute, feel free to fork this repo and create a pull request. 46 | -------------------------------------------------------------------------------- /src/shade: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | export prefix="/opt/shade" 5 | export package_dir="${prefix}"/user/main/ 6 | 7 | export pager=cat 8 | 9 | 10 | export normal=$'\e[0m' 11 | bold="$(tput bold)" 12 | export bold 13 | 14 | 15 | red="$(tput setaf 1)" 16 | export red 17 | green="$(tput setaf 2)" 18 | export green 19 | yellow="$(tput setaf 3)" 20 | export yellow 21 | blue="$(tput setaf 4)" 22 | export blue 23 | 24 | 25 | bold_red="$bold$red" 26 | export bold_red 27 | bold_green="$bold$green" 28 | export bold_green 29 | bold_yellow="$bold$yellow" 30 | export bold_yellow 31 | bold_blue="$bold$blue" 32 | export bold_blue 33 | 34 | 35 | function success() { 36 | echo "--> ${bold_green}${1}${normal}" 37 | } 38 | 39 | 40 | function info() { 41 | echo "--> ${blue}${1}${normal}" 42 | } 43 | 44 | 45 | function warn() { 46 | echo "--> ${bold_yellow}${1}${normal}" 47 | } 48 | 49 | 50 | function error() { 51 | echo "--> ${bold_red}${1}${normal}" 52 | } 53 | 54 | 55 | function fatal_error() { 56 | echo "--> ${bold_red}${1}${normal}" 57 | exit 1 58 | } 59 | 60 | 61 | function chkroot() { 62 | if [[ "${prefix}" == /opt/shade ]]; then 63 | if [[ "${EUID}" -ne 0 ]]; then 64 | fatal_error "Shade must be run as a root user" 65 | fi 66 | fi 67 | } 68 | 69 | 70 | function getinfo() { 71 | grep -i "^\# ${1}" "${package_dir}"/"${pack}" 72 | } 73 | 74 | 75 | function parse() { 76 | getinfo "${1}" | sed "s/^..$1..//" 77 | } 78 | 79 | 80 | function prompt() { 81 | read -rp "--> $1 [${green}Yes${normal}/${red}No${normal}] " response 82 | } 83 | 84 | 85 | if [[ $OSTYPE != *linux* ]]; then 86 | warn "Shade officially supports only Linux. Other operating systems may run shade, but issues may arise." 87 | fi 88 | 89 | 90 | function help() { 91 | cat <> "${prefix}"/repos 122 | while read i; do 123 | git clone "${i}" "${prefix}"/user/main/repo 2>> /tmp/shade-log 124 | mv "${prefix}"/user/main/repo/packages/* "${prefix}"/user/main/ 2>> /tmp/shade-log 125 | rm -rf "${prefix}"/user/main/repo/ 2>> /tmp/shade-log 126 | done < "${prefix}"/repos 127 | success "Initialization done" 128 | info "Add your own repos to ${prefix}/repos and run shade update [--local] to clone them" 129 | } 130 | 131 | 132 | function install() { 133 | chkroot 134 | export package_dir="${prefix}"/user/main/ 135 | args=$(echo "${@}" | sed 's/--local//g' | sed 's/--global//g' | sed 's/install//g') 136 | for pack in ${args}; do 137 | if ! ls "${prefix}"/user/info/"${pack}"-installed >/dev/null 2>&1 ; then 138 | ls "${package_dir}"/"${pack}" >/dev/null 2>&1 || error "Package \"${pack}\" does not exist!" 139 | deps=$(parse "deps") 140 | export deps 141 | source=$(parse "source") 142 | export source 143 | version=$(parse "ver") 144 | export version 145 | if [[ $version =~ git ]]; then 146 | folder=$(parse "source" | sed 's/\/.*\///' | sed 's/\.git//' | sed 's/http.*://') 147 | export folder 148 | elif [[ $version =~ [0-9] ]]; then 149 | folder=$(parse "source" | sed 's/\/.*\///' | sed 's/http.*://' | sed 's/\-.*$//') 150 | export folder 151 | echo "${version}" > "${prefix}"/user/info/"${pack}"-version 152 | elif [[ $version =~ master ]]; then 153 | folder=$(parse "source" | sed 's/\/.*\///' | sed 's/http.*://' | sed 's/\..*$//') 154 | export folder 155 | fi 156 | info "Dependencies: $deps" 157 | info "Please make sure these are installed" 158 | prompt "Open ${pack} buildscript?" 159 | response=${response,,} 160 | if [[ "${response}" =~ ^(yes|y| ) ]] || [[ -z "${response}" ]]; then 161 | "${pager}" "${package_dir}"/"${pack}" 162 | fi 163 | prompt "Install ${pack}?" 164 | response="${response,,}" 165 | if [[ $response =~ ^(yes|y| ) ]] || [[ -z $response ]]; then 166 | start_time=$(date +%s) 167 | find "${prefix}" -name "*" > "${prefix}"/user/info/"${pack}"-pre-install 168 | info "Installing ${pack}" 169 | cd "${prefix}"/user/cache/ || exit 170 | if bash "${package_dir}"/"${pack}" ; then 171 | find "${prefix}" -name "*" > "${prefix}"/user/info/"${pack}"-post-install 172 | if [[ "${version}" =~ git ]]; then 173 | cd "${prefix}"/user/cache/"${folder}" || exit 174 | git rev-parse HEAD > "${prefix}"/user/info/"${pack}"-version 175 | fi 176 | touch "${prefix}"/user/info/"${pack}"-installed 177 | end_time=$(date +%s) 178 | success "${pack} installed in $(((end_time-start_time)/60)) minutes" 179 | else error "${pack} failed to install" 180 | fi 181 | else warn "Skipping ${pack}" 182 | fi 183 | else warn "${pack} already installed, skipping" 184 | fi 185 | done 186 | } 187 | 188 | 189 | function uninstall() { 190 | chkroot 191 | export package_dir="{prefix}"/user/main/ 192 | args=$(echo "${@}" | sed 's/--local//g' | sed 's/--global//g' | sed 's/uninstall//g') 193 | for pack in ${args}; do 194 | ls "${package_dir}"/"${pack}" >/dev/null 2>&1 || error "Package \"${pack}\" does not exist!" 195 | ls "${prefix}"/user/info/"${pack}"-installed >/dev/null 2>&1 || error "Package ${pack} not installed!" 196 | prompt "Review files to remove?" 197 | if [[ "${response}" =~ ^(yes|y| ) ]] || [[ -z "${response}" ]]; then 198 | diff "${prefix}"/user/info/"${pack}"-pre-install "${prefix}"/user/info/"${pack}"-post-install | tail -n +2 | cut -c 3- | less 199 | fi 200 | prompt "Uninstall ${pack}?" 201 | response=${response,,} 202 | if [[ "${response}" =~ ^(yes|y| ) ]] || [[ -z "${response}" ]]; then 203 | comm -13 "${prefix}"/user/info/"${pack}"-pre-install "${prefix}"/user/info/"${pack}"-post-install | xargs rm -rf 204 | rm "${prefix}"/user/info/"${pack}"-installed "${prefix}"/user/info/"${pack}"-pre-install "${prefix}"/user/info/"${pack}"-post-install > /dev/null 2>&1 205 | success "${pack} uninstalled!" 206 | fi 207 | done 208 | } 209 | 210 | function upgrade() { 211 | 212 | inst=$(ls "${prefix}"/user/info/*-installed) 213 | export package_dir="${prefix}"/user/main/ 214 | export has_update=0 215 | for i in $inst; do 216 | pack=$(echo "${i}" | sed 's/-.*//g' | sed 's/\/.*\///g') 217 | version=$(parse "ver") 218 | export 219 | if [[ $version =~ git ]]; then 220 | folder=$(parse "source" | sed 's/\/.*\///' | sed 's/\.git//' | sed 's/http.*://') 221 | export folder 222 | folder=$("${prefix}"/user/cache/"${folder}") 223 | export folder 224 | rm -rf "${folder}" 225 | echo '' 226 | echo "Checking for updates for ${pack}, please wait" 227 | git clone --depth=1 "$(parse source)" "${folder}" > /dev/null 2>&1 228 | cd "${folder}" || exit 229 | if [[ $(git rev-parse HEAD) != $(cat "${prefix}"/user/info/"${pack}"-version) ]]; then 230 | success "${pack} has updates available. Update with shade reinstall ${pack}" 231 | export has_update=$(( has_update+1 )) 232 | else 233 | info "${pack} has no updates available" 234 | fi 235 | elif [[ $version =~ [0-9] ]]; then 236 | folder=$(parse "source" | sed 's/\/.*\///' | sed 's/http.*://' | sed 's/\-.*$//') 237 | export folder 238 | folder=$("${prefix}"/user/cache/"${folder}") 239 | export folder 240 | elif [[ $version =~ master ]]; then 241 | folder=$(parse "source" | sed 's/\/.*\///' | sed 's/http.*://' | sed 's/\..*$//') 242 | export folder 243 | folder=$("${prefix}"/user/cache/"${folder}") 244 | export folder 245 | fi 246 | done 247 | echo 248 | if [[ "${has_update}" == 1 ]]; then 249 | success "${has_update} package has updates available" 250 | else 251 | success "${has_update} packages have updates available" 252 | fi 253 | } 254 | 255 | 256 | function update() { 257 | chkroot 258 | rm -rf "${prefix}"/user/main 259 | mkdir "${prefix}"/user/main 260 | while read i ; do 261 | git clone "${i}" "${prefix}"/user/main/repo 262 | mv "${prefix}"/user/main/repo/packages/* "${prefix}"/user/main/ 263 | rm -rf "${prefix}"/user/main/repo/ 264 | done < "${prefix}"/repos 265 | } 266 | 267 | 268 | function reinstall() { 269 | uninstall "${@}" 270 | install "${@}" 271 | } 272 | 273 | 274 | function list() { 275 | info "Installed packages:" 276 | find "${prefix}"/user/info/*-installed 2>/tmp/shade-log | sed 's/\/.*\///g' | sed 's/-.*//g' 277 | } 278 | 279 | function chonky-packages() { 280 | export package_dir="${prefix}"/user/main/ 281 | args=$(echo "${@}" | sed 's/--local//g' | sed 's/--global//g' | sed 's/chonky-packages//g') 282 | for pack in ${args}; do 283 | comm -13 "${prefix}"/user/info/"${pack}"-pre-install "${prefix}"/user/info/"${pack}"-post-install > "${prefix}"/user/info/"${pack}"-size 284 | cat "${prefix}"/user/info/"${pack}"-size | xargs du -ch | grep -i ^total 285 | done 286 | } 287 | 288 | 289 | for i in "${@}"; do 290 | case "${i}" in 291 | '--local') 292 | prefix=$HOME/.shade ;; 293 | '--global') 294 | prefix=/opt/shade ;; 295 | esac 296 | done 297 | 298 | 299 | case "$1" in 300 | '') help ;; 301 | help) help ;; 302 | init) init ;; 303 | setup) setup ;; 304 | install) install "${@}" ;; 305 | uninstall) uninstall "${@}" ;; 306 | update) update ;; 307 | upgrade) upgrade ;; 308 | reinstall) reinstall "${@}" ;; 309 | list) list ;; 310 | chonky-packages) chonky-packages "${@}" ;; 311 | *) error "$0: invalid option -- '$1'. Try '$0 help' for more information" ;; 312 | esac 313 | --------------------------------------------------------------------------------