├── .gitignore ├── .travis.yml ├── LICENSE.md ├── Makefile ├── README.md └── pkg /.gitignore: -------------------------------------------------------------------------------- 1 | tests/*/build/* 2 | tests/*/*.tar.gz 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: bash 2 | sudo: required 3 | 4 | os: 5 | - linux 6 | 7 | install: 8 | # Install a custom version of shellcheck instead of Travis CI's default 9 | - scversion="latest" # or "v0.4.7", or "latest" 10 | - wget "https://storage.googleapis.com/shellcheck/shellcheck-${scversion}.linux.x86_64.tar.xz" 11 | - tar --xz -xvf "shellcheck-${scversion}.linux.x86_64.tar.xz" 12 | - shellcheck() { "shellcheck-${scversion}/shellcheck" "$@"; } 13 | 14 | script: 15 | - shellcheck -e 2086 -e 2154 -e 2123 -e 2034 -e 1007 pkg 16 | # Check for lines longer than 80 chars. 17 | - if grep '.\{81\}' pkg; then (exit 1); else (exit 0); fi 18 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 kiss linux 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= /usr 2 | 3 | all: 4 | @echo Run \'make install\' to install pkg. 5 | 6 | install: 7 | @mkdir -p $(DESTDIR)$(PREFIX)/bin 8 | @cp -p pkg $(DESTDIR)$(PREFIX)/bin/pkg 9 | @chmod 755 $(DESTDIR)$(PREFIX)/bin/pkg 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pkg 2 | 3 | 4 | 5 | Package Manager for KISS Linux 6 | 7 | **SEE**: https://kissx.github.io/pkg 8 | -------------------------------------------------------------------------------- /pkg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck disable=2154,2123,2034,1007 source=/dev/null 3 | # 4 | # pkg - package manager for kiss linux. 5 | 6 | pkgfile_read() { 7 | [ -f pkgfile ] || die "pkgfile not found" 8 | 9 | . ./pkgfile || die "syntax error in pkgfile" 10 | 11 | [ -z "$name" ] && die "name not defined in pkgfile" 12 | [ -z "$version" ] && die "version not defined in pkgfile" 13 | [ -z "$release" ] && die "release not defined in pkgfile" 14 | 15 | PATH= type build >/dev/null || die "build() not found in pkgfile." 16 | 17 | for dep in $depends; do 18 | pkg_list "$dep" >/dev/null || miss="$miss $dep" 19 | done 20 | [ -n "$miss" ] && die "missing dependencies:$miss" 21 | 22 | pkgfile=1 23 | } 24 | 25 | pkg_get() { 26 | for src in $source; do 27 | src_name=${src##*/} 28 | 29 | [ -f "$src_name" ] && continue 30 | 31 | if [ -z "${src##*://*}" ]; then 32 | log "downloading $src" 33 | 34 | if wget -O "$src_name.partial" -- "$src"; then 35 | mv -f "$src_name.partial" "$src_name" 36 | else 37 | rm -f "$src_name.partial" 38 | die "failed to download $src" 39 | fi 40 | else 41 | die "source file $src not found" 42 | fi 43 | done 44 | } 45 | 46 | pkg_verify() { 47 | pkg_checksum build/.checksum 48 | 49 | diff .checksum build/.checksum || 50 | die "checksum of sources does not match checksum of package" \ 51 | "run 'pkg checksum' to update checksums" 52 | } 53 | 54 | pkg_manifest() { 55 | cd "$og_pwd/build/pkg" >/dev/null 56 | 57 | printf '%s\n' "$version" > "$db_dir/$name/version" 58 | 59 | _() { find . -mindepth 1 "$@" | sed 's/^\.//'; } 60 | _ -not -type d > ../../.manifest 61 | 62 | printf '%s\n' "/$db_dir/$name/manifest" >> ../../.manifest 63 | 64 | _ -type d | sort -r >> ../../.manifest 65 | } 66 | 67 | pkg_extract() { 68 | cd build >/dev/null || die "can't access build dir" 69 | mkdir -p "pkg/$db_dir/$name" 70 | 71 | for pkg in $source; do 72 | file_name=${pkg##*/} 73 | 74 | case $pkg in 75 | *.tar|*.tar.??|*.tar.???|*.tar.????|*.tgz) 76 | tar xf "../$file_name" -C src --strip-components 1 || 77 | die "couldn't extract $file_name" 78 | ;; 79 | 80 | *.zip) 81 | log "warn: You may need to cd into zip directory." 82 | unzip -qd src "../$file_name" || 83 | die "couldn't extract $file_name" 84 | ;; 85 | 86 | *) cp -f "../$file_name" src ;; 87 | esac 88 | done 89 | 90 | _(){ [ "$1" = "src/*" ] && log "warn: no source files found";}; _ src/* 91 | } 92 | 93 | pkg_build() { 94 | cd src >/dev/null || die "can't access src dir." 95 | BUILD=$og_pwd/build/pkg 96 | 97 | set -e errexit 98 | build 99 | set +e errexit 100 | 101 | pkg_manifest 102 | cd "$og_pwd" >/dev/null 103 | 104 | cp .manifest "build/pkg/$db_dir/$name/manifest" 105 | tar pcvf "PKG-${name}_$version-$release.tar.gz" \ 106 | -C build/pkg . >/dev/null || die "failed to create package" 107 | 108 | log "successfuly built $name" 109 | log "package is at PKG-${name}_$version-$release.tar.gz" 110 | } 111 | 112 | pkg_add() { 113 | name=${1%_*.tar.gz*} 114 | name=${name##PKG-} 115 | 116 | [ -f "$1" ] || die "file not found" 117 | [ -z "${1##*.tar.??}" ] || die "add requires a tarball" 118 | [ -n "$PKG_ROOT" ] && mkdir -p "$PKG_ROOT" 119 | 120 | # Test tar file before extraction. 121 | tar tf "$1" >/dev/null || die "couldn't extract $name" 122 | 123 | [ -f "$PKG_ROOT/$db_dir/$name/manifest" ] && pkg_delete "$name" 124 | 125 | tar pxvf "$1" -C "$PKG_ROOT/" || die "couldn't extract $name" 126 | log "successfuly installed $name to $PKG_ROOT/" 127 | 128 | [ -f post-install ] && { 129 | log "running post install hook" 130 | sh post-install 131 | } 132 | } 133 | 134 | pkg_delete() { 135 | pkg_db="$PKG_ROOT/$db_dir/$1/manifest" 136 | 137 | [ -z "$1" ] && die "delete needs an argument" 138 | [ -f "$pkg_db" ] || die "package not installed" 139 | 140 | while read -r line; do 141 | line=$PKG_ROOT/$line 142 | 143 | if [ -d "$line" ]; then 144 | find "$line" -mindepth 1 | read -r || rmdir "$line" 145 | 146 | elif [ -e "$line" ]; then 147 | rm -- "$line" || die "failed to remove package." \ 148 | "check the manifest ($PKG_ROOT/var/db/pkg/$1)" 149 | fi 150 | done < "$pkg_db" 151 | 152 | log "removed $1" 153 | } 154 | 155 | pkg_list() { 156 | cd "$PKG_ROOT/$db_dir" >/dev/null || die "can't access database" 157 | 158 | _() { read -r v < "$1/version"; printf '%s\n' "$1 $v"; } 159 | [ -n "$1" ] && ! [ -f "$1/version" ] && return 1 160 | 161 | for pkg in *; do 162 | [ -f "$1/version" ] && { _ "$1"; break; } 163 | [ -f "$pkg/version" ] || return 1 164 | _ "$pkg" 165 | done 166 | 167 | cd - >/dev/null 168 | } 169 | 170 | pkg_checksum() { 171 | :> "$1" 172 | 173 | for src in $source; do 174 | sha256sum -- "${src##*/}" >> "$1" || die "failed to generate checksums" 175 | done 176 | 177 | log "Saved checksums to $1" 178 | } 179 | 180 | enter_fakeroot() { 181 | type fakeroot >/dev/null || die "fakeroot not installed" 182 | 183 | [ -z "$in_fakeroot" ] && 184 | in_fakeroot=1 exec fakeroot -- "$0" "$@" 185 | } 186 | 187 | clean() { 188 | [ "$pkgfile" = 1 ] || return 189 | [ -f "$og_pwd/pkgfile" ] || return 190 | 191 | rm -rf "$og_pwd/build" 192 | } 193 | 194 | die() { 195 | printf '\033[31mERROR>\033[m %s\n' "$@" >&2 196 | exit 1 197 | } 198 | 199 | log() { 200 | printf '\033[32m=>\033[m %s\n' "$@" 201 | } 202 | 203 | args() { 204 | case $1 in 205 | a*) pkg_add "$2" ;; 206 | 207 | b*) 208 | pkgfile_read 209 | 210 | [ -f .checksum ] || die "checksum not found, run 'pkg checksum'" 211 | 212 | pkg_get 213 | pkg_verify 214 | pkg_extract 215 | pkg_build 216 | ;; 217 | 218 | c*) 219 | pkgfile_read 220 | pkg_get 221 | pkg_checksum .checksum 222 | ;; 223 | 224 | d*) pkg_delete "$2" ;; 225 | l*) pkg_list "$2" ;; 226 | -v) printf '%s\n' "pkg 0.1.0" ;; 227 | 228 | *) 229 | log 'pkg [a]dd pkg.tar.gz' \ 230 | 'pkg [b]uild' \ 231 | 'pkg [c]hecksum' \ 232 | 'pkg [d]el pkg' \ 233 | 'pkg [l]ist [pkg]' 234 | ;; 235 | esac 236 | } 237 | 238 | main() { 239 | enter_fakeroot "$@" 240 | 241 | og_pwd=$PWD 242 | db_dir=var/db/pkg 243 | 244 | mkdir -p "$PKG_ROOT/$db_dir" build/src build/pkg || 245 | die "couldn't create required directories." 246 | 247 | trap clean EXIT 248 | clean 249 | 250 | args "$@" 251 | } 252 | 253 | main "$@" 254 | --------------------------------------------------------------------------------