mirror of
https://github.com/EnumeratedDev/bpm.git
synced 2026-09-16 10:36:12 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f23537ba7d
|
||
|
|
6e9f16837c
|
||
|
|
271e87cb77
|
||
|
|
25ccc208d7
|
||
|
|
9c7e20d27d
|
||
|
|
6206fdbf43
|
||
|
|
9e48d97dc8
|
||
|
|
08a4e24889
|
||
|
|
4a32df6335
|
||
|
|
548b2476bd
|
||
|
|
a660039be1
|
||
|
|
44c2678ef9
|
||
|
|
2a7c6ce5d9
|
||
|
|
f98760d1dd
|
||
|
|
2ba78f16db
|
||
|
|
04a71b573b
|
||
|
|
aa229af8df
|
||
|
|
9912b173ff
|
||
|
|
879c832f60
|
||
|
|
2c91a9332b
|
||
|
|
1895fabfb0
|
||
|
|
0dfb66c6c0
|
||
|
|
dfdf38bad8
|
||
|
|
52f25c8f3f
|
||
|
|
7e372eef91
|
||
|
|
b07a7f8778
|
||
|
|
b2fc963389
|
||
|
|
b27e9fb0df
|
||
|
|
089bc61d58
|
||
|
|
fb821b3190
|
||
|
|
444b2032e2
|
||
|
|
70ba64ca6b
|
||
|
|
ed172f2805
|
||
|
|
f0ea57d500
|
||
|
|
e923aefff9
|
||
|
|
c2d420d854
|
||
|
|
2db01fb0d4
|
||
|
|
b451c5c320
|
||
|
|
27427d5654
|
||
|
|
04e966fef5
|
||
|
|
8a7519628f
|
||
|
|
8986e24334
|
||
|
|
f066e26dc2
|
||
|
|
bee23e2f56
|
||
|
|
d56005e63e
|
||
|
|
c9e16d6df1
|
@@ -7,12 +7,13 @@ SYSCONFDIR := $(PREFIX)/etc
|
|||||||
GO ?= go
|
GO ?= go
|
||||||
|
|
||||||
# Build-time variables
|
# Build-time variables
|
||||||
|
VERSION ?= $(shell git describe --tags --dirty)
|
||||||
ROOT_COMPILATION_UID ?= 65534
|
ROOT_COMPILATION_UID ?= 65534
|
||||||
ROOT_COMPILATION_GID ?= 65534
|
ROOT_COMPILATION_GID ?= 65534
|
||||||
|
|
||||||
build:
|
build:
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd src/bpm; $(GO) build $(GOFLAGS) -ldflags "-w -X 'git.enumerated.dev/bubble-package-manager/bpm/src/bpmlib.rootCompilationUID=$(ROOT_COMPILATION_UID)' -X 'git.enumerated.dev/bubble-package-manager/bpm/src/bpmlib.rootCompilationGID=$(ROOT_COMPILATION_GID)'" -o ../../build/bpm git.enumerated.dev/bubble-package-manager/bpm/src/bpm
|
cd src/bpm; $(GO) build $(GOFLAGS) -ldflags "-w -X 'main.BpmVersion=$(VERSION)' -X 'github.com/EnumeratedDev/bpm/src/bpmlib.rootCompilationUID=$(ROOT_COMPILATION_UID)' -X 'github.com/EnumeratedDev/bpm/src/bpmlib.rootCompilationGID=$(ROOT_COMPILATION_GID)'" -o ../../build/bpm bpm
|
||||||
|
|
||||||
install: build/bpm config/
|
install: build/bpm config/
|
||||||
# Create directory
|
# Create directory
|
||||||
|
|||||||
+11
-7
@@ -1,19 +1,23 @@
|
|||||||
module git.enumerated.dev/bubble-package-manager/bpm/src/bpm
|
module bpm
|
||||||
|
|
||||||
go 1.23
|
go 1.24.0
|
||||||
|
|
||||||
toolchain go1.23.7
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.enumerated.dev/bubble-package-manager/bpm/src/bpmlib v0.5.0
|
github.com/EnumeratedDev/bpm/src/bpmlib v0.0.0
|
||||||
github.com/adrg/strutil v0.3.1
|
github.com/lithammer/fuzzysearch v1.1.8
|
||||||
github.com/spf13/pflag v1.0.10
|
github.com/spf13/pflag v1.0.10
|
||||||
)
|
)
|
||||||
|
|
||||||
replace git.enumerated.dev/bubble-package-manager/bpm/src/bpmlib => ../bpmlib
|
replace github.com/EnumeratedDev/bpm/src/bpmlib => ../bpmlib
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/drone/envsubst v1.0.3 // indirect
|
github.com/drone/envsubst v1.0.3 // indirect
|
||||||
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f // indirect
|
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f // indirect
|
||||||
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
|
github.com/schollz/progressbar/v3 v3.18.0 // indirect
|
||||||
|
golang.org/x/sys v0.37.0 // indirect
|
||||||
|
golang.org/x/term v0.36.0 // indirect
|
||||||
|
golang.org/x/text v0.9.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
+50
-11
@@ -1,6 +1,5 @@
|
|||||||
github.com/adrg/strutil v0.3.1 h1:OLvSS7CSJO8lBii4YmBt8jiK9QOtB9CzCzwl4Ic/Fz4=
|
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=
|
||||||
github.com/adrg/strutil v0.3.1/go.mod h1:8h90y18QLrs11IBffcGX3NW/GFBXCMcNg4M7H6MspPA=
|
github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
|
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
|
||||||
@@ -9,19 +8,59 @@ github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
|||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f h1:xt29M2T6STgldg+WEP51gGePQCsQvklmP2eIhPIBK3g=
|
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f h1:xt29M2T6STgldg+WEP51gGePQCsQvklmP2eIhPIBK3g=
|
||||||
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
|
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
|
||||||
|
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
|
||||||
|
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||||
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA=
|
||||||
|
github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
|
||||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||||
|
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||||
|
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
+248
-56
@@ -14,10 +14,9 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.enumerated.dev/bubble-package-manager/bpm/src/bpmlib"
|
"github.com/EnumeratedDev/bpm/src/bpmlib"
|
||||||
|
|
||||||
"github.com/adrg/strutil"
|
"github.com/lithammer/fuzzysearch/fuzzy"
|
||||||
"github.com/adrg/strutil/metrics"
|
|
||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,7 +25,7 @@ import (
|
|||||||
/* A simple-to-use package manager */
|
/* A simple-to-use package manager */
|
||||||
/* ------------------------------------------------------- */
|
/* ------------------------------------------------------- */
|
||||||
|
|
||||||
var bpmVer = "0.6.0"
|
var BpmVersion = "dev"
|
||||||
|
|
||||||
var currentFlagSet *flag.FlagSet
|
var currentFlagSet *flag.FlagSet
|
||||||
|
|
||||||
@@ -38,21 +37,24 @@ func main() {
|
|||||||
log.Fatalf("Error: could not read BPM config: %s", err)
|
log.Fatalf("Error: could not read BPM config: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute subcommand
|
// Show usage if no arguments specified
|
||||||
subcommand := "help"
|
if len(os.Args) == 1 {
|
||||||
if len(os.Args) >= 2 {
|
printUsage()
|
||||||
subcommand = os.Args[1]
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subcommand := os.Args[1]
|
||||||
|
|
||||||
switch subcommand {
|
switch subcommand {
|
||||||
case "version":
|
case "v", "version":
|
||||||
fmt.Println("Bubble Package Manager (BPM)")
|
fmt.Println("Bubble Package Manager (BPM)")
|
||||||
fmt.Println("Version: " + bpmVer)
|
fmt.Println("Version: " + BpmVersion)
|
||||||
case "q", "query":
|
case "q", "query":
|
||||||
// Setup flags and help
|
// Setup flags and help
|
||||||
currentFlagSet = flag.NewFlagSet("query", flag.ExitOnError)
|
currentFlagSet = flag.NewFlagSet("query", flag.ExitOnError)
|
||||||
currentFlagSet.StringP("root", "R", "/", "Operate on specified root directory")
|
currentFlagSet.StringP("root", "R", "/", "Operate on specified root directory")
|
||||||
currentFlagSet.BoolP("database", "d", false, "Show package information from remote databases")
|
currentFlagSet.BoolP("database", "d", false, "Show package information from remote databases")
|
||||||
|
currentFlagSet.BoolP("human-readable", "h", false, "Show package installed size in a human readable format")
|
||||||
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Show information on the specified packages", os.Args[2:])
|
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Show information on the specified packages", os.Args[2:])
|
||||||
|
|
||||||
showPackageInfo()
|
showPackageInfo()
|
||||||
@@ -62,6 +64,13 @@ func main() {
|
|||||||
currentFlagSet.StringP("root", "R", "/", "Operate on specified root directory")
|
currentFlagSet.StringP("root", "R", "/", "Operate on specified root directory")
|
||||||
currentFlagSet.BoolP("count", "c", false, "Show total package count")
|
currentFlagSet.BoolP("count", "c", false, "Show total package count")
|
||||||
currentFlagSet.BoolP("names", "n", false, "Show all package names")
|
currentFlagSet.BoolP("names", "n", false, "Show all package names")
|
||||||
|
currentFlagSet.BoolP("database", "d", false, "Show packages from remote databases")
|
||||||
|
currentFlagSet.Bool("manual", false, "Show packages installed as dependencies")
|
||||||
|
currentFlagSet.Bool("depends", false, "Show packages installed as dependencies")
|
||||||
|
currentFlagSet.Bool("make-depends", false, "Show packages installed as make dependencies")
|
||||||
|
currentFlagSet.String("sort", "", "Sort listed packages by 'name' or 'size")
|
||||||
|
currentFlagSet.Bool("reverse", false, "Reverse the order in which packages are listed")
|
||||||
|
currentFlagSet.BoolP("human-readable", "h", false, "Show package installed size in a human readable format")
|
||||||
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "List packages", os.Args[2:])
|
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "List packages", os.Args[2:])
|
||||||
|
|
||||||
showPackageList()
|
showPackageList()
|
||||||
@@ -129,6 +138,7 @@ func main() {
|
|||||||
currentFlagSet.BoolP("force", "f", false, "Bypass warnings during package update")
|
currentFlagSet.BoolP("force", "f", false, "Bypass warnings during package update")
|
||||||
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
|
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
|
||||||
currentFlagSet.BoolP("no-sync", "n", false, "Do not sync databases")
|
currentFlagSet.BoolP("no-sync", "n", false, "Do not sync databases")
|
||||||
|
currentFlagSet.Bool("allow-downgrades", false, "Allow package downgrades")
|
||||||
currentFlagSet.BoolP("optional", "o", false, "Install all optional dependencies")
|
currentFlagSet.BoolP("optional", "o", false, "Install all optional dependencies")
|
||||||
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Update installed packages", os.Args[2:])
|
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Update installed packages", os.Args[2:])
|
||||||
|
|
||||||
@@ -149,13 +159,20 @@ func main() {
|
|||||||
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
|
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
|
||||||
currentFlagSet.BoolP("depends", "d", false, "Install required dependencies for package compilation")
|
currentFlagSet.BoolP("depends", "d", false, "Install required dependencies for package compilation")
|
||||||
currentFlagSet.BoolP("skip-checks", "s", false, "Skip the check function in source.sh scripts")
|
currentFlagSet.BoolP("skip-checks", "s", false, "Skip the check function in source.sh scripts")
|
||||||
|
currentFlagSet.BoolP("keep", "k", false, "Keep compilation files after successful package compilation")
|
||||||
currentFlagSet.BoolP("output-directory", "o", false, "Set the output directory for the binary packages")
|
currentFlagSet.BoolP("output-directory", "o", false, "Set the output directory for the binary packages")
|
||||||
currentFlagSet.Int("output-fd", -1, "Set the file descriptor output package names will be written to")
|
currentFlagSet.Int("output-fd", -1, "Set the file descriptor output package names will be written to")
|
||||||
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Compile source packages and convert them to binary ones", os.Args[2:])
|
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Compile source packages and convert them to binary ones", os.Args[2:])
|
||||||
|
|
||||||
compilePackage()
|
compilePackage()
|
||||||
|
case "p", "vercmp":
|
||||||
|
currentFlagSet = flag.NewFlagSet("compile", flag.ExitOnError)
|
||||||
|
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Compare two version numbers", os.Args[2:])
|
||||||
|
|
||||||
|
compareVersions()
|
||||||
default:
|
default:
|
||||||
listSubcommands()
|
printUsage()
|
||||||
|
exitCode = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if exitCode != 0 {
|
if exitCode != 0 {
|
||||||
@@ -167,6 +184,7 @@ func showPackageInfo() {
|
|||||||
// Get flags
|
// Get flags
|
||||||
rootDir, _ := currentFlagSet.GetString("root")
|
rootDir, _ := currentFlagSet.GetString("root")
|
||||||
showDatabaseInfo, _ := currentFlagSet.GetBool("database")
|
showDatabaseInfo, _ := currentFlagSet.GetBool("database")
|
||||||
|
showHumanReadableSize, _ := currentFlagSet.GetBool("human-readable")
|
||||||
|
|
||||||
// Get packages
|
// Get packages
|
||||||
packages := currentFlagSet.Args()
|
packages := currentFlagSet.Args()
|
||||||
@@ -184,9 +202,6 @@ func showPackageInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for n, pkg := range packages {
|
for n, pkg := range packages {
|
||||||
var info *bpmlib.PackageInfo
|
|
||||||
isFile := false
|
|
||||||
showInstallationReason := false
|
|
||||||
if showDatabaseInfo {
|
if showDatabaseInfo {
|
||||||
var err error
|
var err error
|
||||||
var entry *bpmlib.BPMDatabaseEntry
|
var entry *bpmlib.BPMDatabaseEntry
|
||||||
@@ -198,25 +213,33 @@ func showPackageInfo() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info = entry.Info
|
|
||||||
} else if stat, err := os.Stat(pkg); err == nil && !stat.IsDir() {
|
if n != 0 {
|
||||||
bpmpkg, err := bpmlib.ReadPackage(pkg)
|
fmt.Println()
|
||||||
|
}
|
||||||
|
fmt.Println(entry.CreateReadableInfo(rootDir, showHumanReadableSize))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var bpmpkg *bpmlib.BPMPackage
|
||||||
|
isFile := false
|
||||||
|
if stat, err := os.Stat(pkg); err == nil && !stat.IsDir() {
|
||||||
|
bpmpkg, err = bpmlib.ReadPackage(pkg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error: could not read package: %s\n", err)
|
log.Printf("Error: could not read package: %s\n", err)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
info = bpmpkg.PkgInfo
|
|
||||||
isFile = true
|
isFile = true
|
||||||
} else {
|
} else {
|
||||||
if isVirtual, p := bpmlib.IsVirtualPackage(pkg, rootDir); isVirtual {
|
if isVirtual, p := bpmlib.IsVirtualPackage(pkg, rootDir); isVirtual {
|
||||||
info = bpmlib.GetPackageInfo(p, rootDir)
|
bpmpkg = bpmlib.GetPackage(p, rootDir)
|
||||||
} else {
|
} else {
|
||||||
info = bpmlib.GetPackageInfo(pkg, rootDir)
|
bpmpkg = bpmlib.GetPackage(pkg, rootDir)
|
||||||
}
|
}
|
||||||
showInstallationReason = true
|
|
||||||
}
|
}
|
||||||
if info == nil {
|
if bpmpkg == nil {
|
||||||
log.Printf("Error: package (%s) is not installed\n", pkg)
|
log.Printf("Error: package (%s) is not installed\n", pkg)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
@@ -233,7 +256,14 @@ func showPackageInfo() {
|
|||||||
}
|
}
|
||||||
fmt.Println("File: " + abs)
|
fmt.Println("File: " + abs)
|
||||||
}
|
}
|
||||||
fmt.Println(bpmlib.CreateReadableInfo(true, true, true, showInstallationReason, info, rootDir))
|
fmt.Println(bpmpkg.PkgInfo.CreateReadableInfo(rootDir))
|
||||||
|
if bpmpkg.PkgInfo.Type == "binary" {
|
||||||
|
if !showHumanReadableSize {
|
||||||
|
fmt.Printf("Installed size: %d\n", bpmpkg.GetInstalledSize())
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Installed size: %s\n", bpmlib.BytesToHumanReadable(bpmpkg.GetInstalledSize()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,6 +272,19 @@ func showPackageList() {
|
|||||||
rootDir, _ := currentFlagSet.GetString("root")
|
rootDir, _ := currentFlagSet.GetString("root")
|
||||||
showPkgCount, _ := currentFlagSet.GetBool("count")
|
showPkgCount, _ := currentFlagSet.GetBool("count")
|
||||||
showPkgNames, _ := currentFlagSet.GetBool("names")
|
showPkgNames, _ := currentFlagSet.GetBool("names")
|
||||||
|
showDatabase, _ := currentFlagSet.GetBool("database")
|
||||||
|
showManual, _ := currentFlagSet.GetBool("manual")
|
||||||
|
showDepends, _ := currentFlagSet.GetBool("depends")
|
||||||
|
showMakeDepends, _ := currentFlagSet.GetBool("make-depends")
|
||||||
|
sortPackages, _ := currentFlagSet.GetString("sort")
|
||||||
|
reversePackages, _ := currentFlagSet.GetBool("reverse")
|
||||||
|
showHumanReadableSize, _ := currentFlagSet.GetBool("human-readable")
|
||||||
|
|
||||||
|
if !isFlagSet(currentFlagSet, "manual") && !isFlagSet(currentFlagSet, "depends") && !isFlagSet(currentFlagSet, "make-depends") {
|
||||||
|
showManual = true
|
||||||
|
showDepends = true
|
||||||
|
showMakeDepends = true
|
||||||
|
}
|
||||||
|
|
||||||
// Read local databases
|
// Read local databases
|
||||||
err := bpmlib.ReadLocalDatabaseFiles()
|
err := bpmlib.ReadLocalDatabaseFiles()
|
||||||
@@ -251,33 +294,127 @@ func showPackageList() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
packages, err := bpmlib.GetInstalledPackages(rootDir)
|
installedPackageNames, err := bpmlib.GetInstalledPackages(rootDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error: could not get installed packages: %s", err.Error())
|
log.Printf("Error: could not get installed packages: %s", err.Error())
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
installedPackages := make([]struct {
|
||||||
|
pkgInfo bpmlib.PackageInfo
|
||||||
|
installedSize int64
|
||||||
|
}, len(installedPackageNames))
|
||||||
|
for i, pkgName := range installedPackageNames {
|
||||||
|
pkgInfo := *bpmlib.GetPackageInfo(pkgName, rootDir)
|
||||||
|
installedSize := bpmlib.GetPackage(pkgName, rootDir).GetInstalledSize()
|
||||||
|
|
||||||
|
installedPackages[i] = struct {
|
||||||
|
pkgInfo bpmlib.PackageInfo
|
||||||
|
installedSize int64
|
||||||
|
}{
|
||||||
|
pkgInfo: pkgInfo,
|
||||||
|
installedSize: installedSize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
databaseEntries := make([]*bpmlib.BPMDatabaseEntry, 0)
|
||||||
|
for _, db := range bpmlib.BPMDatabases {
|
||||||
|
databaseEntries = append(databaseEntries, slices.Collect(maps.Values(db.Entries))...)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch sortPackages {
|
||||||
|
case "", "name":
|
||||||
|
case "size":
|
||||||
|
slices.SortFunc(installedPackages, func(a, b struct {
|
||||||
|
pkgInfo bpmlib.PackageInfo
|
||||||
|
installedSize int64
|
||||||
|
}) int {
|
||||||
|
return int(b.installedSize - a.installedSize)
|
||||||
|
})
|
||||||
|
slices.SortFunc(databaseEntries, func(a, b *bpmlib.BPMDatabaseEntry) int {
|
||||||
|
return int(b.InstalledSize - a.InstalledSize)
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
log.Printf("Error: cannot sort by '%s'", sortPackages)
|
||||||
|
exitCode = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if reversePackages {
|
||||||
|
slices.Reverse(installedPackages)
|
||||||
|
slices.Reverse(databaseEntries)
|
||||||
|
}
|
||||||
|
|
||||||
if showPkgCount {
|
if showPkgCount {
|
||||||
fmt.Println(len(packages))
|
if showDatabase {
|
||||||
|
fmt.Println(len(databaseEntries))
|
||||||
|
} else {
|
||||||
|
fmt.Println(len(installedPackages))
|
||||||
|
}
|
||||||
} else if showPkgNames {
|
} else if showPkgNames {
|
||||||
for _, pkg := range packages {
|
if showDatabase {
|
||||||
fmt.Println(pkg)
|
for _, entry := range databaseEntries {
|
||||||
|
fmt.Println(entry.Database.Name + "/" + entry.Info.Name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, pkg := range installedPackages {
|
||||||
|
installationReason := bpmlib.GetInstallationReason(pkg.pkgInfo.Name, rootDir)
|
||||||
|
if installationReason == bpmlib.InstallationReasonManual && !showManual {
|
||||||
|
continue
|
||||||
|
} else if installationReason == bpmlib.InstallationReasonDependency && !showDepends {
|
||||||
|
continue
|
||||||
|
} else if installationReason == bpmlib.InstallationReasonMakeDependency && !showMakeDepends {
|
||||||
|
continue
|
||||||
|
} else if installationReason == bpmlib.InstallationReasonUnknown && (!showManual || !showDepends || !showMakeDepends) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(pkg.pkgInfo.Name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if len(packages) == 0 {
|
if showDatabase {
|
||||||
fmt.Println("No packages have been installed")
|
if len(databaseEntries) == 0 {
|
||||||
return
|
fmt.Println("There are no database entries available")
|
||||||
}
|
return
|
||||||
for n, pkg := range packages {
|
|
||||||
info := bpmlib.GetPackageInfo(pkg, rootDir)
|
|
||||||
if info == nil {
|
|
||||||
fmt.Printf("Package (%s) could not be found\n", pkg)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
if n != 0 {
|
for n, entry := range databaseEntries {
|
||||||
fmt.Println()
|
if n != 0 {
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
fmt.Println(entry.CreateReadableInfo(rootDir, showHumanReadableSize))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(installedPackages) == 0 {
|
||||||
|
fmt.Println("No packages have been installed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for n, pkg := range installedPackages {
|
||||||
|
installationReason := bpmlib.GetInstallationReason(pkg.pkgInfo.Name, rootDir)
|
||||||
|
if installationReason == bpmlib.InstallationReasonManual && !showManual {
|
||||||
|
continue
|
||||||
|
} else if installationReason == bpmlib.InstallationReasonDependency && !showDepends {
|
||||||
|
continue
|
||||||
|
} else if installationReason == bpmlib.InstallationReasonMakeDependency && !showMakeDepends {
|
||||||
|
continue
|
||||||
|
} else if installationReason == bpmlib.InstallationReasonUnknown && (!showManual || !showDepends || !showMakeDepends) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if n != 0 {
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(pkg.pkgInfo.CreateReadableInfo(rootDir))
|
||||||
|
if pkg.pkgInfo.Type == "binary" {
|
||||||
|
if !showHumanReadableSize {
|
||||||
|
fmt.Printf("Installed size: %d\n", pkg.installedSize)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Installed size: %s\n", bpmlib.BytesToHumanReadable(pkg.installedSize))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fmt.Println(bpmlib.CreateReadableInfo(true, true, true, true, info, rootDir))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,23 +437,19 @@ func searchForPackages() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, term := range searchTerms {
|
for i, term := range searchTerms {
|
||||||
resultsMap := make(map[*bpmlib.PackageInfo]float64, 0)
|
// Find matches
|
||||||
|
resultsMap := make(map[*bpmlib.BPMDatabaseEntry]int)
|
||||||
// Loop through all packages
|
|
||||||
for _, db := range bpmlib.BPMDatabases {
|
for _, db := range bpmlib.BPMDatabases {
|
||||||
for _, entry := range db.Entries {
|
for _, entry := range db.Entries {
|
||||||
// Calculate string similarity and add to map
|
match := fuzzy.RankMatchNormalizedFold(term, entry.Info.Name)
|
||||||
similarity := strutil.Similarity(entry.Info.Name, term, metrics.NewSmithWatermanGotoh())
|
if match == -1 {
|
||||||
if similarity > 0.8 {
|
|
||||||
resultsMap[entry.Info] = similarity
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
similarity = strutil.Similarity(entry.Info.Description, term, metrics.NewSmithWatermanGotoh())
|
|
||||||
if similarity > 0.8 {
|
resultsMap[entry] = match
|
||||||
resultsMap[entry.Info] = similarity
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(resultsMap) == 0 {
|
if len(resultsMap) == 0 {
|
||||||
log.Printf("Error: no results for term (%s) were found\n", term)
|
log.Printf("Error: no results for term (%s) were found\n", term)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
@@ -326,7 +459,7 @@ func searchForPackages() {
|
|||||||
// Sort results
|
// Sort results
|
||||||
results := slices.Collect(maps.Keys(resultsMap))
|
results := slices.Collect(maps.Keys(resultsMap))
|
||||||
sort.Slice(results, func(i, j int) bool {
|
sort.Slice(results, func(i, j int) bool {
|
||||||
return resultsMap[results[i]] > resultsMap[results[j]]
|
return resultsMap[results[i]] < resultsMap[results[j]]
|
||||||
})
|
})
|
||||||
|
|
||||||
// Print results
|
// Print results
|
||||||
@@ -336,7 +469,7 @@ func searchForPackages() {
|
|||||||
fmt.Printf("Results for term (%s)\n", term)
|
fmt.Printf("Results for term (%s)\n", term)
|
||||||
for j := 0; j < 10 && j < len(results); j++ {
|
for j := 0; j < 10 && j < len(results); j++ {
|
||||||
result := results[j]
|
result := results[j]
|
||||||
fmt.Printf("%d) %s: %s (%s)\n", j+1, result.Name, result.Description, result.GetFullVersion())
|
fmt.Printf("%d) %s/%s: %s (%s)\n", j+1, result.Database.Name, result.Info.Name, result.Info.Description, result.Info.GetFullVersion())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -471,6 +604,9 @@ func installPackages() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get optional dependencies
|
||||||
|
optionalDepends := operation.GetOptionalDependencies()
|
||||||
|
|
||||||
// Execute operation
|
// Execute operation
|
||||||
err = operation.Execute(verbose, force)
|
err = operation.Execute(verbose, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -487,6 +623,18 @@ func installPackages() {
|
|||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show optional dependencies
|
||||||
|
if !installOptional && len(optionalDepends) != 0 {
|
||||||
|
// List optional dependencies
|
||||||
|
fmt.Println("The following optional dependenices have been discovered:")
|
||||||
|
for dependant, depends := range optionalDepends {
|
||||||
|
fmt.Printf("%s: \n", dependant)
|
||||||
|
for _, depend := range depends {
|
||||||
|
fmt.Printf(" - %s\n", depend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func removePackages() {
|
func removePackages() {
|
||||||
@@ -748,6 +896,7 @@ func updatePackages() {
|
|||||||
force, _ := currentFlagSet.GetBool("force")
|
force, _ := currentFlagSet.GetBool("force")
|
||||||
yesAll, _ := currentFlagSet.GetBool("yes")
|
yesAll, _ := currentFlagSet.GetBool("yes")
|
||||||
noSync, _ := currentFlagSet.GetBool("no-sync")
|
noSync, _ := currentFlagSet.GetBool("no-sync")
|
||||||
|
allowDowngrades, _ := currentFlagSet.GetBool("allow-downgrades")
|
||||||
installOptional, _ := currentFlagSet.GetBool("optional")
|
installOptional, _ := currentFlagSet.GetBool("optional")
|
||||||
|
|
||||||
// Check for required permissions
|
// Check for required permissions
|
||||||
@@ -776,14 +925,25 @@ func updatePackages() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Confirmation Prompt
|
||||||
|
if !noSync && !yesAll {
|
||||||
|
if !showConfirmationPrompt("Do you wish to sync all databases?", false) {
|
||||||
|
fmt.Println("Cancelling package update...")
|
||||||
|
exitCode = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create update operation
|
// Create update operation
|
||||||
operation, err := bpmlib.UpdatePackages(rootDir, !noSync, installOptional, force, verbose)
|
operation, err := bpmlib.UpdatePackages(rootDir, !noSync, allowDowngrades, installOptional, force, verbose)
|
||||||
if errors.As(err, &bpmlib.PackageNotFoundErr{}) || errors.As(err, &bpmlib.DependencyNotFoundErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
if errors.As(err, &bpmlib.PackageNotFoundErr{}) || errors.As(err, &bpmlib.DependencyNotFoundErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
||||||
log.Printf("Error: %s", err)
|
log.Printf("Error: %s", err)
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Printf("Error: could not setup operation: %s\n", err)
|
log.Printf("Error: could not setup operation: %s\n", err)
|
||||||
|
exitCode = 1
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exit if operation contains no actions
|
// Exit if operation contains no actions
|
||||||
@@ -836,6 +996,9 @@ func updatePackages() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get optional dependencies
|
||||||
|
optionalDepends := operation.GetOptionalDependencies()
|
||||||
|
|
||||||
// Execute operation
|
// Execute operation
|
||||||
err = operation.Execute(verbose, force)
|
err = operation.Execute(verbose, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -852,6 +1015,18 @@ func updatePackages() {
|
|||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show optional dependencies
|
||||||
|
if !installOptional && len(optionalDepends) != 0 {
|
||||||
|
// List optional dependencies
|
||||||
|
fmt.Println("The following optional dependenices have been discovered:")
|
||||||
|
for dependant, depends := range optionalDepends {
|
||||||
|
fmt.Printf("%s: \n", dependant)
|
||||||
|
for _, depend := range depends {
|
||||||
|
fmt.Printf(" - %s\n", depend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFileOwner() {
|
func getFileOwner() {
|
||||||
@@ -928,6 +1103,8 @@ func getFileOwner() {
|
|||||||
// Print packages
|
// Print packages
|
||||||
if len(pkgList) == 0 {
|
if len(pkgList) == 0 {
|
||||||
fmt.Printf("%s (%s) is not owned by any packages!\n", absPath, pathType)
|
fmt.Printf("%s (%s) is not owned by any packages!\n", absPath, pathType)
|
||||||
|
exitCode = 1
|
||||||
|
return
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%s (%s) is owned by the following packages:\n", absPath, pathType)
|
fmt.Printf("%s (%s) is owned by the following packages:\n", absPath, pathType)
|
||||||
for _, pkg := range pkgList {
|
for _, pkg := range pkgList {
|
||||||
@@ -942,6 +1119,7 @@ func compilePackage() {
|
|||||||
rootDir, _ := currentFlagSet.GetString("root")
|
rootDir, _ := currentFlagSet.GetString("root")
|
||||||
verbose, _ := currentFlagSet.GetBool("verbose")
|
verbose, _ := currentFlagSet.GetBool("verbose")
|
||||||
yesAll, _ := currentFlagSet.GetBool("yes")
|
yesAll, _ := currentFlagSet.GetBool("yes")
|
||||||
|
keepCompilationFiles, _ := currentFlagSet.GetBool("keep")
|
||||||
installSrcPkgDepends, _ := currentFlagSet.GetBool("depends")
|
installSrcPkgDepends, _ := currentFlagSet.GetBool("depends")
|
||||||
skipChecks, _ := currentFlagSet.GetBool("skip-checks")
|
skipChecks, _ := currentFlagSet.GetBool("skip-checks")
|
||||||
outputDirectory, _ := currentFlagSet.GetString("output-directory")
|
outputDirectory, _ := currentFlagSet.GetString("output-directory")
|
||||||
@@ -1041,7 +1219,7 @@ func compilePackage() {
|
|||||||
} else {
|
} else {
|
||||||
// Ensure the required dependencies are installed
|
// Ensure the required dependencies are installed
|
||||||
if len(unmetDepends) != 0 {
|
if len(unmetDepends) != 0 {
|
||||||
log.Printf("Error: could not resolve dependencies: the following dependencies were not found in any databases: " + strings.Join(unmetDepends, ", "))
|
log.Printf("Error: the following dependencies were not found in any databases: %s", strings.Join(unmetDepends, ", "))
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1139,7 +1317,7 @@ func compilePackage() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
outputBpmPackages, err := bpmlib.CompileSourcePackage(sourcePackage, outputDirectory, skipChecks)
|
outputBpmPackages, err := bpmlib.CompileSourcePackage(sourcePackage, outputDirectory, skipChecks, keepCompilationFiles, verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Remove unused packages
|
// Remove unused packages
|
||||||
cleanupFunc()
|
cleanupFunc()
|
||||||
@@ -1168,7 +1346,20 @@ func compilePackage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func listSubcommands() {
|
func compareVersions() {
|
||||||
|
if currentFlagSet.NArg() < 2 {
|
||||||
|
log.Printf("Error: vercmp subcommand requires 2 arguments")
|
||||||
|
exitCode = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v1 := currentFlagSet.Arg(0)
|
||||||
|
v2 := currentFlagSet.Arg(1)
|
||||||
|
|
||||||
|
fmt.Println(bpmlib.CompareVersions(v1, v2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func printUsage() {
|
||||||
fmt.Printf("Usage: %s <subcommand> [options]\n", os.Args[0])
|
fmt.Printf("Usage: %s <subcommand> [options]\n", os.Args[0])
|
||||||
fmt.Println("Description: Manage system packages")
|
fmt.Println("Description: Manage system packages")
|
||||||
fmt.Println("Subcommands:")
|
fmt.Println("Subcommands:")
|
||||||
@@ -1182,6 +1373,7 @@ func listSubcommands() {
|
|||||||
fmt.Println(" u, update Update installed packages")
|
fmt.Println(" u, update Update installed packages")
|
||||||
fmt.Println(" o, owner Show what packages own the specified paths")
|
fmt.Println(" o, owner Show what packages own the specified paths")
|
||||||
fmt.Println(" c, compile Compile source packages and convert them to binary ones")
|
fmt.Println(" c, compile Compile source packages and convert them to binary ones")
|
||||||
|
fmt.Println(" p, vercmp Compare package version numbers")
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupFlagsAndHelp(flagset *flag.FlagSet, usage, desc string, args []string) {
|
func setupFlagsAndHelp(flagset *flag.FlagSet, usage, desc string, args []string) {
|
||||||
|
|||||||
+124
-18
@@ -6,9 +6,11 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -21,7 +23,7 @@ import (
|
|||||||
var rootCompilationUID = "65534"
|
var rootCompilationUID = "65534"
|
||||||
var rootCompilationGID = "65534"
|
var rootCompilationGID = "65534"
|
||||||
|
|
||||||
func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bool) (outputBpmPackages map[string]string, err error) {
|
func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks, keepCompilationFiles, verbose bool) (outputBpmPackages map[string]string, err error) {
|
||||||
// Initialize map
|
// Initialize map
|
||||||
outputBpmPackages = make(map[string]string)
|
outputBpmPackages = make(map[string]string)
|
||||||
|
|
||||||
@@ -122,7 +124,7 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Download files
|
// Download files
|
||||||
err = downloadPackageFiles(bpmpkg.PkgInfo, tempDirectory)
|
err = downloadPackageFiles(bpmpkg.PkgInfo, tempDirectory, verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -135,6 +137,7 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
|
|||||||
env = append(env, "BPM_PKG_NAME="+bpmpkg.PkgInfo.Name)
|
env = append(env, "BPM_PKG_NAME="+bpmpkg.PkgInfo.Name)
|
||||||
env = append(env, "BPM_PKG_VERSION="+bpmpkg.PkgInfo.Version)
|
env = append(env, "BPM_PKG_VERSION="+bpmpkg.PkgInfo.Version)
|
||||||
env = append(env, "BPM_PKG_REVISION="+strconv.Itoa(bpmpkg.PkgInfo.Revision))
|
env = append(env, "BPM_PKG_REVISION="+strconv.Itoa(bpmpkg.PkgInfo.Revision))
|
||||||
|
env = append(env, "BPM_PKG_URL="+bpmpkg.PkgInfo.Url)
|
||||||
env = append(env, "BPM_PKG_ARCH="+bpmpkg.PkgInfo.OutputArch)
|
env = append(env, "BPM_PKG_ARCH="+bpmpkg.PkgInfo.OutputArch)
|
||||||
env = append(env, CompilationBPMConfig.CompilationEnvironment...)
|
env = append(env, CompilationBPMConfig.CompilationEnvironment...)
|
||||||
|
|
||||||
@@ -143,8 +146,8 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
|
|||||||
"set -a\n"+ // Source and export functions and variables in source.sh script
|
"set -a\n"+ // Source and export functions and variables in source.sh script
|
||||||
". \"${BPM_WORKDIR}\"/source.sh\n"+
|
". \"${BPM_WORKDIR}\"/source.sh\n"+
|
||||||
"set +a\n"+
|
"set +a\n"+
|
||||||
"[[ $(type -t prepare) == \"function\" ]] && { echo \"Running prepare() function\"; bash -e -c 'cd \"$BPM_WORKDIR\" && prepare' || exit 1; }\n"+ // Run prepare() function if it exists
|
"[[ $(type -t prepare) == \"function\" ]] && { echo \"Running prepare() function...\"; bash -e -c 'cd \"$BPM_WORKDIR\" && prepare' || exit 1; }\n"+ // Run prepare() function if it exists
|
||||||
"[[ $(type -t build) == \"function\" ]] && { echo \"Running build() function\"; bash -e -c 'cd \"$BPM_SOURCE\" && build' || exit 1; }\n"+ // Run build() function if it exists
|
"[[ $(type -t build) == \"function\" ]] && { echo \"Running build() function...\"; bash -e -c 'cd \"$BPM_SOURCE\" && build' || exit 1; }\n"+ // Run build() function if it exists
|
||||||
"exit 0")
|
"exit 0")
|
||||||
cmd.Dir = tempDirectory
|
cmd.Dir = tempDirectory
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
@@ -165,7 +168,7 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
|
|||||||
"set -a\n"+ // Source and export functions and variables in source.sh script
|
"set -a\n"+ // Source and export functions and variables in source.sh script
|
||||||
". \"${BPM_WORKDIR}\"/source.sh\n"+
|
". \"${BPM_WORKDIR}\"/source.sh\n"+
|
||||||
"set +a\n"+
|
"set +a\n"+
|
||||||
"[[ $(type -t check) == \"function\" ]] && { echo \"Running check() function\"; bash -e -c 'cd \"$BPM_SOURCE\" && check' || exit 1; }\n"+ // Run check() function if it exists
|
"[[ $(type -t check) == \"function\" ]] && { echo \"Running check() function...\"; bash -e -c 'cd \"$BPM_SOURCE\" && check' || exit 1; }\n"+ // Run check() function if it exists
|
||||||
"exit 0")
|
"exit 0")
|
||||||
cmd.Dir = tempDirectory
|
cmd.Dir = tempDirectory
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
@@ -215,9 +218,8 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
|
|||||||
"set -a\n"+ // Source and export functions and variables in source.sh script
|
"set -a\n"+ // Source and export functions and variables in source.sh script
|
||||||
". \"${BPM_WORKDIR}\"/source.sh\n"+
|
". \"${BPM_WORKDIR}\"/source.sh\n"+
|
||||||
"set +a\n"+
|
"set +a\n"+
|
||||||
"echo \"Running "+packageFunctionName+"() function\"\n"+
|
"echo \"Running "+packageFunctionName+"() function...\"\n"+
|
||||||
"( cd \"$BPM_SOURCE\" && fakeroot -s \"$BPM_WORKDIR\"/fakeroot_file bash -e -c '"+packageFunctionName+"' ) || exit 1\n"+ // Run package() function
|
"( cd \"$BPM_SOURCE\" && fakeroot -s \"$BPM_WORKDIR\"/fakeroot_file bash -e -c '"+packageFunctionName+"' ) || exit 1\n") // Run package() function
|
||||||
"fakeroot -i \"$BPM_WORKDIR\"/fakeroot_file find \"$BPM_OUTPUT\" -mindepth 1 -printf \"%P %#m %U %G %s\\n\" > \"$BPM_WORKDIR\"/pkg.files") // Create package file list
|
|
||||||
|
|
||||||
cmd.Dir = tempDirectory
|
cmd.Dir = tempDirectory
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
@@ -232,7 +234,92 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Strip all ELF binaries
|
||||||
|
if !slices.Contains(pkg.Options, "nostrip") {
|
||||||
|
if _, err := exec.LookPath("strip"); err != nil {
|
||||||
|
fmt.Println("Skip stripping ELF binaries. 'strip' not in path")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Stripping ELF binaries...")
|
||||||
|
|
||||||
|
err = filepath.WalkDir(path.Join(tempDirectory, "output_"+pkg.Name), func(path string, d fs.DirEntry, err error) error {
|
||||||
|
cmd = exec.Command("file", "-bi", path)
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mimetype := strings.Split(string(output), ";")[0]
|
||||||
|
|
||||||
|
if strings.HasPrefix(mimetype, "application/x-executable") {
|
||||||
|
cmd := exec.Command("strip", path)
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("Stripped %s (%s)\n", path, mimetype)
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(mimetype, "application/x-pie-executable") || strings.HasPrefix(mimetype, "application/x-sharedlib") {
|
||||||
|
cmd = exec.Command("file", "-b", path)
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
output, err = cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Skip files that use ELF as a container format
|
||||||
|
if strings.Contains(string(output), "no machine") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("strip", "--strip-unneeded", path)
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("Stripped %s (%s)\n", path, mimetype)
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(mimetype, "application/x-archive") {
|
||||||
|
cmd := exec.Command("strip", "--strip-debug", path)
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("Stripped %s (%s)\n", path, mimetype)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate package file list
|
||||||
|
fmt.Println("Generating package file list...")
|
||||||
|
cmd = exec.Command("bash", "-c", "fakeroot -i \"$BPM_WORKDIR\"/fakeroot_file find \"$BPM_OUTPUT\" -mindepth 1 -printf \"%P %#m %U %G %s\\n\" > \"$BPM_WORKDIR\"/pkg.files")
|
||||||
|
cmd.Dir = tempDirectory
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Env = append(env, "BPM_OUTPUT="+path.Join(tempDirectory, "output_"+pkg.Name))
|
||||||
|
if os.Getuid() == 0 {
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
|
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||||
|
}
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Create gzip-compressed archive for the package files
|
// Create gzip-compressed archive for the package files
|
||||||
|
fmt.Println("Generating compressed file archive...")
|
||||||
cmd = exec.Command("bash", "-c", fmt.Sprintf("find %s -printf \"%%P\\n\" | fakeroot -i %s/fakeroot_file tar -czf files.tar.gz --no-recursion -C %s -T -", "output_"+pkg.Name, tempDirectory, "output_"+pkg.Name))
|
cmd = exec.Command("bash", "-c", fmt.Sprintf("find %s -printf \"%%P\\n\" | fakeroot -i %s/fakeroot_file tar -czf files.tar.gz --no-recursion -C %s -T -", "output_"+pkg.Name, tempDirectory, "output_"+pkg.Name))
|
||||||
cmd.Dir = tempDirectory
|
cmd.Dir = tempDirectory
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
@@ -286,6 +373,7 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
|
|||||||
bpmArchiveFiles = append(bpmArchiveFiles, packageScripts...) // Package scripts
|
bpmArchiveFiles = append(bpmArchiveFiles, packageScripts...) // Package scripts
|
||||||
|
|
||||||
// Create final BPM archive
|
// Create final BPM archive
|
||||||
|
fmt.Println("Generating final BPM archive...")
|
||||||
cmd = exec.Command("bash", "-c", "tar -cf final-archive.bpm --owner=0 --group=0 -C \"$BPM_WORKDIR\" "+strings.Join(bpmArchiveFiles, " "))
|
cmd = exec.Command("bash", "-c", "tar -cf final-archive.bpm --owner=0 --group=0 -C \"$BPM_WORKDIR\" "+strings.Join(bpmArchiveFiles, " "))
|
||||||
cmd.Dir = tempDirectory
|
cmd.Dir = tempDirectory
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
@@ -334,18 +422,25 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
|
|||||||
outputBpmPackages[pkgInfo.Name] = outputFilename
|
outputBpmPackages[pkgInfo.Name] = outputFilename
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete temporary directory
|
||||||
|
if !keepCompilationFiles {
|
||||||
|
os.RemoveAll(tempDirectory)
|
||||||
|
}
|
||||||
|
|
||||||
return outputBpmPackages, nil
|
return outputBpmPackages, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadPackageFiles(pkgInfo *PackageInfo, tempDirectory string) error {
|
func downloadPackageFiles(pkgInfo *PackageInfo, tempDirectory string, verbose bool) error {
|
||||||
for _, download := range pkgInfo.Downloads {
|
for _, download := range pkgInfo.Downloads {
|
||||||
// Replace variables
|
// Replace variables
|
||||||
replaceVars := func(s string) string {
|
replaceVars := func(s string) string {
|
||||||
switch s {
|
switch s {
|
||||||
case "BPM_PKG_VERSION":
|
|
||||||
return pkgInfo.Version
|
|
||||||
case "BPM_PKG_NAME":
|
case "BPM_PKG_NAME":
|
||||||
return pkgInfo.Name
|
return pkgInfo.Name
|
||||||
|
case "BPM_PKG_VERSION":
|
||||||
|
return pkgInfo.Version
|
||||||
|
case "BPM_PKG_URL":
|
||||||
|
return pkgInfo.Url
|
||||||
case "BPM_SOURCE":
|
case "BPM_SOURCE":
|
||||||
return path.Join(tempDirectory, "source/")
|
return path.Join(tempDirectory, "source/")
|
||||||
default:
|
default:
|
||||||
@@ -357,6 +452,10 @@ func downloadPackageFiles(pkgInfo *PackageInfo, tempDirectory string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
filepath, err := envsubst.Eval(strings.TrimSpace(download.Filepath), replaceVars)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
extractTo, err := envsubst.Eval(strings.TrimSpace(download.ExtractTo), replaceVars)
|
extractTo, err := envsubst.Eval(strings.TrimSpace(download.ExtractTo), replaceVars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -377,12 +476,14 @@ func downloadPackageFiles(pkgInfo *PackageInfo, tempDirectory string) error {
|
|||||||
|
|
||||||
switch download.Type {
|
switch download.Type {
|
||||||
case "", "file":
|
case "", "file":
|
||||||
filepath := path.Join(tempDirectory, path.Base(downloadUrl))
|
if filepath == "" {
|
||||||
if download.Filepath != "" && download.Filepath[0] != '/' {
|
filepath = path.Join(tempDirectory, path.Base(downloadUrl))
|
||||||
filepath = path.Join(tempDirectory, download.Filepath)
|
}
|
||||||
|
if filepath[0] != '/' {
|
||||||
|
filepath = path.Join(tempDirectory, filepath)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := downloadFile(downloadUrl, filepath, 0644)
|
err := downloadFile("Downloading file "+path.Base(filepath), downloadUrl, filepath, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -409,7 +510,10 @@ func downloadPackageFiles(pkgInfo *PackageInfo, tempDirectory string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !download.NoExtract && (strings.Contains(filepath, ".tar") || strings.HasSuffix(filepath, ".tgz")) {
|
if !download.NoExtract && (strings.Contains(filepath, ".tar") || strings.HasSuffix(filepath, ".tgz")) {
|
||||||
cmd := exec.Command("tar", "xvf", filepath, "--strip-components="+strconv.Itoa(download.ExtractStripComponents))
|
cmd := exec.Command("tar", "xf", filepath, "--strip-components="+strconv.Itoa(download.ExtractStripComponents))
|
||||||
|
if verbose {
|
||||||
|
cmd.Args[1] = "xvf"
|
||||||
|
}
|
||||||
cmd.Dir = tempDirectory
|
cmd.Dir = tempDirectory
|
||||||
if extractTo != "" {
|
if extractTo != "" {
|
||||||
err := os.MkdirAll(extractTo, 0755)
|
err := os.MkdirAll(extractTo, 0755)
|
||||||
@@ -456,10 +560,12 @@ func downloadPackageFiles(pkgInfo *PackageInfo, tempDirectory string) error {
|
|||||||
gitBranch := download.GitBranch
|
gitBranch := download.GitBranch
|
||||||
gitBranch, err := envsubst.Eval(gitBranch, func(s string) string {
|
gitBranch, err := envsubst.Eval(gitBranch, func(s string) string {
|
||||||
switch s {
|
switch s {
|
||||||
case "BPM_PKG_VERSION":
|
|
||||||
return pkgInfo.Version
|
|
||||||
case "BPM_PKG_NAME":
|
case "BPM_PKG_NAME":
|
||||||
return pkgInfo.Name
|
return pkgInfo.Name
|
||||||
|
case "BPM_PKG_VERSION":
|
||||||
|
return pkgInfo.Version
|
||||||
|
case "BPM_PKG_URL":
|
||||||
|
return pkgInfo.Url
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
+172
-15
@@ -1,12 +1,17 @@
|
|||||||
package bpmlib
|
package bpmlib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"maps"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@@ -16,14 +21,15 @@ type BPMDatabase struct {
|
|||||||
DatabaseVersion int `yaml:"database_version"`
|
DatabaseVersion int `yaml:"database_version"`
|
||||||
Entries map[string]*BPMDatabaseEntry `yaml:"entries"`
|
Entries map[string]*BPMDatabaseEntry `yaml:"entries"`
|
||||||
VirtualPackages map[string][]string
|
VirtualPackages map[string][]string
|
||||||
|
Name string
|
||||||
Source string
|
Source string
|
||||||
}
|
}
|
||||||
|
|
||||||
type BPMDatabaseEntry struct {
|
type BPMDatabaseEntry struct {
|
||||||
Info *PackageInfo `yaml:"info"`
|
Info *PackageInfo `yaml:"info"`
|
||||||
Filepath string `yaml:"filepath"`
|
Filepath string `yaml:"filepath"`
|
||||||
DownloadSize uint64 `yaml:"download_size"`
|
DownloadSize int64 `yaml:"download_size"`
|
||||||
InstalledSize uint64 `yaml:"installed_size"`
|
InstalledSize int64 `yaml:"installed_size"`
|
||||||
Database *BPMDatabase
|
Database *BPMDatabase
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,13 +60,15 @@ func (db *configDatabase) ReadLocalDatabase() error {
|
|||||||
|
|
||||||
// Initialize struct values
|
// Initialize struct values
|
||||||
database.VirtualPackages = make(map[string][]string)
|
database.VirtualPackages = make(map[string][]string)
|
||||||
|
database.Name = db.Name
|
||||||
database.Source = db.Source
|
database.Source = db.Source
|
||||||
|
|
||||||
entriesToRemove := make([]string, 0)
|
|
||||||
for entryName, entry := range database.Entries {
|
for entryName, entry := range database.Entries {
|
||||||
entry.Database = database
|
entry.Database = database
|
||||||
|
|
||||||
if entry.Info.IsSplitPackage() {
|
if entry.Info.IsSplitPackage() {
|
||||||
|
delete(database.Entries, entryName)
|
||||||
|
|
||||||
// Handle split packages
|
// Handle split packages
|
||||||
for _, splitPkg := range entry.Info.SplitPackages {
|
for _, splitPkg := range entry.Info.SplitPackages {
|
||||||
// Turn split package into json data
|
// Turn split package into json data
|
||||||
@@ -99,9 +107,6 @@ func (db *configDatabase) ReadLocalDatabase() error {
|
|||||||
for _, p := range splitPkg.Provides {
|
for _, p := range splitPkg.Provides {
|
||||||
database.VirtualPackages[p] = append(database.VirtualPackages[p], splitPkg.Name)
|
database.VirtualPackages[p] = append(database.VirtualPackages[p], splitPkg.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add current entry to list for removal
|
|
||||||
entriesToRemove = append(entriesToRemove, entryName)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Add virtual packages to database
|
// Add virtual packages to database
|
||||||
@@ -111,11 +116,6 @@ func (db *configDatabase) ReadLocalDatabase() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove entries
|
|
||||||
for _, entryName := range entriesToRemove {
|
|
||||||
delete(database.Entries, entryName)
|
|
||||||
}
|
|
||||||
|
|
||||||
BPMDatabases[db.Name] = database
|
BPMDatabases[db.Name] = database
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -131,13 +131,29 @@ func (db *configDatabase) SyncLocalDatabaseFile() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve data from URL
|
// Retrieve data from URL
|
||||||
buffer, err := retrieveUrlData(u)
|
req, err := http.NewRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// Create progress bar
|
||||||
|
bar := createProgressBar(resp.ContentLength, "Syncing "+db.Name, false)
|
||||||
|
|
||||||
|
// Copy data
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
_, err = io.Copy(io.MultiWriter(&buffer, bar), resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal data to ensure it is a valid BPM database
|
// Unmarshal data to ensure it is a valid BPM database
|
||||||
err = yaml.Unmarshal(buffer, &BPMDatabase{})
|
err = yaml.Unmarshal(buffer.Bytes(), &BPMDatabase{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not decode database: %s", err)
|
return fmt.Errorf("could not decode database: %s", err)
|
||||||
}
|
}
|
||||||
@@ -155,7 +171,7 @@ func (db *configDatabase) SyncLocalDatabaseFile() error {
|
|||||||
}
|
}
|
||||||
defer out.Close()
|
defer out.Close()
|
||||||
|
|
||||||
_, err = out.Write(buffer)
|
_, err = out.Write(buffer.Bytes())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -240,10 +256,151 @@ func (db *BPMDatabase) FetchPackage(pkg string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Download package from url
|
// Download package from url
|
||||||
err = downloadFile(u, path.Join("/var/cache/bpm/fetched/", path.Base(entry.Filepath)), 0644)
|
err = downloadFile("Downloading "+entry.Info.Name, u, path.Join("/var/cache/bpm/fetched/", path.Base(entry.Filepath)), 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return path.Join("/var/cache/bpm/fetched/", path.Base(entry.Filepath)), nil
|
return path.Join("/var/cache/bpm/fetched/", path.Base(entry.Filepath)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
|
||||||
|
dependantsMap := make(map[string][]string)
|
||||||
|
for _, db := range BPMDatabases {
|
||||||
|
for _, e := range db.Entries {
|
||||||
|
if slices.Contains(e.Info.Depends, entry.Info.Name) {
|
||||||
|
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], e.Database.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get keys
|
||||||
|
keySlice := slices.Collect(maps.Keys(dependantsMap))
|
||||||
|
slices.Sort(keySlice)
|
||||||
|
|
||||||
|
// Add all dependant entries to slice in alphabetical order
|
||||||
|
for _, entryName := range keySlice {
|
||||||
|
dbs := dependantsMap[entryName]
|
||||||
|
if len(dbs) > 1 {
|
||||||
|
for _, db := range dbs {
|
||||||
|
dependants = append(dependants, db+"/"+entryName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dependants = append(dependants, entryName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependants
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *BPMDatabaseEntry) GetEntryOptionalDependants() (dependants []string) {
|
||||||
|
dependantsMap := make(map[string][]string)
|
||||||
|
for _, db := range BPMDatabases {
|
||||||
|
for _, e := range db.Entries {
|
||||||
|
if slices.Contains(e.Info.OptionalDepends, entry.Info.Name) {
|
||||||
|
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], e.Database.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get keys
|
||||||
|
keySlice := slices.Collect(maps.Keys(dependantsMap))
|
||||||
|
slices.Sort(keySlice)
|
||||||
|
|
||||||
|
// Add all dependant entries to slice in alphabetical order
|
||||||
|
for _, entryName := range keySlice {
|
||||||
|
dbs := dependantsMap[entryName]
|
||||||
|
if len(dbs) > 1 {
|
||||||
|
for _, db := range dbs {
|
||||||
|
dependants = append(dependants, db+"/"+entryName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dependants = append(dependants, entryName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependants
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *BPMDatabaseEntry) CreateReadableInfo(rootDir string, humanReadableSize bool) string {
|
||||||
|
ret := make([]string, 0)
|
||||||
|
appendArray := func(label string, array []string, sort bool) {
|
||||||
|
if len(array) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if sort {
|
||||||
|
// Sort array
|
||||||
|
slices.Sort(array)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = append(ret, fmt.Sprintf("%s: %s", label, strings.Join(array, ", ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = append(ret, "Name: "+entry.Info.Name)
|
||||||
|
ret = append(ret, "Database: "+entry.Database.Name)
|
||||||
|
ret = append(ret, "Description: "+entry.Info.Description)
|
||||||
|
ret = append(ret, "Version: "+entry.Info.GetFullVersion())
|
||||||
|
if entry.Info.Url != "" {
|
||||||
|
ret = append(ret, "URL: "+entry.Info.Url)
|
||||||
|
}
|
||||||
|
if entry.Info.License != "" {
|
||||||
|
ret = append(ret, "License: "+entry.Info.License)
|
||||||
|
}
|
||||||
|
ret = append(ret, "Architecture: "+entry.Info.Arch)
|
||||||
|
if entry.Info.Type == "source" && entry.Info.OutputArch != "" && entry.Info.OutputArch != GetArch() {
|
||||||
|
ret = append(ret, "Output architecture: "+entry.Info.OutputArch)
|
||||||
|
}
|
||||||
|
ret = append(ret, "Type: "+entry.Info.Type)
|
||||||
|
appendArray("Dependencies", entry.Info.Depends, true)
|
||||||
|
if entry.Info.Type == "source" {
|
||||||
|
appendArray("Make Dependencies", entry.Info.MakeDepends, true)
|
||||||
|
}
|
||||||
|
appendArray("Optional dependencies", entry.Info.OptionalDepends, true)
|
||||||
|
dependants := entry.GetEntryDependants()
|
||||||
|
if len(dependants) > 0 {
|
||||||
|
appendArray("Dependant packages", dependants, false)
|
||||||
|
}
|
||||||
|
optionalDependants := entry.GetEntryOptionalDependants()
|
||||||
|
if len(optionalDependants) > 0 {
|
||||||
|
appendArray("Optionally dependant packages", optionalDependants, false)
|
||||||
|
}
|
||||||
|
appendArray("Conflicting packages", entry.Info.Conflicts, true)
|
||||||
|
appendArray("Provided packages", entry.Info.Provides, true)
|
||||||
|
appendArray("Replaces packages", entry.Info.Replaces, true)
|
||||||
|
|
||||||
|
if entry.Info.Type == "source" && len(entry.Info.SplitPackages) != 0 {
|
||||||
|
splitPkgs := make([]string, len(entry.Info.SplitPackages))
|
||||||
|
for i, splitPkgInfo := range entry.Info.SplitPackages {
|
||||||
|
splitPkgs[i] = splitPkgInfo.Name
|
||||||
|
}
|
||||||
|
appendArray("Split Packages", splitPkgs, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rootDir != "" && IsPackageInstalled(entry.Info.Name, rootDir) {
|
||||||
|
installationReason := GetInstallationReason(entry.Info.Name, rootDir)
|
||||||
|
var installationReasonString string
|
||||||
|
switch installationReason {
|
||||||
|
case InstallationReasonManual:
|
||||||
|
installationReasonString = "Manual"
|
||||||
|
case InstallationReasonDependency:
|
||||||
|
installationReasonString = "Dependency"
|
||||||
|
case InstallationReasonMakeDependency:
|
||||||
|
installationReasonString = "Make dependency"
|
||||||
|
default:
|
||||||
|
installationReasonString = "Unknown"
|
||||||
|
}
|
||||||
|
ret = append(ret, "Installation Reason: "+installationReasonString)
|
||||||
|
}
|
||||||
|
if entry.Info.Type == "binary" {
|
||||||
|
installedSize := entry.InstalledSize
|
||||||
|
var installedSizeStr string
|
||||||
|
if humanReadableSize {
|
||||||
|
installedSizeStr = BytesToHumanReadable(installedSize)
|
||||||
|
} else {
|
||||||
|
installedSizeStr = strconv.FormatInt(installedSize, 10)
|
||||||
|
}
|
||||||
|
ret = append(ret, "Installed size: "+installedSizeStr)
|
||||||
|
}
|
||||||
|
return strings.Join(ret, "\n")
|
||||||
|
}
|
||||||
|
|||||||
+56
-28
@@ -1,7 +1,6 @@
|
|||||||
package bpmlib
|
package bpmlib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
)
|
)
|
||||||
@@ -48,6 +47,12 @@ func (pkgInfo *PackageInfo) GetDependencies(includeMakeDepends, includeOptionalD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip ignored packages
|
||||||
|
allDepends = slices.DeleteFunc(allDepends, func(depend pkgInstallationReason) bool {
|
||||||
|
return slices.Contains(MainBPMConfig.IgnorePackages, depend.PkgName)
|
||||||
|
})
|
||||||
|
|
||||||
return allDepends
|
return allDepends
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,53 +175,76 @@ func resolvePackageDependenciesFromDatabase(resolved *[]pkgInstallationReason, u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPackageDependants(pkgName string, rootDir string) ([]string, error) {
|
func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []string) {
|
||||||
ret := make([]string, 0)
|
|
||||||
|
|
||||||
// Get BPM package
|
|
||||||
pkg := GetPackage(pkgName, rootDir)
|
|
||||||
if pkg == nil {
|
|
||||||
return nil, errors.New("package not found: " + pkgName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get installed package names
|
// Get installed package names
|
||||||
pkgs, err := GetInstalledPackages(rootDir)
|
pkgs, ok := localPackageInformation[rootDir]
|
||||||
if err != nil {
|
if !ok {
|
||||||
return nil, errors.New("could not get installed packages")
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through all installed packages
|
// Loop through all installed packages
|
||||||
for _, installedPkgName := range pkgs {
|
for _, installedPkg := range pkgs {
|
||||||
// Get installed BPM package
|
|
||||||
installedPkg := GetPackage(installedPkgName, rootDir)
|
|
||||||
if installedPkg == nil {
|
|
||||||
return nil, errors.New("package not found: " + installedPkgName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip iteration if comparing the same packages
|
// Skip iteration if comparing the same packages
|
||||||
if installedPkg.PkgInfo.Name == pkgName {
|
if installedPkg.Name == pkgInfo.Name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add installed package to list if its dependencies include pkgName
|
// Add installed package to list if its dependencies include pkgName
|
||||||
if slices.ContainsFunc(installedPkg.PkgInfo.Depends, func(n string) bool {
|
if slices.ContainsFunc(installedPkg.Depends, func(n string) bool {
|
||||||
return n == pkgName
|
return n == pkgInfo.Name
|
||||||
}) {
|
}) {
|
||||||
ret = append(ret, installedPkgName)
|
dependants = append(dependants, installedPkg.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through each virtual package
|
// Loop through each virtual package
|
||||||
for _, vpkg := range pkg.PkgInfo.Provides {
|
for _, vpkg := range pkgInfo.Provides {
|
||||||
// Add installed package to list if its dependencies contain a provided virtual package
|
// Add installed package to list if its dependencies contain a provided virtual package
|
||||||
if slices.ContainsFunc(installedPkg.PkgInfo.Depends, func(n string) bool {
|
if slices.ContainsFunc(installedPkg.Depends, func(n string) bool {
|
||||||
return n == vpkg
|
return n == vpkg
|
||||||
}) {
|
}) {
|
||||||
ret = append(ret, installedPkgName)
|
dependants = append(dependants, installedPkg.Name)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, nil
|
return dependants
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pkgInfo *PackageInfo) GetPackageOptionalDependants(rootDir string) (dependants []string) {
|
||||||
|
// Get installed package names
|
||||||
|
pkgs, ok := localPackageInformation[rootDir]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through all installed packages
|
||||||
|
for _, installedPkg := range pkgs {
|
||||||
|
// Skip iteration if comparing the same packages
|
||||||
|
if installedPkg.Name == pkgInfo.Name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add installed package to list if its optional dependencies include pkgName
|
||||||
|
if slices.ContainsFunc(installedPkg.OptionalDepends, func(n string) bool {
|
||||||
|
return n == pkgInfo.Name
|
||||||
|
}) {
|
||||||
|
dependants = append(dependants, installedPkg.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through each virtual package
|
||||||
|
for _, vpkg := range pkgInfo.Provides {
|
||||||
|
// Add installed package to list if its optional dependencies contain a provided virtual package
|
||||||
|
if slices.ContainsFunc(installedPkg.OptionalDepends, func(n string) bool {
|
||||||
|
return n == vpkg
|
||||||
|
}) {
|
||||||
|
dependants = append(dependants, installedPkg.Name)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependants
|
||||||
}
|
}
|
||||||
|
|||||||
+38
-12
@@ -21,7 +21,6 @@ const (
|
|||||||
|
|
||||||
// InstallPackages installs the specified packages into the given root directory by fetching them from databases or directly from local bpm archives
|
// InstallPackages installs the specified packages into the given root directory by fetching them from databases or directly from local bpm archives
|
||||||
func InstallPackages(rootDir string, forceInstallationReason InstallationReason, reinstallMethod ReinstallMethod, installOptionalDependencies, forceInstallation, verbose bool, packages ...string) (operation *BPMOperation, err error) {
|
func InstallPackages(rootDir string, forceInstallationReason InstallationReason, reinstallMethod ReinstallMethod, installOptionalDependencies, forceInstallation, verbose bool, packages ...string) (operation *BPMOperation, err error) {
|
||||||
|
|
||||||
// Setup operation struct
|
// Setup operation struct
|
||||||
operation = &BPMOperation{
|
operation = &BPMOperation{
|
||||||
Actions: make([]OperationAction, 0),
|
Actions: make([]OperationAction, 0),
|
||||||
@@ -31,6 +30,9 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
|||||||
compiledPackages: make(map[string]string),
|
compiledPackages: make(map[string]string),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove duplicates from packages
|
||||||
|
packages = removeDuplicates(packages)
|
||||||
|
|
||||||
// Resolve packages
|
// Resolve packages
|
||||||
pkgsNotFound := make([]string, 0)
|
pkgsNotFound := make([]string, 0)
|
||||||
for _, pkg := range packages {
|
for _, pkg := range packages {
|
||||||
@@ -145,12 +147,9 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
|
|||||||
operation.ReplaceObsoletePackages()
|
operation.ReplaceObsoletePackages()
|
||||||
|
|
||||||
// Check for conflicts
|
// Check for conflicts
|
||||||
conflicts, err := operation.CheckForConflicts()
|
conflicts := operation.CheckForConflicts()
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not complete package conflict check: %s", err)
|
|
||||||
}
|
|
||||||
if len(conflicts) > 0 {
|
if len(conflicts) > 0 {
|
||||||
err = nil
|
err = fmt.Errorf("conflicts detected")
|
||||||
for pkg, conflict := range conflicts {
|
for pkg, conflict := range conflicts {
|
||||||
err = errors.Join(err, PackageConflictErr{pkg, conflict})
|
err = errors.Join(err, PackageConflictErr{pkg, conflict})
|
||||||
}
|
}
|
||||||
@@ -196,6 +195,9 @@ func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ..
|
|||||||
compiledPackages: make(map[string]string),
|
compiledPackages: make(map[string]string),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove duplicates from packages
|
||||||
|
packages = removeDuplicates(packages)
|
||||||
|
|
||||||
// Search for packages
|
// Search for packages
|
||||||
for _, pkg := range packages {
|
for _, pkg := range packages {
|
||||||
bpmpkg := GetPackage(pkg, rootDir)
|
bpmpkg := GetPackage(pkg, rootDir)
|
||||||
@@ -221,11 +223,12 @@ func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ..
|
|||||||
// Get packages and their dependants
|
// Get packages and their dependants
|
||||||
packageDepndants := make(map[string][]string, 0)
|
packageDepndants := make(map[string][]string, 0)
|
||||||
for _, action := range operation.Actions {
|
for _, action := range operation.Actions {
|
||||||
dependants, err := GetPackageDependants(action.(*RemovePackageAction).BpmPackage.PkgInfo.Name, rootDir)
|
// Skip package if ignored
|
||||||
if err != nil {
|
if slices.Contains(MainBPMConfig.IgnorePackages, action.(*RemovePackageAction).BpmPackage.PkgInfo.Name) {
|
||||||
return nil, fmt.Errorf("could not get package dependants: %s", err)
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependants := action.(*RemovePackageAction).BpmPackage.PkgInfo.GetPackageDependants(rootDir)
|
||||||
packageDepndants[action.(*RemovePackageAction).BpmPackage.PkgInfo.Name] = dependants
|
packageDepndants[action.(*RemovePackageAction).BpmPackage.PkgInfo.Name] = dependants
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,6 +241,14 @@ func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ..
|
|||||||
packageDepndants[pkg] = required
|
packageDepndants[pkg] = required
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove dependant packages if ignored
|
||||||
|
for pkg, required := range packageDepndants {
|
||||||
|
required = slices.DeleteFunc(required, func(pkgName string) bool {
|
||||||
|
return slices.Contains(MainBPMConfig.IgnorePackages, pkgName)
|
||||||
|
})
|
||||||
|
packageDepndants[pkg] = required
|
||||||
|
}
|
||||||
|
|
||||||
// Remove empty keys from map
|
// Remove empty keys from map
|
||||||
maps.DeleteFunc(packageDepndants, func(pkg string, required []string) bool {
|
maps.DeleteFunc(packageDepndants, func(pkg string, required []string) bool {
|
||||||
return len(required) == 0
|
return len(required) == 0
|
||||||
@@ -354,7 +365,7 @@ func CleanupCache(rootDir string, cleanupCompilationFiles, cleanupCompiledPackag
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePackages fetches the newest versions of all installed packages from
|
// UpdatePackages fetches the newest versions of all installed packages from
|
||||||
func UpdatePackages(rootDir string, syncDatabase bool, installOptionalDependencies, forceInstallation, verbose bool) (operation *BPMOperation, err error) {
|
func UpdatePackages(rootDir string, syncDatabase bool, allowDowngrades bool, installOptionalDependencies, forceInstallation, verbose bool) (operation *BPMOperation, err error) {
|
||||||
// Sync databases
|
// Sync databases
|
||||||
if syncDatabase {
|
if syncDatabase {
|
||||||
err := SyncDatabase(verbose)
|
err := SyncDatabase(verbose)
|
||||||
@@ -407,8 +418,8 @@ func UpdatePackages(rootDir string, syncDatabase bool, installOptionalDependenci
|
|||||||
if installedInfo == nil {
|
if installedInfo == nil {
|
||||||
return nil, fmt.Errorf("could not get package info for package (%s)", pkg)
|
return nil, fmt.Errorf("could not get package info for package (%s)", pkg)
|
||||||
} else {
|
} else {
|
||||||
comparison := ComparePackageVersions(*entry.Info, *installedInfo)
|
comparison := CompareVersions(entry.Info.GetFullVersion(), installedInfo.GetFullVersion())
|
||||||
if comparison > 0 {
|
if (!allowDowngrades && comparison > 0) || (allowDowngrades && comparison != 0) {
|
||||||
operation.AppendAction(&FetchPackageAction{
|
operation.AppendAction(&FetchPackageAction{
|
||||||
InstallationReason: GetInstallationReason(pkg, rootDir),
|
InstallationReason: GetInstallationReason(pkg, rootDir),
|
||||||
DatabaseEntry: entry,
|
DatabaseEntry: entry,
|
||||||
@@ -432,6 +443,21 @@ func UpdatePackages(rootDir string, syncDatabase bool, installOptionalDependenci
|
|||||||
|
|
||||||
// Replace obsolete packages
|
// Replace obsolete packages
|
||||||
operation.ReplaceObsoletePackages()
|
operation.ReplaceObsoletePackages()
|
||||||
|
|
||||||
|
// Check for conflicts
|
||||||
|
conflicts := operation.CheckForConflicts()
|
||||||
|
if len(conflicts) > 0 {
|
||||||
|
err = fmt.Errorf("conflicts detected")
|
||||||
|
for pkg, conflict := range conflicts {
|
||||||
|
err = errors.Join(err, PackageConflictErr{pkg, conflict})
|
||||||
|
}
|
||||||
|
if !forceInstallation {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
log.Printf("Warning: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return operation, nil
|
return operation, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-2
@@ -1,9 +1,17 @@
|
|||||||
module git.enumerated.dev/bubble-package-manager/bpm/src/bpmlib
|
module github.com/EnumeratedDev/bpm/src/bpmlib
|
||||||
|
|
||||||
go 1.23
|
go 1.24.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/drone/envsubst v1.0.3
|
github.com/drone/envsubst v1.0.3
|
||||||
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f
|
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f
|
||||||
|
github.com/schollz/progressbar/v3 v3.18.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
|
golang.org/x/sys v0.37.0 // indirect
|
||||||
|
golang.org/x/term v0.36.0 // indirect
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,9 +1,29 @@
|
|||||||
|
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=
|
||||||
|
github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
|
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
|
||||||
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
|
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
|
||||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f h1:xt29M2T6STgldg+WEP51gGePQCsQvklmP2eIhPIBK3g=
|
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f h1:xt29M2T6STgldg+WEP51gGePQCsQvklmP2eIhPIBK3g=
|
||||||
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
|
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||||
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA=
|
||||||
|
github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||||
|
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
|
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||||
|
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var localPackageInformation map[string]map[string]*BPMPackage = make(map[string]map[string]*BPMPackage)
|
var localPackageInformation map[string]map[string]*PackageInfo = make(map[string]map[string]*PackageInfo)
|
||||||
|
|
||||||
func initializeLocalPackageInformation(rootDir string) (err error) {
|
func initializeLocalPackageInformation(rootDir string) (err error) {
|
||||||
// Return if information is already initialized
|
// Return if information is already initialized
|
||||||
@@ -17,7 +17,7 @@ func initializeLocalPackageInformation(rootDir string) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tempPackageInformation := make(map[string]*BPMPackage)
|
tempPackageInformation := make(map[string]*PackageInfo)
|
||||||
|
|
||||||
// Get path to installed package information directory
|
// Get path to installed package information directory
|
||||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||||
@@ -25,7 +25,7 @@ func initializeLocalPackageInformation(rootDir string) (err error) {
|
|||||||
// Get directory content
|
// Get directory content
|
||||||
items, err := os.ReadDir(installedDir)
|
items, err := os.ReadDir(installedDir)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
localPackageInformation[rootDir] = make(map[string]*BPMPackage)
|
localPackageInformation[rootDir] = make(map[string]*PackageInfo)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -49,14 +49,8 @@ func initializeLocalPackageInformation(rootDir string) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read package files
|
|
||||||
files := getPackageFiles(info.Name, rootDir)
|
|
||||||
|
|
||||||
// Add package to slice
|
// Add package to slice
|
||||||
tempPackageInformation[info.Name] = &BPMPackage{
|
tempPackageInformation[info.Name] = info
|
||||||
PkgInfo: info,
|
|
||||||
PkgFiles: files,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
localPackageInformation[rootDir] = tempPackageInformation
|
localPackageInformation[rootDir] = tempPackageInformation
|
||||||
@@ -71,10 +65,13 @@ func GetInstalledPackages(rootDir string) (ret []string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Loop through each package and add it to slice
|
// Loop through each package and add it to slice
|
||||||
for _, bpmpkg := range localPackageInformation[rootDir] {
|
for _, pkgInfo := range localPackageInformation[rootDir] {
|
||||||
ret = append(ret, bpmpkg.PkgInfo.Name)
|
ret = append(ret, pkgInfo.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort packages
|
||||||
|
slices.Sort(ret)
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,18 +88,6 @@ func IsPackageInstalled(pkg, rootDir string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPackageInfo(pkg string, rootDir string) *PackageInfo {
|
|
||||||
// Get BPM package
|
|
||||||
bpmpkg := GetPackage(pkg, rootDir)
|
|
||||||
|
|
||||||
// Return nil if not found
|
|
||||||
if bpmpkg == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return bpmpkg.PkgInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsVirtualPackage(pkg, rootDir string) (bool, string) {
|
func IsVirtualPackage(pkg, rootDir string) (bool, string) {
|
||||||
pkgs, err := GetInstalledPackages(rootDir)
|
pkgs, err := GetInstalledPackages(rootDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -143,15 +128,27 @@ func IsPackageProvided(pkg, rootDir string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPackage(pkg, rootDir string) *BPMPackage {
|
func GetPackageInfo(pkg string, rootDir string) *PackageInfo {
|
||||||
err := initializeLocalPackageInformation(rootDir)
|
err := initializeLocalPackageInformation(rootDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
bpmpkg := localPackageInformation[rootDir][pkg]
|
return localPackageInformation[rootDir][pkg]
|
||||||
|
}
|
||||||
|
|
||||||
return bpmpkg
|
func GetPackage(pkg, rootDir string) *BPMPackage {
|
||||||
|
pkgInfo := GetPackageInfo(pkg, rootDir)
|
||||||
|
if pkgInfo == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
files := getPackageFiles(pkgInfo.Name, rootDir)
|
||||||
|
|
||||||
|
return &BPMPackage{
|
||||||
|
PkgInfo: pkgInfo,
|
||||||
|
PkgFiles: files,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllPackageFiles(rootDir string, excludePackages ...string) (map[string][]*BPMPackage, error) {
|
func GetAllPackageFiles(rootDir string, excludePackages ...string) (map[string][]*BPMPackage, error) {
|
||||||
@@ -222,7 +219,7 @@ func getPackageFiles(pkg, rootDir string) []*PackageFileEntry {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
size, err := strconv.ParseUint(stringEntry[len(stringEntry)-1], 0, 64)
|
size, err := strconv.ParseInt(stringEntry[len(stringEntry)-1], 0, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-16
@@ -9,29 +9,22 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func retrieveUrlData(u string) ([]byte, error) {
|
func downloadFile(barText, u, filepath string, perm os.FileMode) error {
|
||||||
resp, err := http.Get(u)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
// Load data into byte buffer
|
|
||||||
buffer, err := io.ReadAll(resp.Body)
|
|
||||||
|
|
||||||
return buffer, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func downloadFile(u, filepath string, perm os.FileMode) error {
|
|
||||||
if strings.HasSuffix(filepath, "/") {
|
if strings.HasSuffix(filepath, "/") {
|
||||||
return fmt.Errorf("Filepath must not end in '/'")
|
return fmt.Errorf("Filepath must not end in '/'")
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := retrieveUrlData(u)
|
req, err := http.NewRequest("GET", u, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
// Create parent directories
|
// Create parent directories
|
||||||
err = os.MkdirAll(path.Dir(filepath), 0755)
|
err = os.MkdirAll(path.Dir(filepath), 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -45,8 +38,12 @@ func downloadFile(u, filepath string, perm os.FileMode) error {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
|
// Create progress bar
|
||||||
|
bar := createProgressBar(resp.ContentLength, barText, false)
|
||||||
|
defer bar.Close()
|
||||||
|
|
||||||
// Copy data
|
// Copy data
|
||||||
_, err = file.Write(data)
|
_, err = io.Copy(io.MultiWriter(file, bar), resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+137
-61
@@ -87,8 +87,8 @@ func (operation *BPMOperation) RemoveAction(pkg, actionType string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (operation *BPMOperation) GetTotalDownloadSize() uint64 {
|
func (operation *BPMOperation) GetTotalDownloadSize() int64 {
|
||||||
var ret uint64 = 0
|
var ret int64 = 0
|
||||||
for _, action := range operation.Actions {
|
for _, action := range operation.Actions {
|
||||||
if action.GetActionType() == "fetch" {
|
if action.GetActionType() == "fetch" {
|
||||||
ret += action.(*FetchPackageAction).DatabaseEntry.DownloadSize
|
ret += action.(*FetchPackageAction).DatabaseEntry.DownloadSize
|
||||||
@@ -97,8 +97,8 @@ func (operation *BPMOperation) GetTotalDownloadSize() uint64 {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (operation *BPMOperation) GetTotalInstalledSize() uint64 {
|
func (operation *BPMOperation) GetTotalInstalledSize() int64 {
|
||||||
var ret uint64 = 0
|
var ret int64 = 0
|
||||||
for _, action := range operation.Actions {
|
for _, action := range operation.Actions {
|
||||||
if action.GetActionType() == "install" {
|
if action.GetActionType() == "install" {
|
||||||
ret += action.(*InstallPackageAction).BpmPackage.GetInstalledSize()
|
ret += action.(*InstallPackageAction).BpmPackage.GetInstalledSize()
|
||||||
@@ -113,14 +113,17 @@ func (operation *BPMOperation) GetFinalActionSize(rootDir string) int64 {
|
|||||||
var ret int64 = 0
|
var ret int64 = 0
|
||||||
for _, action := range operation.Actions {
|
for _, action := range operation.Actions {
|
||||||
if action.GetActionType() == "install" {
|
if action.GetActionType() == "install" {
|
||||||
ret += int64(action.(*InstallPackageAction).BpmPackage.GetInstalledSize())
|
ret += action.(*InstallPackageAction).BpmPackage.GetInstalledSize()
|
||||||
if IsPackageInstalled(action.(*InstallPackageAction).BpmPackage.PkgInfo.Name, rootDir) {
|
if IsPackageInstalled(action.(*InstallPackageAction).BpmPackage.PkgInfo.Name, rootDir) {
|
||||||
ret -= int64(GetPackage(action.(*InstallPackageAction).BpmPackage.PkgInfo.Name, rootDir).GetInstalledSize())
|
ret -= GetPackage(action.(*InstallPackageAction).BpmPackage.PkgInfo.Name, rootDir).GetInstalledSize()
|
||||||
}
|
}
|
||||||
} else if action.GetActionType() == "fetch" {
|
} else if action.GetActionType() == "fetch" {
|
||||||
ret += int64(action.(*FetchPackageAction).DatabaseEntry.InstalledSize)
|
ret += action.(*FetchPackageAction).DatabaseEntry.InstalledSize
|
||||||
|
if IsPackageInstalled(action.(*FetchPackageAction).DatabaseEntry.Info.Name, rootDir) {
|
||||||
|
ret -= action.(*FetchPackageAction).DatabaseEntry.InstalledSize
|
||||||
|
}
|
||||||
} else if action.GetActionType() == "remove" {
|
} else if action.GetActionType() == "remove" {
|
||||||
ret -= int64(action.(*RemovePackageAction).BpmPackage.GetInstalledSize())
|
ret -= action.(*RemovePackageAction).BpmPackage.GetInstalledSize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
@@ -176,10 +179,7 @@ func (operation *BPMOperation) RemoveNeededPackages() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for pkg, action := range removeActions {
|
for pkg, action := range removeActions {
|
||||||
dependants, err := GetPackageDependants(action.BpmPackage.PkgInfo.Name, operation.RootDir)
|
dependants := action.BpmPackage.PkgInfo.GetPackageDependants(operation.RootDir)
|
||||||
if err != nil {
|
|
||||||
return errors.New("could not get dependant packages for package (" + pkg + ")")
|
|
||||||
}
|
|
||||||
dependants = slices.DeleteFunc(dependants, func(d string) bool {
|
dependants = slices.DeleteFunc(dependants, func(d string) bool {
|
||||||
if _, ok := removeActions[d]; ok {
|
if _, ok := removeActions[d]; ok {
|
||||||
return true
|
return true
|
||||||
@@ -232,7 +232,7 @@ func (operation *BPMOperation) Cleanup(cleanupMakeDepends bool) error {
|
|||||||
keepPackages = append(keepPackages, pkg.Name)
|
keepPackages = append(keepPackages, pkg.Name)
|
||||||
resolved := pkg.GetDependenciesRecursive(!cleanupMakeDepends, operation.RootDir)
|
resolved := pkg.GetDependenciesRecursive(!cleanupMakeDepends, operation.RootDir)
|
||||||
for _, value := range resolved {
|
for _, value := range resolved {
|
||||||
if !slices.Contains(keepPackages, value) {
|
if !slices.Contains(keepPackages, value) && !slices.Contains(MainBPMConfig.IgnorePackages, value) {
|
||||||
keepPackages = append(keepPackages, value)
|
keepPackages = append(keepPackages, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,54 +280,92 @@ func (operation *BPMOperation) ReplaceObsoletePackages() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (operation *BPMOperation) CheckForConflicts() (map[string][]string, error) {
|
func (operation *BPMOperation) CheckForConflicts() map[string][]string {
|
||||||
conflicts := make(map[string][]string)
|
conflicts := make(map[string][]string)
|
||||||
installedPackages, err := GetInstalledPackages(operation.RootDir)
|
|
||||||
if err != nil {
|
// Get installed packages
|
||||||
return nil, err
|
installedPackages := localPackageInformation[operation.RootDir]
|
||||||
}
|
|
||||||
allPackages := make([]*PackageInfo, len(installedPackages))
|
// Get packages to be removed
|
||||||
for i, value := range installedPackages {
|
removedPackages := make([]string, 0)
|
||||||
bpmpkg := GetPackage(value, operation.RootDir)
|
for _, value := range slices.Clone(operation.Actions) {
|
||||||
if bpmpkg == nil {
|
if value.GetActionType() != "remove" {
|
||||||
return nil, fmt.Errorf("could not find installed package (%s)", value)
|
continue
|
||||||
}
|
}
|
||||||
allPackages[i] = bpmpkg.PkgInfo
|
|
||||||
|
removedPackages = append(removedPackages, value.(*RemovePackageAction).BpmPackage.PkgInfo.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all new packages to the allPackages slice
|
// Check for conflicts
|
||||||
for _, value := range slices.Clone(operation.Actions) {
|
for _, value := range slices.Clone(operation.Actions) {
|
||||||
|
var pkgInfo *PackageInfo
|
||||||
if value.GetActionType() == "install" {
|
if value.GetActionType() == "install" {
|
||||||
action := value.(*InstallPackageAction)
|
pkgInfo = value.(*InstallPackageAction).BpmPackage.PkgInfo
|
||||||
pkgInfo := action.BpmPackage.PkgInfo
|
|
||||||
allPackages = append(allPackages, pkgInfo)
|
|
||||||
} else if value.GetActionType() == "fetch" {
|
} else if value.GetActionType() == "fetch" {
|
||||||
action := value.(*FetchPackageAction)
|
pkgInfo = value.(*FetchPackageAction).DatabaseEntry.Info
|
||||||
pkgInfo := action.DatabaseEntry.Info
|
} else {
|
||||||
allPackages = append(allPackages, pkgInfo)
|
continue
|
||||||
} else if value.GetActionType() == "remove" {
|
}
|
||||||
action := value.(*RemovePackageAction)
|
|
||||||
pkgInfo := action.BpmPackage.PkgInfo
|
// Check for conflicts with installed packages
|
||||||
for i := len(allPackages) - 1; i >= 0; i-- {
|
for _, installedPkg := range installedPackages {
|
||||||
info := allPackages[i]
|
// Skip if package is to be removed
|
||||||
if info.Name == pkgInfo.Name {
|
if slices.Contains(removedPackages, installedPkg.Name) {
|
||||||
allPackages = append(allPackages[:i], allPackages[i+1:]...)
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if same package
|
||||||
|
if pkgInfo.Name == installedPkg.Name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for new package conflicts
|
||||||
|
if slices.Contains(pkgInfo.Conflicts, installedPkg.Name) {
|
||||||
|
conflicts[pkgInfo.Name] = append(conflicts[pkgInfo.Name], installedPkg.Name)
|
||||||
|
}
|
||||||
|
for _, vpkg := range installedPkg.Provides {
|
||||||
|
if slices.Contains(pkgInfo.Conflicts, vpkg) {
|
||||||
|
conflicts[pkgInfo.Name] = append(conflicts[pkgInfo.Name], vpkg+" ("+installedPkg.Name+")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for installed package conflicts
|
||||||
|
for _, vpkg := range pkgInfo.Provides {
|
||||||
|
if slices.Contains(installedPkg.Conflicts, vpkg) {
|
||||||
|
conflicts[installedPkg.Name] = append(conflicts[installedPkg.Name], vpkg+" ("+pkgInfo.Name+")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for conflicts with other new packages
|
||||||
|
for _, value := range slices.Clone(operation.Actions) {
|
||||||
|
var pkgInfo2 *PackageInfo
|
||||||
|
if value.GetActionType() == "install" {
|
||||||
|
pkgInfo2 = value.(*InstallPackageAction).BpmPackage.PkgInfo
|
||||||
|
} else if value.GetActionType() == "fetch" {
|
||||||
|
pkgInfo2 = value.(*FetchPackageAction).DatabaseEntry.Info
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if same package
|
||||||
|
if pkgInfo.Name == pkgInfo2.Name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for other package conflicts
|
||||||
|
if slices.Contains(pkgInfo.Conflicts, pkgInfo2.Name) {
|
||||||
|
conflicts[pkgInfo.Name] = append(conflicts[pkgInfo.Name], pkgInfo2.Name)
|
||||||
|
}
|
||||||
|
for _, vpkg := range pkgInfo2.Provides {
|
||||||
|
if slices.Contains(pkgInfo.Conflicts, vpkg) {
|
||||||
|
conflicts[pkgInfo.Name] = append(conflicts[pkgInfo.Name], vpkg+" ("+pkgInfo2.Name+")")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, value := range allPackages {
|
return conflicts
|
||||||
for _, conflict := range value.Conflicts {
|
|
||||||
if slices.ContainsFunc(allPackages, func(info *PackageInfo) bool {
|
|
||||||
return info.Name == conflict
|
|
||||||
}) {
|
|
||||||
conflicts[value.Name] = append(conflicts[value.Name], conflict)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return conflicts, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (operation *BPMOperation) ShowOperationSummary() {
|
func (operation *BPMOperation) ShowOperationSummary() {
|
||||||
@@ -373,7 +411,7 @@ func (operation *BPMOperation) ShowOperationSummary() {
|
|||||||
if installedInfo == nil {
|
if installedInfo == nil {
|
||||||
fmt.Fprintf(writer, "%s\t%s\t%s\t%s\t%t\n", pkgInfo.Name, pkgInfo.GetFullVersion(), "Install", installationReasonStr, pkgInfo.Type == "source")
|
fmt.Fprintf(writer, "%s\t%s\t%s\t%s\t%t\n", pkgInfo.Name, pkgInfo.GetFullVersion(), "Install", installationReasonStr, pkgInfo.Type == "source")
|
||||||
} else {
|
} else {
|
||||||
comparison := ComparePackageVersions(*pkgInfo, *installedInfo)
|
comparison := CompareVersions(pkgInfo.GetFullVersion(), installedInfo.GetFullVersion())
|
||||||
if comparison < 0 {
|
if comparison < 0 {
|
||||||
fmt.Fprintf(writer, "%s\t%s -> %s\t%s\t%s\t%t\n", pkgInfo.Name, installedInfo.GetFullVersion(), pkgInfo.GetFullVersion(), "Downgrade", installationReasonStr, pkgInfo.Type == "source")
|
fmt.Fprintf(writer, "%s\t%s -> %s\t%s\t%s\t%t\n", pkgInfo.Name, installedInfo.GetFullVersion(), pkgInfo.GetFullVersion(), "Downgrade", installationReasonStr, pkgInfo.Type == "source")
|
||||||
} else if comparison > 0 {
|
} else if comparison > 0 {
|
||||||
@@ -391,12 +429,12 @@ func (operation *BPMOperation) ShowOperationSummary() {
|
|||||||
fmt.Println("Warning: Operating in " + operation.RootDir)
|
fmt.Println("Warning: Operating in " + operation.RootDir)
|
||||||
}
|
}
|
||||||
if operation.GetTotalDownloadSize() > 0 {
|
if operation.GetTotalDownloadSize() > 0 {
|
||||||
fmt.Printf("%s will be downloaded to complete this operation\n", unsignedBytesToHumanReadable(operation.GetTotalDownloadSize()))
|
fmt.Printf("%s will be downloaded to complete this operation\n", BytesToHumanReadable(operation.GetTotalDownloadSize()))
|
||||||
}
|
}
|
||||||
if operation.GetFinalActionSize(operation.RootDir) > 0 {
|
if operation.GetFinalActionSize(operation.RootDir) > 0 {
|
||||||
fmt.Printf("A total of %s will be installed after the operation finishes\n", bytesToHumanReadable(operation.GetFinalActionSize(operation.RootDir)))
|
fmt.Printf("A total of %s will be installed after the operation finishes\n", BytesToHumanReadable(operation.GetFinalActionSize(operation.RootDir)))
|
||||||
} else if operation.GetFinalActionSize(operation.RootDir) < 0 {
|
} else if operation.GetFinalActionSize(operation.RootDir) < 0 {
|
||||||
fmt.Printf("A total of %s will be freed after the operation finishes\n", strings.TrimPrefix(bytesToHumanReadable(operation.GetFinalActionSize(operation.RootDir)), "-"))
|
fmt.Printf("A total of %s will be freed after the operation finishes\n", strings.TrimPrefix(BytesToHumanReadable(operation.GetFinalActionSize(operation.RootDir)), "-"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,6 +466,40 @@ func (operation *BPMOperation) ShowSourcePackageContent() (sourcePackagesShown i
|
|||||||
return sourcePackagesShown, nil
|
return sourcePackagesShown, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (operation *BPMOperation) GetOptionalDependencies() (optionalDepends map[string][]string) {
|
||||||
|
optionalDepends = make(map[string][]string)
|
||||||
|
|
||||||
|
// Find all optional dependencies
|
||||||
|
for _, value := range slices.Clone(operation.Actions) {
|
||||||
|
var pkgInfo *PackageInfo
|
||||||
|
if value.GetActionType() == "install" {
|
||||||
|
action := value.(*InstallPackageAction)
|
||||||
|
pkgInfo = action.BpmPackage.PkgInfo
|
||||||
|
} else if value.GetActionType() == "fetch" {
|
||||||
|
action := value.(*FetchPackageAction)
|
||||||
|
pkgInfo = action.DatabaseEntry.Info
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, depend := range pkgInfo.OptionalDepends {
|
||||||
|
// Skip if dependency is already installed
|
||||||
|
if IsPackageInstalled(depend, operation.RootDir) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if not a new dependency of the package
|
||||||
|
if installedPkg := GetPackage(pkgInfo.Name, operation.RootDir); installedPkg != nil && slices.Contains(installedPkg.PkgInfo.OptionalDepends, depend) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
optionalDepends[pkgInfo.Name] = append(optionalDepends[pkgInfo.Name], depend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (operation *BPMOperation) RunHooks(verbose bool) error {
|
func (operation *BPMOperation) RunHooks(verbose bool) error {
|
||||||
// Return if hooks directory does not exist
|
// Return if hooks directory does not exist
|
||||||
if stat, err := os.Stat(path.Join(operation.RootDir, "var/lib/bpm/hooks")); err != nil || !stat.IsDir() {
|
if stat, err := os.Stat(path.Join(operation.RootDir, "var/lib/bpm/hooks")); err != nil || !stat.IsDir() {
|
||||||
@@ -481,7 +553,7 @@ func (operation *BPMOperation) FetchPackages() (err error) {
|
|||||||
var bpmpkg *BPMPackage
|
var bpmpkg *BPMPackage
|
||||||
|
|
||||||
// Check if package has already been fetched from download link
|
// Check if package has already been fetched from download link
|
||||||
if _, ok := fetchedPackages[entry.Filepath]; !ok {
|
if fetchedFilepath, ok := fetchedPackages[entry.Filepath]; !ok {
|
||||||
// Fetch package from database
|
// Fetch package from database
|
||||||
fetchedPackage, err := entry.Database.FetchPackage(entry.Info.Name)
|
fetchedPackage, err := entry.Database.FetchPackage(entry.Info.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -496,16 +568,22 @@ func (operation *BPMOperation) FetchPackages() (err error) {
|
|||||||
|
|
||||||
// Add fetched package to map
|
// Add fetched package to map
|
||||||
fetchedPackages[entry.Filepath] = fetchedPackage
|
fetchedPackages[entry.Filepath] = fetchedPackage
|
||||||
|
|
||||||
fmt.Printf("Package (%s) was successfully fetched!\n", entry.Info.Name)
|
|
||||||
} else {
|
} else {
|
||||||
// Read fetched package
|
// Read fetched package
|
||||||
bpmpkg, err = ReadPackage(fetchedPackages[entry.Filepath])
|
bpmpkg, err = ReadPackage(fetchedFilepath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not read package (%s): %s\n", entry.Info.Name, err)
|
return fmt.Errorf("could not read package (%s): %s\n", entry.Info.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Package (%s) was successfully fetched!\n", entry.Info.Name)
|
// Get size of fetched archive
|
||||||
|
stat, err := os.Stat(fetchedFilepath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bar := createProgressBar(stat.Size(), "Downloading "+entry.Info.Name, false)
|
||||||
|
bar.Set64(stat.Size())
|
||||||
|
bar.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
if bpmpkg.PkgInfo.IsSplitPackage() {
|
if bpmpkg.PkgInfo.IsSplitPackage() {
|
||||||
@@ -592,7 +670,7 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
|||||||
|
|
||||||
// Compile source package if not compiled already
|
// Compile source package if not compiled already
|
||||||
if _, ok := operation.compiledPackages[pkgNameToInstall]; !ok {
|
if _, ok := operation.compiledPackages[pkgNameToInstall]; !ok {
|
||||||
outputBpmPackages, err := CompileSourcePackage(value.File, compiledDir, false)
|
outputBpmPackages, err := CompileSourcePackage(value.File, compiledDir, false, false, verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not compile source package (%s): %s\n", value.File, err)
|
return fmt.Errorf("could not compile source package (%s): %s\n", value.File, err)
|
||||||
}
|
}
|
||||||
@@ -625,8 +703,6 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not set installation reason for package (%s): %s\n", value.BpmPackage.PkgInfo.Name, err)
|
return fmt.Errorf("could not set installation reason for package (%s): %s\n", value.BpmPackage.PkgInfo.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Package (%s) was successfully installed\n", bpmpkg.PkgInfo.Name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println("Operation complete!")
|
fmt.Println("Operation complete!")
|
||||||
|
|||||||
+107
-48
@@ -17,7 +17,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
version "github.com/knqyf263/go-rpm-version"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,6 +42,7 @@ type PackageInfo struct {
|
|||||||
Conflicts []string `yaml:"conflicts,omitempty"`
|
Conflicts []string `yaml:"conflicts,omitempty"`
|
||||||
Replaces []string `yaml:"replaces,omitempty"`
|
Replaces []string `yaml:"replaces,omitempty"`
|
||||||
Provides []string `yaml:"provides,omitempty"`
|
Provides []string `yaml:"provides,omitempty"`
|
||||||
|
Options []string `yaml:"options,omitempty"`
|
||||||
Downloads []PackageDownload `yaml:"downloads,omitempty"`
|
Downloads []PackageDownload `yaml:"downloads,omitempty"`
|
||||||
SplitPackages []*PackageInfo `yaml:"split_packages,omitempty"`
|
SplitPackages []*PackageInfo `yaml:"split_packages,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ type PackageInfo struct {
|
|||||||
type PackageDownload struct {
|
type PackageDownload struct {
|
||||||
Url string `yaml:"url"`
|
Url string `yaml:"url"`
|
||||||
Type string `yaml:"type,omitempty"`
|
Type string `yaml:"type,omitempty"`
|
||||||
Filepath string `yaml:"filepath,omitempty,omitempty"`
|
Filepath string `yaml:"filepath,omitempty"`
|
||||||
|
|
||||||
// Archive options
|
// Archive options
|
||||||
NoExtract bool `yaml:"no_extract,omitempty"`
|
NoExtract bool `yaml:"no_extract,omitempty"`
|
||||||
@@ -69,11 +69,11 @@ type PackageFileEntry struct {
|
|||||||
OctalPerms uint32
|
OctalPerms uint32
|
||||||
UserID int
|
UserID int
|
||||||
GroupID int
|
GroupID int
|
||||||
SizeInBytes uint64
|
SizeInBytes int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *BPMPackage) GetInstalledSize() uint64 {
|
func (pkg *BPMPackage) GetInstalledSize() int64 {
|
||||||
var totalSize uint64 = 0
|
var totalSize int64 = 0
|
||||||
for _, entry := range pkg.PkgFiles {
|
for _, entry := range pkg.PkgFiles {
|
||||||
totalSize += entry.SizeInBytes
|
totalSize += entry.SizeInBytes
|
||||||
}
|
}
|
||||||
@@ -120,13 +120,6 @@ const (
|
|||||||
InstallationReasonUnknown InstallationReason = "unknown"
|
InstallationReasonUnknown InstallationReason = "unknown"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ComparePackageVersions(info1, info2 PackageInfo) int {
|
|
||||||
v1 := version.NewVersion(info1.GetFullVersion())
|
|
||||||
v2 := version.NewVersion(info2.GetFullVersion())
|
|
||||||
|
|
||||||
return v1.Compare(v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetInstallationReason(pkg, rootDir string) InstallationReason {
|
func GetInstallationReason(pkg, rootDir string) InstallationReason {
|
||||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||||
pkgDir := path.Join(installedDir, pkg)
|
pkgDir := path.Join(installedDir, pkg)
|
||||||
@@ -239,7 +232,7 @@ func ReadPackage(filename string) (*BPMPackage, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
size, err := strconv.ParseUint(stringEntry[len(stringEntry)-1], 0, 64)
|
size, err := strconv.ParseInt(stringEntry[len(stringEntry)-1], 0, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -375,9 +368,44 @@ func executePackageScript(pkg, rootDir string, verbose bool, packageScript strin
|
|||||||
cmd := exec.Command("/bin/bash", "-c", content)
|
cmd := exec.Command("/bin/bash", "-c", content)
|
||||||
// Setup subprocess environment
|
// Setup subprocess environment
|
||||||
cmd.Dir = "/"
|
cmd.Dir = "/"
|
||||||
// Run hook in chroot if using the -R flag
|
// Run package script in chroot if using the -R flag
|
||||||
if rootDir != "/" {
|
if rootDir != "/" {
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{Chroot: rootDir}
|
cmd.SysProcAttr = &syscall.SysProcAttr{Chroot: rootDir}
|
||||||
|
|
||||||
|
// Bind mount /etc/resolv.conf
|
||||||
|
mounted, err := func() (bool, error) {
|
||||||
|
if _, err := os.Stat("/etc/resolv.conf"); err != nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat(path.Join(rootDir, "etc/resolv.conf")); os.IsNotExist(err) {
|
||||||
|
err = os.WriteFile(path.Join(rootDir, "/etc/resolv.conf"), nil, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mntCmd := exec.Command("mount", "-o", "ro,bind", "/etc/resolv.conf", path.Join(rootDir, "/etc/resolv.conf"))
|
||||||
|
if verbose {
|
||||||
|
mntCmd.Stdout = os.Stdout
|
||||||
|
mntCmd.Stderr = os.Stderr
|
||||||
|
}
|
||||||
|
err = mntCmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if mounted {
|
||||||
|
defer exec.Command("umount", "-f", path.Join(rootDir, "/etc/resolv.conf")).Run()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Show output if verbose
|
// Show output if verbose
|
||||||
if verbose {
|
if verbose {
|
||||||
@@ -434,6 +462,7 @@ func ReadPackageInfo(contents string) (*PackageInfo, error) {
|
|||||||
Conflicts: make([]string, 0),
|
Conflicts: make([]string, 0),
|
||||||
Replaces: make([]string, 0),
|
Replaces: make([]string, 0),
|
||||||
Provides: make([]string, 0),
|
Provides: make([]string, 0),
|
||||||
|
Options: make([]string, 0),
|
||||||
Downloads: make([]PackageDownload, 0),
|
Downloads: make([]PackageDownload, 0),
|
||||||
SplitPackages: make([]*PackageInfo, 0),
|
SplitPackages: make([]*PackageInfo, 0),
|
||||||
}
|
}
|
||||||
@@ -507,39 +536,47 @@ func ReadPackageInfo(contents string) (*PackageInfo, error) {
|
|||||||
return pkgInfo, nil
|
return pkgInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateReadableInfo(showArchitecture, showType, showPackageRelations, showInstallationReason bool, pkgInfo *PackageInfo, rootDir string) string {
|
func (pkgInfo *PackageInfo) CreateReadableInfo(rootDir string) string {
|
||||||
ret := make([]string, 0)
|
ret := make([]string, 0)
|
||||||
appendArray := func(label string, array []string) {
|
appendArray := func(label string, array []string) {
|
||||||
if len(array) == 0 {
|
if len(array) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = append(ret, fmt.Sprintf("%s: %s", label, strings.Join(array, ", ")))
|
ret = append(ret, fmt.Sprintf("%s: %s", label, strings.Join(array, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = append(ret, "Name: "+pkgInfo.Name)
|
ret = append(ret, "Name: "+pkgInfo.Name)
|
||||||
ret = append(ret, "Description: "+pkgInfo.Description)
|
ret = append(ret, "Description: "+pkgInfo.Description)
|
||||||
ret = append(ret, "Version: "+pkgInfo.GetFullVersion())
|
ret = append(ret, "Version: "+pkgInfo.GetFullVersion())
|
||||||
ret = append(ret, "URL: "+pkgInfo.Url)
|
if pkgInfo.Url != "" {
|
||||||
ret = append(ret, "License: "+pkgInfo.License)
|
ret = append(ret, "URL: "+pkgInfo.Url)
|
||||||
if showArchitecture {
|
|
||||||
ret = append(ret, "Architecture: "+pkgInfo.Arch)
|
|
||||||
}
|
}
|
||||||
if showType {
|
if pkgInfo.License != "" {
|
||||||
ret = append(ret, "Type: "+pkgInfo.Type)
|
ret = append(ret, "License: "+pkgInfo.License)
|
||||||
}
|
}
|
||||||
if showPackageRelations {
|
ret = append(ret, "Architecture: "+pkgInfo.Arch)
|
||||||
appendArray("Dependencies", pkgInfo.Depends)
|
if pkgInfo.Type == "source" && pkgInfo.OutputArch != "" && pkgInfo.OutputArch != GetArch() {
|
||||||
if pkgInfo.Type == "source" {
|
ret = append(ret, "Output architecture: "+pkgInfo.Arch)
|
||||||
appendArray("Make Dependencies", pkgInfo.MakeDepends)
|
|
||||||
}
|
|
||||||
appendArray("Optional dependencies", pkgInfo.OptionalDepends)
|
|
||||||
dependants, err := GetPackageDependants(pkgInfo.Name, rootDir)
|
|
||||||
if err == nil {
|
|
||||||
appendArray("Dependant packages", dependants)
|
|
||||||
}
|
|
||||||
appendArray("Conflicting packages", pkgInfo.Conflicts)
|
|
||||||
appendArray("Provided packages", pkgInfo.Provides)
|
|
||||||
appendArray("Replaces packages", pkgInfo.Replaces)
|
|
||||||
}
|
}
|
||||||
|
ret = append(ret, "Type: "+pkgInfo.Type)
|
||||||
|
appendArray("Dependencies", pkgInfo.Depends)
|
||||||
|
if pkgInfo.Type == "source" {
|
||||||
|
appendArray("Make Dependencies", pkgInfo.MakeDepends)
|
||||||
|
}
|
||||||
|
appendArray("Optional dependencies", pkgInfo.OptionalDepends)
|
||||||
|
dependants := pkgInfo.GetPackageDependants(rootDir)
|
||||||
|
if len(dependants) > 0 {
|
||||||
|
appendArray("Dependant packages", dependants)
|
||||||
|
}
|
||||||
|
optionalDependants := pkgInfo.GetPackageOptionalDependants(rootDir)
|
||||||
|
if len(optionalDependants) > 0 {
|
||||||
|
appendArray("Optionally dependant packages", optionalDependants)
|
||||||
|
}
|
||||||
|
appendArray("Conflicting packages", pkgInfo.Conflicts)
|
||||||
|
appendArray("Provided packages", pkgInfo.Provides)
|
||||||
|
appendArray("Replaces packages", pkgInfo.Replaces)
|
||||||
|
|
||||||
if pkgInfo.Type == "source" && len(pkgInfo.SplitPackages) != 0 {
|
if pkgInfo.Type == "source" && len(pkgInfo.SplitPackages) != 0 {
|
||||||
splitPkgs := make([]string, len(pkgInfo.SplitPackages))
|
splitPkgs := make([]string, len(pkgInfo.SplitPackages))
|
||||||
for i, splitPkgInfo := range pkgInfo.SplitPackages {
|
for i, splitPkgInfo := range pkgInfo.SplitPackages {
|
||||||
@@ -547,7 +584,8 @@ func CreateReadableInfo(showArchitecture, showType, showPackageRelations, showIn
|
|||||||
}
|
}
|
||||||
appendArray("Split Packages", splitPkgs)
|
appendArray("Split Packages", splitPkgs)
|
||||||
}
|
}
|
||||||
if IsPackageInstalled(pkgInfo.Name, rootDir) && showInstallationReason {
|
|
||||||
|
if rootDir != "" && IsPackageInstalled(pkgInfo.Name, rootDir) {
|
||||||
installationReason := GetInstallationReason(pkgInfo.Name, rootDir)
|
installationReason := GetInstallationReason(pkgInfo.Name, rootDir)
|
||||||
var installationReasonString string
|
var installationReasonString string
|
||||||
switch installationReason {
|
switch installationReason {
|
||||||
@@ -562,27 +600,21 @@ func CreateReadableInfo(showArchitecture, showType, showPackageRelations, showIn
|
|||||||
}
|
}
|
||||||
ret = append(ret, "Installation Reason: "+installationReasonString)
|
ret = append(ret, "Installation Reason: "+installationReasonString)
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(ret, "\n")
|
return strings.Join(ret, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string) error {
|
func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string) error {
|
||||||
if !IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir) {
|
|
||||||
err := executePackageScript(filename, rootDir, verbose, "pre_install.sh")
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Warning: %s\n", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err := executePackageScript(filename, rootDir, verbose, "pre_update.sh")
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Warning: %s\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
seenHardlinks := make(map[string]string)
|
seenHardlinks := make(map[string]string)
|
||||||
file, err := os.Open(filename)
|
file, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize progress bar
|
||||||
|
bar := createProgressBar(bpmpkg.GetInstalledSize(), "Installing "+bpmpkg.PkgInfo.Name, verbose)
|
||||||
|
defer bar.Close()
|
||||||
|
|
||||||
tarballFile, err := readTarballFile(filename, "files.tar.gz")
|
tarballFile, err := readTarballFile(filename, "files.tar.gz")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -594,6 +626,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
packageFilesReader := tar.NewReader(archive)
|
packageFilesReader := tar.NewReader(archive)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
header, err := packageFilesReader.Next()
|
header, err := packageFilesReader.Next()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@@ -630,6 +663,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
|||||||
if verbose {
|
if verbose {
|
||||||
fmt.Printf("Created directory %s (%o)\n", extractFilename, header.Mode)
|
fmt.Printf("Created directory %s (%o)\n", extractFilename, header.Mode)
|
||||||
}
|
}
|
||||||
|
bar.Add64(header.Size)
|
||||||
case tar.TypeReg:
|
case tar.TypeReg:
|
||||||
skip := false
|
skip := false
|
||||||
if _, err := os.Stat(extractFilename); err == nil {
|
if _, err := os.Stat(extractFilename); err == nil {
|
||||||
@@ -686,6 +720,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
|||||||
if verbose {
|
if verbose {
|
||||||
fmt.Printf("Created File: %s (%o)\n", extractFilename, header.Mode)
|
fmt.Printf("Created File: %s (%o)\n", extractFilename, header.Mode)
|
||||||
}
|
}
|
||||||
|
bar.Add64(header.Size)
|
||||||
case tar.TypeSymlink:
|
case tar.TypeSymlink:
|
||||||
err := os.Remove(extractFilename)
|
err := os.Remove(extractFilename)
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
@@ -700,6 +735,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
|||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Created Symlink: " + extractFilename + " -> " + header.Linkname)
|
fmt.Println("Created Symlink: " + extractFilename + " -> " + header.Linkname)
|
||||||
}
|
}
|
||||||
|
bar.Add64(header.Size)
|
||||||
case tar.TypeLink:
|
case tar.TypeLink:
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("Detected Hard Link: " + extractFilename + " -> " + path.Join(rootDir, strings.TrimPrefix(header.Linkname, "files/")))
|
fmt.Println("Detected Hard Link: " + extractFilename + " -> " + path.Join(rootDir, strings.TrimPrefix(header.Linkname, "files/")))
|
||||||
@@ -709,6 +745,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
|||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
bar.Add64(header.Size)
|
||||||
default:
|
default:
|
||||||
return errors.New("unknown type (" + strconv.Itoa(int(header.Typeflag)) + ") in " + extractFilename)
|
return errors.New("unknown type (" + strconv.Itoa(int(header.Typeflag)) + ") in " + extractFilename)
|
||||||
}
|
}
|
||||||
@@ -743,6 +780,20 @@ func installPackage(filename, rootDir string, verbose, force bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
packageInstalled := IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir)
|
packageInstalled := IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir)
|
||||||
|
|
||||||
|
// Run pre-* package scripts
|
||||||
|
if !packageInstalled {
|
||||||
|
err := executePackageScript(filename, rootDir, verbose, "pre_install.sh")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Warning: %s\n", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := executePackageScript(filename, rootDir, verbose, "pre_update.sh")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Warning: %s\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if package is installed and remove current files
|
// Check if package is installed and remove current files
|
||||||
if packageInstalled {
|
if packageInstalled {
|
||||||
// Fetching and reversing package file entry list
|
// Fetching and reversing package file entry list
|
||||||
@@ -924,6 +975,7 @@ func installPackage(filename, rootDir string, verbose, force bool) error {
|
|||||||
f.Close()
|
f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run post-* package scripts
|
||||||
if !packageInstalled {
|
if !packageInstalled {
|
||||||
err = executePackageScript(filename, rootDir, verbose, "post_install.sh")
|
err = executePackageScript(filename, rootDir, verbose, "post_install.sh")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -943,7 +995,7 @@ func installPackage(filename, rootDir string, verbose, force bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add or update package information for rootDir
|
// Add or update package information for rootDir
|
||||||
localPackageInformation[rootDir][bpmpkg.PkgInfo.Name] = bpmpkg
|
localPackageInformation[rootDir][bpmpkg.PkgInfo.Name] = bpmpkg.PkgInfo
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -961,8 +1013,11 @@ func removePackage(pkg string, verbose bool, rootDir string) error {
|
|||||||
log.Printf("Warning: %s\n", err)
|
log.Printf("Warning: %s\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get BPM package
|
||||||
|
bpmpkg := GetPackage(pkg, rootDir)
|
||||||
|
|
||||||
// Fetching and reversing package file entry list
|
// Fetching and reversing package file entry list
|
||||||
fileEntries := GetPackage(pkg, rootDir).PkgFiles
|
fileEntries := bpmpkg.PkgFiles
|
||||||
sort.Slice(fileEntries, func(i, j int) bool {
|
sort.Slice(fileEntries, func(i, j int) bool {
|
||||||
return fileEntries[i].Path < fileEntries[j].Path
|
return fileEntries[i].Path < fileEntries[j].Path
|
||||||
})
|
})
|
||||||
@@ -972,8 +1027,12 @@ func removePackage(pkg string, verbose bool, rootDir string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bar := createProgressBar(bpmpkg.GetInstalledSize(), "Removing "+bpmpkg.PkgInfo.Name, verbose)
|
||||||
|
defer bar.Close()
|
||||||
|
|
||||||
// Removing package files
|
// Removing package files
|
||||||
for _, entry := range fileEntries {
|
for _, entry := range fileEntries {
|
||||||
|
bar.Add64(entry.SizeInBytes)
|
||||||
file := path.Join(rootDir, entry.Path)
|
file := path.Join(rootDir, entry.Path)
|
||||||
lstat, err := os.Lstat(file)
|
lstat, err := os.Lstat(file)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
|||||||
+69
-22
@@ -2,10 +2,15 @@ package bpmlib
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
version "github.com/knqyf263/go-rpm-version"
|
||||||
|
"github.com/schollz/progressbar/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BPMLock struct {
|
type BPMLock struct {
|
||||||
@@ -13,20 +18,6 @@ type BPMLock struct {
|
|||||||
path string
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lock *BPMLock) Unlock() error {
|
|
||||||
err := lock.file.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.Remove(lock.path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func LockBPM(rootDir string) (*BPMLock, error) {
|
func LockBPM(rootDir string) (*BPMLock, error) {
|
||||||
// Create parent directories if they don't already exist
|
// Create parent directories if they don't already exist
|
||||||
err := os.MkdirAll(path.Join(rootDir, "/var/lib/bpm"), 0755)
|
err := os.MkdirAll(path.Join(rootDir, "/var/lib/bpm"), 0755)
|
||||||
@@ -49,6 +40,20 @@ func LockBPM(rootDir string) (*BPMLock, error) {
|
|||||||
return &BPMLock{f, path.Join(rootDir, "var/lib/bpm/bpm.lock")}, nil
|
return &BPMLock{f, path.Join(rootDir, "var/lib/bpm/bpm.lock")}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lock *BPMLock) Unlock() error {
|
||||||
|
err := lock.file.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Remove(lock.path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func GetArch() string {
|
func GetArch() string {
|
||||||
uname := syscall.Utsname{}
|
uname := syscall.Utsname{}
|
||||||
err := syscall.Uname(&uname)
|
err := syscall.Uname(&uname)
|
||||||
@@ -64,6 +69,47 @@ func GetArch() string {
|
|||||||
return string(byteString[:indexLength])
|
return string(byteString[:indexLength])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CompareVersions(version1, version2 string) int {
|
||||||
|
v1 := version.NewVersion(version1)
|
||||||
|
v2 := version.NewVersion(version2)
|
||||||
|
|
||||||
|
return v1.Compare(v2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createProgressBar(max int64, description string, hideBar bool) *progressbar.ProgressBar {
|
||||||
|
var output io.Writer
|
||||||
|
if hideBar {
|
||||||
|
output = io.Discard
|
||||||
|
} else {
|
||||||
|
output = os.Stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(description) < 40 {
|
||||||
|
for i := len(description); i < 40; i++ {
|
||||||
|
description += " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(description) > 40 {
|
||||||
|
overflow := len(description) - 37
|
||||||
|
description = description[:len(description)-overflow] + "..."
|
||||||
|
}
|
||||||
|
|
||||||
|
return progressbar.NewOptions64(max,
|
||||||
|
progressbar.OptionSetDescription(description),
|
||||||
|
progressbar.OptionSetWriter(output),
|
||||||
|
progressbar.OptionShowBytes(true),
|
||||||
|
progressbar.OptionShowTotalBytes(true),
|
||||||
|
progressbar.OptionSetWidth(20),
|
||||||
|
progressbar.OptionThrottle(65*time.Millisecond),
|
||||||
|
progressbar.OptionShowCount(),
|
||||||
|
progressbar.OptionOnCompletion(func() {
|
||||||
|
fmt.Fprint(output, "\n")
|
||||||
|
}),
|
||||||
|
progressbar.OptionSpinnerType(14),
|
||||||
|
progressbar.OptionSetRenderBlankState(true),
|
||||||
|
progressbar.OptionSetTheme(progressbar.ThemeASCII))
|
||||||
|
}
|
||||||
|
|
||||||
func stringSliceRemove(s []string, r string) []string {
|
func stringSliceRemove(s []string, r string) []string {
|
||||||
for i, v := range s {
|
for i, v := range s {
|
||||||
if v == r {
|
if v == r {
|
||||||
@@ -73,7 +119,7 @@ func stringSliceRemove(s []string, r string) []string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func unsignedBytesToHumanReadable(b uint64) string {
|
func BytesToHumanReadable(b int64) string {
|
||||||
bf := float64(b)
|
bf := float64(b)
|
||||||
for _, unit := range []string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"} {
|
for _, unit := range []string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"} {
|
||||||
if math.Abs(bf) < 1024.0 {
|
if math.Abs(bf) < 1024.0 {
|
||||||
@@ -84,13 +130,14 @@ func unsignedBytesToHumanReadable(b uint64) string {
|
|||||||
return fmt.Sprintf("%.1fYiB", bf)
|
return fmt.Sprintf("%.1fYiB", bf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func bytesToHumanReadable(b int64) string {
|
func removeDuplicates[T comparable](sliceList []T) []T {
|
||||||
bf := float64(b)
|
allKeys := make(map[T]bool)
|
||||||
for _, unit := range []string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"} {
|
list := []T{}
|
||||||
if math.Abs(bf) < 1024.0 {
|
for _, item := range sliceList {
|
||||||
return fmt.Sprintf("%3.1f%sB", bf, unit)
|
if _, value := allKeys[item]; !value {
|
||||||
|
allKeys[item] = true
|
||||||
|
list = append(list, item)
|
||||||
}
|
}
|
||||||
bf /= 1024.0
|
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%.1fYiB", bf)
|
return list
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user