mirror of
https://github.com/Jguer/yay.git
synced 2024-11-07 17:47:21 +01:00
Merge branch 'master' into travis-exp
This commit is contained in:
commit
70fd80c1f1
6
Gopkg.lock
generated
6
Gopkg.lock
generated
@ -5,19 +5,19 @@
|
||||
branch = "master"
|
||||
name = "github.com/jguer/go-alpm"
|
||||
packages = ["."]
|
||||
revision = "11d6aadda57c8fb4f93969333cb990677d28d4f9"
|
||||
revision = "1114f773cdfb05f577438f7a0538eccabc9cf012"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mikkeloscar/aur"
|
||||
packages = ["."]
|
||||
revision = "9050804dc7d471393053322aaaa40428fbd32de3"
|
||||
revision = "837b260b8e90895c45737e2e72313fe5bce6f2c4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mikkeloscar/gopkgbuild"
|
||||
packages = ["."]
|
||||
revision = "32274fc52aa8f5eb28711da734179e9aea27b31f"
|
||||
revision = "2bb4f1f1db67f81fe50f9c1c4ad9db4f20fd6b22"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
|
282
README.md
282
README.md
@ -4,12 +4,11 @@ Yet another Yogurt - An AUR Helper written in Go
|
||||
|
||||
#### Packages
|
||||
|
||||
[![yay](https://img.shields.io/aur/version/yay.svg?label=yay)](https://aur.archlinux.org/packages/yay/) [![yay-bin](https://img.shields.io/aur/version/yay-bin.svg?label=yay-bin)](https://aur.archlinux.org/packages/yay-bin/) [![yay-git](https://img.shields.io/aur/version/yay-git.svg?label=yay-git)](https://aur.archlinux.org/packages/yay-git/) [![GitHub license](https://img.shields.io/badge/license-AGPL-blue.svg)](https://raw.githubusercontent.com/Jguer/yay/master/LICENSE)
|
||||
|
||||
[![yay](https://img.shields.io/aur/version/yay.svg?label=yay)](https://aur.archlinux.org/packages/yay/) [![yay-bin](https://img.shields.io/aur/version/yay-bin.svg?label=yay-bin)](https://aur.archlinux.org/packages/yay-bin/) [![yay-git](https://img.shields.io/aur/version/yay-git.svg?label=yay-git)](https://aur.archlinux.org/packages/yay-git/) [![GitHub license](https://img.shields.io/github/license/jguer/yay.svg)](https://github.com/Jguer/yay/blob/master/LICENSE)
|
||||
There's a point in everyone's life when you feel the need to write an AUR helper because there are only about 20 of them.
|
||||
So say hi to 20+1.
|
||||
|
||||
Yay was created with a few objectives in mind and based on the design of [yaourt](https://github.com/archlinuxfr/yaourt) and [apacman](https://github.com/oshazard/apacman):
|
||||
Yay was created with a few objectives in mind and based on the design of [yaourt](https://github.com/archlinuxfr/yaourt), [apacman](https://github.com/oshazard/apacman) and [pacaur](https://github.com/rmarquis/pacaur):
|
||||
|
||||
* Have almost no dependencies.
|
||||
* Provide an interface for pacman.
|
||||
@ -25,15 +24,83 @@ Yay was created with a few objectives in mind and based on the design of [yaourt
|
||||
* Search narrowing (`yay linux header` will first search linux and then narrow on header)
|
||||
* No sourcing of PKGBUILD is done
|
||||
* The binary has no dependencies that pacman doesn't already have.
|
||||
* Sources build dependencies
|
||||
* Removes make dependencies at the end of build process
|
||||
* Advanced dependency solving
|
||||
* Remove make dependencies at the end of the build process
|
||||
|
||||
#### Frequently Asked Questions
|
||||
## Installation
|
||||
|
||||
* Yay does not display colored output. How do I fix it?
|
||||
If you are migrating from another AUR helper you can simply install Yay from
|
||||
the AUR like any other package.
|
||||
|
||||
The initial installation of Yay can be done by cloning the PKGBUILD and
|
||||
building with makepkg.
|
||||
```sh
|
||||
git clone https://aur.archlinux.org/yay.git
|
||||
cd yay
|
||||
makepkg -si
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributors are always welcome!
|
||||
|
||||
If you plan to make any large changes or changes that may not be 100% agreed
|
||||
on, we suggest opening an issue detailing your ideas first.
|
||||
|
||||
Otherwise send us a pull request and we will be happy to review it.
|
||||
|
||||
### Code Style
|
||||
|
||||
All code should be formatted through `go fmt`. This tool will automatically
|
||||
format code for you. Although it is recommended you write code in this style
|
||||
and just use this tool to catch mistakes.
|
||||
|
||||
### Building
|
||||
|
||||
Yay is easy to build with its only build dependency being `go` and the
|
||||
assumption of `base-devel` being installed.
|
||||
|
||||
Run `make` to build Yay. This will generate a binary called `yay` in the same
|
||||
directory as the Makefile.
|
||||
|
||||
Run `make test` to test Yay. This will check the code is formatted correctly,
|
||||
run the code through `go vet` and run unit tests.
|
||||
|
||||
Yay's Makefile automatically sets the `GOPATH` to `$PWD/.go`. This makes it easy to
|
||||
build using the dependencies in `vendor/`. Running manual go commands such as
|
||||
`go build` will require that you to either set the `GOPATH` manually or `go get`
|
||||
The dependencies into your own `GOPATH`.
|
||||
|
||||
### Vendored Dependencies
|
||||
|
||||
Yay depends on a couple of other projects. These are stored in `vendor/` and
|
||||
are built into Yay at build time. They do not need to be installed separately.
|
||||
|
||||
Currently yay Depends on:
|
||||
|
||||
* https://github.com/Jguer/go-alpm
|
||||
* https://github.com/mikkeloscar/gopkgbuild
|
||||
* https://github.com/mikkeloscar/aur
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
* Yay does not display colored output. How do I fix it?
|
||||
Make sure you have the `Color` option in your `/etc/pacman.conf` [#123](https://github.com/Jguer/yay/issues/123)
|
||||
|
||||
#### Example of Custom Operations
|
||||
* Sometimes diffs are printed to the terminal and other times they are pages
|
||||
via less. How do I fix this?
|
||||
Yay uses `git diff` to display diffs, by default git tells less to not page
|
||||
if the output can fit one terminal length. This can be overridden by
|
||||
exporting your own flags `export LESS=SRX`.
|
||||
|
||||
* Yay is not asking me to edit PKGBUILDS and I don't like diff menu! What do?
|
||||
`yay --editmenu --nodiffmenu --save`
|
||||
|
||||
* Only act on AUR packages or only on repo packages?
|
||||
`yay -{OPERATION} --aur`
|
||||
`yay -{OPERATION} --repo`
|
||||
|
||||
## Examples of Custom Operations
|
||||
|
||||
* `yay <Search Term>` presents package selection menu
|
||||
* `yay -Ps` prints system statistics
|
||||
@ -41,197 +108,12 @@ Yay was created with a few objectives in mind and based on the design of [yaourt
|
||||
* `yay -Yc` cleans unneeded dependencies
|
||||
* `yay -G` downloads PKGBUILD from ABS or AUR
|
||||
* `yay -Y --gendb` generates development package DB used for devel updates.
|
||||
* `yay -Syu --devel --timeupdate` Normal update but also check for development
|
||||
package updates and uses PKGBUILD modification time and not version to
|
||||
determine update
|
||||
|
||||
<img src="http://jguer.github.io/yay/yayupgrade.png" width="450">
|
||||
<img src="http://jguer.github.io/yay/yay2.png" width="450">
|
||||
<img src="http://jguer.github.io/yay/yay4.png" width="450">
|
||||
## Images
|
||||
|
||||
### Changelog
|
||||
|
||||
#### v5.675
|
||||
|
||||
* Recursively remove dependencies when using yay -Yc
|
||||
* Highlight diff between old and new versions better
|
||||
* Fix regression where repo upgrades were marked as deps during sysupgrades
|
||||
* Added `--editorflags` to add flags to editor execution
|
||||
|
||||
#### v5.657
|
||||
|
||||
* By default running `yay` will trigger `yay -Syu`
|
||||
* Updated Shell completions
|
||||
* `-Ss` shows difference between installed and in-repo versions
|
||||
* Allow sorting AUR results by fields other than votes
|
||||
* votes|popularity|id|baseid|name|base|submitted|modified
|
||||
* Added flags for automatic menu input
|
||||
* --answerclean --answeredit --answerupgrade
|
||||
* --noanswerclean --noansweredit --noanswerupgrade
|
||||
* Fixed versioned dep checking
|
||||
* Usual fixes to parsing, dependency sourcing and other PKGBUILD atrocities
|
||||
|
||||
#### v5.608
|
||||
|
||||
* Updated Shell completions
|
||||
* Added `-Qu` to extended pacman options
|
||||
* Provides now supported in `-Si`
|
||||
* Improved build method
|
||||
* Improved conflict checking
|
||||
* PKGBUILDs with unsupported arch can force build now
|
||||
* PGP Key automatic importing
|
||||
* GPG option passing
|
||||
* `db/name` support re-added
|
||||
|
||||
#### 4.505
|
||||
|
||||
* `yay` used to auto save permanent configuration options, now `--save` must be passed to save permanent configuration options
|
||||
* Competions updated
|
||||
* Number menu is now used to edit PKGBuilds and Clean Builds
|
||||
* Devel updates of `-git` packages now uses `git ls-remote` which makes it compatible with other platforms besides github.
|
||||
* Devel update checking is faster as well
|
||||
* Updated man page
|
||||
|
||||
#### 3.440
|
||||
|
||||
* Closed a lot of issues
|
||||
* Updated bash and zsh completions
|
||||
* New colour scheme
|
||||
* Small parsing fixes
|
||||
* Automatically delete package from transaction if $EDITOR exits with non-zero #140
|
||||
* Added check depends support
|
||||
|
||||
#### 3.373
|
||||
|
||||
* Version bump to V3 to reflect all of the changes to syntax
|
||||
* `yay -Pd` prints default config
|
||||
* `yay -Pg` prints current config
|
||||
* Fixes #174
|
||||
* Fixes #176
|
||||
* Fixes -G being unable to download split packages
|
||||
* Fixes #171
|
||||
* Fixes -Si failing when given a non existing package on https://github.com/Jguer/yay/pull/155
|
||||
* Fixes other small bugs on 2.350 without adding new features
|
||||
|
||||
#### 2.350
|
||||
|
||||
* Adds sudo loop (off by default, enable only by editing config file) #147
|
||||
* Adds replace package support #154 #134
|
||||
* Minor display improvements #150 for example
|
||||
* Fixes GenDB
|
||||
* Fixes Double options passing to pacman
|
||||
* Noconfirm works more as expected
|
||||
* Minor fixes and refactoring
|
||||
* Yay filters out the repository name if it's included.
|
||||
* Fixes #122
|
||||
|
||||
#### 2.298
|
||||
|
||||
* Adds #115
|
||||
|
||||
#### 2.296
|
||||
|
||||
* New argument parsing @Morganamilo (check manpage or --help for new
|
||||
information)
|
||||
* yay -Qstats changed to yay -Ps or yay -P --stats
|
||||
* yay -Cd changed to yay -Yc or yay -Y --clean
|
||||
* yay -Pu (--upgrades) prints update list
|
||||
* yay -Pn (--numberupgrades) prints number of updates
|
||||
* yay -G also possible through -Yg or -Y --getpkgbuild (yay -G will be
|
||||
discontinued once it's possible to add options to the getpkgbuild operation)
|
||||
* yay now counts from 1 instead of 0 @Morganamilo
|
||||
* Support for ranges when selecting packages @samosaara
|
||||
* Pacaur style ask all questions first and download first @Morganamilo
|
||||
* Updated vendor dependencies (Fixes pacman.conf parsing errors and PKGBUILD
|
||||
parsing errors)
|
||||
* Updated completions
|
||||
|
||||
#### 2.219
|
||||
|
||||
* Updated manpage
|
||||
* Updated --help
|
||||
* Fixed AUR update fails with large number of packages #59
|
||||
* Check if package is already in upgrade list and skip it. #60
|
||||
* Add -V and -h for flag parsing @AnthonyLam
|
||||
* Prevent file corruption by truncating the files @maximbaz
|
||||
* Print VCS error details @maximbaz
|
||||
* Using '-' doesn't raise an error @PietroCarrara
|
||||
* use Command.Dir in aur.PkgInstall; Fixes #32 #47 @afg984
|
||||
* Suffix YayConf.BuildDir with uid to avoid permission issues @afg984 (Not included in last changelog)
|
||||
|
||||
#### 2.200
|
||||
|
||||
* Development github package support re-added
|
||||
|
||||
#### 2.196
|
||||
|
||||
* XDG_CONFIG_HOME support
|
||||
* XDG_CACHE_HOME support
|
||||
|
||||
#### 2.165
|
||||
|
||||
* Upgrade list now allows skipping upgrade install
|
||||
|
||||
#### 2.159
|
||||
|
||||
* Qstats now warns about packages not available in AUR
|
||||
|
||||
#### 2.152
|
||||
|
||||
* Fetching backend changed to Mikkel Oscar's [Aur](https://github.com/mikkeloscar/aur)
|
||||
* Added support for development packages from github.
|
||||
* Pacman backend rewritten and simplified
|
||||
* Added config framework.
|
||||
|
||||
#### 1.115
|
||||
|
||||
* Added AUR completions (updates on first completion every 48h)
|
||||
|
||||
#### 1.101
|
||||
|
||||
* Search speed and quality improved [#3](https://github.com/Jguer/yay/issues/3)
|
||||
|
||||
#### 1.100
|
||||
|
||||
* Added manpage
|
||||
* Improved search [#3](https://github.com/Jguer/yay/issues/3)
|
||||
* Added -G to get pkgbuild from the AUR or ABS. [#6](https://github.com/Jguer/yay/issues/6)
|
||||
* Fixed [#8](https://github.com/Jguer/yay/issues/8)
|
||||
* Completed and decluttered zsh completions
|
||||
* If `$EDITOR` or `$VISUAL` is not set yay will prompt you for an editor [#7](https://github.com/Jguer/yay/issues/7)
|
||||
|
||||
#### 1.91
|
||||
|
||||
* `--downtop` has been replaced with `--bottomup` (as is logical)
|
||||
* `yay -Ssq` and `yay -Sqs` now displays AUR packages with less information
|
||||
* Repository search now uses the same criteria as pacman
|
||||
|
||||
#### 1.85
|
||||
|
||||
* yay now does -Si for AUR packages
|
||||
* Fixed package install bugs
|
||||
|
||||
#### 1.83
|
||||
|
||||
* Added new dependency resolver for future features
|
||||
* Sort package statistics
|
||||
|
||||
#### 1.80
|
||||
|
||||
* yay now warns when installing orphan packages
|
||||
* Added orphan status to number menu
|
||||
* Qstats now checks if system has orphan packages installed
|
||||
|
||||
#### 1.78
|
||||
|
||||
* Added foreign package statistics to Qstats
|
||||
* Group installing is now possible
|
||||
* Better handling of package dependency installing
|
||||
|
||||
#### 1.76
|
||||
|
||||
* Fixed critical bug that prevented AUR dependencies from being installed.
|
||||
|
||||
#### 1.70
|
||||
|
||||
* Stable for everyday use
|
||||
* Bottom up package display
|
||||
* Number menu like yaourt/apacman
|
||||
* System package statistics
|
||||
<img src="https://cdn.rawgit.com/Jguer/jguer.github.io/5412b8d6/yay/yay-ps.png" width="450">
|
||||
<img src="https://cdn.rawgit.com/Jguer/jguer.github.io/5412b8d6/yay/yayupgrade.png" width="450">
|
||||
<img src="https://cdn.rawgit.com/Jguer/jguer.github.io/5412b8d6/yay/yaysearch.png" width="450">
|
||||
|
8
clean.go
8
clean.go
@ -124,7 +124,7 @@ func cleanAUR(keepInstalled, keepCurrent, removeAll bool) error {
|
||||
|
||||
// Most people probably don't use keep current and that is the only
|
||||
// case where this is needed.
|
||||
// Querying the AUR is slow and needs internet so dont do it if we
|
||||
// Querying the AUR is slow and needs internet so don't do it if we
|
||||
// don't need to.
|
||||
if keepCurrent {
|
||||
info, err := aurInfo(cachedPackages, &aurWarnings{})
|
||||
@ -138,7 +138,11 @@ func cleanAUR(keepInstalled, keepCurrent, removeAll bool) error {
|
||||
}
|
||||
|
||||
for _, pkg := range remotePackages {
|
||||
installedBases.set(pkg.Name())
|
||||
if pkg.Base() != "" {
|
||||
installedBases.set(pkg.Base())
|
||||
} else {
|
||||
installedBases.set(pkg.Name())
|
||||
}
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
|
141
cmd.go
141
cmd.go
@ -35,6 +35,9 @@ New operations:
|
||||
yay {-P --print} [options]
|
||||
yay {-G --getpkgbuild} [package(s)]
|
||||
|
||||
New options:
|
||||
--repo Assume targets are from the repositories
|
||||
-a --aur Assume targets are from the AUR
|
||||
Permanent configuration options:
|
||||
--save Causes the following options to be saved back to the
|
||||
config file when used
|
||||
@ -53,13 +56,23 @@ Permanent configuration options:
|
||||
--config <file> pacman.conf file to use
|
||||
|
||||
--requestsplitn <n> Max amount of packages to query per AUR request
|
||||
--sortby <field> Sort AUR results by a specific field during search
|
||||
--sortby <field> Sort AUR results by a specific field during search
|
||||
--answerclean <a> Set a predetermined answer for the clean build menu
|
||||
--answerdiff <a> Set a predetermined answer for the diff menu
|
||||
--answeredit <a> Set a predetermined answer for the edit pkgbuild menu
|
||||
--answerupgrade <a> Set a predetermined answer for the upgrade menu
|
||||
--noanswerclean Unset the answer for the clean build menu
|
||||
--noanswerdiff Unset the answer for the edit diff menu
|
||||
--noansweredit Unset the answer for the edit pkgbuild menu
|
||||
--noanswerupgrade Unset the answer for the upgrade menu
|
||||
--cleanmenu Give the option to clean build PKGBUILDS
|
||||
--diffmenu Give the option to show diffs for build files
|
||||
--editmenu Give the option to edit/view PKGBUILDS
|
||||
--upgrademenu Show a detailed list of updates with the option to skip any
|
||||
--nocleanmenu Don't clean build PKGBUILDS
|
||||
--nodiffmenu Don't show diffs for build files
|
||||
--noeditmenu Don't edit/view PKGBUILDS
|
||||
--noupgrademenu Don't show the upgrade menu
|
||||
|
||||
--afterclean Remove package sources after successful install
|
||||
--noafterclean Do not remove package sources after successful build
|
||||
@ -77,6 +90,10 @@ Permanent configuration options:
|
||||
--redownload Always download pkgbuilds of targets
|
||||
--noredownload Skip pkgbuild download if in cache and up to date
|
||||
--redownloadall Always download pkgbuilds of all AUR packages
|
||||
--provides Look for matching provders when searching for packages
|
||||
--noprovides Just look for packages by pkgname
|
||||
--pgpfetch Prompt to import PGP keys from PKGBUILDs
|
||||
--nopgpfetch Don't prompt to import PGP keys
|
||||
|
||||
--sudoloop Loop sudo calls in the background to avoid timeout
|
||||
--nosudoloop Do not loop sudo calls in the background
|
||||
@ -91,6 +108,7 @@ Print specific options:
|
||||
-n --numberupgrades Print number of updates
|
||||
-s --stats Display system package statistics
|
||||
-u --upgrades Print update list
|
||||
-w --news Print arch news
|
||||
|
||||
Yay specific options:
|
||||
-c --clean Remove unneeded dependencies
|
||||
@ -252,6 +270,10 @@ func handleConfig(option, value string) bool {
|
||||
config.AnswerClean = value
|
||||
case "noanswerclean":
|
||||
config.AnswerClean = ""
|
||||
case "answerdiff":
|
||||
config.AnswerDiff = value
|
||||
case "noanswerdiff":
|
||||
config.AnswerDiff = ""
|
||||
case "answeredit":
|
||||
config.AnswerEdit = value
|
||||
case "noansweredit":
|
||||
@ -295,6 +317,34 @@ func handleConfig(option, value string) bool {
|
||||
config.SudoLoop = true
|
||||
case "nosudoloop":
|
||||
config.SudoLoop = false
|
||||
case "provides":
|
||||
config.Provides = true
|
||||
case "noprovides":
|
||||
config.Provides = false
|
||||
case "pgpfetch":
|
||||
config.PGPFetch = true
|
||||
case "nopgpfetch":
|
||||
config.PGPFetch = false
|
||||
case "upgrademenu":
|
||||
config.UpgradeMenu = true
|
||||
case "noupgrademenu":
|
||||
config.UpgradeMenu = false
|
||||
case "cleanmenu":
|
||||
config.CleanMenu = true
|
||||
case "nocleanmenu":
|
||||
config.CleanMenu = false
|
||||
case "diffmenu":
|
||||
config.DiffMenu = true
|
||||
case "nodiffmenu":
|
||||
config.DiffMenu = false
|
||||
case "editmenu":
|
||||
config.EditMenu = true
|
||||
case "noeditmenu":
|
||||
config.EditMenu = false
|
||||
case "a", "aur":
|
||||
mode = ModeAUR
|
||||
case "repo":
|
||||
mode = ModeRepo
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@ -318,6 +368,8 @@ func handlePrint() (err error) {
|
||||
err = printNumberOfUpdates()
|
||||
case cmdArgs.existsArg("u", "upgrades"):
|
||||
err = printUpdateList(cmdArgs)
|
||||
case cmdArgs.existsArg("w", "news"):
|
||||
err = printNewsFeed()
|
||||
case cmdArgs.existsArg("c", "complete"):
|
||||
switch {
|
||||
case cmdArgs.existsArg("f", "fish"):
|
||||
@ -350,22 +402,21 @@ func handleYay() (err error) {
|
||||
}
|
||||
|
||||
func handleGetpkgbuild() (err error) {
|
||||
err = getPkgbuilds(cmdArgs.formatTargets())
|
||||
err = getPkgbuilds(cmdArgs.targets)
|
||||
return
|
||||
}
|
||||
|
||||
func handleYogurt() (err error) {
|
||||
options := cmdArgs.formatArgs()
|
||||
targets := cmdArgs.formatTargets()
|
||||
|
||||
config.SearchMode = NumberMenu
|
||||
err = numberMenu(targets, options)
|
||||
err = numberMenu(cmdArgs.targets, options)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func handleSync() (err error) {
|
||||
targets := cmdArgs.formatTargets()
|
||||
targets := cmdArgs.targets
|
||||
|
||||
if cmdArgs.existsArg("y", "refresh") {
|
||||
arguments := cmdArgs.copy()
|
||||
@ -374,7 +425,7 @@ func handleSync() (err error) {
|
||||
arguments.delArg("s", "search")
|
||||
arguments.delArg("i", "info")
|
||||
arguments.delArg("l", "list")
|
||||
arguments.targets = make(stringSet)
|
||||
arguments.clearTargets()
|
||||
err = passToPacman(arguments)
|
||||
if err != nil {
|
||||
return
|
||||
@ -407,30 +458,50 @@ func handleSync() (err error) {
|
||||
}
|
||||
|
||||
func handleRemove() (err error) {
|
||||
removeVCSPackage(cmdArgs.formatTargets())
|
||||
removeVCSPackage(cmdArgs.targets)
|
||||
err = passToPacman(cmdArgs)
|
||||
return
|
||||
}
|
||||
|
||||
// NumberMenu presents a CLI for selecting packages to install.
|
||||
func numberMenu(pkgS []string, flags []string) (err error) {
|
||||
aurQ, aurErr := narrowSearch(pkgS, true)
|
||||
numaq := len(aurQ)
|
||||
repoQ, numpq, err := queryRepo(pkgS)
|
||||
if err != nil {
|
||||
return
|
||||
pkgS = removeInvalidTargets(pkgS)
|
||||
var aurErr error
|
||||
var repoErr error
|
||||
var aq aurQuery
|
||||
var pq repoQuery
|
||||
var lenaq int
|
||||
var lenpq int
|
||||
|
||||
if mode == ModeAUR || mode == ModeAny {
|
||||
aq, aurErr = narrowSearch(pkgS, true)
|
||||
lenaq = len(aq)
|
||||
}
|
||||
if mode == ModeRepo || mode == ModeAny {
|
||||
pq, lenpq, repoErr = queryRepo(pkgS)
|
||||
if repoErr != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if numpq == 0 && numaq == 0 {
|
||||
return fmt.Errorf("no packages match search")
|
||||
if lenpq == 0 && lenaq == 0 {
|
||||
return fmt.Errorf("No packages match search")
|
||||
}
|
||||
|
||||
if config.SortMode == BottomUp {
|
||||
aurQ.printSearch(numpq + 1)
|
||||
repoQ.printSearch()
|
||||
if mode == ModeAUR || mode == ModeAny {
|
||||
aq.printSearch(lenpq + 1)
|
||||
}
|
||||
if mode == ModeRepo || mode == ModeAny {
|
||||
pq.printSearch()
|
||||
}
|
||||
} else {
|
||||
repoQ.printSearch()
|
||||
aurQ.printSearch(numpq + 1)
|
||||
if mode == ModeRepo || mode == ModeAny {
|
||||
pq.printSearch()
|
||||
}
|
||||
if mode == ModeAUR || mode == ModeAny {
|
||||
aq.printSearch(lenpq + 1)
|
||||
}
|
||||
}
|
||||
|
||||
if aurErr != nil {
|
||||
@ -457,8 +528,8 @@ func numberMenu(pkgS []string, flags []string) (err error) {
|
||||
|
||||
isInclude := len(exclude) == 0 && len(otherExclude) == 0
|
||||
|
||||
for i, pkg := range repoQ {
|
||||
target := len(repoQ) - i
|
||||
for i, pkg := range pq {
|
||||
target := len(pq) - i
|
||||
if config.SortMode == TopDown {
|
||||
target = i + 1
|
||||
}
|
||||
@ -471,10 +542,10 @@ func numberMenu(pkgS []string, flags []string) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
for i, pkg := range aurQ {
|
||||
target := len(aurQ) - i + len(repoQ)
|
||||
for i, pkg := range aq {
|
||||
target := len(aq) - i + len(pq)
|
||||
if config.SortMode == TopDown {
|
||||
target = i + 1 + len(repoQ)
|
||||
target = i + 1 + len(pq)
|
||||
}
|
||||
|
||||
if isInclude && include.get(target) {
|
||||
@ -512,7 +583,7 @@ func passToPacman(args *arguments) error {
|
||||
|
||||
argArr = append(argArr, "--")
|
||||
|
||||
argArr = append(argArr, args.formatTargets()...)
|
||||
argArr = append(argArr, args.targets...)
|
||||
|
||||
cmd = exec.Command(argArr[0], argArr[1:]...)
|
||||
|
||||
@ -544,7 +615,7 @@ func passToPacmanCapture(args *arguments) (string, string, error) {
|
||||
|
||||
argArr = append(argArr, "--")
|
||||
|
||||
argArr = append(argArr, args.formatTargets()...)
|
||||
argArr = append(argArr, args.targets...)
|
||||
|
||||
cmd = exec.Command(argArr[0], argArr[1:]...)
|
||||
cmd.Stdout = &outbuf
|
||||
@ -588,7 +659,6 @@ func passToMakepkgCapture(dir string, args ...string) (string, string, error) {
|
||||
args = append(args, mflags...)
|
||||
|
||||
cmd := exec.Command(config.MakepkgBin, args...)
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
cmd.Dir = dir
|
||||
cmd.Stdout = &outbuf
|
||||
cmd.Stderr = &errbuf
|
||||
@ -615,3 +685,22 @@ func passToGit(dir string, _args ...string) (err error) {
|
||||
err = cmd.Run()
|
||||
return
|
||||
}
|
||||
|
||||
func passToGitCapture(dir string, _args ...string) (string, string, error) {
|
||||
var outbuf, errbuf bytes.Buffer
|
||||
gitflags := strings.Fields(config.GitFlags)
|
||||
args := []string{"-C", dir}
|
||||
args = append(args, gitflags...)
|
||||
args = append(args, _args...)
|
||||
|
||||
cmd := exec.Command(config.GitBin, args...)
|
||||
cmd.Dir = dir
|
||||
cmd.Stdout = &outbuf
|
||||
cmd.Stderr = &errbuf
|
||||
|
||||
err := cmd.Run()
|
||||
stdout := outbuf.String()
|
||||
stderr := errbuf.String()
|
||||
|
||||
return stdout, stderr, err
|
||||
}
|
||||
|
@ -51,6 +51,9 @@ _pacman_pkg() {
|
||||
)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
_yay() {
|
||||
local common core cur database prev query remove sync upgrade yays print o
|
||||
COMPREPLY=()
|
||||
@ -65,14 +68,16 @@ _yay() {
|
||||
'c g i l p s u w y')
|
||||
upgrade=('asdeps asexplicit force needed nodeps assume-installed print recursive' 'p')
|
||||
yays=('clean gendb' 'c')
|
||||
print=('complete defaultconfig config numberupgrades stats upgrades' 'c d g n
|
||||
s u')
|
||||
print=('complete defaultconfig config numberupgrades stats upgrades news' 'c d g n
|
||||
s u w')
|
||||
common=('arch cachedir color config confirm dbpath debug gpgdir help hookdir logfile
|
||||
noconfirm noprogressbar noscriptlet quiet save mflags buildir editor
|
||||
makepkg pacman tar git gpg gpgflags config requestsplitn sudoloop nosudoloop
|
||||
redownload noredownload redownloadall rebuild rebuildall rebuildtree norebuild
|
||||
sortby answerclean answeredit answerupgrade noanswerclean noansweredit
|
||||
noanswerupgrade root verbose' 'b d h q r v')
|
||||
sortby answerclean answerdiff answeredit answerupgrade noanswerclean noanswerdiff
|
||||
noansweredit noanswerupgrade cleanmenu diffmenu editmenu upgrademenu
|
||||
nocleanmenu nodiffmenu noupgrademenu provides noprovides pgpfetch nopgpfetch
|
||||
root verbose aur repo' 'a b d h q r v')
|
||||
core=('database files help query remove sync upgrade version' 'D F Q R S U V h')
|
||||
|
||||
for o in 'D database' 'F files' 'Q query' 'R remove' 'S sync' 'U upgrade' 'Y yays' 'P print'; do
|
||||
|
@ -3,6 +3,8 @@
|
||||
# Updated for yay by jguer
|
||||
|
||||
set -l progname yay
|
||||
complete -e -c $progname
|
||||
complete -c $progname -f
|
||||
|
||||
set -l listinstalled "(pacman -Q | string replace ' ' \t)"
|
||||
# This might be an issue if another package manager is also installed (e.g. for containers)
|
||||
@ -10,7 +12,7 @@ set -l listall "(yay -Pcf)"
|
||||
set -l listrepos "(__fish_print_pacman_repos)"
|
||||
set -l listgroups "(pacman -Sg)\t'Package Group'"
|
||||
set -l listpacman "(__fish_print_packages)"
|
||||
set -l noopt 'not __fish_contains_opt -s S -s D -s Q -s R -s U -s T -s F database query sync remove upgrade deptest files'
|
||||
set -l noopt 'not __fish_contains_opt -s Y -s G -s V -s S -s D -s Q -s R -s U -s T -s F database query sync remove upgrade deptest files'
|
||||
set -l database '__fish_contains_opt -s D database'
|
||||
set -l getpkgbuild '__fish_contains_opt -s G getpkgbuild'
|
||||
set -l print '__fish_contains_opt -s P print'
|
||||
@ -21,30 +23,29 @@ set -l upgrade '__fish_contains_opt -s U upgrade'
|
||||
set -l files '__fish_contains_opt -s F files'
|
||||
set -l yayspecific '__fish_contains_opt -s Y yay'
|
||||
|
||||
complete -c pacman -e
|
||||
complete -c pacman -f
|
||||
|
||||
# HACK: We only need these two to coerce fish to stop file completion and complete options
|
||||
complete -c $progname -n $noopt -a "-D" -d "Modify the package database"
|
||||
complete -c $progname -n $noopt -a "-Q" -d "Query the package database"
|
||||
# complete -c $progname -n $noopt -a "-D" -d "Modify the package database"
|
||||
# complete -c $progname -n $noopt -a "-Q" -d "Query the package database"
|
||||
|
||||
# Primary operations
|
||||
complete -c $progname -s D -f -l database -n $noopt -d 'Modify the package database'
|
||||
complete -c $progname -s Q -f -l query -n $noopt -d 'Query the package database'
|
||||
complete -c $progname -s F -f -l files -n $noopt -d 'Query the files database'
|
||||
complete -c $progname -s G -f -l getpkgbuild -n $noopt -d 'Get PKGBUILD from ABS or AUR'
|
||||
complete -c $progname -s P -f -l print -n $noopt -d 'Print information'
|
||||
complete -c $progname -s Q -f -l query -n $noopt -d 'Query the package database'
|
||||
complete -c $progname -s R -f -l remove -n $noopt -d 'Remove packages from the system'
|
||||
complete -c $progname -s S -f -l sync -n $noopt -d 'Synchronize packages'
|
||||
complete -c $progname -s T -f -l deptest -n $noopt -d 'Check if dependencies are installed'
|
||||
complete -c $progname -s U -f -l upgrade -n $noopt -d 'Upgrade or add a local package'
|
||||
complete -c $progname -s F -f -l files -n $noopt -d 'Query the files database'
|
||||
complete -c $progname -s G -f -l getpkgbuild -n $noopt -d 'Get PKGBUILD from ABS or AUR'
|
||||
complete -c $progname -s P -f -l print -n $noopt -d 'Print information'
|
||||
complete -c $progname -s Y -f -l yay -n $noopt -d 'Yay specific operations'
|
||||
|
||||
complete -c $progname -s V -f -l version -d 'Display version and exit'
|
||||
complete -c $progname -s h -f -l help -d 'Display help'
|
||||
complete -c $progname -s V -f -l version -n $noopt -d 'Display version and exit'
|
||||
complete -c $progname -s h -f -l help -n $noopt -d 'Display help'
|
||||
|
||||
# General options
|
||||
# Only offer these once a command has been given so they get prominent display
|
||||
complete -c $progname -n "not $noopt" -s a -l aur -d 'Assume targets are from the repositories'
|
||||
complete -c $progname -n "not $noopt" -l repo -d 'Assume targets are from the AUR'
|
||||
|
||||
complete -c $progname -n "not $noopt" -s b -l dbpath -d 'Alternative database location' -xa '(__fish_complete_directories)'
|
||||
complete -c $progname -n "not $noopt" -s r -l root -d 'Alternative installation root'
|
||||
complete -c $progname -n "not $noopt" -s v -l verbose -d 'Output more status messages'
|
||||
@ -73,6 +74,7 @@ complete -c $progname -n "not $noopt" -l mflags -d 'Pass the following options t
|
||||
complete -c $progname -n "not $noopt" -l gpgflags -d 'Pass the following options to gpg' -f
|
||||
complete -c $progname -n "not $noopt" -l buildir -d 'Specify the build directory' -f
|
||||
complete -c $progname -n "not $noopt" -l editor -d 'Editor to use' -f
|
||||
complete -c $progname -n "not $noopt" -l editorflags -d 'Editor flags to use' -f
|
||||
complete -c $progname -n "not $noopt" -l makepkg -d 'Makepkg command to use' -f
|
||||
complete -c $progname -n "not $noopt" -l pacman -d 'Pacman command to use' -f
|
||||
complete -c $progname -n "not $noopt" -l tar -d 'Tar command to use' -f
|
||||
@ -98,16 +100,32 @@ complete -c $progname -n "not $noopt" -l noanswerclean -d 'Unset the answer for
|
||||
complete -c $progname -n "not $noopt" -l noansweredit -d 'Unset the answer for the edit pkgbuild menu' -f
|
||||
complete -c $progname -n "not $noopt" -l noanswerupgrade -d 'Unset the answer for the upgrade menu' -f
|
||||
|
||||
complete -c $progname -n "not $noopt" -l cleanmenu -d 'Give the option to clean build PKGBUILDS' -f
|
||||
complete -c $progname -n "not $noopt" -l diffmenu -d 'Give the option to show diffs for build files' -f
|
||||
complete -c $progname -n "not $noopt" -l editmenu -d 'Give the option to edit/view PKGBUILDS' -f
|
||||
complete -c $progname -n "not $noopt" -l upgrademenu -d 'Show a detailed list of updates with the option to skip any' -f
|
||||
complete -c $progname -n "not $noopt" -l nocleanmenu -d 'Do not clean build PKGBUILDS' -f
|
||||
complete -c $progname -n "not $noopt" -l nodiffmenu -d 'Do not show diffs for build files' -f
|
||||
complete -c $progname -n "not $noopt" -l noeditmenu -d 'Do not edit/view PKGBUILDS' -f
|
||||
complete -c $progname -n "not $noopt" -l noupgrademenu -d 'Do not show the upgrade menu' -f
|
||||
|
||||
|
||||
complete -c $progname -n "not $noopt" -l provides -d 'Look for matching provders when searching for packages'
|
||||
complete -c $progname -n "not $noopt" -l noprovides -d 'Just look for packages by pkgname'
|
||||
complete -c $progname -n "not $noopt" -l pgpfetch -d 'Prompt to import PGP keys from PKGBUILDs'
|
||||
complete -c $progname -n "not $noopt" -l nopgpfetch -d 'Do not prompt to import PGP keys'
|
||||
|
||||
# Yay options
|
||||
complete -c $progname -n $yayspecific -s c -l clean -d 'Remove unneeded dependencies' -f
|
||||
complete -c $progname -n $yayspecific -s g -l getpkgbuild -d 'Download PKGBUILD from ABS or AUR' -xa "$listall" -f
|
||||
complete -c $progname -n $yayspecific -l gendb -d 'Display system package statistics' -f
|
||||
complete -c $progname -n $yayspecific -l gendb -d 'Generate development package DB' -f
|
||||
|
||||
# Print options
|
||||
complete -c $progname -n $print -s d -l defaultconfig -d 'Print current yay configuration' -f
|
||||
complete -c $progname -n $print -s n -l numberupgrades -d 'Print number of updates' -f
|
||||
complete -c $progname -n $print -s s -l stats -d 'Display system package statistics' -f
|
||||
complete -c $progname -n $print -s u -l upgrades -d 'Print update list' -f
|
||||
complete -c $progname -n $print -s w -l news -d 'Print arch news'
|
||||
complete -c $progname -n $print -s q -l quiet -d 'Do not print news description'
|
||||
|
||||
# Transaction options (sync, remove, upgrade)
|
||||
for condition in sync remove upgrade
|
||||
@ -195,8 +213,7 @@ complete -c $progname -n "$files" -s q -l quiet -d 'Show less information' -f
|
||||
complete -c $progname -n "$files" -l machinereadable -d 'Show in machine readable format: repo\0pkgname\0pkgver\0path\n' -f
|
||||
|
||||
# Upgrade options
|
||||
# Theoretically, pacman reads packages in all formats that libarchive supports
|
||||
# In practice, it's going to be tar.xz or tar.gz
|
||||
# Using "pkg.tar.*" here would change __fish_complete_suffix's descriptions to "unknown"
|
||||
complete -c $progname -n "$upgrade" -xa '(__fish_complete_suffix pkg.tar.xz)' -d 'Package file'
|
||||
complete -c $progname -n "$upgrade" -xa '(__fish_complete_suffix pkg.tar.gz)' -d 'Package file'
|
||||
complete -c $progname -n "$upgrade" -xa '(__fish_complete_suffix pkg.tar.lzo)' -d 'Package file'
|
||||
complete -c $progname -n "$upgrade" -xa '(__fish_complete_suffix pkg.tar)' -d 'Package file'
|
||||
|
@ -22,6 +22,9 @@ _pacman_opts_commands=(
|
||||
|
||||
# options for passing to _arguments: options common to all commands
|
||||
_pacman_opts_common=(
|
||||
'--repo[Assume targets are from the repositories]'
|
||||
{-a,--aur}'[Assume targets are from the AUR]'
|
||||
|
||||
'--arch[Set an alternate architecture]'
|
||||
{-b,--dbpath}'[Alternate database location]:database_location:_files -/'
|
||||
'--color[colorize the output]:color options:(always never auto)'
|
||||
@ -43,6 +46,7 @@ _pacman_opts_common=(
|
||||
|
||||
'--builddir[Directory to use for building AUR Packages]:build dir:_files -/'
|
||||
'--editor[Editor to use when editing PKGBUILDs]:editor:_files'
|
||||
'--editorflags[Flags to pass to editor]'
|
||||
'--makepkg[makepkg command to use]:makepkg:_files'
|
||||
'--pacman[pacman command to use]:pacman:_files'
|
||||
'--tar[bsdtar command to use]:tar:_files'
|
||||
@ -52,11 +56,18 @@ _pacman_opts_common=(
|
||||
'--sortby[Sort AUR results by a specific field during search]:sortby options:(votes popularity id baseid name base submitted modified)'
|
||||
'--answerclean[Set a predetermined answer for the clean build menu]:answer'
|
||||
'--answeredit[Set a predetermined answer for the edit pkgbuild menu]:answer'
|
||||
'--answerupgrade[Set a predetermined answer for the upgrade menu]:answe'
|
||||
'--answerupgrade[Set a predetermined answer for the upgrade menu]:answer'
|
||||
'--noanswerclean[Unset the answer for the clean build menu]'
|
||||
'--noansweredit[Unset the answer for the edit pkgbuild menu]'
|
||||
'--noanswerupgrade[Unset the answer for the upgrade menu]'
|
||||
|
||||
'--cleanmenu[Give the option to clean build PKGBUILDS]'
|
||||
'--diffmenu[Give the option to show diffs for build files]'
|
||||
'--editmenu[Give the option to edit/view PKGBUILDS]'
|
||||
'--upgrademenu[Show a detailed list of updates with the option to skip any]'
|
||||
"--nocleanmenu[Don't clean build PKGBUILDS]"
|
||||
"--nodiffmenu[Don't show diffs for build files]"
|
||||
"--noeditmenu[Don't edit/view PKGBUILDS]"
|
||||
"--noupgrademenu[Don't show the upgrade menu]"
|
||||
|
||||
'--bottomup[Show AUR packages first]'
|
||||
'--topdown[Show repository packages first]'
|
||||
@ -71,6 +82,10 @@ _pacman_opts_common=(
|
||||
'--noredownload[Skip pkgbuild download if in cache and up to date]'
|
||||
'--rebuild[Always build target packages]'
|
||||
'--rebuildall[Always build all AUR packages]'
|
||||
'--provides[Look for matching provders when searching for packages]'
|
||||
'--noprovides[Just look for packages by pkgname]'
|
||||
'--pgpfetch[Prompt to import PGP keys from PKGBUILDs]'
|
||||
"--nopgpfetch[Don't prompt to import PGP keys]"
|
||||
'--rebuildtree[Always build all AUR packages even if installed]'
|
||||
'--norebuild[Skip package build if in cache and up to date]'
|
||||
'--mflags[Pass arguments to makepkg]:mflags'
|
||||
@ -134,6 +149,7 @@ _pacman_opts_print_modifiers=(
|
||||
{-n,--numberupgrades}'[Print number of updates]'
|
||||
{-s,--stats}'[Display system package statistics]'
|
||||
{-u,--upgrades}'[Print update list]'
|
||||
{-w,--news}'[Print arch news]'
|
||||
)
|
||||
# options for passing to _arguments: options for --remove command
|
||||
_pacman_opts_remove=(
|
||||
|
25
config.go
25
config.go
@ -25,6 +25,14 @@ const (
|
||||
TopDown
|
||||
)
|
||||
|
||||
type targetMode int
|
||||
|
||||
const (
|
||||
ModeAUR targetMode = iota
|
||||
ModeRepo
|
||||
ModeAny
|
||||
)
|
||||
|
||||
// Configuration stores yay's config.
|
||||
type Configuration struct {
|
||||
BuildDir string `json:"buildDir"`
|
||||
@ -37,6 +45,7 @@ type Configuration struct {
|
||||
ReDownload string `json:"redownload"`
|
||||
ReBuild string `json:"rebuild"`
|
||||
AnswerClean string `json:"answerclean"`
|
||||
AnswerDiff string `json:"answerdiff"`
|
||||
AnswerEdit string `json:"answeredit"`
|
||||
AnswerUpgrade string `json:"answerupgrade"`
|
||||
GitBin string `json:"gitbin"`
|
||||
@ -54,6 +63,12 @@ type Configuration struct {
|
||||
Devel bool `json:"devel"`
|
||||
CleanAfter bool `json:"cleanAfter"`
|
||||
GitClone bool `json:"gitclone"`
|
||||
Provides bool `json:"provides"`
|
||||
PGPFetch bool `json:"pgpfetch"`
|
||||
UpgradeMenu bool `json:"upgrademenu"`
|
||||
CleanMenu bool `json:"cleanmenu"`
|
||||
DiffMenu bool `json:"diffmenu"`
|
||||
EditMenu bool `json:"editmenu"`
|
||||
}
|
||||
|
||||
var version = "5.688"
|
||||
@ -97,6 +112,9 @@ var alpmConf alpm.PacmanConfig
|
||||
// AlpmHandle is the alpm handle used by yay.
|
||||
var alpmHandle *alpm.Handle
|
||||
|
||||
// Mode is used to restrict yay to AUR or repo only modes
|
||||
var mode targetMode = ModeAny
|
||||
|
||||
func readAlpmConfig(pacmanconf string) (conf alpm.PacmanConfig, err error) {
|
||||
file, err := os.Open(pacmanconf)
|
||||
if err != nil {
|
||||
@ -134,6 +152,7 @@ func defaultSettings(config *Configuration) {
|
||||
config.MakepkgBin = "makepkg"
|
||||
config.NoConfirm = false
|
||||
config.PacmanBin = "pacman"
|
||||
config.PGPFetch = true
|
||||
config.PacmanConf = "/etc/pacman.conf"
|
||||
config.GpgFlags = ""
|
||||
config.MFlags = ""
|
||||
@ -149,9 +168,15 @@ func defaultSettings(config *Configuration) {
|
||||
config.ReDownload = "no"
|
||||
config.ReBuild = "no"
|
||||
config.AnswerClean = ""
|
||||
config.AnswerDiff = ""
|
||||
config.AnswerEdit = ""
|
||||
config.AnswerUpgrade = ""
|
||||
config.GitClone = true
|
||||
config.Provides = true
|
||||
config.UpgradeMenu = true
|
||||
config.CleanMenu = true
|
||||
config.DiffMenu = true
|
||||
config.EditMenu = false
|
||||
}
|
||||
|
||||
// Editor returns the preferred system editor.
|
||||
|
354
conflicts.go
354
conflicts.go
@ -1,354 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
alpm "github.com/jguer/go-alpm"
|
||||
gopkg "github.com/mikkeloscar/gopkgbuild"
|
||||
)
|
||||
|
||||
// Checks a single conflict against every other to be installed package's
|
||||
// name and its provides.
|
||||
func checkInnerConflict(name string, conflict string, conflicts map[string]stringSet, dc *depCatagories) {
|
||||
deps, err := gopkg.ParseDeps([]string{conflict})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
dep := deps[0]
|
||||
|
||||
for _, pkg := range dc.Aur {
|
||||
if name == pkg.Name {
|
||||
continue
|
||||
}
|
||||
|
||||
version, err := gopkg.NewCompleteVersion(pkg.Version)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dep.Name == pkg.Name && version.Satisfies(dep) {
|
||||
addMapStringSet(conflicts, name, pkg.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, provide := range pkg.Provides {
|
||||
// Provides are not versioned unless explicitly defined as
|
||||
// such. If a conflict is versioned but a provide is
|
||||
// not it can not conflict.
|
||||
if (dep.MaxVer != nil || dep.MinVer != nil) && !strings.ContainsAny(provide, "><=") {
|
||||
continue
|
||||
}
|
||||
|
||||
var version *gopkg.CompleteVersion
|
||||
var err error
|
||||
|
||||
pname, pversion := splitNameFromDep(provide)
|
||||
|
||||
if dep.Name != pname {
|
||||
continue
|
||||
}
|
||||
|
||||
if pversion != "" {
|
||||
version, err = gopkg.NewCompleteVersion(provide)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if version != nil && version.Satisfies(dep) {
|
||||
addMapStringSet(conflicts, name, pkg.Name)
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dc.Repo {
|
||||
if name == pkg.Name() {
|
||||
continue
|
||||
}
|
||||
|
||||
version, err := gopkg.NewCompleteVersion(pkg.Version())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if dep.Name == pkg.Name() && version.Satisfies(dep) {
|
||||
addMapStringSet(conflicts, name, pkg.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
pkg.Provides().ForEach(func(provide alpm.Depend) error {
|
||||
// Provides are not versioned unless explicitly defined as
|
||||
// such. If a conflict is versioned but a provide is
|
||||
// not it can not conflict.
|
||||
if (dep.MaxVer != nil || dep.MinVer != nil) && provide.Mod == alpm.DepModAny {
|
||||
return nil
|
||||
}
|
||||
|
||||
if dep.Name != pkg.Name() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if provide.Mod == alpm.DepModAny {
|
||||
addMapStringSet(conflicts, name, pkg.Name())
|
||||
return fmt.Errorf("")
|
||||
}
|
||||
|
||||
version, err := gopkg.NewCompleteVersion(provide.Version)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if version.Satisfies(dep) {
|
||||
addMapStringSet(conflicts, name, pkg.Name())
|
||||
return fmt.Errorf("")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Checks every to be installed package's conflicts against every other to be
|
||||
// installed package and its provides.
|
||||
func checkForInnerConflicts(dc *depCatagories) map[string]stringSet {
|
||||
conflicts := make(map[string]stringSet)
|
||||
|
||||
for _, pkg := range dc.Aur {
|
||||
for _, cpkg := range pkg.Conflicts {
|
||||
checkInnerConflict(pkg.Name, cpkg, conflicts, dc)
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dc.Repo {
|
||||
pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
|
||||
checkInnerConflict(pkg.Name(), conflict.String(), conflicts, dc)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return conflicts
|
||||
}
|
||||
|
||||
// Checks a provide or packagename from a to be installed package
|
||||
// against every already installed package's conflicts
|
||||
func checkReverseConflict(name string, provide string, conflicts map[string]stringSet) error {
|
||||
var version *gopkg.CompleteVersion
|
||||
var err error
|
||||
|
||||
localDb, err := alpmHandle.LocalDb()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pname, pversion := splitNameFromDep(provide)
|
||||
if pversion != "" {
|
||||
version, err = gopkg.NewCompleteVersion(pversion)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
localDb.PkgCache().ForEach(func(pkg alpm.Package) error {
|
||||
if name == pkg.Name() {
|
||||
return nil
|
||||
}
|
||||
|
||||
pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
|
||||
deps, err := gopkg.ParseDeps([]string{conflict.String()})
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
dep := deps[0]
|
||||
// Provides are not versioned unless explicitly defined as
|
||||
// such. If a conflict is versioned but a provide is
|
||||
// not it can not conflict.
|
||||
if (dep.MaxVer != nil || dep.MinVer != nil) && version == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if dep.Name != pname {
|
||||
return nil
|
||||
}
|
||||
|
||||
if version == nil || version.Satisfies(dep) {
|
||||
// Todo
|
||||
addMapStringSet(conflicts, name, pkg.Name()+" ("+provide+")")
|
||||
return fmt.Errorf("")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks the conflict of a to be installed package against the package name and
|
||||
// provides of every installed package.
|
||||
func checkConflict(name string, conflict string, conflicts map[string]stringSet) error {
|
||||
localDb, err := alpmHandle.LocalDb()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
deps, err := gopkg.ParseDeps([]string{conflict})
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
dep := deps[0]
|
||||
|
||||
localDb.PkgCache().ForEach(func(pkg alpm.Package) error {
|
||||
if name == pkg.Name() {
|
||||
return nil
|
||||
}
|
||||
|
||||
version, err := gopkg.NewCompleteVersion(pkg.Version())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if dep.Name == pkg.Name() && version.Satisfies(dep) {
|
||||
addMapStringSet(conflicts, name, pkg.Name())
|
||||
return nil
|
||||
}
|
||||
|
||||
pkg.Provides().ForEach(func(provide alpm.Depend) error {
|
||||
if dep.Name != provide.Name {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Provides arent version unless explicitly defined as
|
||||
// such. If a conflict is versioned but a provide is
|
||||
// not it can not conflict.
|
||||
if (dep.MaxVer != nil || dep.MinVer != nil) && provide.Mod == alpm.DepModAny {
|
||||
return nil
|
||||
}
|
||||
|
||||
if provide.Mod == alpm.DepModAny {
|
||||
addMapStringSet(conflicts, name, pkg.Name()+" ("+provide.Name+")")
|
||||
return fmt.Errorf("")
|
||||
}
|
||||
|
||||
version, err := gopkg.NewCompleteVersion(provide.Version)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if version.Satisfies(dep) {
|
||||
addMapStringSet(conflicts, name, pkg.Name()+" ("+provide.Name+")")
|
||||
return fmt.Errorf("")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks every to be installed package's conflicts against the names and
|
||||
// provides of every already installed package and checks every to be installed
|
||||
// package's name and provides against every already installed package.
|
||||
func checkForConflicts(dc *depCatagories) (map[string]stringSet, error) {
|
||||
conflicts := make(map[string]stringSet)
|
||||
|
||||
for _, pkg := range dc.Aur {
|
||||
for _, cpkg := range pkg.Conflicts {
|
||||
checkConflict(pkg.Name, cpkg, conflicts)
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dc.Repo {
|
||||
pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
|
||||
checkConflict(pkg.Name(), conflict.String(), conflicts)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
for _, pkg := range dc.Aur {
|
||||
checkReverseConflict(pkg.Name, pkg.Name, conflicts)
|
||||
for _, ppkg := range pkg.Provides {
|
||||
checkReverseConflict(pkg.Name, ppkg, conflicts)
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dc.Repo {
|
||||
checkReverseConflict(pkg.Name(), pkg.Name(), conflicts)
|
||||
pkg.Provides().ForEach(func(provide alpm.Depend) error {
|
||||
checkReverseConflict(pkg.Name(), provide.String(), conflicts)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return conflicts, nil
|
||||
}
|
||||
|
||||
// Combiles checkForConflicts() and checkForInnerConflicts() in parallel and
|
||||
// does some printing.
|
||||
func checkForAllConflicts(dc *depCatagories) error {
|
||||
var err error
|
||||
var conflicts map[string]stringSet
|
||||
var innerConflicts map[string]stringSet
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
|
||||
fmt.Println(bold(cyan("::") + bold(" Checking for conflicts...")))
|
||||
go func() {
|
||||
conflicts, err = checkForConflicts(dc)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
fmt.Println(bold(cyan("::") + bold(" Checking for inner conflicts...")))
|
||||
go func() {
|
||||
innerConflicts = checkForInnerConflicts(dc)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(innerConflicts) != 0 {
|
||||
fmt.Println()
|
||||
fmt.Println(bold(red(arrow)), bold("Inner conflicts found:"))
|
||||
|
||||
for name, pkgs := range innerConflicts {
|
||||
str := red(bold(smallArrow)) + " " + name + ":"
|
||||
for pkg := range pkgs {
|
||||
str += " " + cyan(pkg)
|
||||
}
|
||||
|
||||
fmt.Println(str)
|
||||
}
|
||||
|
||||
return fmt.Errorf("Unresolvable package conflicts, aborting")
|
||||
}
|
||||
|
||||
if len(conflicts) != 0 {
|
||||
fmt.Println()
|
||||
fmt.Println(bold(red(arrow)), bold("Package conflicts found:"))
|
||||
for name, pkgs := range conflicts {
|
||||
str := red(bold(smallArrow)) + " Installing " + cyan(name) + " will remove:"
|
||||
for pkg := range pkgs {
|
||||
str += " " + cyan(pkg)
|
||||
}
|
||||
|
||||
fmt.Println(str)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
170
dep.go
Normal file
170
dep.go
Normal file
@ -0,0 +1,170 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
alpm "github.com/jguer/go-alpm"
|
||||
rpc "github.com/mikkeloscar/aur"
|
||||
)
|
||||
|
||||
type providers struct {
|
||||
lookfor string
|
||||
Pkgs []*rpc.Pkg
|
||||
}
|
||||
|
||||
func makeProviders(name string) providers {
|
||||
return providers{
|
||||
name,
|
||||
make([]*rpc.Pkg, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (q providers) Len() int {
|
||||
return len(q.Pkgs)
|
||||
}
|
||||
|
||||
func (q providers) Less(i, j int) bool {
|
||||
if q.lookfor == q.Pkgs[i].Name {
|
||||
return true
|
||||
}
|
||||
|
||||
if q.lookfor == q.Pkgs[j].Name {
|
||||
return false
|
||||
}
|
||||
|
||||
return lessRunes([]rune(q.Pkgs[i].Name), []rune(q.Pkgs[j].Name))
|
||||
}
|
||||
|
||||
func (q providers) Swap(i, j int) {
|
||||
q.Pkgs[i], q.Pkgs[j] = q.Pkgs[j], q.Pkgs[i]
|
||||
}
|
||||
|
||||
func splitDep(dep string) (string, string, string) {
|
||||
mod := ""
|
||||
|
||||
split := strings.FieldsFunc(dep, func(c rune) bool {
|
||||
match := c == '>' || c == '<' || c == '='
|
||||
|
||||
if match {
|
||||
mod += string(c)
|
||||
}
|
||||
|
||||
return match
|
||||
})
|
||||
|
||||
if len(split) == 1 {
|
||||
return split[0], "", ""
|
||||
}
|
||||
|
||||
return split[0], mod, split[1]
|
||||
}
|
||||
|
||||
func pkgSatisfies(name, version, dep string) bool {
|
||||
depName, depMod, depVersion := splitDep(dep)
|
||||
|
||||
if depName != name {
|
||||
return false
|
||||
}
|
||||
|
||||
return verSatisfies(version, depMod, depVersion)
|
||||
}
|
||||
|
||||
func provideSatisfies(provide, dep string) bool {
|
||||
depName, depMod, depVersion := splitDep(dep)
|
||||
provideName, provideMod, provideVersion := splitDep(provide)
|
||||
|
||||
if provideName != depName {
|
||||
return false
|
||||
}
|
||||
|
||||
// Unversioned provieds can not satisfy a versioned dep
|
||||
if provideMod == "" && depMod != "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return verSatisfies(provideVersion, depMod, depVersion)
|
||||
}
|
||||
|
||||
func verSatisfies(ver1, mod, ver2 string) bool {
|
||||
switch mod {
|
||||
case "=":
|
||||
return alpm.VerCmp(ver1, ver2) == 0
|
||||
case "<":
|
||||
return alpm.VerCmp(ver1, ver2) < 0
|
||||
case "<=":
|
||||
return alpm.VerCmp(ver1, ver2) <= 0
|
||||
case ">":
|
||||
return alpm.VerCmp(ver1, ver2) > 0
|
||||
case ">=":
|
||||
return alpm.VerCmp(ver1, ver2) >= 0
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func satisfiesAur(dep string, pkg *rpc.Pkg) bool {
|
||||
if pkgSatisfies(pkg.Name, pkg.Version, dep) {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, provide := range pkg.Provides {
|
||||
if provideSatisfies(provide, dep) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func satisfiesRepo(dep string, pkg *alpm.Package) bool {
|
||||
if pkgSatisfies(pkg.Name(), pkg.Version(), dep) {
|
||||
return true
|
||||
}
|
||||
|
||||
if pkg.Provides().ForEach(func(provide alpm.Depend) error {
|
||||
if provideSatisfies(provide.String(), dep) {
|
||||
return fmt.Errorf("")
|
||||
}
|
||||
|
||||
return nil
|
||||
}) != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
//split apart db/package to db and package
|
||||
func splitDbFromName(pkg string) (string, string) {
|
||||
split := strings.SplitN(pkg, "/", 2)
|
||||
|
||||
if len(split) == 2 {
|
||||
return split[0], split[1]
|
||||
}
|
||||
return "", split[0]
|
||||
}
|
||||
|
||||
func getBases(pkgs map[string]*rpc.Pkg) map[string][]*rpc.Pkg {
|
||||
bases := make(map[string][]*rpc.Pkg)
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
_, ok := bases[pkg.PackageBase]
|
||||
if !ok {
|
||||
bases[pkg.PackageBase] = make([]*rpc.Pkg, 0)
|
||||
}
|
||||
bases[pkg.PackageBase] = append(bases[pkg.PackageBase], pkg)
|
||||
}
|
||||
|
||||
return bases
|
||||
}
|
||||
|
||||
func isDevelName(name string) bool {
|
||||
for _, suffix := range []string{"git", "svn", "hg", "bzr", "nightly"} {
|
||||
if strings.HasSuffix(name, "-"+suffix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Contains(name, "-always-")
|
||||
}
|
275
depCheck.go
Normal file
275
depCheck.go
Normal file
@ -0,0 +1,275 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
alpm "github.com/jguer/go-alpm"
|
||||
// gopkg "github.com/mikkeloscar/gopkgbuild"
|
||||
)
|
||||
|
||||
func (dp *depPool) checkInnerConflict(name string, conflict string, conflicts mapStringSet) {
|
||||
for _, pkg := range dp.Aur {
|
||||
if pkg.Name == name {
|
||||
continue
|
||||
}
|
||||
|
||||
if satisfiesAur(conflict, pkg) {
|
||||
conflicts.Add(name, pkg.Name)
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dp.Repo {
|
||||
if pkg.Name() == name {
|
||||
continue
|
||||
}
|
||||
|
||||
if satisfiesRepo(conflict, pkg) {
|
||||
conflicts.Add(name, pkg.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (dp *depPool) checkForwardConflict(name string, conflict string, conflicts mapStringSet) {
|
||||
dp.LocalDb.PkgCache().ForEach(func(pkg alpm.Package) error {
|
||||
if pkg.Name() == name || dp.hasPackage(pkg.Name()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if satisfiesRepo(conflict, &pkg) {
|
||||
n := pkg.Name()
|
||||
if n != conflict {
|
||||
n += " (" + conflict + ")"
|
||||
}
|
||||
conflicts.Add(name, n)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (dp *depPool) checkReverseConflict(name string, conflict string, conflicts mapStringSet) {
|
||||
for _, pkg := range dp.Aur {
|
||||
if pkg.Name == name {
|
||||
continue
|
||||
}
|
||||
|
||||
if satisfiesAur(conflict, pkg) {
|
||||
if name != conflict {
|
||||
name += " (" + conflict + ")"
|
||||
}
|
||||
|
||||
conflicts.Add(pkg.Name, name)
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dp.Repo {
|
||||
if pkg.Name() == name {
|
||||
continue
|
||||
}
|
||||
|
||||
if satisfiesRepo(conflict, pkg) {
|
||||
if name != conflict {
|
||||
name += " (" + conflict + ")"
|
||||
}
|
||||
|
||||
conflicts.Add(pkg.Name(), name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (dp *depPool) checkInnerConflicts(conflicts mapStringSet) {
|
||||
for _, pkg := range dp.Aur {
|
||||
for _, conflict := range pkg.Conflicts {
|
||||
dp.checkInnerConflict(pkg.Name, conflict, conflicts)
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dp.Repo {
|
||||
pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
|
||||
dp.checkInnerConflict(pkg.Name(), conflict.String(), conflicts)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (dp *depPool) checkForwardConflicts(conflicts mapStringSet) {
|
||||
for _, pkg := range dp.Aur {
|
||||
for _, conflict := range pkg.Conflicts {
|
||||
dp.checkForwardConflict(pkg.Name, conflict, conflicts)
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dp.Repo {
|
||||
pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
|
||||
dp.checkForwardConflict(pkg.Name(), conflict.String(), conflicts)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (dp *depPool) checkReverseConflicts(conflicts mapStringSet) {
|
||||
dp.LocalDb.PkgCache().ForEach(func(pkg alpm.Package) error {
|
||||
if dp.hasPackage(pkg.Name()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
|
||||
dp.checkReverseConflict(pkg.Name(), conflict.String(), conflicts)
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (dp *depPool) CheckConflicts() error {
|
||||
var wg sync.WaitGroup
|
||||
innerConflicts := make(mapStringSet)
|
||||
conflicts := make(mapStringSet)
|
||||
wg.Add(2)
|
||||
|
||||
fmt.Println(bold(cyan("::") + bold(" Checking for conflicts...")))
|
||||
go func() {
|
||||
dp.checkForwardConflicts(conflicts)
|
||||
dp.checkReverseConflicts(conflicts)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
fmt.Println(bold(cyan("::") + bold(" Checking for inner conflicts...")))
|
||||
go func() {
|
||||
dp.checkInnerConflicts(innerConflicts)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if len(innerConflicts) != 0 {
|
||||
fmt.Println()
|
||||
fmt.Println(bold(red(arrow)), bold("Inner conflicts found:"))
|
||||
|
||||
for name, pkgs := range innerConflicts {
|
||||
str := red(bold(smallArrow)) + " " + name + ":"
|
||||
for pkg := range pkgs {
|
||||
str += " " + cyan(pkg) + ","
|
||||
}
|
||||
str = strings.TrimSuffix(str, ",")
|
||||
|
||||
fmt.Println(str)
|
||||
}
|
||||
|
||||
return fmt.Errorf("Unresolvable package conflicts, aborting")
|
||||
}
|
||||
|
||||
if len(conflicts) != 0 {
|
||||
fmt.Println()
|
||||
fmt.Println(bold(red(arrow)), bold("Package conflicts found:"))
|
||||
for name, pkgs := range conflicts {
|
||||
str := red(bold(smallArrow)) + " Installing " + cyan(name) + " will remove:"
|
||||
for pkg := range pkgs {
|
||||
str += " " + cyan(pkg) + ","
|
||||
}
|
||||
str = strings.TrimSuffix(str, ",")
|
||||
|
||||
fmt.Println(str)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type missing struct {
|
||||
Good stringSet
|
||||
Missing map[string][][]string
|
||||
}
|
||||
|
||||
func (dp *depPool) _checkMissing(dep string, stack []string, missing *missing) {
|
||||
if missing.Good.get(dep) {
|
||||
return
|
||||
}
|
||||
|
||||
if trees, ok := missing.Missing[dep]; ok {
|
||||
for _, tree := range trees {
|
||||
if stringSliceEqual(tree, stack) {
|
||||
return
|
||||
}
|
||||
}
|
||||
missing.Missing[dep] = append(missing.Missing[dep], stack)
|
||||
return
|
||||
}
|
||||
|
||||
aurPkg := dp.findSatisfierAur(dep)
|
||||
if aurPkg != nil {
|
||||
missing.Good.set(dep)
|
||||
for _, deps := range [3][]string{aurPkg.Depends, aurPkg.MakeDepends, aurPkg.CheckDepends} {
|
||||
for _, aurDep := range deps {
|
||||
if _, err := dp.LocalDb.PkgCache().FindSatisfier(aurDep); err == nil {
|
||||
missing.Good.set(aurDep)
|
||||
continue
|
||||
}
|
||||
|
||||
dp._checkMissing(aurDep, append(stack, aurPkg.Name), missing)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
repoPkg := dp.findSatisfierRepo(dep)
|
||||
if repoPkg != nil {
|
||||
missing.Good.set(dep)
|
||||
repoPkg.Depends().ForEach(func(repoDep alpm.Depend) error {
|
||||
if _, err := dp.LocalDb.PkgCache().FindSatisfier(repoDep.String()); err == nil {
|
||||
missing.Good.set(repoDep.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
dp._checkMissing(repoDep.String(), append(stack, repoPkg.Name()), missing)
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
missing.Missing[dep] = [][]string{stack}
|
||||
}
|
||||
|
||||
func (dp *depPool) CheckMissing() error {
|
||||
missing := &missing{
|
||||
make(stringSet),
|
||||
make(map[string][][]string),
|
||||
}
|
||||
|
||||
for _, target := range dp.Targets {
|
||||
dp._checkMissing(target.DepString(), make([]string, 0), missing)
|
||||
}
|
||||
|
||||
if len(missing.Missing) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Println(bold(red(arrow+" Error: ")) + "Could not find all required packages:")
|
||||
for dep, trees := range missing.Missing {
|
||||
for _, tree := range trees {
|
||||
|
||||
fmt.Print(" ", cyan(dep))
|
||||
|
||||
if len(tree) == 0 {
|
||||
fmt.Print(" (Target")
|
||||
} else {
|
||||
fmt.Print(" (Wanted by: ")
|
||||
for n := 0; n < len(tree)-1; n++ {
|
||||
fmt.Print(cyan(tree[n]), " -> ")
|
||||
}
|
||||
fmt.Print(cyan(tree[len(tree)-1]))
|
||||
}
|
||||
|
||||
fmt.Println(")")
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("")
|
||||
}
|
120
depOrder.go
Normal file
120
depOrder.go
Normal file
@ -0,0 +1,120 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
alpm "github.com/jguer/go-alpm"
|
||||
rpc "github.com/mikkeloscar/aur"
|
||||
)
|
||||
|
||||
type depOrder struct {
|
||||
Aur []*rpc.Pkg
|
||||
Repo []*alpm.Package
|
||||
Runtime stringSet
|
||||
Bases map[string][]*rpc.Pkg
|
||||
}
|
||||
|
||||
func makeDepOrder() *depOrder {
|
||||
return &depOrder{
|
||||
make([]*rpc.Pkg, 0),
|
||||
make([]*alpm.Package, 0),
|
||||
make(stringSet),
|
||||
make(map[string][]*rpc.Pkg),
|
||||
}
|
||||
}
|
||||
|
||||
func getDepOrder(dp *depPool) *depOrder {
|
||||
do := makeDepOrder()
|
||||
|
||||
for _, target := range dp.Targets {
|
||||
dep := target.DepString()
|
||||
aurPkg := dp.Aur[dep]
|
||||
if aurPkg != nil && pkgSatisfies(aurPkg.Name, aurPkg.Version, dep) {
|
||||
do.orderPkgAur(aurPkg, dp, true)
|
||||
}
|
||||
|
||||
aurPkg = dp.findSatisfierAur(dep)
|
||||
if aurPkg != nil {
|
||||
do.orderPkgAur(aurPkg, dp, true)
|
||||
}
|
||||
|
||||
repoPkg := dp.findSatisfierRepo(dep)
|
||||
if repoPkg != nil {
|
||||
do.orderPkgRepo(repoPkg, dp, true)
|
||||
}
|
||||
}
|
||||
|
||||
return do
|
||||
}
|
||||
|
||||
func (do *depOrder) orderPkgAur(pkg *rpc.Pkg, dp *depPool, runtime bool) {
|
||||
if runtime {
|
||||
do.Runtime.set(pkg.Name)
|
||||
}
|
||||
delete(dp.Aur, pkg.Name)
|
||||
|
||||
for i, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} {
|
||||
for _, dep := range deps {
|
||||
aurPkg := dp.findSatisfierAur(dep)
|
||||
if aurPkg != nil {
|
||||
do.orderPkgAur(aurPkg, dp, runtime && i == 0)
|
||||
}
|
||||
|
||||
repoPkg := dp.findSatisfierRepo(dep)
|
||||
if repoPkg != nil {
|
||||
do.orderPkgRepo(repoPkg, dp, runtime && i == 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := do.Bases[pkg.PackageBase]; !ok {
|
||||
do.Aur = append(do.Aur, pkg)
|
||||
do.Bases[pkg.PackageBase] = make([]*rpc.Pkg, 0)
|
||||
}
|
||||
do.Bases[pkg.PackageBase] = append(do.Bases[pkg.PackageBase], pkg)
|
||||
}
|
||||
|
||||
func (do *depOrder) orderPkgRepo(pkg *alpm.Package, dp *depPool, runtime bool) {
|
||||
if runtime {
|
||||
do.Runtime.set(pkg.Name())
|
||||
}
|
||||
delete(dp.Repo, pkg.Name())
|
||||
|
||||
pkg.Depends().ForEach(func(dep alpm.Depend) (err error) {
|
||||
repoPkg := dp.findSatisfierRepo(dep.String())
|
||||
if repoPkg != nil {
|
||||
do.orderPkgRepo(repoPkg, dp, runtime)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
do.Repo = append(do.Repo, pkg)
|
||||
}
|
||||
|
||||
func (do *depOrder) HasMake() bool {
|
||||
lenAur := 0
|
||||
for _, base := range do.Bases {
|
||||
lenAur += len(base)
|
||||
}
|
||||
|
||||
return len(do.Runtime) != lenAur+len(do.Repo)
|
||||
}
|
||||
|
||||
func (do *depOrder) getMake() []string {
|
||||
makeOnly := make([]string, 0, len(do.Aur)+len(do.Repo)-len(do.Runtime))
|
||||
|
||||
for _, base := range do.Bases {
|
||||
for _, pkg := range base {
|
||||
if !do.Runtime.get(pkg.Name) {
|
||||
makeOnly = append(makeOnly, pkg.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range do.Repo {
|
||||
if !do.Runtime.get(pkg.Name()) {
|
||||
makeOnly = append(makeOnly, pkg.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return makeOnly
|
||||
}
|
477
depPool.go
Normal file
477
depPool.go
Normal file
@ -0,0 +1,477 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
alpm "github.com/jguer/go-alpm"
|
||||
rpc "github.com/mikkeloscar/aur"
|
||||
)
|
||||
|
||||
type target struct {
|
||||
Db string
|
||||
Name string
|
||||
Mod string
|
||||
Version string
|
||||
}
|
||||
|
||||
func toTarget(pkg string) target {
|
||||
db, dep := splitDbFromName(pkg)
|
||||
name, mod, version := splitDep(dep)
|
||||
|
||||
return target{
|
||||
db,
|
||||
name,
|
||||
mod,
|
||||
version,
|
||||
}
|
||||
}
|
||||
|
||||
func (t target) DepString() string {
|
||||
return t.Name + t.Mod + t.Version
|
||||
}
|
||||
|
||||
func (t target) String() string {
|
||||
if t.Db != "" {
|
||||
return t.Db + "/" + t.DepString()
|
||||
}
|
||||
|
||||
return t.DepString()
|
||||
}
|
||||
|
||||
type depPool struct {
|
||||
Targets []target
|
||||
Explicit stringSet
|
||||
Repo map[string]*alpm.Package
|
||||
Aur map[string]*rpc.Pkg
|
||||
AurCache map[string]*rpc.Pkg
|
||||
Groups []string
|
||||
LocalDb *alpm.Db
|
||||
SyncDb alpm.DbList
|
||||
Warnings *aurWarnings
|
||||
}
|
||||
|
||||
func makeDepPool() (*depPool, error) {
|
||||
localDb, err := alpmHandle.LocalDb()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
syncDb, err := alpmHandle.SyncDbs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dp := &depPool{
|
||||
make([]target, 0),
|
||||
make(stringSet),
|
||||
make(map[string]*alpm.Package),
|
||||
make(map[string]*rpc.Pkg),
|
||||
make(map[string]*rpc.Pkg),
|
||||
make([]string, 0),
|
||||
localDb,
|
||||
syncDb,
|
||||
nil,
|
||||
}
|
||||
|
||||
return dp, nil
|
||||
}
|
||||
|
||||
// Includes db/ prefixes and group installs
|
||||
func (dp *depPool) ResolveTargets(pkgs []string) error {
|
||||
// RPC requests are slow
|
||||
// Combine as many AUR package requests as possible into a single RPC
|
||||
// call
|
||||
aurTargets := make(stringSet)
|
||||
|
||||
pkgs = removeInvalidTargets(pkgs)
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
var err error
|
||||
target := toTarget(pkg)
|
||||
|
||||
// skip targets already satisfied
|
||||
// even if the user enters db/pkg and aur/pkg the latter will
|
||||
// still get skipped even if it's from a different database to
|
||||
// the one specified
|
||||
// this is how pacman behaves
|
||||
if dp.hasPackage(target.DepString()) {
|
||||
continue
|
||||
}
|
||||
|
||||
var foundPkg *alpm.Package
|
||||
var singleDb *alpm.Db
|
||||
|
||||
// aur/ prefix means we only check the aur
|
||||
if target.Db == "aur" || mode == ModeAUR {
|
||||
dp.Targets = append(dp.Targets, target)
|
||||
aurTargets.set(target.DepString())
|
||||
continue
|
||||
}
|
||||
|
||||
// If there'ss a different priefix only look in that repo
|
||||
if target.Db != "" {
|
||||
singleDb, err = alpmHandle.SyncDbByName(target.Db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
foundPkg, err = singleDb.PkgCache().FindSatisfier(target.DepString())
|
||||
//otherwise find it in any repo
|
||||
} else {
|
||||
foundPkg, err = dp.SyncDb.FindSatisfier(target.DepString())
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
dp.Targets = append(dp.Targets, target)
|
||||
dp.Explicit.set(foundPkg.Name())
|
||||
dp.ResolveRepoDependency(foundPkg)
|
||||
continue
|
||||
} else {
|
||||
//check for groups
|
||||
//currently we don't resolve the packages in a group
|
||||
//only check if the group exists
|
||||
//would be better to check the groups from singleDb if
|
||||
//the user specified a db but there's no easy way to do
|
||||
//it without making alpm_lists so don't bother for now
|
||||
//db/group is probably a rare use case
|
||||
group, err := dp.SyncDb.PkgCachebyGroup(target.Name)
|
||||
if err == nil {
|
||||
dp.Groups = append(dp.Groups, target.String())
|
||||
group.ForEach(func(pkg alpm.Package) error {
|
||||
dp.Explicit.set(pkg.Name())
|
||||
return nil
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
//if there was no db prefix check the aur
|
||||
if target.Db == "" {
|
||||
aurTargets.set(target.DepString())
|
||||
}
|
||||
|
||||
dp.Targets = append(dp.Targets, target)
|
||||
}
|
||||
|
||||
if len(aurTargets) > 0 && (mode == ModeAny || mode == ModeAUR) {
|
||||
return dp.resolveAURPackages(aurTargets, true)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pseudo provides finder.
|
||||
// Try to find provides by performing a search of the package name
|
||||
// This effectively performs -Ss on each package
|
||||
// then runs -Si on each result to cache the information.
|
||||
//
|
||||
// For example if you were to -S yay then yay -Ss would give:
|
||||
// yay-git yay-bin yay realyog pacui pacui-git ruby-yard
|
||||
// These packages will all be added to the cache in case they are needed later
|
||||
// Ofcouse only the first three packages provide yay, the rest are just false
|
||||
// positives.
|
||||
//
|
||||
// This method increases dependency resolve time
|
||||
func (dp *depPool) findProvides(pkgs stringSet) error {
|
||||
var mux sync.Mutex
|
||||
var wg sync.WaitGroup
|
||||
|
||||
doSearch := func(pkg string) {
|
||||
defer wg.Done()
|
||||
var err error
|
||||
var results []rpc.Pkg
|
||||
|
||||
// Hack for a bigger search result, if the user wants
|
||||
// java-envronment we can search for just java instead and get
|
||||
// more hits.
|
||||
words := strings.Split(pkg, "-")
|
||||
|
||||
for i := range words {
|
||||
results, err = rpc.SearchByNameDesc(strings.Join(words[:i+1], "-"))
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
mux.Lock()
|
||||
if _, ok := dp.AurCache[result.Name]; !ok {
|
||||
pkgs.set(result.Name)
|
||||
}
|
||||
mux.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
for pkg := range pkgs {
|
||||
if _, err := dp.LocalDb.PkgByName(pkg); err == nil {
|
||||
continue
|
||||
}
|
||||
wg.Add(1)
|
||||
go doSearch(pkg)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dp *depPool) cacheAURPackages(_pkgs stringSet) error {
|
||||
pkgs := _pkgs.copy()
|
||||
query := make([]string, 0)
|
||||
|
||||
for pkg := range pkgs {
|
||||
if _, ok := dp.AurCache[pkg]; ok {
|
||||
pkgs.remove(pkg)
|
||||
}
|
||||
}
|
||||
|
||||
if len(pkgs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if config.Provides {
|
||||
err := dp.findProvides(pkgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for pkg := range pkgs {
|
||||
if _, ok := dp.AurCache[pkg]; !ok {
|
||||
name, _, _ := splitDep(pkg)
|
||||
query = append(query, name)
|
||||
}
|
||||
}
|
||||
|
||||
info, err := aurInfo(query, dp.Warnings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pkg := range info {
|
||||
// Dump everything in cache just in case we need it later
|
||||
dp.AurCache[pkg.Name] = pkg
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dp *depPool) resolveAURPackages(pkgs stringSet, explicit bool) error {
|
||||
newPackages := make(stringSet)
|
||||
newAURPackages := make(stringSet)
|
||||
|
||||
err := dp.cacheAURPackages(pkgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(pkgs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for name := range pkgs {
|
||||
_, ok := dp.Aur[name]
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
|
||||
pkg := dp.findSatisfierAurCache(name)
|
||||
if pkg == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if explicit {
|
||||
dp.Explicit.set(pkg.Name)
|
||||
}
|
||||
dp.Aur[pkg.Name] = pkg
|
||||
|
||||
for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} {
|
||||
for _, dep := range deps {
|
||||
newPackages.set(dep)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for dep := range newPackages {
|
||||
if dp.hasSatisfier(dep) {
|
||||
continue
|
||||
}
|
||||
|
||||
//has satisfier installed: skip
|
||||
_, isInstalled := dp.LocalDb.PkgCache().FindSatisfier(dep)
|
||||
if isInstalled == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
//has satisfier in repo: fetch it
|
||||
repoPkg, inRepos := dp.SyncDb.FindSatisfier(dep)
|
||||
if inRepos == nil {
|
||||
dp.ResolveRepoDependency(repoPkg)
|
||||
continue
|
||||
}
|
||||
|
||||
//assume it's in the aur
|
||||
//ditch the versioning because the RPC can't handle it
|
||||
newAURPackages.set(dep)
|
||||
|
||||
}
|
||||
|
||||
err = dp.resolveAURPackages(newAURPackages, false)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (dp *depPool) ResolveRepoDependency(pkg *alpm.Package) {
|
||||
dp.Repo[pkg.Name()] = pkg
|
||||
|
||||
pkg.Depends().ForEach(func(dep alpm.Depend) (err error) {
|
||||
//have satisfier in dep tree: skip
|
||||
if dp.hasSatisfier(dep.String()) {
|
||||
return
|
||||
}
|
||||
|
||||
//has satisfier installed: skip
|
||||
_, isInstalled := dp.LocalDb.PkgCache().FindSatisfier(dep.String())
|
||||
if isInstalled == nil {
|
||||
return
|
||||
}
|
||||
|
||||
//has satisfier in repo: fetch it
|
||||
repoPkg, inRepos := dp.SyncDb.FindSatisfier(dep.String())
|
||||
if inRepos != nil {
|
||||
return
|
||||
}
|
||||
|
||||
dp.ResolveRepoDependency(repoPkg)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func getDepPool(pkgs []string, warnings *aurWarnings) (*depPool, error) {
|
||||
dp, err := makeDepPool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dp.Warnings = warnings
|
||||
err = dp.ResolveTargets(pkgs)
|
||||
|
||||
return dp, err
|
||||
}
|
||||
|
||||
func (dp *depPool) findSatisfierAur(dep string) *rpc.Pkg {
|
||||
for _, pkg := range dp.Aur {
|
||||
if satisfiesAur(dep, pkg) {
|
||||
return pkg
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// This is mostly used to promote packages from the cache
|
||||
// to the Install list
|
||||
// Provide a pacman style provider menu if there's more than one candidate
|
||||
// This acts slightly differently from Pacman, It will give
|
||||
// a menu even if a package with a matching name exists. I believe this
|
||||
// method is better because most of the time you are choosing between
|
||||
// foo and foo-git.
|
||||
// Using Pacman's ways trying to install foo would never give you
|
||||
// a menu.
|
||||
// TODO: maybe intermix repo providers in the menu
|
||||
func (dp *depPool) findSatisfierAurCache(dep string) *rpc.Pkg {
|
||||
depName, _, _ := splitDep(dep)
|
||||
seen := make(stringSet)
|
||||
providers := makeProviders(depName)
|
||||
|
||||
if _, err := dp.LocalDb.PkgByName(depName); err == nil {
|
||||
if pkg, ok := dp.AurCache[dep]; ok && pkgSatisfies(pkg.Name, pkg.Version, dep) {
|
||||
return pkg
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if cmdArgs.op == "Y" || cmdArgs.op == "yay" {
|
||||
for _, pkg := range dp.AurCache {
|
||||
if pkgSatisfies(pkg.Name, pkg.Version, dep) {
|
||||
for _, target := range dp.Targets {
|
||||
if target.Name == pkg.Name {
|
||||
return pkg
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dp.AurCache {
|
||||
if seen.get(pkg.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if pkgSatisfies(pkg.Name, pkg.Version, dep) {
|
||||
providers.Pkgs = append(providers.Pkgs, pkg)
|
||||
seen.set(pkg.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, provide := range pkg.Provides {
|
||||
if provideSatisfies(provide, dep) {
|
||||
providers.Pkgs = append(providers.Pkgs, pkg)
|
||||
seen.set(pkg.Name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if providers.Len() == 1 {
|
||||
return providers.Pkgs[0]
|
||||
}
|
||||
|
||||
if providers.Len() > 1 {
|
||||
sort.Sort(providers)
|
||||
return providerMenu(dep, providers)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dp *depPool) findSatisfierRepo(dep string) *alpm.Package {
|
||||
for _, pkg := range dp.Repo {
|
||||
if satisfiesRepo(dep, pkg) {
|
||||
return pkg
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dp *depPool) hasSatisfier(dep string) bool {
|
||||
return dp.findSatisfierRepo(dep) != nil || dp.findSatisfierAur(dep) != nil
|
||||
}
|
||||
|
||||
func (dp *depPool) hasPackage(name string) bool {
|
||||
for _, pkg := range dp.Repo {
|
||||
if pkg.Name() == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dp.Aur {
|
||||
if pkg.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dp.Groups {
|
||||
if pkg == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
650
dependencies.go
650
dependencies.go
@ -1,650 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
alpm "github.com/jguer/go-alpm"
|
||||
rpc "github.com/mikkeloscar/aur"
|
||||
gopkg "github.com/mikkeloscar/gopkgbuild"
|
||||
)
|
||||
|
||||
type depTree struct {
|
||||
ToProcess stringSet
|
||||
Repo map[string]*alpm.Package
|
||||
Aur map[string]*rpc.Pkg
|
||||
Missing stringSet
|
||||
Groups stringSet
|
||||
Provides map[string]string
|
||||
Warnings *aurWarnings
|
||||
}
|
||||
|
||||
type depCatagories struct {
|
||||
Repo []*alpm.Package
|
||||
Aur []*rpc.Pkg
|
||||
MakeOnly stringSet
|
||||
Bases map[string][]*rpc.Pkg
|
||||
}
|
||||
|
||||
func makeDepTree() *depTree {
|
||||
dt := depTree{
|
||||
make(stringSet),
|
||||
make(map[string]*alpm.Package),
|
||||
make(map[string]*rpc.Pkg),
|
||||
make(stringSet),
|
||||
make(stringSet),
|
||||
make(map[string]string),
|
||||
&aurWarnings{},
|
||||
}
|
||||
|
||||
return &dt
|
||||
}
|
||||
|
||||
func makeDependCatagories() *depCatagories {
|
||||
dc := depCatagories{
|
||||
make([]*alpm.Package, 0),
|
||||
make([]*rpc.Pkg, 0),
|
||||
make(stringSet),
|
||||
make(map[string][]*rpc.Pkg),
|
||||
}
|
||||
|
||||
return &dc
|
||||
}
|
||||
|
||||
// Cut the version requirement from a dependency leaving just the name.
|
||||
func splitNameFromDep(dep string) (string, string) {
|
||||
split := strings.FieldsFunc(dep, func(c rune) bool {
|
||||
return c == '>' || c == '<' || c == '='
|
||||
})
|
||||
|
||||
if len(split) == 1 {
|
||||
return split[0], ""
|
||||
}
|
||||
|
||||
return split[0], split[1]
|
||||
}
|
||||
|
||||
//split apart db/package to db and package
|
||||
func splitDbFromName(pkg string) (string, string) {
|
||||
split := strings.SplitN(pkg, "/", 2)
|
||||
|
||||
if len(split) == 2 {
|
||||
return split[0], split[1]
|
||||
}
|
||||
return "", split[0]
|
||||
}
|
||||
|
||||
func isDevelName(name string) bool {
|
||||
for _, suffix := range []string{"git", "svn", "hg", "bzr", "nightly"} {
|
||||
if strings.HasSuffix(name, suffix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Contains(name, "-always-")
|
||||
}
|
||||
|
||||
func getBases(pkgs map[string]*rpc.Pkg) map[string][]*rpc.Pkg {
|
||||
bases := make(map[string][]*rpc.Pkg)
|
||||
|
||||
nextpkg:
|
||||
for _, pkg := range pkgs {
|
||||
for _, base := range bases[pkg.PackageBase] {
|
||||
if base == pkg {
|
||||
continue nextpkg
|
||||
}
|
||||
}
|
||||
|
||||
_, ok := bases[pkg.PackageBase]
|
||||
if !ok {
|
||||
bases[pkg.PackageBase] = make([]*rpc.Pkg, 0)
|
||||
}
|
||||
bases[pkg.PackageBase] = append(bases[pkg.PackageBase], pkg)
|
||||
}
|
||||
|
||||
return bases
|
||||
}
|
||||
|
||||
func aurFindProvider(name string, dt *depTree) (string, *rpc.Pkg) {
|
||||
dep, _ := splitNameFromDep(name)
|
||||
aurpkg, exists := dt.Aur[dep]
|
||||
|
||||
if exists {
|
||||
return dep, aurpkg
|
||||
}
|
||||
|
||||
dep, exists = dt.Provides[dep]
|
||||
if exists {
|
||||
aurpkg, exists = dt.Aur[dep]
|
||||
if exists {
|
||||
return dep, aurpkg
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
|
||||
}
|
||||
|
||||
func repoFindProvider(name string, dt *depTree) (string, *alpm.Package) {
|
||||
dep, _ := splitNameFromDep(name)
|
||||
alpmpkg, exists := dt.Repo[dep]
|
||||
|
||||
if exists {
|
||||
return dep, alpmpkg
|
||||
}
|
||||
|
||||
dep, exists = dt.Provides[dep]
|
||||
if exists {
|
||||
alpmpkg, exists = dt.Repo[dep]
|
||||
if exists {
|
||||
return dep, alpmpkg
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
|
||||
}
|
||||
|
||||
// Step two of dependency resolving. We already have all the information on the
|
||||
// packages we need, now it's just about ordering them correctly.
|
||||
// pkgs is a list of targets, the packages we want to install. Dependencies are
|
||||
// not included.
|
||||
// For each package we want we iterate down the tree until we hit the bottom.
|
||||
// This is done recursively for each branch.
|
||||
// The start of the tree is defined as the package we want.
|
||||
// When we hit the bottom of the branch we know thats the first package
|
||||
// we need to install so we add it to the start of the to install
|
||||
// list (dc.Aur and dc.Repo).
|
||||
// We work our way up until there is another branch to go down and do it all
|
||||
// again.
|
||||
//
|
||||
// Here is a visual example:
|
||||
//
|
||||
// a
|
||||
// / \
|
||||
// b c
|
||||
// / \
|
||||
// d e
|
||||
//
|
||||
// We see a and it needs b and c
|
||||
// We see b and it needs d and e
|
||||
// We see d - it needs nothing so we add d to our list and move up
|
||||
// We see e - it needs nothing so we add e to our list and move up
|
||||
// We see c - it needs nothing so we add c to our list and move up
|
||||
//
|
||||
// The final install order would come out as debca
|
||||
//
|
||||
// There is a little more to this, handling provides, multiple packages wanting the
|
||||
// same dependencies, etc. This is just the basic premise.
|
||||
func getDepCatagories(pkgs []string, dt *depTree) (*depCatagories, error) {
|
||||
dc := makeDependCatagories()
|
||||
seen := make(stringSet)
|
||||
|
||||
dc.Bases = getBases(dt.Aur)
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
dep, alpmpkg := repoFindProvider(pkg, dt)
|
||||
if alpmpkg != nil {
|
||||
repoDepCatagoriesRecursive(alpmpkg, dc, dt, false)
|
||||
dc.Repo = append(dc.Repo, alpmpkg)
|
||||
delete(dt.Repo, dep)
|
||||
}
|
||||
|
||||
dep, aurpkg := aurFindProvider(pkg, dt)
|
||||
if aurpkg != nil {
|
||||
depCatagoriesRecursive(aurpkg, dc, dt, false, seen)
|
||||
if !seen.get(aurpkg.PackageBase) {
|
||||
dc.Aur = append(dc.Aur, aurpkg)
|
||||
seen.set(aurpkg.PackageBase)
|
||||
}
|
||||
|
||||
delete(dt.Aur, dep)
|
||||
}
|
||||
}
|
||||
|
||||
for _, base := range dc.Bases {
|
||||
for _, pkg := range base {
|
||||
for _, dep := range pkg.Depends {
|
||||
dc.MakeOnly.remove(dep)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dc.Repo {
|
||||
pkg.Depends().ForEach(func(_dep alpm.Depend) error {
|
||||
dep := _dep.Name
|
||||
dc.MakeOnly.remove(dep)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
dc.MakeOnly.remove(pkg)
|
||||
}
|
||||
|
||||
dupes := make(map[*alpm.Package]struct{})
|
||||
filteredRepo := make([]*alpm.Package, 0)
|
||||
|
||||
for _, pkg := range dc.Repo {
|
||||
_, ok := dupes[pkg]
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
dupes[pkg] = struct{}{}
|
||||
filteredRepo = append(filteredRepo, pkg)
|
||||
}
|
||||
|
||||
dc.Repo = filteredRepo
|
||||
|
||||
return dc, nil
|
||||
}
|
||||
|
||||
func repoDepCatagoriesRecursive(pkg *alpm.Package, dc *depCatagories, dt *depTree, isMake bool) {
|
||||
pkg.Depends().ForEach(func(_dep alpm.Depend) error {
|
||||
dep, alpmpkg := repoFindProvider(_dep.Name, dt)
|
||||
if alpmpkg != nil {
|
||||
delete(dt.Repo, dep)
|
||||
repoDepCatagoriesRecursive(alpmpkg, dc, dt, isMake)
|
||||
|
||||
if isMake {
|
||||
dc.MakeOnly.set(alpmpkg.Name())
|
||||
}
|
||||
|
||||
dc.Repo = append(dc.Repo, alpmpkg)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func depCatagoriesRecursive(_pkg *rpc.Pkg, dc *depCatagories, dt *depTree, isMake bool, seen stringSet) {
|
||||
for _, pkg := range dc.Bases[_pkg.PackageBase] {
|
||||
for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} {
|
||||
for _, pkg := range deps {
|
||||
dep, aurpkg := aurFindProvider(pkg, dt)
|
||||
if aurpkg != nil {
|
||||
delete(dt.Aur, dep)
|
||||
depCatagoriesRecursive(aurpkg, dc, dt, isMake, seen)
|
||||
|
||||
if !seen.get(aurpkg.PackageBase) {
|
||||
dc.Aur = append(dc.Aur, aurpkg)
|
||||
seen.set(aurpkg.PackageBase)
|
||||
}
|
||||
|
||||
if isMake {
|
||||
dc.MakeOnly.set(aurpkg.Name)
|
||||
}
|
||||
}
|
||||
|
||||
dep, alpmpkg := repoFindProvider(pkg, dt)
|
||||
if alpmpkg != nil {
|
||||
delete(dt.Repo, dep)
|
||||
repoDepCatagoriesRecursive(alpmpkg, dc, dt, isMake)
|
||||
|
||||
if isMake {
|
||||
dc.MakeOnly.set(alpmpkg.Name())
|
||||
}
|
||||
|
||||
dc.Repo = append(dc.Repo, alpmpkg)
|
||||
}
|
||||
|
||||
}
|
||||
isMake = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is step one for dependency resolving. pkgs is a slice of the packages you
|
||||
// want to resolve the dependencies for. They can be a mix of aur and repo
|
||||
// dependencies. All unmet dependencies will be resolved.
|
||||
//
|
||||
// For Aur dependencies depends, makedepends and checkdepends are resolved but
|
||||
// for repo packages only depends are resolved as they are prebuilt.
|
||||
// The return will be split into three categories: Repo, Aur and Missing.
|
||||
// The return is in no way ordered. This step is is just aimed at gathering the
|
||||
// packages we need.
|
||||
//
|
||||
// This has been designed to make the least amount of rpc requests as possible.
|
||||
// Web requests are probably going to be the bottleneck here so minimizing them
|
||||
// provides a nice speed boost.
|
||||
//
|
||||
// Here is a visual expample of the request system.
|
||||
// Remember only unsatisfied packages are requested, if a package is already
|
||||
// installed we dont bother.
|
||||
//
|
||||
// a
|
||||
// / \
|
||||
// b c
|
||||
// / \
|
||||
// d e
|
||||
//
|
||||
// We see a so we send a request for a
|
||||
// We see a wants b and c so we send a request for b and c
|
||||
// We see d and e so we send a request for d and e
|
||||
//
|
||||
// Thats 5 packages in 3 requests. The amount of requests needed should always be
|
||||
// the same as the height of the tree.
|
||||
// The example does not really do this justice, In the real world where packages
|
||||
// have 10+ dependencies each this is a very nice optimization.
|
||||
func getDepTree(pkgs []string, warnings *aurWarnings) (*depTree, error) {
|
||||
dt := makeDepTree()
|
||||
dt.Warnings = warnings
|
||||
|
||||
localDb, err := alpmHandle.LocalDb()
|
||||
if err != nil {
|
||||
return dt, err
|
||||
}
|
||||
syncDb, err := alpmHandle.SyncDbs()
|
||||
if err != nil {
|
||||
return dt, err
|
||||
}
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
db, name := splitDbFromName(pkg)
|
||||
var foundPkg *alpm.Package
|
||||
var singleDb *alpm.Db
|
||||
|
||||
if db == "aur" {
|
||||
dt.ToProcess.set(name)
|
||||
continue
|
||||
}
|
||||
|
||||
// Check the repos for a matching dep
|
||||
if db != "" {
|
||||
singleDb, err = alpmHandle.SyncDbByName(db)
|
||||
if err != nil {
|
||||
return dt, err
|
||||
}
|
||||
foundPkg, err = singleDb.PkgCache().FindSatisfier(name)
|
||||
} else {
|
||||
foundPkg, err = syncDb.FindSatisfier(name)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
repoTreeRecursive(foundPkg, dt, localDb, syncDb)
|
||||
continue
|
||||
} else {
|
||||
//would be better to check the groups from singleDb if
|
||||
//the user specified a db but theres no easy way to do
|
||||
//it without making alpm_lists so dont bother for now
|
||||
//db/group is probably a rare use case
|
||||
_, err := syncDb.PkgCachebyGroup(name)
|
||||
|
||||
if err == nil {
|
||||
dt.Groups.set(pkg)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if db == "" {
|
||||
dt.ToProcess.set(name)
|
||||
} else {
|
||||
dt.Missing.set(pkg)
|
||||
}
|
||||
}
|
||||
|
||||
if len(dt.ToProcess) > 0 {
|
||||
fmt.Println(bold(cyan("::") + bold(" Querying AUR...")))
|
||||
}
|
||||
|
||||
err = depTreeRecursive(dt, localDb, syncDb, false)
|
||||
if err != nil {
|
||||
return dt, err
|
||||
}
|
||||
|
||||
if !cmdArgs.existsArg("d", "nodeps") {
|
||||
err = checkVersions(dt)
|
||||
}
|
||||
|
||||
dt.Warnings.Print()
|
||||
|
||||
return dt, err
|
||||
}
|
||||
|
||||
// Takes a repo package,
|
||||
// gives all of the non installed deps,
|
||||
// repeats on each sub dep.
|
||||
func repoTreeRecursive(pkg *alpm.Package, dt *depTree, localDb *alpm.Db, syncDb alpm.DbList) (err error) {
|
||||
_, exists := dt.Repo[pkg.Name()]
|
||||
if exists {
|
||||
return
|
||||
}
|
||||
|
||||
_, exists = dt.Provides[pkg.Name()]
|
||||
if exists {
|
||||
return
|
||||
}
|
||||
|
||||
dt.Repo[pkg.Name()] = pkg
|
||||
(*pkg).Provides().ForEach(func(dep alpm.Depend) (err error) {
|
||||
dt.Provides[dep.Name] = pkg.Name()
|
||||
return nil
|
||||
})
|
||||
|
||||
(*pkg).Depends().ForEach(func(dep alpm.Depend) (err error) {
|
||||
_, exists := dt.Repo[dep.Name]
|
||||
if exists {
|
||||
return
|
||||
}
|
||||
|
||||
_, isInstalled := localDb.PkgCache().FindSatisfier(dep.String())
|
||||
if isInstalled == nil {
|
||||
return
|
||||
}
|
||||
|
||||
repoPkg, inRepos := syncDb.FindSatisfier(dep.String())
|
||||
if inRepos == nil {
|
||||
repoTreeRecursive(repoPkg, dt, localDb, syncDb)
|
||||
return
|
||||
}
|
||||
|
||||
dt.Missing.set(dep.String())
|
||||
|
||||
return
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func depTreeRecursive(dt *depTree, localDb *alpm.Db, syncDb alpm.DbList, isMake bool) (err error) {
|
||||
if len(dt.ToProcess) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
nextProcess := make(stringSet)
|
||||
currentProcess := make(stringSet)
|
||||
// Strip version conditions
|
||||
for _dep := range dt.ToProcess {
|
||||
dep, _ := splitNameFromDep(_dep)
|
||||
currentProcess.set(dep)
|
||||
}
|
||||
|
||||
// Assume toprocess only contains aur stuff we have not seen
|
||||
info, err := aurInfo(currentProcess.toSlice(), dt.Warnings)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Cache the results
|
||||
for _, pkg := range info {
|
||||
dt.Aur[pkg.Name] = pkg
|
||||
|
||||
for _, provide := range pkg.Provides {
|
||||
name, _ := splitNameFromDep(provide)
|
||||
dt.Provides[name] = pkg.Name
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through to process and check if we now have
|
||||
// each packaged cached.
|
||||
// If not cached, we assume it is missing.
|
||||
for pkgName := range currentProcess {
|
||||
pkg, exists := dt.Aur[pkgName]
|
||||
|
||||
// Did not get it in the request.
|
||||
if !exists {
|
||||
dt.Missing.set(pkgName)
|
||||
continue
|
||||
}
|
||||
|
||||
// for each dep and makedep
|
||||
for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} {
|
||||
for _, versionedDep := range deps {
|
||||
dep, _ := splitNameFromDep(versionedDep)
|
||||
|
||||
_, exists = dt.Aur[dep]
|
||||
// We have it cached so skip.
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
|
||||
_, exists = dt.Provides[dep]
|
||||
// We have it cached so skip.
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
|
||||
_, exists = dt.Repo[dep]
|
||||
// We have it cached so skip.
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
|
||||
_, exists = dt.Missing[dep]
|
||||
// We know it does not resolve so skip.
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if already installed.
|
||||
_, isInstalled := localDb.PkgCache().FindSatisfier(versionedDep)
|
||||
if isInstalled == nil && config.ReBuild != "tree" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check the repos for a matching dep.
|
||||
repoPkg, inRepos := syncDb.FindSatisfier(versionedDep)
|
||||
if inRepos == nil {
|
||||
if isInstalled == nil && config.ReBuild == "tree" {
|
||||
continue
|
||||
}
|
||||
|
||||
repoTreeRecursive(repoPkg, dt, localDb, syncDb)
|
||||
continue
|
||||
}
|
||||
|
||||
// If all else fails add it to next search.
|
||||
nextProcess.set(versionedDep)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dt.ToProcess = nextProcess
|
||||
depTreeRecursive(dt, localDb, syncDb, true)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func checkVersions(dt *depTree) error {
|
||||
has := make(map[string][]string)
|
||||
allDeps := make([]*gopkg.Dependency, 0)
|
||||
|
||||
localDb, err := alpmHandle.LocalDb()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pkg := range dt.Aur {
|
||||
for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} {
|
||||
for _, dep := range deps {
|
||||
_, _dep := splitNameFromDep(dep)
|
||||
if _dep != "" {
|
||||
deps, _ := gopkg.ParseDeps([]string{dep})
|
||||
if deps[0] != nil {
|
||||
allDeps = append(allDeps, deps[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addMapStringSlice(has, pkg.Name, pkg.Version)
|
||||
|
||||
if !isDevelName(pkg.Name) {
|
||||
for _, name := range pkg.Provides {
|
||||
_name, _ver := splitNameFromDep(name)
|
||||
if _ver != "" {
|
||||
addMapStringSlice(has, _name, _ver)
|
||||
} else {
|
||||
delete(has, _name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dt.Repo {
|
||||
pkg.Depends().ForEach(func(dep alpm.Depend) error {
|
||||
if dep.Mod != alpm.DepModAny {
|
||||
deps, _ := gopkg.ParseDeps([]string{dep.String()})
|
||||
if deps[0] != nil {
|
||||
allDeps = append(allDeps, deps[0])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
addMapStringSlice(has, pkg.Name(), pkg.Version())
|
||||
|
||||
pkg.Provides().ForEach(func(dep alpm.Depend) error {
|
||||
if dep.Mod != alpm.DepModAny {
|
||||
addMapStringSlice(has, dep.Name, dep.Version)
|
||||
} else {
|
||||
delete(has, dep.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
localDb.PkgCache().ForEach(func(pkg alpm.Package) error {
|
||||
pkg.Provides().ForEach(func(dep alpm.Depend) error {
|
||||
if dep.Mod != alpm.DepModAny {
|
||||
addMapStringSlice(has, dep.Name, dep.Version)
|
||||
} else {
|
||||
delete(has, dep.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
for _, dep := range allDeps {
|
||||
satisfied := false
|
||||
verStrs, ok := has[dep.Name]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, verStr := range verStrs {
|
||||
version, err := gopkg.NewCompleteVersion(verStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if version.Satisfies(dep) {
|
||||
satisfied = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !satisfied {
|
||||
dt.Missing.set(dep.String())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
178
doc/yay.8
178
doc/yay.8
@ -1,5 +1,5 @@
|
||||
'\" t
|
||||
.TH "YAY" "8" "2018-02-29" "Yay v3\&.460+" "Yay Manual"
|
||||
.TH "YAY" "8" "2018\-06\-04" "Yay v6\&.784+" "Yay Manual"
|
||||
.nh
|
||||
.ad l
|
||||
.SH "NAME"
|
||||
@ -20,29 +20,29 @@ This manpage only covers options unique to Yay\&. For other options see
|
||||
\fBpacman(8)\fR\&.
|
||||
.SH "YAY OPERATIONS"
|
||||
.PP
|
||||
\fB\-Y, --yay\fR
|
||||
\fB\-Y, \-\-yay\fR
|
||||
.RS 4
|
||||
Perform yay specific operations\&. This is the default if no other operation is
|
||||
selected\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-P, --print\fR
|
||||
\fB\-P, \-\-print\fR
|
||||
.RS 4
|
||||
Perform yay specific print operations\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-G, --getpkgbuild\fR
|
||||
\fB\-G, \-\-getpkgbuild\fR
|
||||
.RS 4
|
||||
Downloads PKGBUILD from ABS or AUR\&.
|
||||
.RE
|
||||
.PP
|
||||
If no arguments are provided 'yay -Syu' will be performed\&.
|
||||
If no arguments are provided 'yay \-Syu' will be performed\&.
|
||||
.RE
|
||||
.PP
|
||||
If no operation is selected -Y will be assumed\&.
|
||||
If no operation is selected \-Y will be assumed\&.
|
||||
.SH "EXTENDED PACMAN OPERATIONS"
|
||||
.PP
|
||||
\fB\-S, -Si, -Ss, -Su, -Sc, -Qu\fR
|
||||
\fB\-S, \-Si, \-Ss, \-Su, \-Sc, \-Qu\fR
|
||||
.RS 4
|
||||
These operations are extended to support both AUR and repo packages\&.
|
||||
.RE
|
||||
@ -58,9 +58,23 @@ sources or built packages but will keep already downloaded vcs sources\&.
|
||||
\fB\-R\fR
|
||||
.RS 4
|
||||
Yay will also remove cached data about devel packages\&.
|
||||
|
||||
.RE
|
||||
.SH "YAY OPTIONS (APPLY TO -Y AND --YAY)"
|
||||
.SH "NEW OPTIONS"
|
||||
.PP
|
||||
\fB \-\-repo\fR
|
||||
.RS 4
|
||||
Assume all targets are from the repositories\&. Additionally Actions such as
|
||||
sysupgrade will only act on repository packages\&.
|
||||
.RE
|
||||
\fB\-a \-\-aur\fR
|
||||
.RS 4
|
||||
Assume all targets are from the AUR\&. Additionally Actions such as
|
||||
sysupgrade will only act on AUR packages\&.
|
||||
|
||||
Note that dependency resolving will still act as normal and include repository
|
||||
packages\&.
|
||||
.RE
|
||||
.SH "YAY OPTIONS (APPLY TO \-Y AND \-\-YAY)"
|
||||
.PP
|
||||
\fB<NO OPTION>\fR
|
||||
.RS 4
|
||||
@ -80,7 +94,7 @@ used when migrating to Yay from another AUR helper.
|
||||
.RS 4
|
||||
Remove unneeded dependencies\&.
|
||||
.RE
|
||||
.SH "PRINT OPTIONS (APPLY TO -P AND --PRINT)"
|
||||
.SH "PRINT OPTIONS (APPLY TO \-P AND \-\-PRINT)"
|
||||
\fB\-c \-\-complete\fR
|
||||
.RS 4
|
||||
Print a list of all AUR and repo packages\&. This is to allow shell completion
|
||||
@ -105,20 +119,33 @@ Print current yay configuration\&.
|
||||
\fB\-n \-\-numberupgrades\fR
|
||||
.RS 4
|
||||
Print number of packages that need to be updated\&. Note this does not perform
|
||||
a database refresh\&. Run \fByay -Sy\fR Before this for an up to date result\&.
|
||||
a database refresh\&. Run \fByay \-Sy\fR Before this for an up to date result\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-s \-\-stats\fR
|
||||
.RS 4
|
||||
Displays information about installed packages and system health\&. If there are
|
||||
orphaned, out-of-date or packages that no longer exist on the AUR warnings will
|
||||
orphaned, out\-of\-date or packages that no longer exist on the AUR warnings will
|
||||
be displayed\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-u \-\-upgrades\fR
|
||||
.RS 4
|
||||
Print Names of packages that need to be updated\&. Note this does not perform
|
||||
a database refresh\&. Run \fByay -Sy\fR Before this for an up to date result\&.
|
||||
a database refresh\&. Run \fByay \-Sy\fR Before this for an up to date result\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-w \-\-news\fR
|
||||
.RS 4
|
||||
Print new news from the Archlinux homepage\&. News is considered new if it is
|
||||
newer than the build date of all native packages\&. Pass this twice to show all
|
||||
available news\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-q \-\-quiet\fR
|
||||
.RS 4
|
||||
Only show titles when printing news\&.
|
||||
.RE
|
||||
.PP
|
||||
.SH "PERMANENT CONFIGURATION SETTINGS"
|
||||
.PP
|
||||
@ -205,6 +232,13 @@ will be used instead of reading from standard input but will be treated exactly
|
||||
the same when parsed\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-answerdiff <All|None|Installed|NotInstalled|...>\fR
|
||||
.RS 4
|
||||
Set a predetermined answer for the edit diff menu question\&. This answer
|
||||
will be used instead of reading from standard input but will be treated exactly
|
||||
the same when parsed\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-answeredit <All|None|Installed|NotInstalled|...>\fR
|
||||
.RS 4
|
||||
Set a predetermined answer for the edit pkgbuild menu question\&. This answer
|
||||
@ -224,6 +258,11 @@ reading from standard input but will be treated exactly the same\&.
|
||||
Unset the answer for the clean build menu\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-noanswerdiff\fR
|
||||
.RS 4
|
||||
Unset the answer for the diff menu\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-noansweredit\fR
|
||||
.RS 4
|
||||
Unset the answer for the edit pkgbuild menu\&.
|
||||
@ -234,6 +273,59 @@ Unset the answer for the edit pkgbuild menu\&.
|
||||
Unset the answer for the upgrade menu\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-cleanmenu\fR
|
||||
.RS 4
|
||||
Show the clean menu\&. This menu gives you the chance to fully delete the
|
||||
downloaded build files from Yay's cache before redownloing a fresh copy\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-diffmenu\fR
|
||||
.RS 4
|
||||
Show the diff menu\&. This menu gives you the option to view diffs from
|
||||
build files before building\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-editmenu\fR
|
||||
.RS 4
|
||||
Show the edit menu\&. This menu gives you the option to edit or view PKGBUILDs
|
||||
before building\&.
|
||||
|
||||
\fBWarning\fR: Yay resolves dependencies ahead of time via the RPC\&. It is not
|
||||
recommended to edit pkgbuild variables unless you know what you are doing\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-upgrademenu\fR
|
||||
.RS 4
|
||||
Show a detailed list of updates in a similar format to VerbosePkgLists\&.
|
||||
Upgrades can also be skipped using numbers, number ranges or repo names\&.
|
||||
Adidionally ^ can be used to invert the selection\&.
|
||||
|
||||
\fBWarning\fR: It is not recommended to skip updates from the repositores as
|
||||
this can lead to partial upgrades\&. This feature is intended to easily skip AUR
|
||||
updates on the fly that may be broken or have a long compile time\&. Ultimately
|
||||
it is up to the user what upgrades they skip\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-nocleanmenu\fR
|
||||
.RS 4
|
||||
Do not show the clean menu\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-nodiffmenu\fR
|
||||
.RS 4
|
||||
Do not show the diff menu\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-noeditmenu\fR
|
||||
.RS 4
|
||||
Do not show the edit menu\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-noupgrademenu\fR
|
||||
.RS 4
|
||||
Do not show the upgrade menu\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-topdown\fR
|
||||
.RS 4
|
||||
Display repository packages first and then AUR packages\&.
|
||||
@ -258,9 +350,9 @@ Do not check for development packages updates during sysupgrade\&.
|
||||
\fB\-\-gitclone\fR
|
||||
.RS 4
|
||||
Use git to download and update PKGBUILDs\&. PKGBUILDs previously downloaded
|
||||
using tarball will continue to use tarballs until the package is clean built\&.
|
||||
Similarly, PKGBUILDs managed with git will continue to use git until the package
|
||||
is clean built.\&.
|
||||
using tarball will continue to use tarballs until the package is clean
|
||||
built\&. Similarly, PKGBUILDs managed with git will continue to use git until
|
||||
the package is clean built.\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-nogitclone\fR
|
||||
@ -269,6 +361,18 @@ Download and update PKGBUILDs using tarballs\&. The above conditions about
|
||||
previously installed packages still apply\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-showdiffs\fR
|
||||
.RS 4
|
||||
Show diffs for build files\&. Diffs are shown via \fBgit diff\fR which uses
|
||||
less by default\&. This behaviour can be changed via git's config, the
|
||||
\fB$GIT_PAGER\fR or \fB$PAGER\fR environment variables\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-noshowdiffs\fR
|
||||
.RS 4
|
||||
Show diffs for build files\&. Files will be opened by the editor\%.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-afterclean\fR
|
||||
.RS 4
|
||||
Remove package sources after successful Install\&.
|
||||
@ -307,6 +411,32 @@ When downloading pkgbuilds if the pkgbuild is found in cache and is equal or
|
||||
newer than the AUR's version use that instead of downloading a new one\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-provides\fR
|
||||
.RS 4
|
||||
Look for matching providers when searching for AUR packages\&. When multiple
|
||||
providers are found a menu will appear prompting you to pick one\&. This
|
||||
increases dependency resolve time although this should not be noticeable\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-noprovides\fR
|
||||
.RS 4
|
||||
Do not look for matching providers when searching for AUR packages\&. If
|
||||
multiple providers happen to be found the menu will still appear\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-pgpfetch\fR
|
||||
.RS 4
|
||||
Prompt to import unknown PGP keys from the \fBvalidpgpkeys\fR field of each
|
||||
PKGBUILD.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-pgpfetch\fR
|
||||
.RS 4
|
||||
Do not prompt to import unknown PGP keys\&. This is likley to cause a build
|
||||
failiure unless using options such as \fB\-\-skippgpcheck\fR or a customized
|
||||
gpg config\%.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-rebuild\fR
|
||||
.RS 4
|
||||
Always build target packages even when a copy is available in cache\&.
|
||||
@ -365,37 +495,37 @@ yay \fIfoo\fR
|
||||
Search and install from the repos and the \fBAUR\fR\ using yogurt mode\&.
|
||||
.RE
|
||||
.PP
|
||||
yay -Syu
|
||||
yay \-Syu
|
||||
.RS 4
|
||||
Update package list and upgrade all currently installed repo and \fBAUR\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
yay -S \fIfoo\fR
|
||||
yay \-S \fIfoo\fR
|
||||
.RS 4
|
||||
Installs package \fIfoo\fR from the repos or the \fBAUR\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
yay -Ss \fIfoo\fR
|
||||
yay \-Ss \fIfoo\fR
|
||||
.RS 4
|
||||
Searches for package \fIfoo\fR on the repos or the \fBAUR\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
yay -Si \fIfoo\fR
|
||||
yay \-Si \fIfoo\fR
|
||||
.RS 4
|
||||
Gets information about package \fIfoo\fR from the repos or the \fBAUR\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
yay -S \fIfoo\fR --mflags "--skipchecksums --skippgpcheck"
|
||||
yay \-S \fIfoo\fR \-\-mflags "\-\-skipchecksums \-\-skippgpcheck"
|
||||
.RS 4
|
||||
Installs \fIfoo\fR while skipping checksums and pgp checks\&.
|
||||
.RE
|
||||
.PP
|
||||
yay --devel --save
|
||||
yay \-\-devel \-\-save
|
||||
.RS 4
|
||||
Sets devel to true in the config\&.
|
||||
.RE
|
||||
.PP
|
||||
yay -P --stats
|
||||
yay \-P \-\-stats
|
||||
.RS 4
|
||||
Shows statistics for installed packages and system health\&.
|
||||
.RE
|
||||
@ -435,7 +565,7 @@ and built packages from those packages\&.
|
||||
\fBPACMAN.CONF\fR
|
||||
.RS 4
|
||||
Yay uses Pacman's config file to set certain pacman options either through
|
||||
go-alpm or Yay itself. Options inherited include most libalpm options and
|
||||
go\-alpm or Yay itself. Options inherited include most libalpm options and
|
||||
pacman options\&.
|
||||
.PP
|
||||
Notably \fBDatabases\fR, \fBColor\fR and \fB*Path/*Dir\fR options are used\&.
|
||||
|
166
download.go
166
download.go
@ -21,11 +21,7 @@ func shouldUseGit(path string) bool {
|
||||
}
|
||||
|
||||
_, err = os.Stat(filepath.Join(path, ".git"))
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
return err == nil || os.IsExist(err)
|
||||
}
|
||||
|
||||
func downloadFile(path string, url string) (err error) {
|
||||
@ -48,25 +44,47 @@ func downloadFile(path string, url string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func gitDownload(url string, path string, name string) error {
|
||||
func gitHasDiff(path string, name string) (bool, error) {
|
||||
stdout, stderr, err := passToGitCapture(filepath.Join(path, name), "rev-parse", "HEAD")
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("%s%s", stderr, err)
|
||||
}
|
||||
|
||||
head := strings.TrimSpace(stdout)
|
||||
|
||||
stdout, stderr, err = passToGitCapture(filepath.Join(path, name), "rev-parse", "HEAD@{upstream}")
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("%s%s", stderr, err)
|
||||
}
|
||||
|
||||
upstream := strings.TrimSpace(stdout)
|
||||
|
||||
return head != upstream, nil
|
||||
}
|
||||
|
||||
func gitDownload(url string, path string, name string) (bool, error) {
|
||||
_, err := os.Stat(filepath.Join(path, name, ".git"))
|
||||
if os.IsNotExist(err) {
|
||||
err = passToGit(path, "clone", url, name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error cloning %s", name)
|
||||
return false, fmt.Errorf("error cloning %s", name)
|
||||
}
|
||||
|
||||
return nil
|
||||
return true, nil
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("error reading %s", filepath.Join(path, name, ".git"))
|
||||
return false, fmt.Errorf("error reading %s", filepath.Join(path, name, ".git"))
|
||||
}
|
||||
|
||||
err = passToGit(filepath.Join(path, name), "fetch")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error fetching %s", name)
|
||||
return false, fmt.Errorf("error fetching %s", name)
|
||||
}
|
||||
|
||||
err = passToGit(filepath.Join(path, name), "reset", "--hard", "HEAD")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func gitMerge(url string, path string, name string) error {
|
||||
err := passToGit(filepath.Join(path, name), "reset", "--hard", "HEAD")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error resetting %s", name)
|
||||
}
|
||||
@ -79,15 +97,20 @@ func gitDownload(url string, path string, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func gitDiff(path string, name string) error {
|
||||
err := passToGit(filepath.Join(path, name), "diff", "HEAD..HEAD@{upstream}")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DownloadAndUnpack downloads url tgz and extracts to path.
|
||||
func downloadAndUnpack(url string, path string, trim bool) (err error) {
|
||||
func downloadAndUnpack(url string, path string) (err error) {
|
||||
err = os.MkdirAll(path, 0755)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tokens := strings.Split(url, "/")
|
||||
fileName := tokens[len(tokens)-1]
|
||||
fileName := filepath.Base(url)
|
||||
|
||||
tarLocation := filepath.Join(path, fileName)
|
||||
defer os.Remove(tarLocation)
|
||||
@ -97,13 +120,7 @@ func downloadAndUnpack(url string, path string, trim bool) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if trim {
|
||||
err = exec.Command("/bin/sh", "-c",
|
||||
config.TarBin+" --strip-components 2 --include='*/"+fileName[:len(fileName)-7]+"/trunk/' -xf "+tarLocation+" -C "+path).Run()
|
||||
os.Rename(path+"trunk", path+fileName[:len(fileName)-7]) // kurwa
|
||||
} else {
|
||||
err = exec.Command(config.TarBin, "-xf", tarLocation, "-C", path).Run()
|
||||
}
|
||||
err = exec.Command(config.TarBin, "-xf", tarLocation, "-C", path).Run()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -112,23 +129,40 @@ func downloadAndUnpack(url string, path string, trim bool) (err error) {
|
||||
}
|
||||
|
||||
func getPkgbuilds(pkgs []string) error {
|
||||
//possibleAurs := make([]string, 0, 0)
|
||||
missing := false
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
missing, err := getPkgbuildsfromABS(pkgs, wd)
|
||||
if err != nil {
|
||||
return err
|
||||
pkgs = removeInvalidTargets(pkgs)
|
||||
|
||||
aur, repo, err := packageSlices(pkgs)
|
||||
|
||||
if len(repo) > 0 {
|
||||
missing, err = getPkgbuildsfromABS(repo, wd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(aur) > 0 {
|
||||
_missing, err := getPkgbuildsfromAUR(aur, wd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
missing = missing || _missing
|
||||
}
|
||||
|
||||
if missing {
|
||||
err = fmt.Errorf("")
|
||||
}
|
||||
|
||||
err = getPkgbuildsfromAUR(missing, wd)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetPkgbuild downloads pkgbuild from the ABS.
|
||||
func getPkgbuildsfromABS(pkgs []string, path string) (missing []string, err error) {
|
||||
func getPkgbuildsfromABS(pkgs []string, path string) (missing bool, err error) {
|
||||
dbList, err := alpmHandle.SyncDbs()
|
||||
if err != nil {
|
||||
return
|
||||
@ -136,8 +170,14 @@ func getPkgbuildsfromABS(pkgs []string, path string) (missing []string, err erro
|
||||
|
||||
nextPkg:
|
||||
for _, pkgN := range pkgs {
|
||||
pkgDb, name := splitDbFromName(pkgN)
|
||||
|
||||
for _, db := range dbList.Slice() {
|
||||
pkg, err := db.PkgByName(pkgN)
|
||||
if pkgDb != "" && db.Name() != pkgDb {
|
||||
continue
|
||||
}
|
||||
|
||||
pkg, err := db.PkgByName(name)
|
||||
if err == nil {
|
||||
var url string
|
||||
name := pkg.Base()
|
||||
@ -145,52 +185,84 @@ nextPkg:
|
||||
name = pkg.Name()
|
||||
}
|
||||
|
||||
if db.Name() == "core" || db.Name() == "extra" {
|
||||
url = "https://projects.archlinux.org/svntogit/packages.git/snapshot/packages/" + name + ".tar.gz"
|
||||
} else if db.Name() == "community" || db.Name() == "multilib" {
|
||||
url = "https://projects.archlinux.org/svntogit/community.git/snapshot/community-packages/" + name + ".tar.gz"
|
||||
} else {
|
||||
fmt.Println(pkgN + " not in standard repositories")
|
||||
if _, err := os.Stat(filepath.Join(path, name)); err == nil {
|
||||
fmt.Println(bold(red(arrow)), bold(cyan(name)), "directory already exists")
|
||||
continue nextPkg
|
||||
}
|
||||
|
||||
errD := downloadAndUnpack(url, path, true)
|
||||
if errD != nil {
|
||||
fmt.Println(bold(red(arrow))+" "+bold(cyan(pkg.Name())), bold(red(errD.Error())))
|
||||
switch db.Name() {
|
||||
case "core", "extra":
|
||||
url = "https://git.archlinux.org/svntogit/packages.git/snapshot/packages/" + name + ".tar.gz"
|
||||
case "community", "multilib":
|
||||
url = "https://git.archlinux.org/svntogit/community.git/snapshot/packages/" + name + ".tar.gz"
|
||||
default:
|
||||
fmt.Println(pkgN, "not in standard repositories")
|
||||
continue nextPkg
|
||||
}
|
||||
|
||||
errD := downloadAndUnpack(url, cacheHome)
|
||||
if errD != nil {
|
||||
fmt.Println(bold(red(arrow)), bold(cyan(pkg.Name())), bold(red(errD.Error())))
|
||||
}
|
||||
|
||||
errD = exec.Command("mv", filepath.Join(cacheHome, "packages", name, "trunk"), filepath.Join(path, name)).Run()
|
||||
if errD != nil {
|
||||
fmt.Println(bold(red(arrow)), bold(cyan(pkg.Name())), bold(red(errD.Error())))
|
||||
} else {
|
||||
fmt.Println(bold(yellow(arrow)), "Downloaded", cyan(pkg.Name()), "from ABS")
|
||||
}
|
||||
|
||||
fmt.Println(bold(yellow(arrow)), "Downloaded", cyan(pkg.Name()), "from ABS")
|
||||
continue nextPkg
|
||||
}
|
||||
}
|
||||
|
||||
missing = append(missing, pkgN)
|
||||
fmt.Println(pkgN, "could not find package in database")
|
||||
missing = true
|
||||
}
|
||||
|
||||
if _, err := os.Stat(filepath.Join(cacheHome, "packages")); err == nil {
|
||||
os.RemoveAll(filepath.Join(cacheHome, "packages"))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetPkgbuild downloads pkgbuild from the AUR.
|
||||
func getPkgbuildsfromAUR(pkgs []string, dir string) (err error) {
|
||||
aq, err := aurInfoPrint(pkgs)
|
||||
func getPkgbuildsfromAUR(pkgs []string, dir string) (bool, error) {
|
||||
missing := false
|
||||
strippedPkgs := make([]string, 0)
|
||||
for _, pkg := range pkgs {
|
||||
_, name := splitDbFromName(pkg)
|
||||
strippedPkgs = append(strippedPkgs, name)
|
||||
}
|
||||
|
||||
aq, err := aurInfoPrint(strippedPkgs)
|
||||
if err != nil {
|
||||
return err
|
||||
return missing, err
|
||||
}
|
||||
|
||||
for _, pkg := range aq {
|
||||
var err error
|
||||
if _, err := os.Stat(filepath.Join(dir, pkg.PackageBase)); err == nil {
|
||||
fmt.Println(bold(red(arrow)), bold(cyan(pkg.Name)), "directory already exists")
|
||||
continue
|
||||
}
|
||||
|
||||
if shouldUseGit(filepath.Join(dir, pkg.PackageBase)) {
|
||||
err = gitDownload(baseURL+"/"+pkg.PackageBase+".git", dir, pkg.PackageBase)
|
||||
_, err = gitDownload(baseURL+"/"+pkg.PackageBase+".git", dir, pkg.PackageBase)
|
||||
} else {
|
||||
err = downloadAndUnpack(baseURL+aq[0].URLPath, dir, false)
|
||||
err = downloadAndUnpack(baseURL+aq[0].URLPath, dir)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fmt.Println(bold(green(arrow)), bold(green("Downloaded")), bold(magenta(pkg.Name)), bold(green("from AUR")))
|
||||
fmt.Println(bold(yellow(arrow)), "Downloaded", cyan(pkg.PackageBase), "from AUR")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
if len(aq) != len(pkgs) {
|
||||
missing = true
|
||||
}
|
||||
|
||||
return missing, err
|
||||
}
|
||||
|
700
install.go
700
install.go
@ -15,16 +15,14 @@ import (
|
||||
|
||||
// Install handles package installs
|
||||
func install(parser *arguments) error {
|
||||
requestTargets := parser.targets.toSlice()
|
||||
var err error
|
||||
var incompatible stringSet
|
||||
var dc *depCatagories
|
||||
var toClean []*rpc.Pkg
|
||||
var toEdit []*rpc.Pkg
|
||||
var do *depOrder
|
||||
|
||||
var aurUp upSlice
|
||||
var repoUp upSlice
|
||||
|
||||
requestTargets := parser.copy().targets
|
||||
warnings := &aurWarnings{}
|
||||
|
||||
removeMake := false
|
||||
@ -41,6 +39,18 @@ func install(parser *arguments) error {
|
||||
remoteNamesCache := sliceToStringSet(remoteNames)
|
||||
localNamesCache := sliceToStringSet(localNames)
|
||||
|
||||
//create the arguments to pass for the repo install
|
||||
arguments := parser.copy()
|
||||
arguments.delArg("y", "refresh")
|
||||
arguments.delArg("asdeps", "asdep")
|
||||
arguments.delArg("asexplicit", "asexp")
|
||||
arguments.op = "S"
|
||||
arguments.clearTargets()
|
||||
|
||||
if mode == ModeAUR {
|
||||
arguments.delArg("u", "sysupgrade")
|
||||
}
|
||||
|
||||
//if we are doing -u also request all packages needing update
|
||||
if parser.existsArg("u", "sysupgrade") {
|
||||
aurUp, repoUp, err = upList(warnings)
|
||||
@ -48,61 +58,13 @@ func install(parser *arguments) error {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, up := range aurUp {
|
||||
requestTargets = append(requestTargets, "aur/"+up.Name)
|
||||
}
|
||||
warnings.print()
|
||||
|
||||
for _, up := range repoUp {
|
||||
requestTargets = append(requestTargets, up.Name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//if len(aurTargets) > 0 || parser.existsArg("u", "sysupgrade") && len(remoteNames) > 0 {
|
||||
// fmt.Println(bold(cyan("::") + " Querying AUR..."))
|
||||
//}
|
||||
dt, err := getDepTree(requestTargets, warnings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Deptree will handle db/pkg prefixes. Now they can be striped from the
|
||||
// targets.
|
||||
for pkg := range parser.targets {
|
||||
_, name := splitDbFromName(pkg)
|
||||
parser.targets.remove(pkg)
|
||||
parser.targets.set(name)
|
||||
}
|
||||
|
||||
for i, pkg := range requestTargets {
|
||||
_, name := splitDbFromName(pkg)
|
||||
requestTargets[i] = name
|
||||
}
|
||||
|
||||
if len(dt.Missing) > 0 {
|
||||
str := bold(red(arrow+" Error: ")) + "Could not find all required packages:"
|
||||
|
||||
for name := range dt.Missing {
|
||||
str += "\n " + name
|
||||
}
|
||||
|
||||
return fmt.Errorf("%s", str)
|
||||
}
|
||||
|
||||
//create the arguments to pass for the repo install
|
||||
arguments := parser.copy()
|
||||
arguments.delArg("y", "refresh")
|
||||
arguments.op = "S"
|
||||
arguments.targets = make(stringSet)
|
||||
|
||||
if parser.existsArg("u", "sysupgrade") {
|
||||
ignore, aurUp, err := upgradePkgs(aurUp, repoUp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
requestTargets = parser.targets.toSlice()
|
||||
|
||||
for _, up := range repoUp {
|
||||
if !ignore.get(up.Name) {
|
||||
requestTargets = append(requestTargets, up.Name)
|
||||
@ -114,7 +76,16 @@ func install(parser *arguments) error {
|
||||
requestTargets = append(requestTargets, up)
|
||||
}
|
||||
|
||||
arguments.addParam("ignore", strings.Join(ignore.toSlice(), ","))
|
||||
value, _, exists := cmdArgs.getArg("ignore")
|
||||
|
||||
if len(ignore) > 0 {
|
||||
ignoreStr := strings.Join(ignore.toSlice(), ",")
|
||||
if exists {
|
||||
ignoreStr += "," + value
|
||||
}
|
||||
arguments.options["ignore"] = ignoreStr
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
|
||||
for pkg := range aurUp {
|
||||
@ -122,91 +93,148 @@ func install(parser *arguments) error {
|
||||
}
|
||||
}
|
||||
|
||||
hasAur := false
|
||||
for pkg := range parser.targets {
|
||||
_, ok := dt.Aur[pkg]
|
||||
if ok {
|
||||
hasAur = true
|
||||
}
|
||||
}
|
||||
targets := sliceToStringSet(parser.targets)
|
||||
|
||||
if hasAur && 0 == os.Geteuid() {
|
||||
return fmt.Errorf(bold(red(arrow)) + " Refusing to install AUR Packages as root, Aborting.")
|
||||
}
|
||||
|
||||
dc, err = getDepCatagories(requestTargets, dt)
|
||||
dp, err := getDepPool(requestTargets, warnings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pkg := range dc.Repo {
|
||||
err = dp.CheckMissing()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(dp.Aur) == 0 {
|
||||
parser.op = "S"
|
||||
parser.delArg("y", "refresh")
|
||||
parser.options["ignore"] = arguments.options["ignore"]
|
||||
return passToPacman(parser)
|
||||
}
|
||||
|
||||
if len(dp.Aur) > 0 && 0 == os.Geteuid() {
|
||||
return fmt.Errorf(bold(red(arrow)) + " Refusing to install AUR Packages as root, Aborting.")
|
||||
}
|
||||
|
||||
err = dp.CheckConflicts()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
do = getDepOrder(dp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pkg := range do.Repo {
|
||||
arguments.addTarget(pkg.DB().Name() + "/" + pkg.Name())
|
||||
}
|
||||
|
||||
for pkg := range dt.Groups {
|
||||
for _, pkg := range dp.Groups {
|
||||
arguments.addTarget(pkg)
|
||||
}
|
||||
|
||||
if len(dc.Aur) == 0 && len(arguments.targets) == 0 && !parser.existsArg("u", "sysupgrade") {
|
||||
if len(do.Aur) == 0 && len(arguments.targets) == 0 && (!parser.existsArg("u", "sysupgrade") || mode == ModeAUR) {
|
||||
fmt.Println("There is nothing to do")
|
||||
return nil
|
||||
}
|
||||
|
||||
if hasAur {
|
||||
hasAur = len(dc.Aur) != 0
|
||||
do.Print()
|
||||
fmt.Println()
|
||||
|
||||
err = checkForAllConflicts(dc)
|
||||
if err != nil {
|
||||
return err
|
||||
if do.HasMake() {
|
||||
if !continueTask("Remove make dependencies after install?", "yY") {
|
||||
removeMake = true
|
||||
}
|
||||
}
|
||||
|
||||
printDepCatagories(dc)
|
||||
fmt.Println()
|
||||
|
||||
if len(dc.MakeOnly) > 0 {
|
||||
if !continueTask("Remove make dependencies after install?", "yY") {
|
||||
removeMake = true
|
||||
}
|
||||
}
|
||||
|
||||
toClean, toEdit, err = cleanEditNumberMenu(dc.Aur, dc.Bases, remoteNamesCache)
|
||||
if config.CleanMenu {
|
||||
askClean := pkgbuildNumberMenu(do.Aur, do.Bases, remoteNamesCache)
|
||||
toClean, err := cleanNumberMenu(do.Aur, do.Bases, remoteNamesCache, askClean)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cleanBuilds(toClean)
|
||||
}
|
||||
|
||||
err = downloadPkgBuilds(dc.Aur, parser.targets, dc.Bases)
|
||||
toSkip := pkgBuildsToSkip(do.Aur, targets)
|
||||
cloned, err := downloadPkgBuilds(do.Aur, do.Bases, toSkip)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var toDiff []*rpc.Pkg
|
||||
var toEdit []*rpc.Pkg
|
||||
|
||||
if config.DiffMenu {
|
||||
pkgbuildNumberMenu(do.Aur, do.Bases, remoteNamesCache)
|
||||
toDiff, err = diffNumberMenu(do.Aur, do.Bases, remoteNamesCache)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(toDiff) > 0 {
|
||||
err = showPkgBuildDiffs(toDiff, do.Bases, cloned)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(toDiff) > 0 {
|
||||
oldValue := config.NoConfirm
|
||||
config.NoConfirm = false
|
||||
fmt.Println()
|
||||
if !continueTask(bold(green("Proceed with install?")), "nN") {
|
||||
return fmt.Errorf("Aborting due to user")
|
||||
}
|
||||
config.NoConfirm = oldValue
|
||||
}
|
||||
|
||||
err = mergePkgBuilds(do.Aur)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.EditMenu {
|
||||
pkgbuildNumberMenu(do.Aur, do.Bases, remoteNamesCache)
|
||||
toEdit, err = editNumberMenu(do.Aur, do.Bases, remoteNamesCache)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(toEdit) > 0 {
|
||||
err = editPkgBuilds(toEdit)
|
||||
err = editPkgBuilds(toEdit, do.Bases)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldValue := config.NoConfirm
|
||||
config.NoConfirm = false
|
||||
if !continueTask(bold(green("Proceed with install?")), "nN") {
|
||||
return fmt.Errorf("Aborting due to user")
|
||||
}
|
||||
config.NoConfirm = oldValue
|
||||
}
|
||||
}
|
||||
|
||||
//initial srcinfo parse before pkgver() bump
|
||||
err = parseSRCINFOFiles(dc.Aur, srcinfosStale, dc.Bases)
|
||||
if err != nil {
|
||||
return err
|
||||
if len(toEdit) > 0 {
|
||||
oldValue := config.NoConfirm
|
||||
config.NoConfirm = false
|
||||
fmt.Println()
|
||||
if !continueTask(bold(green("Proceed with install?")), "nN") {
|
||||
return fmt.Errorf("Aborting due to user")
|
||||
}
|
||||
config.NoConfirm = oldValue
|
||||
}
|
||||
|
||||
incompatible, err = getIncompatible(dc.Aur, srcinfosStale, dc.Bases)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//initial srcinfo parse before pkgver() bump
|
||||
err = parseSRCINFOFiles(do.Aur, srcinfosStale, do.Bases)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = checkPgpKeys(dc.Aur, dc.Bases, srcinfosStale)
|
||||
incompatible, err = getIncompatible(do.Aur, srcinfosStale, do.Bases)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.PGPFetch {
|
||||
err = checkPgpKeys(do.Aur, do.Bases, srcinfosStale)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -220,10 +248,19 @@ func install(parser *arguments) error {
|
||||
|
||||
depArguments := makeArguments()
|
||||
depArguments.addArg("D", "asdeps")
|
||||
expArguments := makeArguments()
|
||||
expArguments.addArg("D", "asexplicit")
|
||||
|
||||
for _, pkg := range dc.Repo {
|
||||
if !parser.targets.get(pkg.Name()) && !localNamesCache.get(pkg.Name()) && !remoteNamesCache.get(pkg.Name()) {
|
||||
for _, pkg := range do.Repo {
|
||||
if !dp.Explicit.get(pkg.Name()) && !localNamesCache.get(pkg.Name()) && !remoteNamesCache.get(pkg.Name()) {
|
||||
depArguments.addTarget(pkg.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
if parser.existsArg("asdeps", "asdep") && dp.Explicit.get(pkg.Name()) {
|
||||
depArguments.addTarget(pkg.Name())
|
||||
} else if parser.existsArg("asexp", "asexplicit") && dp.Explicit.get(pkg.Name()) {
|
||||
expArguments.addTarget(pkg.Name())
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,51 +270,50 @@ func install(parser *arguments) error {
|
||||
return fmt.Errorf("%s%s", stderr, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(expArguments.targets) > 0 {
|
||||
_, stderr, err := passToPacmanCapture(expArguments)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s%s", stderr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hasAur {
|
||||
//conflicts have been checked so answer y for them
|
||||
ask, _ := strconv.Atoi(cmdArgs.globals["ask"])
|
||||
uask := alpm.QuestionType(ask) | alpm.QuestionTypeConflictPkg
|
||||
cmdArgs.globals["ask"] = fmt.Sprint(uask)
|
||||
//conflicts have been checked so answer y for them
|
||||
ask, _ := strconv.Atoi(cmdArgs.globals["ask"])
|
||||
uask := alpm.QuestionType(ask) | alpm.QuestionTypeConflictPkg
|
||||
cmdArgs.globals["ask"] = fmt.Sprint(uask)
|
||||
|
||||
err = downloadPkgBuildsSources(do.Aur, do.Bases, incompatible)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = buildInstallPkgBuilds(dp, do, srcinfosStale, parser, incompatible)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if removeMake {
|
||||
removeArguments := makeArguments()
|
||||
removeArguments.addArg("R", "u")
|
||||
|
||||
for _, pkg := range do.getMake() {
|
||||
removeArguments.addTarget(pkg)
|
||||
}
|
||||
|
||||
oldValue := config.NoConfirm
|
||||
config.NoConfirm = true
|
||||
err = passToPacman(removeArguments)
|
||||
config.NoConfirm = oldValue
|
||||
|
||||
err = downloadPkgBuildsSources(dc.Aur, dc.Bases, incompatible)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = buildInstallPkgBuilds(dc.Aur, srcinfosStale, parser.targets, parser, dc.Bases, incompatible)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(dc.MakeOnly) > 0 {
|
||||
if !removeMake {
|
||||
return nil
|
||||
}
|
||||
|
||||
removeArguments := makeArguments()
|
||||
removeArguments.addArg("R", "u")
|
||||
|
||||
for pkg := range dc.MakeOnly {
|
||||
removeArguments.addTarget(pkg)
|
||||
}
|
||||
|
||||
oldValue := config.NoConfirm
|
||||
config.NoConfirm = true
|
||||
err = passToPacman(removeArguments)
|
||||
config.NoConfirm = oldValue
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if config.CleanAfter {
|
||||
clean(dc.Aur)
|
||||
}
|
||||
|
||||
return nil
|
||||
if config.CleanAfter {
|
||||
clean(do.Aur)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -318,31 +354,44 @@ nextpkg:
|
||||
return incompatible, nil
|
||||
}
|
||||
|
||||
func getVersionFromPkgbuild(dir string) (string, error) {
|
||||
func parsePackageList(dir string) (map[string]string, string, error) {
|
||||
stdout, stderr, err := passToMakepkgCapture(dir, "--packagelist")
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s%s", stderr, err)
|
||||
return nil, "", fmt.Errorf("%s%s", stderr, err)
|
||||
}
|
||||
|
||||
line := strings.Split(stdout, "\n")[0]
|
||||
split := strings.Split(line, "-")
|
||||
var version string
|
||||
lines := strings.Split(stdout, "\n")
|
||||
pkgdests := make(map[string]string)
|
||||
|
||||
if len(split) < 4 {
|
||||
return "", fmt.Errorf("Can not parse version from: %s", split)
|
||||
for _, line := range lines {
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
fileName := filepath.Base(line)
|
||||
split := strings.Split(fileName, "-")
|
||||
|
||||
if len(split) < 4 {
|
||||
return nil, "", fmt.Errorf("Can not find package name : %s", split)
|
||||
}
|
||||
|
||||
// pkgname-pkgver-pkgrel-arch.pkgext
|
||||
// This assumes 3 dashes after the pkgname, Will cause an error
|
||||
// if the PKGEXT contains a dash. Please no one do that.
|
||||
pkgname := strings.Join(split[:len(split)-3], "-")
|
||||
version = strings.Join(split[len(split)-3:len(split)-2], "-")
|
||||
pkgdests[pkgname] = line
|
||||
}
|
||||
//pkg-name-pkgver-pkgrel-arch: extract pkgver-pkgrel
|
||||
ver := split[len(split)-3] + "-" + split[len(split)-2]
|
||||
return ver, nil
|
||||
|
||||
return pkgdests, version, nil
|
||||
}
|
||||
|
||||
func cleanEditNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed stringSet) ([]*rpc.Pkg, []*rpc.Pkg, error) {
|
||||
func pkgbuildNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed stringSet) bool {
|
||||
toPrint := ""
|
||||
askClean := false
|
||||
|
||||
toClean := make([]*rpc.Pkg, 0)
|
||||
toEdit := make([]*rpc.Pkg, 0)
|
||||
|
||||
for n, pkg := range pkgs {
|
||||
dir := filepath.Join(config.BuildDir, pkg.PackageBase)
|
||||
|
||||
@ -362,76 +411,108 @@ func cleanEditNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed
|
||||
|
||||
fmt.Print(toPrint)
|
||||
|
||||
if askClean {
|
||||
fmt.Println(bold(green(arrow + " Packages to cleanBuild?")))
|
||||
fmt.Println(bold(green(arrow) + cyan(" [N]one ") + "[A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)"))
|
||||
fmt.Print(bold(green(arrow + " ")))
|
||||
cleanInput, err := getInput(config.AnswerClean)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return askClean
|
||||
}
|
||||
|
||||
cInclude, cExclude, cOtherInclude, cOtherExclude := parseNumberMenu(cleanInput)
|
||||
cIsInclude := len(cExclude) == 0 && len(cOtherExclude) == 0
|
||||
func cleanNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed stringSet, hasClean bool) ([]*rpc.Pkg, error) {
|
||||
toClean := make([]*rpc.Pkg, 0)
|
||||
|
||||
if cOtherInclude.get("abort") || cOtherInclude.get("ab") {
|
||||
return nil, nil, fmt.Errorf("Aborting due to user")
|
||||
}
|
||||
if !hasClean {
|
||||
return toClean, nil
|
||||
}
|
||||
|
||||
if !cOtherInclude.get("n") && !cOtherInclude.get("none") {
|
||||
for i, pkg := range pkgs {
|
||||
dir := filepath.Join(config.BuildDir, pkg.PackageBase)
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
fmt.Println(bold(green(arrow + " Packages to cleanBuild?")))
|
||||
fmt.Println(bold(green(arrow) + cyan(" [N]one ") + "[A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)"))
|
||||
fmt.Print(bold(green(arrow + " ")))
|
||||
cleanInput, err := getInput(config.AnswerClean)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !cIsInclude && cExclude.get(len(pkgs)-i) {
|
||||
continue
|
||||
}
|
||||
cInclude, cExclude, cOtherInclude, cOtherExclude := parseNumberMenu(cleanInput)
|
||||
cIsInclude := len(cExclude) == 0 && len(cOtherExclude) == 0
|
||||
|
||||
if installed.get(pkg.Name) && (cOtherInclude.get("i") || cOtherInclude.get("installed")) {
|
||||
toClean = append(toClean, pkg)
|
||||
continue
|
||||
}
|
||||
if cOtherInclude.get("abort") || cOtherInclude.get("ab") {
|
||||
return nil, fmt.Errorf("Aborting due to user")
|
||||
}
|
||||
|
||||
if !installed.get(pkg.Name) && (cOtherInclude.get("no") || cOtherInclude.get("notinstalled")) {
|
||||
toClean = append(toClean, pkg)
|
||||
continue
|
||||
}
|
||||
if !cOtherInclude.get("n") && !cOtherInclude.get("none") {
|
||||
for i, pkg := range pkgs {
|
||||
dir := filepath.Join(config.BuildDir, pkg.PackageBase)
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
if cOtherInclude.get("a") || cOtherInclude.get("all") {
|
||||
toClean = append(toClean, pkg)
|
||||
continue
|
||||
}
|
||||
if !cIsInclude && cExclude.get(len(pkgs)-i) {
|
||||
continue
|
||||
}
|
||||
|
||||
if cIsInclude && (cInclude.get(len(pkgs)-i) || cOtherInclude.get(pkg.PackageBase)) {
|
||||
toClean = append(toClean, pkg)
|
||||
continue
|
||||
}
|
||||
if installed.get(pkg.Name) && (cOtherInclude.get("i") || cOtherInclude.get("installed")) {
|
||||
toClean = append(toClean, pkg)
|
||||
continue
|
||||
}
|
||||
|
||||
if !cIsInclude && (!cExclude.get(len(pkgs)-i) && !cOtherExclude.get(pkg.PackageBase)) {
|
||||
toClean = append(toClean, pkg)
|
||||
continue
|
||||
}
|
||||
if !installed.get(pkg.Name) && (cOtherInclude.get("no") || cOtherInclude.get("notinstalled")) {
|
||||
toClean = append(toClean, pkg)
|
||||
continue
|
||||
}
|
||||
|
||||
if cOtherInclude.get("a") || cOtherInclude.get("all") {
|
||||
toClean = append(toClean, pkg)
|
||||
continue
|
||||
}
|
||||
|
||||
if cIsInclude && (cInclude.get(len(pkgs)-i) || cOtherInclude.get(pkg.PackageBase)) {
|
||||
toClean = append(toClean, pkg)
|
||||
continue
|
||||
}
|
||||
|
||||
if !cIsInclude && (!cExclude.get(len(pkgs)-i) && !cOtherExclude.get(pkg.PackageBase)) {
|
||||
toClean = append(toClean, pkg)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(bold(green(arrow + " PKGBUILDs to edit?")))
|
||||
return toClean, nil
|
||||
}
|
||||
|
||||
func editNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed stringSet) ([]*rpc.Pkg, error) {
|
||||
return editDiffNumberMenu(pkgs, bases, installed, false)
|
||||
}
|
||||
|
||||
func diffNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed stringSet) ([]*rpc.Pkg, error) {
|
||||
return editDiffNumberMenu(pkgs, bases, installed, true)
|
||||
}
|
||||
|
||||
func editDiffNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed stringSet, diff bool) ([]*rpc.Pkg, error) {
|
||||
toEdit := make([]*rpc.Pkg, 0)
|
||||
var editInput string
|
||||
var err error
|
||||
|
||||
fmt.Println(bold(green(arrow) + cyan(" [N]one ") + "[A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)"))
|
||||
|
||||
fmt.Print(bold(green(arrow + " ")))
|
||||
|
||||
editInput, err := getInput(config.AnswerEdit)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
if diff {
|
||||
fmt.Println(bold(green(arrow + " Diffs to show?")))
|
||||
fmt.Print(bold(green(arrow + " ")))
|
||||
editInput, err = getInput(config.AnswerDiff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
fmt.Println(bold(green(arrow + " PKGBUILDs to edit?")))
|
||||
fmt.Print(bold(green(arrow + " ")))
|
||||
editInput, err = getInput(config.AnswerEdit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
eInclude, eExclude, eOtherInclude, eOtherExclude := parseNumberMenu(editInput)
|
||||
eIsInclude := len(eExclude) == 0 && len(eOtherExclude) == 0
|
||||
|
||||
if eOtherInclude.get("abort") || eOtherInclude.get("ab") {
|
||||
return nil, nil, fmt.Errorf("Aborting due to user")
|
||||
return nil, fmt.Errorf("Aborting due to user")
|
||||
}
|
||||
|
||||
if !eOtherInclude.get("n") && !eOtherInclude.get("none") {
|
||||
@ -465,7 +546,7 @@ func cleanEditNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed
|
||||
}
|
||||
}
|
||||
|
||||
return toClean, toEdit, nil
|
||||
return toEdit, nil
|
||||
}
|
||||
|
||||
func cleanBuilds(pkgs []*rpc.Pkg) {
|
||||
@ -476,20 +557,67 @@ func cleanBuilds(pkgs []*rpc.Pkg) {
|
||||
}
|
||||
}
|
||||
|
||||
func editPkgBuilds(pkgs []*rpc.Pkg) error {
|
||||
func showPkgBuildDiffs(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, cloned stringSet) error {
|
||||
for _, pkg := range pkgs {
|
||||
dir := filepath.Join(config.BuildDir, pkg.PackageBase)
|
||||
if shouldUseGit(dir) {
|
||||
start := "HEAD"
|
||||
|
||||
if cloned.get(pkg.PackageBase) {
|
||||
start = gitEmptyTree
|
||||
} else {
|
||||
hasDiff, err := gitHasDiff(config.BuildDir, pkg.PackageBase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !hasDiff {
|
||||
fmt.Printf("%s %s: %s\n", bold(yellow(arrow)), cyan(formatPkgbase(pkg, bases)), bold("No changes -- skipping"))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
args := []string{"diff", start + "..HEAD@{upstream}", "--src-prefix", dir + "/", "--dst-prefix", dir + "/"}
|
||||
if useColor {
|
||||
args = append(args, "--color=always")
|
||||
} else {
|
||||
args = append(args, "--color=never")
|
||||
}
|
||||
err := passToGit(dir, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
editor, editorArgs := editor()
|
||||
editorArgs = append(editorArgs, filepath.Join(dir, "PKGBUILD"))
|
||||
editcmd := exec.Command(editor, editorArgs...)
|
||||
editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
err := editcmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Editor did not exit successfully, Aborting: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func editPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) error {
|
||||
pkgbuilds := make([]string, 0, len(pkgs))
|
||||
for _, pkg := range pkgs {
|
||||
dir := filepath.Join(config.BuildDir, pkg.PackageBase)
|
||||
pkgbuilds = append(pkgbuilds, filepath.Join(dir, "PKGBUILD"))
|
||||
}
|
||||
|
||||
editor, editorArgs := editor()
|
||||
editorArgs = append(editorArgs, pkgbuilds...)
|
||||
editcmd := exec.Command(editor, editorArgs...)
|
||||
editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
err := editcmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Editor did not exit successfully, Aborting: %s", err)
|
||||
if len(pkgbuilds) > 0 {
|
||||
editor, editorArgs := editor()
|
||||
editorArgs = append(editorArgs, pkgbuilds...)
|
||||
editcmd := exec.Command(editor, editorArgs...)
|
||||
editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
err := editcmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Editor did not exit successfully, Aborting: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -530,40 +658,73 @@ func tryParsesrcinfosFile(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD,
|
||||
}
|
||||
}
|
||||
|
||||
func downloadPkgBuilds(pkgs []*rpc.Pkg, targets stringSet, bases map[string][]*rpc.Pkg) error {
|
||||
for k, pkg := range pkgs {
|
||||
func pkgBuildsToSkip(pkgs []*rpc.Pkg, targets stringSet) stringSet {
|
||||
toSkip := make(stringSet)
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
if config.ReDownload == "no" || (config.ReDownload == "yes" && !targets.get(pkg.Name)) {
|
||||
dir := filepath.Join(config.BuildDir, pkg.PackageBase, ".SRCINFO")
|
||||
pkgbuild, err := gopkg.ParseSRCINFO(dir)
|
||||
|
||||
if err == nil {
|
||||
version, err := gopkg.NewCompleteVersion(pkg.Version)
|
||||
if err == nil {
|
||||
if !version.Newer(pkgbuild.Version()) {
|
||||
str := bold(cyan("::") + " PKGBUILD up to date, Skipping (%d/%d): %s\n")
|
||||
fmt.Printf(str, k+1, len(pkgs), cyan(formatPkgbase(pkg, bases)))
|
||||
continue
|
||||
versionRPC, errR := gopkg.NewCompleteVersion(pkg.Version)
|
||||
versionPKG, errP := gopkg.NewCompleteVersion(pkgbuild.Version())
|
||||
if errP == nil && errR == nil {
|
||||
if !versionRPC.Newer(versionPKG) {
|
||||
toSkip.set(pkg.PackageBase)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toSkip
|
||||
}
|
||||
|
||||
func mergePkgBuilds(pkgs []*rpc.Pkg) error {
|
||||
for _, pkg := range pkgs {
|
||||
if shouldUseGit(filepath.Join(config.BuildDir, pkg.PackageBase)) {
|
||||
err := gitMerge(baseURL+"/"+pkg.PackageBase+".git", config.BuildDir, pkg.PackageBase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func downloadPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, toSkip stringSet) (stringSet, error) {
|
||||
cloned := make(stringSet)
|
||||
|
||||
for k, pkg := range pkgs {
|
||||
if toSkip.get(pkg.PackageBase) {
|
||||
str := bold(cyan("::") + " PKGBUILD up to date, Skipping (%d/%d): %s\n")
|
||||
fmt.Printf(str, k+1, len(pkgs), cyan(formatPkgbase(pkg, bases)))
|
||||
continue
|
||||
}
|
||||
|
||||
str := bold(cyan("::") + " Downloading PKGBUILD (%d/%d): %s\n")
|
||||
|
||||
fmt.Printf(str, k+1, len(pkgs), cyan(formatPkgbase(pkg, bases)))
|
||||
|
||||
var err error
|
||||
if shouldUseGit(filepath.Join(config.BuildDir, pkg.PackageBase)) {
|
||||
err = gitDownload(baseURL+"/"+pkg.PackageBase+".git", config.BuildDir, pkg.PackageBase)
|
||||
clone, err := gitDownload(baseURL+"/"+pkg.PackageBase+".git", config.BuildDir, pkg.PackageBase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if clone {
|
||||
cloned.set(pkg.PackageBase)
|
||||
}
|
||||
} else {
|
||||
err = downloadAndUnpack(baseURL+pkg.URLPath, config.BuildDir, false)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
err := downloadAndUnpack(baseURL+pkg.URLPath, config.BuildDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return cloned, nil
|
||||
}
|
||||
|
||||
func downloadPkgBuildsSources(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, incompatible stringSet) (err error) {
|
||||
@ -584,45 +745,42 @@ func downloadPkgBuildsSources(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, inco
|
||||
return
|
||||
}
|
||||
|
||||
func buildInstallPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, targets stringSet, parser *arguments, bases map[string][]*rpc.Pkg, incompatible stringSet) error {
|
||||
arch, err := alpmHandle.Arch()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
func buildInstallPkgBuilds(dp *depPool, do *depOrder, srcinfos map[string]*gopkg.PKGBUILD, parser *arguments, incompatible stringSet) error {
|
||||
for _, pkg := range do.Aur {
|
||||
dir := filepath.Join(config.BuildDir, pkg.PackageBase)
|
||||
built := true
|
||||
|
||||
srcinfo := srcinfos[pkg.PackageBase]
|
||||
|
||||
args := []string{"--nobuild", "-fC"}
|
||||
|
||||
if incompatible.get(pkg.PackageBase) {
|
||||
args = append(args, "--ignorearch")
|
||||
}
|
||||
|
||||
//pkgver bump
|
||||
err := passToMakepkg(dir, "--nobuild", "-fCc")
|
||||
err := passToMakepkg(dir, args...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error making: %s", pkg.Name)
|
||||
}
|
||||
|
||||
version, err := getVersionFromPkgbuild(dir)
|
||||
pkgdests, version, err := parsePackageList(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.ReBuild == "no" || (config.ReBuild == "yes" && !targets.get(pkg.Name)) {
|
||||
for _, split := range bases[pkg.PackageBase] {
|
||||
file, err := completeFileName(dir, split.Name+"-"+version+"-"+arch+".pkg")
|
||||
if err != nil {
|
||||
return err
|
||||
if config.ReBuild == "no" || (config.ReBuild == "yes" && !dp.Explicit.get(pkg.Name)) {
|
||||
for _, split := range do.Bases[pkg.PackageBase] {
|
||||
pkgdest, ok := pkgdests[split.Name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Could not find PKGDEST for: %s", split.Name)
|
||||
}
|
||||
|
||||
if file == "" {
|
||||
file, err = completeFileName(dir, split.Name+"-"+version+"-"+"any"+".pkg")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if file == "" {
|
||||
_, err := os.Stat(pkgdest)
|
||||
if os.IsNotExist(err) {
|
||||
built = false
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -631,9 +789,9 @@ func buildInstallPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD,
|
||||
|
||||
if built {
|
||||
fmt.Println(bold(yellow(arrow)),
|
||||
cyan(pkg.Name+"-"+pkg.Version)+bold(" Already made -- skipping build"))
|
||||
cyan(pkg.Name+"-"+version)+bold(" Already made -- skipping build"))
|
||||
} else {
|
||||
args := []string{"-Ccf", "--noconfirm"}
|
||||
args := []string{"-cf", "--noconfirm", "--noextract", "--noprepare", "--holdver"}
|
||||
|
||||
if incompatible.get(pkg.PackageBase) {
|
||||
args = append(args, "--ignorearch")
|
||||
@ -646,7 +804,7 @@ func buildInstallPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD,
|
||||
}
|
||||
|
||||
arguments := parser.copy()
|
||||
arguments.targets = make(stringSet)
|
||||
arguments.clearTargets()
|
||||
arguments.op = "U"
|
||||
arguments.delArg("confirm")
|
||||
arguments.delArg("c", "clean")
|
||||
@ -658,6 +816,8 @@ func buildInstallPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD,
|
||||
|
||||
depArguments := makeArguments()
|
||||
depArguments.addArg("D", "asdeps")
|
||||
expArguments := makeArguments()
|
||||
expArguments.addArg("D", "asexplicit")
|
||||
|
||||
//remotenames: names of all non repo packages on the system
|
||||
_, _, localNames, remoteNames, err := filterPackages()
|
||||
@ -670,28 +830,24 @@ func buildInstallPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD,
|
||||
remoteNamesCache := sliceToStringSet(remoteNames)
|
||||
localNamesCache := sliceToStringSet(localNames)
|
||||
|
||||
for _, split := range bases[pkg.PackageBase] {
|
||||
file, err := completeFileName(dir, split.Name+"-"+version+"-"+arch+".pkg")
|
||||
if err != nil {
|
||||
return err
|
||||
for _, split := range do.Bases[pkg.PackageBase] {
|
||||
pkgdest, ok := pkgdests[split.Name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Could not find PKGDEST for: %s", split.Name)
|
||||
}
|
||||
|
||||
if file == "" {
|
||||
file, err = completeFileName(dir, split.Name+"-"+version+"-"+"any"+".pkg")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if file == "" {
|
||||
return fmt.Errorf("Could not find built package " + split.Name + "-" + version + "-" + arch + ".pkg")
|
||||
}
|
||||
|
||||
arguments.addTarget(file)
|
||||
//if !targets.get(split.Name) {
|
||||
if !targets.get(split.Name) && !localNamesCache.get(split.Name) && !remoteNamesCache.get(split.Name) {
|
||||
arguments.addTarget(pkgdest)
|
||||
if !dp.Explicit.get(split.Name) && !localNamesCache.get(split.Name) && !remoteNamesCache.get(split.Name) {
|
||||
depArguments.addTarget(split.Name)
|
||||
}
|
||||
|
||||
if dp.Explicit.get(split.Name) {
|
||||
if parser.existsArg("asdeps", "asdep") {
|
||||
depArguments.addTarget(split.Name)
|
||||
} else if parser.existsArg("asexplicit", "asexp") {
|
||||
expArguments.addTarget(split.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oldConfirm := config.NoConfirm
|
||||
@ -701,7 +857,7 @@ func buildInstallPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD,
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pkg := range bases[pkg.PackageBase] {
|
||||
for _, pkg := range do.Bases[pkg.PackageBase] {
|
||||
updateVCSData(pkg.Name, srcinfo.Source)
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@ -36,10 +37,6 @@ func newPkg(basename string) *rpc.Pkg {
|
||||
return &rpc.Pkg{Name: basename, PackageBase: basename}
|
||||
}
|
||||
|
||||
func newSplitPkg(basename, name string) *rpc.Pkg {
|
||||
return &rpc.Pkg{Name: name, PackageBase: basename}
|
||||
}
|
||||
|
||||
func getPgpKey(key string) string {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
@ -73,7 +70,7 @@ func TestImportKeys(t *testing.T) {
|
||||
config.GpgFlags = fmt.Sprintf("--homedir %s --keyserver 127.0.0.1", keyringDir)
|
||||
|
||||
server := startPgpKeyServer()
|
||||
defer server.Shutdown(nil)
|
||||
defer server.Shutdown(context.TODO())
|
||||
|
||||
casetests := []struct {
|
||||
keys []string
|
||||
@ -138,7 +135,7 @@ func TestCheckPgpKeys(t *testing.T) {
|
||||
config.GpgFlags = fmt.Sprintf("--homedir %s --keyserver 127.0.0.1", keyringDir)
|
||||
|
||||
server := startPgpKeyServer()
|
||||
defer server.Shutdown(nil)
|
||||
defer server.Shutdown(context.TODO())
|
||||
|
||||
casetests := []struct {
|
||||
pkgs []*rpc.Pkg
|
||||
|
53
main.go
53
main.go
@ -10,29 +10,39 @@ import (
|
||||
alpm "github.com/jguer/go-alpm"
|
||||
)
|
||||
|
||||
func initPaths() {
|
||||
if configHome = os.Getenv("XDG_CONFIG_HOME"); configHome != "" {
|
||||
if info, err := os.Stat(configHome); err == nil && info.IsDir() {
|
||||
configHome = configHome + "/yay"
|
||||
} else {
|
||||
configHome = filepath.Join(os.Getenv("HOME"), ".config/yay")
|
||||
func setPaths() error {
|
||||
if _configHome, set := os.LookupEnv("XDG_CONFIG_HOME"); set {
|
||||
if _configHome == "" {
|
||||
return fmt.Errorf("XDG_CONFIG_HOME set but empty")
|
||||
}
|
||||
configHome = filepath.Join(_configHome, "yay")
|
||||
} else if _configHome, set := os.LookupEnv("HOME"); set {
|
||||
if _configHome == "" {
|
||||
return fmt.Errorf("HOME set but empty")
|
||||
}
|
||||
configHome = filepath.Join(_configHome, ".config/yay")
|
||||
} else {
|
||||
configHome = filepath.Join(os.Getenv("HOME"), ".config/yay")
|
||||
return fmt.Errorf("XDG_CONFIG_HOME and HOME unset")
|
||||
}
|
||||
|
||||
if cacheHome = os.Getenv("XDG_CACHE_HOME"); cacheHome != "" {
|
||||
if info, err := os.Stat(cacheHome); err == nil && info.IsDir() {
|
||||
cacheHome = filepath.Join(cacheHome, "yay")
|
||||
} else {
|
||||
cacheHome = filepath.Join(os.Getenv("HOME"), ".cache/yay")
|
||||
if _cacheHome, set := os.LookupEnv("XDG_CACHE_HOME"); set {
|
||||
if _cacheHome == "" {
|
||||
return fmt.Errorf("XDG_CACHE_HOME set but empty")
|
||||
}
|
||||
cacheHome = filepath.Join(_cacheHome, "yay")
|
||||
} else if _cacheHome, set := os.LookupEnv("HOME"); set {
|
||||
if _cacheHome == "" {
|
||||
return fmt.Errorf("XDG_CACHE_HOME set but empty")
|
||||
}
|
||||
cacheHome = filepath.Join(_cacheHome, ".cache/yay")
|
||||
} else {
|
||||
cacheHome = filepath.Join(os.Getenv("HOME"), "/.cache/yay")
|
||||
return fmt.Errorf("XDG_CACHE_HOME and HOME unset")
|
||||
}
|
||||
|
||||
configFile = filepath.Join(configHome, configFileName)
|
||||
vcsFile = filepath.Join(cacheHome, vcsFileName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func initConfig() (err error) {
|
||||
@ -60,6 +70,14 @@ func initConfig() (err error) {
|
||||
err)
|
||||
defaultSettings(&config)
|
||||
}
|
||||
if _, err = os.Stat(config.BuildDir); os.IsNotExist(err) {
|
||||
err = os.MkdirAll(config.BuildDir, 0755)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Unable to create BuildDir directory:\n%s\n"+
|
||||
"The error was:\n%s", config.BuildDir, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,7 +194,12 @@ func main() {
|
||||
goto cleanup
|
||||
}
|
||||
|
||||
initPaths()
|
||||
err = setPaths()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
status = 1
|
||||
goto cleanup
|
||||
}
|
||||
|
||||
err = initConfig()
|
||||
if err != nil {
|
||||
@ -212,7 +235,7 @@ func main() {
|
||||
|
||||
cleanup:
|
||||
//cleanup
|
||||
//from here on out dont exit if an error occurs
|
||||
//from here on out don't exit if an error occurs
|
||||
//if we fail to save the configuration
|
||||
//at least continue on and try clean up other parts
|
||||
|
||||
|
130
parser.go
130
parser.go
@ -1,7 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
@ -13,7 +15,7 @@ import (
|
||||
// Other types of sets are used throughout the code but do not have
|
||||
// their own typedef.
|
||||
// String sets and <type>sets should be used throughout the code when applicable,
|
||||
// they are a lot more flexable than slices and provide easy lookup.
|
||||
// they are a lot more flexible than slices and provide easy lookup.
|
||||
type stringSet map[string]struct{}
|
||||
|
||||
func (set stringSet) set(v string) {
|
||||
@ -39,6 +41,16 @@ func (set stringSet) toSlice() []string {
|
||||
return slice
|
||||
}
|
||||
|
||||
func (set stringSet) copy() stringSet {
|
||||
newSet := make(stringSet)
|
||||
|
||||
for str := range set {
|
||||
newSet.set(str)
|
||||
}
|
||||
|
||||
return newSet
|
||||
}
|
||||
|
||||
func sliceToStringSet(in []string) stringSet {
|
||||
set := make(stringSet)
|
||||
|
||||
@ -60,7 +72,7 @@ type arguments struct {
|
||||
options map[string]string
|
||||
globals map[string]string
|
||||
doubles stringSet // Tracks args passed twice such as -yy and -dd
|
||||
targets stringSet
|
||||
targets []string
|
||||
}
|
||||
|
||||
func makeArguments() *arguments {
|
||||
@ -69,7 +81,7 @@ func makeArguments() *arguments {
|
||||
make(map[string]string),
|
||||
make(map[string]string),
|
||||
make(stringSet),
|
||||
make(stringSet),
|
||||
make([]string, 0),
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,9 +98,8 @@ func (parser *arguments) copy() (cp *arguments) {
|
||||
cp.globals[k] = v
|
||||
}
|
||||
|
||||
for k, v := range parser.targets {
|
||||
cp.targets[k] = v
|
||||
}
|
||||
cp.targets = make([]string, len(parser.targets))
|
||||
copy(cp.targets, parser.targets)
|
||||
|
||||
for k, v := range parser.doubles {
|
||||
cp.doubles[k] = v
|
||||
@ -220,9 +231,12 @@ func (parser *arguments) getArg(options ...string) (arg string, double bool, exi
|
||||
existCount := 0
|
||||
|
||||
for _, option := range options {
|
||||
arg, exists = parser.options[option]
|
||||
var value string
|
||||
|
||||
value, exists = parser.options[option]
|
||||
|
||||
if exists {
|
||||
arg = value
|
||||
existCount++
|
||||
_, exists = parser.doubles[option]
|
||||
|
||||
@ -232,9 +246,10 @@ func (parser *arguments) getArg(options ...string) (arg string, double bool, exi
|
||||
|
||||
}
|
||||
|
||||
arg, exists = parser.globals[option]
|
||||
value, exists = parser.globals[option]
|
||||
|
||||
if exists {
|
||||
arg = value
|
||||
existCount++
|
||||
_, exists = parser.doubles[option]
|
||||
|
||||
@ -252,15 +267,11 @@ func (parser *arguments) getArg(options ...string) (arg string, double bool, exi
|
||||
}
|
||||
|
||||
func (parser *arguments) addTarget(targets ...string) {
|
||||
for _, target := range targets {
|
||||
parser.targets[target] = struct{}{}
|
||||
}
|
||||
parser.targets = append(parser.targets, targets...)
|
||||
}
|
||||
|
||||
func (parser *arguments) delTarget(targets ...string) {
|
||||
for _, target := range targets {
|
||||
delete(parser.targets, target)
|
||||
}
|
||||
func (parser *arguments) clearTargets() {
|
||||
parser.targets = make([]string, 0)
|
||||
}
|
||||
|
||||
// Multiple args acts as an OR operator
|
||||
@ -275,14 +286,6 @@ func (parser *arguments) existsDouble(options ...string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (parser *arguments) formatTargets() (args []string) {
|
||||
for target := range parser.targets {
|
||||
args = append(args, target)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (parser *arguments) formatArgs() (args []string) {
|
||||
var op string
|
||||
|
||||
@ -297,15 +300,15 @@ func (parser *arguments) formatArgs() (args []string) {
|
||||
continue
|
||||
}
|
||||
|
||||
formatedOption := formatArg(option)
|
||||
args = append(args, formatedOption)
|
||||
formattedOption := formatArg(option)
|
||||
args = append(args, formattedOption)
|
||||
|
||||
if hasParam(option) {
|
||||
args = append(args, arg)
|
||||
}
|
||||
|
||||
if parser.existsDouble(option) {
|
||||
args = append(args, formatedOption)
|
||||
args = append(args, formattedOption)
|
||||
}
|
||||
}
|
||||
|
||||
@ -314,15 +317,15 @@ func (parser *arguments) formatArgs() (args []string) {
|
||||
|
||||
func (parser *arguments) formatGlobals() (args []string) {
|
||||
for option, arg := range parser.globals {
|
||||
formatedOption := formatArg(option)
|
||||
args = append(args, formatedOption)
|
||||
formattedOption := formatArg(option)
|
||||
args = append(args, formattedOption)
|
||||
|
||||
if hasParam(option) {
|
||||
args = append(args, arg)
|
||||
}
|
||||
|
||||
if parser.existsDouble(option) {
|
||||
args = append(args, formatedOption)
|
||||
args = append(args, formattedOption)
|
||||
}
|
||||
}
|
||||
|
||||
@ -466,6 +469,8 @@ func hasParam(arg string) bool {
|
||||
return true
|
||||
case "answerclean":
|
||||
return true
|
||||
case "answerdiff":
|
||||
return true
|
||||
case "answeredit":
|
||||
return true
|
||||
case "answerupgrade":
|
||||
@ -619,8 +624,8 @@ func (parser *arguments) parseCommandLine() (err error) {
|
||||
//of course the implementation is up to the caller, this function mearley parses
|
||||
//the input and organizes it
|
||||
func parseNumberMenu(input string) (intRanges, intRanges, stringSet, stringSet) {
|
||||
include := make(intRanges, 0, 0)
|
||||
exclude := make(intRanges, 0, 0)
|
||||
include := make(intRanges, 0)
|
||||
exclude := make(intRanges, 0)
|
||||
otherInclude := make(stringSet)
|
||||
otherExclude := make(stringSet)
|
||||
|
||||
@ -669,3 +674,66 @@ func parseNumberMenu(input string) (intRanges, intRanges, stringSet, stringSet)
|
||||
|
||||
return include, exclude, otherInclude, otherExclude
|
||||
}
|
||||
|
||||
// Crude html parsing, good enough for the arch news
|
||||
// This is only displayed in the terminal so there should be no security
|
||||
// concerns
|
||||
func parseNews(str string) string {
|
||||
var buffer bytes.Buffer
|
||||
var tagBuffer bytes.Buffer
|
||||
var escapeBuffer bytes.Buffer
|
||||
inTag := false
|
||||
inEscape := false
|
||||
|
||||
for _, char := range str {
|
||||
if inTag {
|
||||
if char == '>' {
|
||||
inTag = false
|
||||
switch tagBuffer.String() {
|
||||
case "code":
|
||||
buffer.WriteString(cyanCode)
|
||||
case "/code":
|
||||
buffer.WriteString(resetCode)
|
||||
case "/p":
|
||||
buffer.WriteRune('\n')
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
tagBuffer.WriteRune(char)
|
||||
continue
|
||||
}
|
||||
|
||||
if inEscape {
|
||||
if char == ';' {
|
||||
inEscape = false
|
||||
escapeBuffer.WriteRune(char)
|
||||
s := html.UnescapeString(escapeBuffer.String())
|
||||
buffer.WriteString(s)
|
||||
continue
|
||||
}
|
||||
|
||||
escapeBuffer.WriteRune(char)
|
||||
continue
|
||||
}
|
||||
|
||||
if char == '<' {
|
||||
inTag = true
|
||||
tagBuffer.Reset()
|
||||
continue
|
||||
}
|
||||
|
||||
if char == '&' {
|
||||
inEscape = true
|
||||
escapeBuffer.Reset()
|
||||
escapeBuffer.WriteRune(char)
|
||||
continue
|
||||
}
|
||||
|
||||
buffer.WriteRune(char)
|
||||
}
|
||||
|
||||
buffer.WriteString(resetCode)
|
||||
return buffer.String()
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ func intRangesEqual(a, b intRanges) bool {
|
||||
r1 := a[n]
|
||||
r2 := b[n]
|
||||
|
||||
if r1.min != r1.min || r1.max != r2.max {
|
||||
if r1.min != r2.min || r1.max != r2.max {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
274
print.go
274
print.go
@ -1,7 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -13,7 +18,7 @@ import (
|
||||
const arrow = "==>"
|
||||
const smallArrow = " ->"
|
||||
|
||||
func (warnings *aurWarnings) Print() {
|
||||
func (warnings *aurWarnings) print() {
|
||||
if len(warnings.Missing) > 0 {
|
||||
fmt.Print(bold(yellow(smallArrow)) + " Missing AUR Packages:")
|
||||
for _, name := range warnings.Missing {
|
||||
@ -153,23 +158,38 @@ func formatPkgbase(pkg *rpc.Pkg, bases map[string][]*rpc.Pkg) string {
|
||||
return str
|
||||
}
|
||||
|
||||
func (u upgrade) StylizedNameWithRepository() string {
|
||||
return bold(colourHash(u.Repository)) + "/" + bold(u.Name)
|
||||
}
|
||||
|
||||
// Print prints the details of the packages to upgrade.
|
||||
func (u upSlice) Print(start int) {
|
||||
func (u upSlice) print() {
|
||||
longestName, longestVersion := 0, 0
|
||||
for _, pack := range u {
|
||||
packNameLen := len(pack.StylizedNameWithRepository())
|
||||
version, _ := getVersionDiff(pack.LocalVersion, pack.RemoteVersion)
|
||||
packVersionLen := len(version)
|
||||
longestName = max(packNameLen, longestName)
|
||||
longestVersion = max(packVersionLen, longestVersion)
|
||||
}
|
||||
|
||||
namePadding := fmt.Sprintf("%%-%ds ", longestName)
|
||||
versionPadding := fmt.Sprintf("%%-%ds", longestVersion)
|
||||
numberPadding := fmt.Sprintf("%%%dd ", len(fmt.Sprintf("%v", len(u))))
|
||||
|
||||
for k, i := range u {
|
||||
left, right := getVersionDiff(i.LocalVersion, i.RemoteVersion)
|
||||
|
||||
fmt.Print(magenta(fmt.Sprintf("%3d ", len(u)+start-k-1)))
|
||||
fmt.Print(bold(colourHash(i.Repository)), "/", bold(i.Name))
|
||||
fmt.Print(magenta(fmt.Sprintf(numberPadding, len(u)-k)))
|
||||
|
||||
w := 70 - len(i.Repository) - len(i.Name)
|
||||
padding := fmt.Sprintf("%%%ds", w)
|
||||
fmt.Printf(padding, left)
|
||||
fmt.Printf(" -> %s\n", right)
|
||||
fmt.Printf(namePadding, i.StylizedNameWithRepository())
|
||||
|
||||
fmt.Printf("%s -> %s\n", fmt.Sprintf(versionPadding, left), right)
|
||||
}
|
||||
}
|
||||
|
||||
// printDownloadsFromRepo prints repository packages to be downloaded
|
||||
func printDepCatagories(dc *depCatagories) {
|
||||
func (do *depOrder) Print() {
|
||||
repo := ""
|
||||
repoMake := ""
|
||||
aur := ""
|
||||
@ -180,47 +200,47 @@ func printDepCatagories(dc *depCatagories) {
|
||||
aurLen := 0
|
||||
aurMakeLen := 0
|
||||
|
||||
for _, pkg := range dc.Repo {
|
||||
if dc.MakeOnly.get(pkg.Name()) {
|
||||
repoMake += " " + pkg.Name() + "-" + pkg.Version()
|
||||
repoMakeLen++
|
||||
} else {
|
||||
for _, pkg := range do.Repo {
|
||||
if do.Runtime.get(pkg.Name()) {
|
||||
repo += " " + pkg.Name() + "-" + pkg.Version()
|
||||
repoLen++
|
||||
} else {
|
||||
repoMake += " " + pkg.Name() + "-" + pkg.Version()
|
||||
repoMakeLen++
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range dc.Aur {
|
||||
for _, pkg := range do.Aur {
|
||||
pkgStr := " " + pkg.PackageBase + "-" + pkg.Version
|
||||
pkgStrMake := pkgStr
|
||||
|
||||
push := false
|
||||
pushMake := false
|
||||
|
||||
if len(dc.Bases[pkg.PackageBase]) > 1 || pkg.PackageBase != pkg.Name {
|
||||
if len(do.Bases[pkg.PackageBase]) > 1 || pkg.PackageBase != pkg.Name {
|
||||
pkgStr += " ("
|
||||
pkgStrMake += " ("
|
||||
|
||||
for _, split := range dc.Bases[pkg.PackageBase] {
|
||||
if dc.MakeOnly.get(split.Name) {
|
||||
pkgStrMake += split.Name + " "
|
||||
aurMakeLen++
|
||||
pushMake = true
|
||||
} else {
|
||||
for _, split := range do.Bases[pkg.PackageBase] {
|
||||
if do.Runtime.get(split.Name) {
|
||||
pkgStr += split.Name + " "
|
||||
aurLen++
|
||||
push = true
|
||||
} else {
|
||||
pkgStrMake += split.Name + " "
|
||||
aurMakeLen++
|
||||
pushMake = true
|
||||
}
|
||||
}
|
||||
|
||||
pkgStr = pkgStr[:len(pkgStr)-1] + ")"
|
||||
pkgStrMake = pkgStrMake[:len(pkgStrMake)-1] + ")"
|
||||
} else if dc.MakeOnly.get(pkg.Name) {
|
||||
aurMakeLen++
|
||||
pushMake = true
|
||||
} else {
|
||||
} else if do.Runtime.get(pkg.Name) {
|
||||
aurLen++
|
||||
push = true
|
||||
} else {
|
||||
aurMakeLen++
|
||||
pushMake = true
|
||||
}
|
||||
|
||||
if push {
|
||||
@ -247,25 +267,31 @@ func printDownloads(repoName string, length int, packages string) {
|
||||
fmt.Println(repoInfo + cyan(packages))
|
||||
}
|
||||
|
||||
func printInfoValue(str, value string) {
|
||||
fmt.Printf(bold("%-16s%s")+" %s\n", str, ":", value)
|
||||
}
|
||||
|
||||
// PrintInfo prints package info like pacman -Si.
|
||||
func PrintInfo(a *rpc.Pkg) {
|
||||
fmt.Println(bold("Repository :"), "aur")
|
||||
fmt.Println(bold("Name :"), a.Name)
|
||||
fmt.Println(bold("Version :"), a.Version)
|
||||
fmt.Println(bold("Description :"), a.Description)
|
||||
fmt.Println(bold("URL :"), a.URL)
|
||||
fmt.Println(bold("Licenses :"), strings.Join(a.License, " "))
|
||||
fmt.Println(bold("Provides :"), strings.Join(a.Provides, " "))
|
||||
fmt.Println(bold("Depends On :"), strings.Join(a.Depends, " "))
|
||||
fmt.Println(bold("Make Deps :"), strings.Join(a.MakeDepends, " "))
|
||||
fmt.Println(bold("Check Deps :"), strings.Join(a.CheckDepends, " "))
|
||||
fmt.Println(bold("Optional Deps :"), strings.Join(a.OptDepends, " "))
|
||||
fmt.Println(bold("Conflicts With :"), strings.Join(a.Conflicts, " "))
|
||||
fmt.Println(bold("Maintainer :"), a.Maintainer)
|
||||
fmt.Println(bold("Votes :"), a.NumVotes)
|
||||
fmt.Println(bold("Popularity :"), a.Popularity)
|
||||
printInfoValue("Repository", "aur")
|
||||
printInfoValue("Name", a.Name)
|
||||
printInfoValue("Version", a.Version)
|
||||
printInfoValue("Description", a.Description)
|
||||
printInfoValue("URL", a.URL)
|
||||
printInfoValue("Licenses", strings.Join(a.License, " "))
|
||||
printInfoValue("Provides", strings.Join(a.Provides, " "))
|
||||
printInfoValue("Depends On", strings.Join(a.Depends, " "))
|
||||
printInfoValue("Make Deps", strings.Join(a.MakeDepends, " "))
|
||||
printInfoValue("Check Deps", strings.Join(a.CheckDepends, " "))
|
||||
printInfoValue("Optional Deps", strings.Join(a.OptDepends, " "))
|
||||
printInfoValue("Conflicts With", strings.Join(a.Conflicts, " "))
|
||||
printInfoValue("Maintainer", a.Maintainer)
|
||||
printInfoValue("Votes", fmt.Sprintf("%d", a.NumVotes))
|
||||
printInfoValue("Popularity", fmt.Sprintf("%f", a.Popularity))
|
||||
if a.OutOfDate != 0 {
|
||||
fmt.Println(bold("Out-of-date :"), "Yes", "["+formatTime(a.OutOfDate)+"]")
|
||||
printInfoValue("Out-of-date", "Yes ["+formatTime(a.OutOfDate)+"]")
|
||||
} else {
|
||||
printInfoValue("Out-of-date", "No")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
@ -337,32 +363,37 @@ func printNumberOfUpdates() error {
|
||||
|
||||
//TODO: Make it less hacky
|
||||
func printUpdateList(parser *arguments) error {
|
||||
targets := sliceToStringSet(parser.targets)
|
||||
warnings := &aurWarnings{}
|
||||
old := os.Stdout // keep backup of the real stdout
|
||||
os.Stdout = nil
|
||||
_, _, localNames, remoteNames, err := filterPackages()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
aurUp, repoUp, err := upList(warnings)
|
||||
os.Stdout = old // restoring the real stdout
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
noTargets := len(parser.targets) == 0
|
||||
noTargets := len(targets) == 0
|
||||
|
||||
if !parser.existsArg("m", "foreigne") {
|
||||
if !parser.existsArg("m", "foreign") {
|
||||
for _, pkg := range repoUp {
|
||||
if noTargets || parser.targets.get(pkg.Name) {
|
||||
if noTargets || targets.get(pkg.Name) {
|
||||
fmt.Printf("%s %s -> %s\n", bold(pkg.Name), green(pkg.LocalVersion), green(pkg.RemoteVersion))
|
||||
delete(parser.targets, pkg.Name)
|
||||
delete(targets, pkg.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !parser.existsArg("n", "native") {
|
||||
for _, pkg := range aurUp {
|
||||
if noTargets || parser.targets.get(pkg.Name) {
|
||||
if noTargets || targets.get(pkg.Name) {
|
||||
fmt.Printf("%s %s -> %s\n", bold(pkg.Name), green(pkg.LocalVersion), green(pkg.RemoteVersion))
|
||||
delete(parser.targets, pkg.Name)
|
||||
delete(targets, pkg.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -370,7 +401,7 @@ func printUpdateList(parser *arguments) error {
|
||||
missing := false
|
||||
|
||||
outer:
|
||||
for pkg := range parser.targets {
|
||||
for pkg := range targets {
|
||||
for _, name := range localNames {
|
||||
if name == pkg {
|
||||
continue outer
|
||||
@ -394,10 +425,93 @@ outer:
|
||||
return nil
|
||||
}
|
||||
|
||||
// Formats a unix timestamp to yyyy/mm/dd
|
||||
type item struct {
|
||||
Title string `xml:"title"`
|
||||
Link string `xml:"link"`
|
||||
Description string `xml:"description"`
|
||||
PubDate string `xml:"pubDate"`
|
||||
Creator string `xml:"dc:creator"`
|
||||
}
|
||||
|
||||
func (item item) print(buildTime time.Time) {
|
||||
var fd string
|
||||
date, err := time.Parse(time.RFC1123Z, item.PubDate)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fd = formatTime(int(date.Unix()))
|
||||
if _, double, _ := cmdArgs.getArg("news", "w"); !double && !buildTime.IsZero() {
|
||||
if buildTime.After(date) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(bold(magenta(fd)), bold(strings.TrimSpace(item.Title)))
|
||||
//fmt.Println(strings.TrimSpace(item.Link))
|
||||
|
||||
if !cmdArgs.existsArg("q", "quiet") {
|
||||
desc := strings.TrimSpace(parseNews(item.Description))
|
||||
fmt.Println(desc)
|
||||
}
|
||||
}
|
||||
|
||||
type channel struct {
|
||||
Title string `xml:"title"`
|
||||
Link string `xml:"link"`
|
||||
Description string `xml:"description"`
|
||||
Language string `xml:"language"`
|
||||
Lastbuilddate string `xml:"lastbuilddate"`
|
||||
Items []item `xml:"item"`
|
||||
}
|
||||
|
||||
type rss struct {
|
||||
Channel channel `xml:"channel"`
|
||||
}
|
||||
|
||||
func printNewsFeed() error {
|
||||
resp, err := http.Get("https://archlinux.org/feeds/news")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rss := rss{}
|
||||
|
||||
d := xml.NewDecoder(bytes.NewReader(body))
|
||||
err = d.Decode(&rss)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buildTime, err := lastBuildTime()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.SortMode == BottomUp {
|
||||
for i := len(rss.Channel.Items) - 1; i >= 0; i-- {
|
||||
rss.Channel.Items[i].print(buildTime)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(rss.Channel.Items); i++ {
|
||||
rss.Channel.Items[i].print(buildTime)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Formats a unix timestamp to ISO 8601 date (yyyy-mm-dd)
|
||||
func formatTime(i int) string {
|
||||
t := time.Unix(int64(i), 0)
|
||||
return fmt.Sprintf("%d/%02d/%02d", t.Year(), int(t.Month()), t.Day())
|
||||
return t.Format("2006-01-02")
|
||||
}
|
||||
|
||||
const (
|
||||
@ -460,3 +574,61 @@ func colourHash(name string) (output string) {
|
||||
}
|
||||
return fmt.Sprintf("\x1b[%dm%s\x1b[0m", hash%6+31, name)
|
||||
}
|
||||
|
||||
func providerMenu(dep string, providers providers) *rpc.Pkg {
|
||||
size := providers.Len()
|
||||
|
||||
fmt.Print(bold(cyan(":: ")))
|
||||
str := bold(fmt.Sprintf(bold("There are %d providers available for %s:"), size, dep))
|
||||
|
||||
size = 1
|
||||
str += bold(cyan("\n:: ")) + bold("Repository AUR\n ")
|
||||
|
||||
for _, pkg := range providers.Pkgs {
|
||||
str += fmt.Sprintf("%d) %s ", size, pkg.Name)
|
||||
size++
|
||||
}
|
||||
|
||||
fmt.Println(str)
|
||||
|
||||
for {
|
||||
fmt.Print("\nEnter a number (default=1): ")
|
||||
|
||||
if config.NoConfirm {
|
||||
fmt.Println()
|
||||
break
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
numberBuf, overflow, err := reader.ReadLine()
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
break
|
||||
}
|
||||
|
||||
if overflow {
|
||||
fmt.Println("Input too long")
|
||||
continue
|
||||
}
|
||||
|
||||
if string(numberBuf) == "" {
|
||||
return providers.Pkgs[0]
|
||||
}
|
||||
|
||||
num, err := strconv.Atoi(string(numberBuf))
|
||||
if err != nil {
|
||||
fmt.Printf("%s invalid number: %s\n", red("error:"), string(numberBuf))
|
||||
continue
|
||||
}
|
||||
|
||||
if num < 1 || num > size {
|
||||
fmt.Printf("%s invalid value: %d is not between %d and %d\n", red("error:"), num, 1, size)
|
||||
continue
|
||||
}
|
||||
|
||||
return providers.Pkgs[num-1]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
83
query.go
83
query.go
@ -5,6 +5,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
alpm "github.com/jguer/go-alpm"
|
||||
rpc "github.com/mikkeloscar/aur"
|
||||
@ -158,23 +159,41 @@ func narrowSearch(pkgS []string, sortS bool) (aurQuery, error) {
|
||||
|
||||
// SyncSearch presents a query to the local repos and to the AUR.
|
||||
func syncSearch(pkgS []string) (err error) {
|
||||
aq, aurErr := narrowSearch(pkgS, true)
|
||||
pq, _, err := queryRepo(pkgS)
|
||||
if err != nil {
|
||||
return err
|
||||
pkgS = removeInvalidTargets(pkgS)
|
||||
var aurErr error
|
||||
var repoErr error
|
||||
var aq aurQuery
|
||||
var pq repoQuery
|
||||
|
||||
if mode == ModeAUR || mode == ModeAny {
|
||||
aq, aurErr = narrowSearch(pkgS, true)
|
||||
}
|
||||
if mode == ModeRepo || mode == ModeAny {
|
||||
pq, _, repoErr = queryRepo(pkgS)
|
||||
if repoErr != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if config.SortMode == BottomUp {
|
||||
aq.printSearch(1)
|
||||
pq.printSearch()
|
||||
if mode == ModeAUR || mode == ModeAny {
|
||||
aq.printSearch(1)
|
||||
}
|
||||
if mode == ModeRepo || mode == ModeAny {
|
||||
pq.printSearch()
|
||||
}
|
||||
} else {
|
||||
pq.printSearch()
|
||||
aq.printSearch(1)
|
||||
if mode == ModeRepo || mode == ModeAny {
|
||||
pq.printSearch()
|
||||
}
|
||||
if mode == ModeAUR || mode == ModeAny {
|
||||
aq.printSearch(1)
|
||||
}
|
||||
}
|
||||
|
||||
if aurErr != nil {
|
||||
fmt.Printf("Error during AUR search: %s\n", aurErr)
|
||||
fmt.Println("Showing Repo packags only")
|
||||
fmt.Println("Showing Repo packages only")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -183,6 +202,8 @@ func syncSearch(pkgS []string) (err error) {
|
||||
// SyncInfo serves as a pacman -Si for repo packages and AUR packages.
|
||||
func syncInfo(pkgS []string) (err error) {
|
||||
var info []*rpc.Pkg
|
||||
missing := false
|
||||
pkgS = removeInvalidTargets(pkgS)
|
||||
aurS, repoS, err := packageSlices(pkgS)
|
||||
if err != nil {
|
||||
return
|
||||
@ -198,6 +219,7 @@ func syncInfo(pkgS []string) (err error) {
|
||||
|
||||
info, err = aurInfoPrint(noDb)
|
||||
if err != nil {
|
||||
missing = true
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
@ -205,7 +227,8 @@ func syncInfo(pkgS []string) (err error) {
|
||||
// Repo always goes first
|
||||
if len(repoS) != 0 {
|
||||
arguments := cmdArgs.copy()
|
||||
arguments.delTarget(aurS...)
|
||||
arguments.clearTargets()
|
||||
arguments.addTarget(repoS...)
|
||||
err = passToPacman(arguments)
|
||||
|
||||
if err != nil {
|
||||
@ -213,12 +236,20 @@ func syncInfo(pkgS []string) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
if len(aurS) != 0 {
|
||||
if len(aurS) != len(info) {
|
||||
missing = true
|
||||
}
|
||||
|
||||
if len(info) != 0 {
|
||||
for _, pkg := range info {
|
||||
PrintInfo(pkg)
|
||||
}
|
||||
}
|
||||
|
||||
if missing {
|
||||
err = fmt.Errorf("")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -283,10 +314,10 @@ func packageSlices(toCheck []string) (aur []string, repo []string, err error) {
|
||||
db, name := splitDbFromName(_pkg)
|
||||
found := false
|
||||
|
||||
if db == "aur" {
|
||||
if db == "aur" || mode == ModeAUR {
|
||||
aur = append(aur, _pkg)
|
||||
continue
|
||||
} else if db != "" {
|
||||
} else if db != "" || mode == ModeRepo {
|
||||
repo = append(repo, _pkg)
|
||||
continue
|
||||
}
|
||||
@ -332,7 +363,7 @@ func hangingPackages(removeOptional bool) (hanging []string, err error) {
|
||||
// State = 2 - Keep package and have iterated over dependencies
|
||||
safePackages := make(map[string]uint8)
|
||||
// provides stores a mapping from the provides name back to the original package name
|
||||
provides := make(map[string]stringSet)
|
||||
provides := make(mapStringSet)
|
||||
packages := localDb.PkgCache()
|
||||
|
||||
// Mark explicit dependencies and enumerate the provides list
|
||||
@ -344,7 +375,7 @@ func hangingPackages(removeOptional bool) (hanging []string, err error) {
|
||||
}
|
||||
|
||||
pkg.Provides().ForEach(func(dep alpm.Depend) error {
|
||||
addMapStringSet(provides, dep.Name, pkg.Name())
|
||||
provides.Add(dep.Name, pkg.Name())
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
@ -353,7 +384,7 @@ func hangingPackages(removeOptional bool) (hanging []string, err error) {
|
||||
|
||||
iterateAgain := true
|
||||
processDependencies := func(pkg alpm.Package) error {
|
||||
if state, _ := safePackages[pkg.Name()]; state == 0 || state == 2 {
|
||||
if state := safePackages[pkg.Name()]; state == 0 || state == 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -407,6 +438,24 @@ func hangingPackages(removeOptional bool) (hanging []string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func lastBuildTime() (time.Time, error) {
|
||||
var time time.Time
|
||||
|
||||
pkgs, _, _, _, err := filterPackages()
|
||||
if err != nil {
|
||||
return time, err
|
||||
}
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
thisTime := pkg.BuildDate()
|
||||
if thisTime.After(time) {
|
||||
time = thisTime
|
||||
}
|
||||
}
|
||||
|
||||
return time, nil
|
||||
}
|
||||
|
||||
// Statistics returns statistics about packages installed in system
|
||||
func statistics() (info struct {
|
||||
Totaln int
|
||||
@ -516,7 +565,7 @@ func aurInfoPrint(names []string) ([]*rpc.Pkg, error) {
|
||||
return info, err
|
||||
}
|
||||
|
||||
warnings.Print()
|
||||
warnings.print()
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
108
upgrade.go
108
upgrade.go
@ -138,31 +138,39 @@ func upList(warnings *aurWarnings) (aurUp upSlice, repoUp upSlice, err error) {
|
||||
var aurErr error
|
||||
var develErr error
|
||||
|
||||
fmt.Println(bold(cyan("::") + bold(" Searching databases for updates...")))
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
repoUp, repoErr = upRepo(local)
|
||||
wg.Done()
|
||||
}()
|
||||
pkgdata := make(map[string]*rpc.Pkg)
|
||||
|
||||
fmt.Println(bold(cyan("::") + bold(" Searching AUR for updates...")))
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
aurUp, aurErr = upAUR(remote, remoteNames, warnings)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
if config.Devel {
|
||||
fmt.Println(bold(cyan("::") + bold(" Checking development packages...")))
|
||||
if mode == ModeAny || mode == ModeRepo {
|
||||
fmt.Println(bold(cyan("::") + bold(" Searching databases for updates...")))
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
develUp, develErr = upDevel(remote)
|
||||
repoUp, repoErr = upRepo(local)
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
if mode == ModeAny || mode == ModeAUR {
|
||||
fmt.Println(bold(cyan("::") + bold(" Searching AUR for updates...")))
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
aurUp, aurErr = upAUR(remote, remoteNames, pkgdata, warnings)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
if config.Devel {
|
||||
fmt.Println(bold(cyan("::") + bold(" Checking development packages...")))
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
develUp, develErr = upDevel(remote)
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
printLocalNewerThanAUR(remote, pkgdata)
|
||||
|
||||
errs := make([]string, 0)
|
||||
for _, e := range []error{repoErr, aurErr, develErr} {
|
||||
if e != nil {
|
||||
@ -193,8 +201,8 @@ func upList(warnings *aurWarnings) (aurUp upSlice, repoUp upSlice, err error) {
|
||||
}
|
||||
|
||||
func upDevel(remote []alpm.Package) (toUpgrade upSlice, err error) {
|
||||
toUpdate := make([]alpm.Package, 0, 0)
|
||||
toRemove := make([]string, 0, 0)
|
||||
toUpdate := make([]alpm.Package, 0)
|
||||
toRemove := make([]string, 0)
|
||||
|
||||
var mux1 sync.Mutex
|
||||
var mux2 sync.Mutex
|
||||
@ -228,9 +236,7 @@ func upDevel(remote []alpm.Package) (toUpgrade upSlice, err error) {
|
||||
|
||||
for _, pkg := range toUpdate {
|
||||
if pkg.ShouldIgnore() {
|
||||
left, right := getVersionDiff(pkg.Version(), "latest-commit")
|
||||
fmt.Print(yellow(bold(smallArrow)))
|
||||
fmt.Printf(" Ignoring package upgrade %s (%s => %s)\n", cyan(pkg.Name()), left, right)
|
||||
printIgnoringPackage(pkg, "latest-commit")
|
||||
} else {
|
||||
toUpgrade = append(toUpgrade, upgrade{pkg.Name(), "devel", pkg.Version(), "latest-commit"})
|
||||
}
|
||||
@ -242,14 +248,16 @@ func upDevel(remote []alpm.Package) (toUpgrade upSlice, err error) {
|
||||
|
||||
// upAUR gathers foreign packages and checks if they have new versions.
|
||||
// Output: Upgrade type package list.
|
||||
func upAUR(remote []alpm.Package, remoteNames []string, warnings *aurWarnings) (upSlice, error) {
|
||||
func upAUR(
|
||||
remote []alpm.Package, remoteNames []string,
|
||||
pkgdata map[string]*rpc.Pkg, warnings *aurWarnings) (upSlice, error) {
|
||||
|
||||
toUpgrade := make(upSlice, 0)
|
||||
_pkgdata, err := aurInfo(remoteNames, warnings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkgdata := make(map[string]*rpc.Pkg)
|
||||
for _, pkg := range _pkgdata {
|
||||
pkgdata[pkg.Name] = pkg
|
||||
}
|
||||
@ -263,9 +271,7 @@ func upAUR(remote []alpm.Package, remoteNames []string, warnings *aurWarnings) (
|
||||
if (config.TimeUpdate && (int64(aurPkg.LastModified) > pkg.BuildDate().Unix())) ||
|
||||
(alpm.VerCmp(pkg.Version(), aurPkg.Version) < 0) {
|
||||
if pkg.ShouldIgnore() {
|
||||
left, right := getVersionDiff(pkg.Version(), aurPkg.Version)
|
||||
fmt.Print(yellow(bold(smallArrow)))
|
||||
fmt.Printf(" Ignoring package upgrade: %s (%s => %s)\n", cyan(pkg.Name()), left, right)
|
||||
printIgnoringPackage(pkg, aurPkg.Version)
|
||||
} else {
|
||||
toUpgrade = append(toUpgrade, upgrade{aurPkg.Name, "aur", pkg.Version(), aurPkg.Version})
|
||||
}
|
||||
@ -275,6 +281,35 @@ func upAUR(remote []alpm.Package, remoteNames []string, warnings *aurWarnings) (
|
||||
return toUpgrade, nil
|
||||
}
|
||||
|
||||
func printIgnoringPackage(pkg alpm.Package, newPkgVersion string) {
|
||||
left, right := getVersionDiff(pkg.Version(), newPkgVersion)
|
||||
|
||||
fmt.Println(
|
||||
yellow(bold(smallArrow)) + fmt.Sprintf(
|
||||
" Ignoring package upgrade: %s (%s -> %s)",
|
||||
cyan(pkg.Name()), left, right))
|
||||
}
|
||||
|
||||
func printLocalNewerThanAUR(
|
||||
remote []alpm.Package, pkgdata map[string]*rpc.Pkg) {
|
||||
for _, pkg := range remote {
|
||||
aurPkg, ok := pkgdata[pkg.Name()]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
left, right := getVersionDiff(pkg.Version(), aurPkg.Version)
|
||||
|
||||
if !isDevelName(pkg.Name()) &&
|
||||
alpm.VerCmp(pkg.Version(), aurPkg.Version) > 0 {
|
||||
fmt.Println(
|
||||
yellow(bold(smallArrow)) + fmt.Sprintf(
|
||||
" Local package is newer than AUR: %s (%s -> %s)",
|
||||
cyan(pkg.Name()), left, right))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// upRepo gathers local packages and checks if they have new versions.
|
||||
// Output: Upgrade type package list.
|
||||
func upRepo(local []alpm.Package) (upSlice, error) {
|
||||
@ -289,9 +324,7 @@ func upRepo(local []alpm.Package) (upSlice, error) {
|
||||
newPkg := pkg.NewVersion(dbList)
|
||||
if newPkg != nil {
|
||||
if pkg.ShouldIgnore() {
|
||||
left, right := getVersionDiff(pkg.Version(), newPkg.Version())
|
||||
fmt.Print(yellow(bold(smallArrow)))
|
||||
fmt.Printf(" Ignoring package upgrade: %s (%s => %s)\n", cyan(pkg.Name()), left, right)
|
||||
printIgnoringPackage(pkg, newPkg.Version())
|
||||
} else {
|
||||
slice = append(slice, upgrade{pkg.Name(), newPkg.DB().Name(), pkg.Version(), newPkg.Version()})
|
||||
}
|
||||
@ -305,15 +338,24 @@ func upgradePkgs(aurUp, repoUp upSlice) (stringSet, stringSet, error) {
|
||||
ignore := make(stringSet)
|
||||
aurNames := make(stringSet)
|
||||
|
||||
if len(aurUp)+len(repoUp) == 0 {
|
||||
allUpLen := len(repoUp) + len(aurUp)
|
||||
if allUpLen == 0 {
|
||||
return ignore, aurNames, nil
|
||||
}
|
||||
|
||||
if !config.UpgradeMenu {
|
||||
for _, pkg := range aurUp {
|
||||
aurNames.set(pkg.Name)
|
||||
}
|
||||
|
||||
return ignore, aurNames, nil
|
||||
}
|
||||
|
||||
sort.Sort(repoUp)
|
||||
sort.Sort(aurUp)
|
||||
fmt.Printf("%s"+bold(" %d ")+"%s\n", bold(cyan("::")), len(aurUp)+len(repoUp), bold("Packages to upgrade."))
|
||||
repoUp.Print(len(aurUp) + 1)
|
||||
aurUp.Print(1)
|
||||
allUp := append(repoUp, aurUp...)
|
||||
fmt.Printf("%s"+bold(" %d ")+"%s\n", bold(cyan("::")), allUpLen, bold("Packages to upgrade."))
|
||||
allUp.print()
|
||||
|
||||
fmt.Println(bold(green(arrow + " Packages to not upgrade: (eg: 1 2 3, 1-3, ^4 or repo name)")))
|
||||
fmt.Print(bold(green(arrow + " ")))
|
||||
|
87
utils.go
87
utils.go
@ -1,12 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"fmt"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
const gitEmptyTree = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
|
||||
|
||||
type mapStringSet map[string]stringSet
|
||||
|
||||
type intRange struct {
|
||||
min int
|
||||
max int
|
||||
@ -49,39 +51,12 @@ func max(a, b int) int {
|
||||
return a
|
||||
}
|
||||
|
||||
func addMapStringSet(h map[string]stringSet, n string, v string) {
|
||||
_, ok := h[n]
|
||||
func (mss mapStringSet) Add(n string, v string) {
|
||||
_, ok := mss[n]
|
||||
if !ok {
|
||||
h[n] = make(stringSet)
|
||||
mss[n] = make(stringSet)
|
||||
}
|
||||
h[n].set(v)
|
||||
}
|
||||
|
||||
func addMapStringSlice(h map[string][]string, n string, v string) {
|
||||
_, ok := h[n]
|
||||
if !ok {
|
||||
h[n] = make([]string, 0, 1)
|
||||
}
|
||||
h[n] = append(h[n], v)
|
||||
}
|
||||
|
||||
func completeFileName(dir, name string) (string, error) {
|
||||
files, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(file.Name(), name) {
|
||||
return filepath.Join(dir, file.Name()), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
mss[n].set(v)
|
||||
}
|
||||
|
||||
func lessRunes(iRunes, jRunes []rune) bool {
|
||||
@ -109,3 +84,47 @@ func lessRunes(iRunes, jRunes []rune) bool {
|
||||
|
||||
return len(iRunes) < len(jRunes)
|
||||
}
|
||||
|
||||
func stringSliceEqual(a, b []string) bool {
|
||||
if a == nil && b == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < len(a); i++ {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func removeInvalidTargets(targets []string) []string {
|
||||
filteredTargets := make([]string, 0)
|
||||
|
||||
for _, target := range targets {
|
||||
db, _ := splitDbFromName(target)
|
||||
|
||||
if db == "aur" && mode == ModeRepo {
|
||||
fmt.Printf("%s %s %s\n", bold(yellow(arrow)), cyan(target), bold("Can't use target with option --repo -- skipping"))
|
||||
continue
|
||||
}
|
||||
|
||||
if db != "aur" && db != "" && mode == ModeAUR {
|
||||
fmt.Printf("%s %s %s\n", bold(yellow(arrow)), cyan(target), bold("Can't use target with option --aur -- skipping"))
|
||||
continue
|
||||
}
|
||||
|
||||
filteredTargets = append(filteredTargets, target)
|
||||
}
|
||||
|
||||
return filteredTargets
|
||||
}
|
||||
|
12
vcs.go
12
vcs.go
@ -18,7 +18,7 @@ type vcsInfo map[string]shaInfos
|
||||
type shaInfos map[string]shaInfo
|
||||
type shaInfo struct {
|
||||
Protocols []string `json:"protocols"`
|
||||
Brach string `json:"branch"`
|
||||
Branch string `json:"branch"`
|
||||
SHA string `json:"sha"`
|
||||
}
|
||||
|
||||
@ -43,7 +43,8 @@ func createDevelDB() error {
|
||||
|
||||
bases := getBases(infoMap)
|
||||
|
||||
downloadPkgBuilds(info, sliceToStringSet(remoteNames), bases)
|
||||
toSkip := pkgBuildsToSkip(info, sliceToStringSet(remoteNames))
|
||||
downloadPkgBuilds(info, bases, toSkip)
|
||||
tryParsesrcinfosFile(info, srcinfosStale, bases)
|
||||
|
||||
for _, pkg := range info {
|
||||
@ -136,6 +137,7 @@ func getCommit(url string, branch string, protocols []string) string {
|
||||
|
||||
cmd := exec.Command(config.GitBin, "ls-remote", protocol+"://"+url, branch)
|
||||
cmd.Stdout = &outbuf
|
||||
cmd.Env = append(cmd.Env, "GIT_TERMINAL_PROMPT=0")
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
@ -179,7 +181,7 @@ func (infos shaInfos) needsUpdate() bool {
|
||||
hasUpdate := make(chan struct{})
|
||||
|
||||
checkHash := func(url string, info shaInfo) {
|
||||
hash := getCommit(url, info.Brach, info.Protocols)
|
||||
hash := getCommit(url, info.Branch, info.Protocols)
|
||||
if hash != "" && hash != info.SHA {
|
||||
hasUpdate <- struct{}{}
|
||||
} else {
|
||||
@ -205,10 +207,6 @@ func (infos shaInfos) needsUpdate() bool {
|
||||
}
|
||||
}
|
||||
|
||||
func inStore(pkgName string) shaInfos {
|
||||
return savedInfo[pkgName]
|
||||
}
|
||||
|
||||
func saveVCSInfo() error {
|
||||
marshalledinfo, err := json.MarshalIndent(savedInfo, "", "\t")
|
||||
if err != nil || string(marshalledinfo) == "null" {
|
||||
|
11
vendor/github.com/jguer/go-alpm/conf.go
generated
vendored
11
vendor/github.com/jguer/go-alpm/conf.go
generated
vendored
@ -114,18 +114,14 @@ func (rdr *confReader) ParseLine() (tok iniToken, err error) {
|
||||
rdr.Lineno++
|
||||
|
||||
line = bytes.TrimSpace(line)
|
||||
|
||||
comment := bytes.IndexByte(line, '#')
|
||||
if comment >= 0 {
|
||||
line = line[:comment]
|
||||
}
|
||||
|
||||
if len(line) == 0 {
|
||||
tok.Type = tokenComment
|
||||
return
|
||||
}
|
||||
|
||||
switch line[0] {
|
||||
case '#':
|
||||
tok.Type = tokenComment
|
||||
return
|
||||
case '[':
|
||||
closing := bytes.IndexByte(line, ']')
|
||||
if closing < 0 {
|
||||
@ -205,6 +201,7 @@ lineloop:
|
||||
curRepo.Servers = append(curRepo.Servers, line.Values...)
|
||||
continue lineloop
|
||||
case "Include":
|
||||
conf.Include = append(conf.Include, line.Values[0])
|
||||
f, err := os.Open(line.Values[0])
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error while processing Include directive at line %d: %s",
|
||||
|
2
vendor/github.com/jguer/go-alpm/db.go
generated
vendored
2
vendor/github.com/jguer/go-alpm/db.go
generated
vendored
@ -89,7 +89,7 @@ func (h Handle) RegisterSyncDb(dbname string, siglevel SigLevel) (*Db, error) {
|
||||
cName := C.CString(dbname)
|
||||
defer C.free(unsafe.Pointer(cName))
|
||||
|
||||
db := C.alpm_register_syncdb(h.ptr, cName, C.alpm_siglevel_t(siglevel))
|
||||
db := C.alpm_register_syncdb(h.ptr, cName, C.int(siglevel))
|
||||
if db == nil {
|
||||
return nil, h.LastError()
|
||||
}
|
||||
|
6
vendor/github.com/jguer/go-alpm/enums.go
generated
vendored
6
vendor/github.com/jguer/go-alpm/enums.go
generated
vendored
@ -62,7 +62,7 @@ func (mod DepMod) String() string {
|
||||
}
|
||||
|
||||
// Signature checking level.
|
||||
type SigLevel uint
|
||||
type SigLevel int
|
||||
|
||||
const (
|
||||
SigPackage SigLevel = 1 << iota
|
||||
@ -76,10 +76,10 @@ const (
|
||||
SigDatabaseMarginalOk
|
||||
SigDatabaseUnknownOk
|
||||
)
|
||||
const SigUseDefault SigLevel = 1 << 31
|
||||
const SigUseDefault SigLevel = 1 << 30
|
||||
|
||||
// Signature status
|
||||
type SigStatus uint
|
||||
type SigStatus int
|
||||
|
||||
const (
|
||||
SigStatusValid SigStatus = iota
|
||||
|
6
vendor/github.com/jguer/go-alpm/handle.go
generated
vendored
6
vendor/github.com/jguer/go-alpm/handle.go
generated
vendored
@ -534,7 +534,7 @@ func (h Handle) GetDefaultSigLevel() (SigLevel, error) {
|
||||
}
|
||||
|
||||
func (h Handle) SetDefaultSigLevel(siglevel SigLevel) error {
|
||||
ok := C.alpm_option_set_default_siglevel(h.ptr, C.alpm_siglevel_t(siglevel))
|
||||
ok := C.alpm_option_set_default_siglevel(h.ptr, C.int(siglevel))
|
||||
|
||||
if ok < 0 {
|
||||
return h.LastError()
|
||||
@ -552,7 +552,7 @@ func (h Handle) GetLocalFileSigLevel() (SigLevel, error) {
|
||||
}
|
||||
|
||||
func (h Handle) SetLocalFileSigLevel(siglevel SigLevel) error {
|
||||
ok := C.alpm_option_set_local_file_siglevel(h.ptr, C.alpm_siglevel_t(siglevel))
|
||||
ok := C.alpm_option_set_local_file_siglevel(h.ptr, C.int(siglevel))
|
||||
|
||||
if ok < 0 {
|
||||
return h.LastError()
|
||||
@ -570,7 +570,7 @@ func (h Handle) GetRemoteFileSigLevel() (SigLevel, error) {
|
||||
}
|
||||
|
||||
func (h Handle) SetRemoteFileSigLevel(siglevel SigLevel) error {
|
||||
ok := C.alpm_option_set_remote_file_siglevel(h.ptr, C.alpm_siglevel_t(siglevel))
|
||||
ok := C.alpm_option_set_remote_file_siglevel(h.ptr, C.int(siglevel))
|
||||
|
||||
if ok < 0 {
|
||||
return h.LastError()
|
||||
|
10
vendor/github.com/jguer/go-alpm/package.go
generated
vendored
10
vendor/github.com/jguer/go-alpm/package.go
generated
vendored
@ -159,18 +159,16 @@ func (pkg Package) OptionalDepends() DependList {
|
||||
}
|
||||
|
||||
// Depends returns the package's check dependency list.
|
||||
//Exists in futre alpm
|
||||
/*func (pkg Package) CheckDepends() DependList {
|
||||
func (pkg Package) CheckDepends() DependList {
|
||||
ptr := unsafe.Pointer(C.alpm_pkg_get_checkdepends(pkg.pmpkg))
|
||||
return DependList{(*list)(ptr)}
|
||||
}*/
|
||||
}
|
||||
|
||||
// Depends returns the package's make dependency list.
|
||||
//Exists in futre alpm
|
||||
/*func (pkg Package) MakeDepends() DependList {
|
||||
func (pkg Package) MakeDepends() DependList {
|
||||
ptr := unsafe.Pointer(C.alpm_pkg_get_makedepends(pkg.pmpkg))
|
||||
return DependList{(*list)(ptr)}
|
||||
}*/
|
||||
}
|
||||
|
||||
// Description returns the package's description.
|
||||
func (pkg Package) Description() string {
|
||||
|
5
vendor/github.com/mikkeloscar/aur/aur.go
generated
vendored
5
vendor/github.com/mikkeloscar/aur/aur.go
generated
vendored
@ -7,7 +7,8 @@ import (
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const aurURL = "https://aur.archlinux.org/rpc.php?"
|
||||
//AURURL is the base string from which the query is built
|
||||
var AURURL = "https://aur.archlinux.org/rpc.php?"
|
||||
|
||||
type response struct {
|
||||
Error string `json:"error"`
|
||||
@ -46,7 +47,7 @@ type Pkg struct {
|
||||
|
||||
func get(values url.Values) ([]Pkg, error) {
|
||||
values.Set("v", "5")
|
||||
resp, err := http.Get(aurURL + values.Encode())
|
||||
resp, err := http.Get(AURURL + values.Encode())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
2
vendor/github.com/mikkeloscar/gopkgbuild/lex.go
generated
vendored
2
vendor/github.com/mikkeloscar/gopkgbuild/lex.go
generated
vendored
@ -211,6 +211,8 @@ func lexEnv(l *lexer) stateFn {
|
||||
}
|
||||
case r == '\t':
|
||||
l.ignore()
|
||||
case r == ' ':
|
||||
l.ignore()
|
||||
case r == '#':
|
||||
return lexComment
|
||||
default:
|
||||
|
2
vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild.go
generated
vendored
2
vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild.go
generated
vendored
@ -616,7 +616,7 @@ func isLowerAlpha(c rune) bool {
|
||||
|
||||
// check if c is a valid pkgname char
|
||||
func isValidPkgnameChar(c rune) bool {
|
||||
return isLowerAlpha(c) || isDigit(c) || c == '@' || c == '.' || c == '_' || c == '+' || c == '-'
|
||||
return isAlphaNumeric(c) || c == '@' || c == '.' || c == '_' || c == '+' || c == '-'
|
||||
}
|
||||
|
||||
// check if c is a valid pkgver char
|
||||
|
27
vendor/github.com/mikkeloscar/gopkgbuild/version.go
generated
vendored
27
vendor/github.com/mikkeloscar/gopkgbuild/version.go
generated
vendored
@ -74,33 +74,18 @@ func NewCompleteVersion(s string) (*CompleteVersion, error) {
|
||||
return nil, fmt.Errorf("invalid version format: %s", s)
|
||||
}
|
||||
|
||||
// Older returns true if a is older than the argument version string
|
||||
func (a *CompleteVersion) Older(v string) bool {
|
||||
b, err := NewCompleteVersion(v)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Older returns true if a is older than the argument version
|
||||
func (a *CompleteVersion) Older(b *CompleteVersion) bool {
|
||||
return a.cmp(b) == -1
|
||||
}
|
||||
|
||||
// Newer returns true if a is newer than the argument version string
|
||||
func (a *CompleteVersion) Newer(v string) bool {
|
||||
b, err := NewCompleteVersion(v)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Newer returns true if a is newer than the argument version
|
||||
func (a *CompleteVersion) Newer(b *CompleteVersion) bool {
|
||||
return a.cmp(b) == 1
|
||||
}
|
||||
|
||||
// Equal returns true if a is equal to the argument version string
|
||||
func (a *CompleteVersion) Equal(v string) bool {
|
||||
b, err := NewCompleteVersion(v)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Equal returns true if a is equal to the argument version
|
||||
func (a *CompleteVersion) Equal(b *CompleteVersion) bool {
|
||||
return a.cmp(b) == 0
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user