JustinTimperio / pacback

Advanced Version Control for Arch Linux
MIT License
148 stars 4 forks source link

Bad offered packages version order #15

Open mirh opened 4 years ago

mirh commented 4 years ago

Describe the Bug:\ 10 seems understood as lesser than 6

Output of Command Example, this is fine:

(1) xfce4-wavelan-plugin-0.6.0-1
(2) xfce4-wavelan-plugin-0.6.0-2
(3) xfce4-wavelan-plugin-0.6.1-1

Example, this is bad

(1) xfce4-weather-plugin-0.10.0-1
(2) xfce4-weather-plugin-0.8.10-1
(3) xfce4-weather-plugin-0.8.11-1

Machine:

JustinTimperio commented 4 years ago

This is not really a bug. Pacback does its best to sort the output but there is no guarantee that it will be able to perfectly sort the output. The sort function is called here...

    '''Lets a user select between an arbitrary number of options.
    Returns value the user selects. Input `exit` or `quit` to return False.'''
    ordered_list = sorted(list(options))
    counter = 1
    while True:
        for o in ordered_list:
            print('(' + str(counter) + ') ' + o)
            counter += 1
        ans = input('\033[1m' + 'Enter Your Selection With an INT: ' + '\033[0m').strip()

        if re.findall(r'^([1-9]|0[1-9]|[1-9][0-9]|[1-9][1-9][0-9])$', ans):
            if int(ans) < counter:
                return ordered_list[int(ans) - 1]
        elif ans.strip() == 'exit' or 'quit':
            return False
        else:
            counter = 1
            print('No Validate INT Given!')

If you want to figure out how to fix ordered_list = sorted(list(options)) so that it always orders versions correctly be my guest but I don't really have time to fix such a minor issue currently.

mirh commented 4 years ago

Np, no hurry. Of the different python version compare ideas I saw, I feel like comparing tuples is the simplest one then (taking into consideration of epochs perhaps?).

JustinTimperio commented 4 years ago

So I have looked at ordering in that way but versions are embedded in the filename which makes them extremely difficult to trim effectively. Unfortunately, version naming conventions are pretty arbitrary and don't always follow guidelines. A search of a filesystem will return:

/var/lib/pacback/restore-points/rp10/pac_cache/typescript-3.7.4-1-any.pkg.tar.xz
/var/lib/pacback/restore-points/rp10/pac_cache/typescript-3.7.3-1-any.pkg.tar.xz
/var/lib/pacback/restore-points/rp10/pac_cache/typescript-3.7.2-1-any.pkg.tar.xz

Which trims to:

(1) typescript-3.7.4-1
(2) typescript-3.7.3-1
(3) typescript-3.7.2-1

From here I could try and convert each package name into a tuple or list to parse version but this has a lot of issues. For instance, look at these potential package versions it would need to parse:

signon-ui-0.17+20150611-2
rtmpdump-1:2.4.r96.fa8646d-5
numix-icon-theme-git-0.r1988.6276c6896-1
mobile-broadband-provider-info-20190618-1
libtool-2.4.6+42+gb88cebd5-8
adobe-source-code-pro-fonts-2.030ro+1.050it-5
re2-20200101-1
wxgtk2-3.0.4-2
x264-3:0.157.r2980.34c06d1-2
x265-3.2.1-1

I honestly can't begin to explain how much of a nightmare these formats are. The best I have been able to do so far is : r = re.split("\d+-\d+|\d+(?:\.\d+)+|\d:\d+(?:\.\d+)+", p)[0] This does the job 90% of the time but dealing with the exceptions is nearly impossible. Maybe someone smarter than me has figured this out but I'm stuck.

I've moved all the relevant sorting into pacback itself so you can see the code here:

#<#><#><#><#><#><#>#<#>#<#
#<># Rollback Packages
#<#><#><#><#><#><#>#<#>#<#

def user_pkg_search(search_pkg, cache):
    '''Provides more accurate searches for single pkg names without a version.'''
    pkgs = trim_pkg_list(cache)
    found = set()

    for p in pkgs:
        r = re.split("\d+-\d+|\d+(?:\.\d+)+|\d:\d+(?:\.\d+)+", p)[0]
        if r.strip()[-1] == '-':
            x = r.strip()[:-1]
        else:
            x = r
        if re.fullmatch(re.escape(search_pkg.lower().strip()), x):
            found.add(p)

    if not found:
        PS.prError('No Packages Found!')
        if PS.YN_Frame('Do You Want to Extend the Regex Search?') is True:
            for p in pkgs:
                if re.findall(re.escape(search_pkg.lower().strip()), p):
                    found.add(p)

    return found

def rollback_packages(pkg_list):
    '''Allows User to Rollback Any Number of Packages By Name'''
    PS.Start_Log('RbPkgs', log_file)
    PS.prWorking('Searching File System for Packages...')
    cache = fetch_paccache()
    pkg_paths = list()
    PS.Write_To_Log('UserSearch', 'Started Search for ' + ' '.join(pkg_list), log_file)

    for pkg in pkg_list:
        found_pkgs = user_pkg_search(pkg, cache)
        sort_pkgs = sorted(found_pkgs, reverse=True)

        if len(found_pkgs) > 0:
            PS.Write_To_Log('UserSearch', 'Found ' + str(len(found_pkgs)) + ' pkgs for ' + pkg, log_file)
            PS.prSuccess('Pacback Found the Following Package Versions for ' + pkg + ':')
            answer = PS.Multi_Choice_Frame(sort_pkgs)

            if answer is False:
                PS.Write_To_Log('UserSearch', 'User Force Exited Selection For ' + pkg, log_file)
            else:
                for x in cache:
                    if re.findall(re.escape(answer), x):
                        path = x
                        pkg_paths.append(path)
                        break

        else:
            PS.prError('No Packages Found Under the Name: ' + pkg)
            PS.Write_To_Log('UserSearch', 'Search ' + pkg.upper() + ' Returned Zero Results', log_file)

    PS.pacman(' '.join(pkg_paths), '-U')
    PS.Write_To_Log('UserSearch', 'Sent ' + ' '.join(pkg_paths) + ' to Pacman -U', log_file)
    PS.End_Log('RbPkgs', log_file)
mirh commented 4 years ago

The rule in my mind is pretty simple actually (then please, by all means, don't spend too much time on this if it becomes crazy in practice.. btw your regex guessing wrongly spelt packages is amazing)

Put aside the optionally leading : and the always trailing -, just make a new item in the tuple every time you match a dot? If the version is fucked up, it's not like you can be expected to differentiate between git revisions.

Put even aside that hypens and colons are even disallowed by the spec in pkgver, so in theory you could even treat them like normal separators.