diff options
author | Mike Frysinger <vapier@gentoo.org> | 2014-01-19 23:38:10 -0500 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2014-01-19 23:38:10 -0500 |
commit | 840bf7e8df3c86e161f7855a37b008b5cf16f2d8 (patch) | |
tree | de84133e0ace57b86d6f7c6ffeba2d3202f8077b | |
parent | Fix echangelog test (diff) | |
download | gentoolkit-840bf7e8df3c86e161f7855a37b008b5cf16f2d8.tar.gz gentoolkit-840bf7e8df3c86e161f7855a37b008b5cf16f2d8.tar.bz2 gentoolkit-840bf7e8df3c86e161f7855a37b008b5cf16f2d8.zip |
ekeyword: rewrite in python
A clean rewrite from scratch with unittests all that goodness.
URL: https://bugs.gentoo.org/267565
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/ekeyword/AUTHORS | 12 | ||||
-rw-r--r-- | src/ekeyword/ChangeLog | 46 | ||||
-rw-r--r-- | src/ekeyword/Makefile | 20 | ||||
-rw-r--r-- | src/ekeyword/README | 14 | ||||
-rwxr-xr-x | src/ekeyword/ekeyword | 246 | ||||
-rw-r--r-- | src/ekeyword/ekeyword.pod | 68 | ||||
-rwxr-xr-x | src/ekeyword/ekeyword.py | 433 | ||||
-rwxr-xr-x | src/ekeyword/ekeyword_unittest.py | 368 | ||||
-rw-r--r-- | src/ekeyword/tests/process-1.ebuild | 5 | ||||
l--------- | src/ekeyword/tests/profiles/arch-only/profiles/arch.list | 1 | ||||
-rw-r--r-- | src/ekeyword/tests/profiles/both/profiles/arch.list | 45 | ||||
-rw-r--r-- | src/ekeyword/tests/profiles/both/profiles/profiles.desc | 295 | ||||
-rw-r--r-- | src/ekeyword/tests/profiles/none/profiles/.keep | 0 | ||||
l--------- | src/ekeyword/tests/profiles/profiles-only/profiles/profiles.desc | 1 | ||||
-rwxr-xr-x | src/ekeyword2/ekeyword2 | 96 |
16 files changed, 1171 insertions, 480 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/src/ekeyword/AUTHORS b/src/ekeyword/AUTHORS index 3605b38..353a45e 100644 --- a/src/ekeyword/AUTHORS +++ b/src/ekeyword/AUTHORS @@ -1,6 +1,10 @@ -Christian Ruppert <idl0r@gentoo.org> -Paul Varner <fuzzyray@gentoo.org> -Mike Frysinger <vapier@gentoo.org> +Current python version: + Mike Frysinger <vapier@gentoo.org> + +Previous perl version: + Christian Ruppert <idl0r@gentoo.org> + Paul Varner <fuzzyray@gentoo.org> + Mike Frysinger <vapier@gentoo.org> Original author: -Aron Griffis <agriffis@gentoo.org> + Aron Griffis <agriffis@gentoo.org> diff --git a/src/ekeyword/ChangeLog b/src/ekeyword/ChangeLog deleted file mode 100644 index 68d99e5..0000000 --- a/src/ekeyword/ChangeLog +++ /dev/null @@ -1,46 +0,0 @@ -24 Apr 2009 Paul Varner <fuzzyray@gentoo.org> - * Handle multiline KEYWORDS - -07 Jan 2009 Mike Frysinger <vapier@gentoo.org> - * Support intended KEYWORDS - * Convert every instance of KEYWORDS in the file - * Error out on invalid arguments #156827 - * Tighten up diff output to show KEYWORDS changes - -27 Oct 2005 Aron Griffis <agriffis@gentoo.org> - * Fix handling of comments - * Add support for bare ~ as a synonym for ~all - -23 Mar 2005 Aron Griffis <agriffis@gentoo.org> - * Only modify non-masked keywords with "all" - -17 Mar 2005 Aron Griffis <agriffis@gentoo.org> - * Sort keywords alphabetically - -09 Nov 2004 Aron Griffis <agriffis@gentoo.org> - * Fix mismatching of ppc vs. ppc-macos #69683 - -15 Sep 2004 Aron Griffis <agriffis@gentoo.org> - * Update for GLEP 22 keywords - * Change copyright line for Gentoo Foundation - -12 Apr 2004 Aron Griffis <agriffis@gentoo.org> - * Add ability to remove keywords with ^, for example: - ekeyword ^alpha blah.ebuild - * Add support for -*, for example: ekeyword -* would add it; - ekeyword ^* would remove it. - * Add a man-page for ekeyword - -09 Apr 2004 Aron Griffis <agriffis@gentoo.org> - * Add ability to modify all keywords via all, ~all, or -all, for - example: ekeyword -all ~alpha ia64 blah.ebuild - -31 Mar 2004 Aron Griffis <agriffis@gentoo.org> - * Fix bug 28426 with patch from Mr_Bones_ to keep ekeyword from confusing - ppc and ppc64 - -2004-01-12 Aron Griffis <agriffis@gentoo.org> - * Allow multiple keywords - -2004-01-07 Karl Trygve Kalleberg <karltk@gentoo.org> - * Added Makefile diff --git a/src/ekeyword/Makefile b/src/ekeyword/Makefile index da0116a..cfa1a06 100644 --- a/src/ekeyword/Makefile +++ b/src/ekeyword/Makefile @@ -6,21 +6,15 @@ include ../../makedefs.mak -%.1 : %.pod - pod2man $< > $@ +.PHONY: all clean dist +all: -.PHONY: all -all: ekeyword.1 - -dist: ekeyword.1 +dist: mkdir -p ../../$(DISTDIR)/src/ekeyword - cp Makefile AUTHORS README ChangeLog ekeyword ekeyword.1 ../../$(DISTDIR)/src/ekeyword/ + cp Makefile AUTHORS README ekeyword.py ekeyword_unittest.py \ + ../../$(DISTDIR)/src/ekeyword/ install: all - install -m 0755 ekeyword $(BINDIR)/ + install -m 0755 ekeyword.py $(BINDIR)/ekeyword install -d $(DOCDIR)/ekeyword - install -m 0644 AUTHORS README ChangeLog $(DOCDIR)/ekeyword/ - install -m 0644 ekeyword.1 $(MAN1DIR)/ - -clean: - $(RM) ekeyword.1 + install -m 0644 AUTHORS README $(DOCDIR)/ekeyword/ diff --git a/src/ekeyword/README b/src/ekeyword/README index ec7ff5e..b147e4a 100644 --- a/src/ekeyword/README +++ b/src/ekeyword/README @@ -1,5 +1,5 @@ Package : ekeyword -Version : 0.1.0 +Version : 1.0 Author : See AUTHORS MOTIVATION @@ -12,9 +12,9 @@ N/A IMPROVEMENTS -- Should rewrite to Python, and use Portage directly to select candidate - ebuilds. -- Should add entry to ChangeLog. - -For improvements, send a mail to agriffis@gentoo.org or make out a bug at -bugs.gentoo.org. +- Should we allow users to pass in */-*/~*? +- Should we collapse multiple globs into one. +- Should we support multiline KEYWORDS values? No... +- Support autodetection of ~user homedir expansions. + e.g. If "arm" is a user, then "~arm" will be passed in as "/home/arm". + We should catch that and normalize it back to "~arm". diff --git a/src/ekeyword/ekeyword b/src/ekeyword/ekeyword deleted file mode 100755 index 33ebb4f..0000000 --- a/src/ekeyword/ekeyword +++ /dev/null @@ -1,246 +0,0 @@ -#!/usr/bin/perl -w -# -# Copyright 2003-2010, Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 -# Written by Aron Griffis <agriffis@gentoo.org> -# -# ekeyword: Update the KEYWORDS in an ebuild. For example: -# -# $ ekeyword ~alpha oaf-0.6.8-r1.ebuild -# - ppc sparc x86 -# + ~alpha ppc sparc x86 - -use strict; - -my ($kw_re) = '^(?:([-~^]?)(\w[\w-]*)|([-^]\*))$'; -my (@kw); - -my $PORTDIR = undef; -my %ARCH = (); - -sub file_parse { - my $fname = shift; - my @content = (); - - if ( ! -r $fname ) { - printf STDERR ("Error: File '%s' doesn't exist or is not readable!\n", $fname); - exit(1); - } - - open(my $fh, '<', $fname); - while(defined(my $line = <$fh>)) { - chomp($line); - $line =~ s/^\s*//g; - $line =~ s/\s*$//g; - $line =~ s/\s+/ /g; - next if length($line) eq 0; - - next if $line =~ m/^#/; - - push(@content, $line); - } - close($fh); - - return @content; -} - -sub get_portdir { - open(my $ph, '-|', 'portageq portdir'); - chomp(my $portdir = <$ph>); - close($ph); - - if (length($portdir) eq 0) { - printf STDERR ("Error: Couldn't determine your PORTDIR...\n"); - exit(1); - } - return $portdir; -} - -sub get_architectures { - foreach my $arch (file_parse("${PORTDIR}/profiles/arch.list")) { - $ARCH{$arch} = 0; - } -} - -sub get_architectures_status { - foreach my $line (file_parse("${PORTDIR}/profiles/profiles.desc")) { - my ($arch, undef, $status) = split(/\s/, $line, 3); - - if(defined($ARCH{$arch})) { - $ARCH{$arch} = 1 if $status eq "dev" and $ARCH{$arch} < 3; # Don't override stable - $ARCH{$arch} = 2 if $status eq "exp" and $ARCH{$arch} < 3; # Don't override stable - $ARCH{$arch} = 3 if $status eq "stable"; - } - } -} - -# make sure the cmdline consists of keywords and ebuilds -unless (@ARGV > 0) { - # NOTE: ~all will ignore all -arch keywords - print STDERR "syntax: ekeyword { arch | ~[arch] | -[arch] } ebuild...\n"; - print STDERR "instead of 'arch' you can also use 'all' which covers all existing keywords...\n"; - exit(1); -} -for my $a (@ARGV) { - $a = '~all' if $a eq '~' or $a eq $ENV{'HOME'}; # for vapier - next if $a =~ /$kw_re/o; # keyword - next if $a =~ /^\S+\.ebuild$/; # ebuild - die "I don't understand $a\n"; -} - -$PORTDIR = get_portdir(); -get_architectures(); -get_architectures_status(); - -my $files = 0; -my $line; -for my $f (@ARGV) { - if ($f =~ m/$kw_re/o) { - my $arch = $2; - - if(length($arch) > 0 && $arch ne "all") { - if(!defined($ARCH{$arch})) { - printf STDERR ("'%s' is an unknown architecture! skipping...\n", $arch); - next; - } - } - - push(@kw, $f); - next; - } - - print "$f\n"; - - open(my $fh_in, "<", $f) or die "Can't read $f: $!\n"; - open(my $fh_out, ">", "${f}.new") or die "Can't create ${f}.new: ${!}\n"; - - my $count = 0; - while($line = <$fh_in>) { - $count++ if $line =~ m/^\s*KEYWORDS=/; - } - seek($fh_in, 0, 0); - - while ($line = <$fh_in>) { - if ($line =~ m/^\s*KEYWORDS=/) { - - # extract the quoted section from KEYWORDS - while ($line !~ m/^\s*KEYWORDS=["'](?:.+)?["']/) { - chomp($line); - my $next = <$fh_in>; - $line = join(" ", $line, $next); - } - (my $quoted = $line) =~ s/^.*?["'](.*?)["'].*/$1/s; - - if($count > 1 && length($quoted) eq 0) { - # Skip empty KEYWORDS variables in case they occur more than - # once, bug 321475. - print $fh_out $line; - next; - } - - # replace -* with -STAR for our convenience below - $quoted =~ s/-\*/-STAR/; - - # Pre sort/unique - # NOTE: It will not detect duplicates where one is e.g. ~amd64 and - # one amd64 - my %hash = map { $_, 1 } split(/\s+/, $quoted); - $quoted = join(" ", keys(%hash)); - - for my $k (@kw) { - my ($leader, $arch, $star) = ($k =~ /$kw_re/o); - - # handle -* and ^* - if (defined $star) { - $leader = substr($star, 0, 1); - $arch = 'STAR'; - } - - # remove keywords - if ($leader eq '^') { - if ($arch eq 'all') { - $quoted = ''; - } else { - $quoted =~ s/[-~]?\Q$arch\E(\s|$)/$1/; - } - - # add or modify keywords - } else { - if ($arch eq 'all') { - # modify all non-masked keywords in the list - - # Don't add stable keywords for != stable architectures - if(length($leader) eq 0) { - my @new; - foreach my $tmp (split(/\s/, $quoted)) { - my ($_leader, $_arch, undef) = ($tmp =~ m/$kw_re/o); - $_leader = "" if !defined($_leader); - $_arch = "" if !defined($_arch); - - if($_leader eq "~" && ($ARCH{$_arch} && $ARCH{$_arch} eq 3) ) { - push(@new, $_arch); - next; - } - else { - push(@new, "${_leader}${_arch}"); - next; - } - } - $quoted = join(" ", @new); - } - else { - $quoted =~ s/(^|\s)~?(?=\w)/$1$leader/g; - } - } else { - # modify or add keyword - unless ($quoted =~ s/[-~]?\Q$arch\E(\s|$)/$leader$arch$1/) { - # modification failed, need to add - if ($arch eq 'STAR') { - $quoted = "$leader$arch $quoted"; - } else { - $quoted .= " $leader$arch"; - } - } - } - } - } - - # replace -STAR with -* - $quoted =~ s/-STAR\b/-*/; - - # sort keywords and fix spacing - $quoted = join " ", sort { - (my $sa = $a) =~ s/^\W//; - (my $sb = $b) =~ s/^\W//; - return -1 if $sa eq '*'; - return +1 if $sb eq '*'; - $sa .= "-"; - $sb .= "-"; - $sa =~ s/([a-z0-9]+)-([a-z0-9]*)/$2-$1/g; - $sb =~ s/([a-z0-9]+)-([a-z0-9]*)/$2-$1/g; - $sa cmp $sb; - } split(/\s+/, $quoted); - - # re-insert quoted to KEYWORDS - $line =~ s/(["']).*?["']/$1$quoted$1/; - - print $fh_out $line or die "Can't write $f.new: $!\n"; - } else { - print $fh_out $line; - next; - } - } - - close($fh_in); - close($fh_out); - - system("diff -U 0 ${f} ${f}.new"); - rename("$f.new", "$f") or die "Can't rename: $!\n"; - $files++; -} - -if ($files == 0) { - die "No ebuilds processed!"; -} - -# vim:ts=4 sw=4 diff --git a/src/ekeyword/ekeyword.pod b/src/ekeyword/ekeyword.pod deleted file mode 100644 index ff837b9..0000000 --- a/src/ekeyword/ekeyword.pod +++ /dev/null @@ -1,68 +0,0 @@ -=head1 NAME - -ekeyword - Gentoo: modify package KEYWORDS - -=head1 SYNOPSIS - -ekeyword { arch|~arch|-arch|^arch } ebuild... - -=head1 DESCRIPTION - -This tool provides a simple way to add or update KEYWORDS in a set of -ebuilds. Each command-line argument is processed in order, so that -keywords are added to the current list as they appear, and ebuilds are -processed as they appear. - -Instead of specifying a specific arch, it's possible to use the word -"all". This causes the change to apply to all keywords presently -specified in the ebuild. - -The ^ leader instructs ekeyword to remove the specified arch. - -=head1 OPTIONS - -Presently ekeyword is simple enough that it supplies no options. -Probably I'll add B<--help> and B<--version> in the future, but for -now it's enough to track the gentoolkit version. - -=head1 EXAMPLES - -To mark a single arch stable: - - $ ekeyword alpha metalog-0.7-r1.ebuild - metalog-0.7-r1.ebuild - -KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86" - +KEYWORDS="alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86" - -When bumping a package, to mark all arches for testing: - - $ ekeyword ~all metalog-0.7-r2.ebuild - metalog-0.7-r2.ebuild - -KEYWORDS="alpha amd64 hppa ia64 mips ppc sparc x86" - +KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86" - -To signify that a package is broken for all arches except one: - - $ ekeyword ^all -* ~x86 metalog-0.7-r3.ebuild - metalog-0.7-r3.ebuild - -KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86" - +KEYWORDS="-* ~x86" - -To do lots of things at once: - - $ ekeyword alpha metalog-0.7-r1.ebuild \ - ~all metalog-0.7-r2.ebuild ^all -* ~x86 metalog-0.7-r3.ebuild - metalog-0.7-r1.ebuild - -KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86" - +KEYWORDS="alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86" - metalog-0.7-r2.ebuild - -KEYWORDS="alpha amd64 hppa ia64 mips ppc sparc x86" - +KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86" - metalog-0.7-r3.ebuild - -KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86" - +KEYWORDS="-* ~x86" - -=head1 NOTES - -This tool was written by Aron Griffis <agriffis@gentoo.org>. Bugs -found should be filed against me at http://bugs.gentoo.org/ diff --git a/src/ekeyword/ekeyword.py b/src/ekeyword/ekeyword.py new file mode 100755 index 0000000..37a25ee --- /dev/null +++ b/src/ekeyword/ekeyword.py @@ -0,0 +1,433 @@ +#!/usr/bin/python +# Copyright 2014 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# Written by Mike Frysinger <vapier@gentoo.org> + +"""Manage KEYWORDS in ebuilds easily. + +This tool provides a simple way to add or update KEYWORDS in a set of ebuilds. +Each command-line argument is processed in order, so that keywords are added to +the current list as they appear, and ebuilds are processed as they appear. + +Instead of specifying a specific arch, it's possible to use the word "all". +This causes the change to apply to all keywords presently specified in the +ebuild. + +The ^ leader instructs ekeyword to remove the specified arch. + +Examples: + + # Mark all existing arches in the ebuild as stable. + $ ekeyword all foo-1.ebuild + + # Mark arm as stable and x86 as unstable. + $ ekeyword arm ~x86 foo-1.ebuild + + # Mark hppa as unsupported (explicitly adds -hppa). + $ ekeyword -hppa foo-1.ebuild + + # Delete alpha keywords from all ebuilds. + $ ekeyword ^alpha *.ebuild + + # Mark sparc as stable for foo-1 and m68k as unstable for foo-2. + $ ekeyword sparc foo-1.ebuild ~m68k foo-2.ebuild + + # Mark s390 as the same state as amd64. + $ ekeyword s390=amd64 foo-1.ebuild +""" + +from __future__ import print_function + +import argparse +import collections +import difflib +import os +import re +import sys + +import portage +from portage.output import colorize, nocolor + + +VERSION = '1.0 awesome' + +Op = collections.namedtuple('Op', ('op', 'arch', 'ref_arch')) + + +def keyword_to_arch(keyword): + """Given a keyword, strip it down to its arch value + + When an ARCH shows up in KEYWORDS, it may have prefixes like ~ or -. + Strip all that cruft off to get back to the ARCH. + """ + return keyword.lstrip('-~') + + +def sort_keywords(arches): + """Sort |arches| list in the order developers expect""" + keywords = [] + + # Globs always come first. + for g in ('-*', '*', '~*'): + if g in arches: + arches.remove(g) + keywords.append(g) + + def arch_cmp(a1, a2): + # Sort independent of leading marker (~ or -). + a1 = keyword_to_arch(a1) + a2 = keyword_to_arch(a2) + + # If a keyword has a "-" in it, then it always comes after ones + # that do not. We want things like alpha/mips/sparc showing up + # before amd64-fbsd and amd64-linux. + if '-' in a1 and not '-' in a2: + return 1 + elif '-' not in a1 and '-' in a2: + return -1 + else: + return cmp(a1, a2) + + keywords += sorted(arches, cmp=arch_cmp) + + return keywords + + +def diff_keywords(old_keywords, new_keywords, format='color-inline'): + """Show pretty diff between list of keywords""" + def show_diff(s): + output = '' + + for tag, i0, i1, j0, j1 in s.get_opcodes(): + + if tag == 'equal': + output += s.a[i0:i1] + + if tag in ('delete', 'replace'): + o = s.a[i0:i1] + if format == 'color-inline': + o = colorize('bg_darkred', o) + else: + o = '-{%s}' % o + output += o + + if tag in ('insert', 'replace'): + o = s.b[j0:j1] + if format == 'color-inline': + o = colorize('bg_darkgreen', o) + else: + o = '+{%s}' % o + output += o + + return output + + sold = ' '.join(old_keywords) + snew = ' '.join(new_keywords) + s = difflib.SequenceMatcher(str.isspace, sold, snew, autojunk=False) + return show_diff(s) + + +def process_keywords(keywords, ops, arch_status=None): + """Process |ops| for |keywords|""" + new_keywords = set(keywords).copy() + + # Process each op one at a time. + for op, oarch, refarch in ops: + # Figure out which keywords we need to modify. + if oarch == 'all': + if not arch_status: + raise ValueError('unable to process "all" w/out profiles.desc') + old_arches = set([keyword_to_arch(a) for a in new_keywords]) + if op is None: + # Process just stable keywords. + arches = [k for k, v in arch_status.items() + if v == 'stable' and k in old_arches] + else: + # Process all possible keywords. We use the arch_status as a + # master list. If it lacks some keywords, then we might miss + # somethings here, but not much we can do. + arches = set(arch_status.keys()) | old_arches + else: + arches = (oarch,) + + if refarch: + # Figure out the state for this arch based on the reference arch. + # TODO: Add support for "all" keywords. + # XXX: Should this ignore the '-' state ? Does it make sense to + # sync e.g. "s390" to "-ppc" ? + refkeyword = [x for x in new_keywords if refarch == keyword_to_arch(x)] + if not refkeyword: + op = '^' + elif refkeyword[0].startswith('~'): + op = '~' + elif refkeyword[0].startswith('-'): + op = '-' + else: + op = None + + # Finally do the actual update of the keywords list. + for arch in arches: + new_keywords -= set(['%s%s' % (x, arch) for x in ('', '~', '-')]) + + if op is None: + new_keywords.add(arch) + elif op in ('~', '-'): + new_keywords.add('%s%s' % (op, arch)) + elif op == '^': + # Already deleted. Whee. + pass + else: + raise ValueError('unknown operation %s' % op) + + return new_keywords + + +def process_content(ebuild, data, ops, arch_status=None, verbose=False, + quiet=False, format='color-inline'): + """Process |ops| for |data|""" + # Set up the user display style based on verbose/quiet settings. + if verbose: + disp_name = ebuild + def logit(msg): + print('%s: %s' % (disp_name, msg)) + elif quiet: + def logit(msg): + pass + else: + # Chop the full path and the .ebuild suffix. + disp_name = os.path.basename(ebuild)[:-7] + def logit(msg): + print('%s: %s' % (disp_name, msg)) + + # Match any KEYWORDS= entry that isn't commented out. + keywords_re = re.compile(r'^([^#]*\bKEYWORDS=)([\'"])(.*)(\2)(.*)') + updated = False + content = [] + + # Walk each line of the ebuild looking for KEYWORDS to process. + for line in data: + m = keywords_re.match(line) + if not m: + content.append(line) + continue + + # Ok, we've got it, now let's process things. + old_keywords = set(m.group(3).split()) + new_keywords = process_keywords( + old_keywords, ops, arch_status=arch_status) + + # Finally let's present the results to the user. + if new_keywords != old_keywords: + # Only do the diff work if something actually changed. + updated = True + old_keywords = sort_keywords(old_keywords) + new_keywords = sort_keywords(new_keywords) + line = '%s"%s"%s\n' % (m.group(1), ' '.join(new_keywords), + m.group(5)) + if format in ('color-inline', 'inline'): + logit(diff_keywords(old_keywords, new_keywords, format=format)) + else: + if format == 'long-multi': + logit(' '.join(['%*s' % (len(keyword_to_arch(x)) + 1, x) + for x in old_keywords])) + logit(' '.join(['%*s' % (len(keyword_to_arch(x)) + 1, x) + for x in new_keywords])) + else: + deleted_keywords = [x for x in old_keywords + if x not in new_keywords] + logit('--- %s' % ' '.join(deleted_keywords)) + added_keywords = [x for x in new_keywords + if x not in old_keywords] + logit('+++ %s' % ' '.join(added_keywords)) + + content.append(line) + + if not updated: + logit('no updates') + + return updated, content + + +def process_ebuild(ebuild, ops, arch_status=None, verbose=False, quiet=False, + dry_run=False, format='color-inline'): + """Process |ops| for |ebuild|""" + with open(ebuild, 'rb') as f: + updated, content = process_content( + ebuild, f, ops, arch_status=arch_status, + verbose=verbose, quiet=quiet, format=format) + if updated and not dry_run: + with open(ebuild, 'wb') as f: + f.writelines(content) + + +def load_profile_data(portdir=None, repo='gentoo'): + """Load the list of known arches from the tree""" + if portdir is None: + portdir = portage.db['/']['vartree'].settings.repositories[repo].location + + arch_status = {} + + try: + arch_list = os.path.join(portdir, 'profiles', 'arch.list') + with open(arch_list) as f: + for line in f: + line = line.split('#', 1)[0].strip() + if line: + arch_status[line] = None + except IOError: + pass + + try: + profile_status = { + 'stable': 0, + 'dev': 1, + 'exp': 2, + None: 3, + } + profiles_list = os.path.join(portdir, 'profiles', 'profiles.desc') + with open(profiles_list) as f: + for line in f: + line = line.split('#', 1)[0].split() + if line: + arch, profile, status = line + arch_status.setdefault(arch, status) + curr_status = profile_status[arch_status[arch]] + new_status = profile_status[status] + if new_status < curr_status: + arch_status[arch] = status + except IOError: + pass + + if arch_status: + arch_status['all'] = None + else: + print('warning: could not read profile files: %s' % arch_list, file=sys.stderr) + print('warning: will not be able to verify args are correct', file=sys.stderr) + + return arch_status + + +def arg_to_op(arg): + """Convert a command line |arg| to an Op""" + arch_prefixes = ('-', '~', '^') + + op = None + arch = arg + refarch = None + + if arg and arg[0] in arch_prefixes: + op, arch = arg[0], arg[1:] + + if '=' in arch: + if not op is None: + raise ValueError('Cannot use an op and a refarch') + arch, refarch = arch.split('=', 1) + + return Op(op, arch, refarch) + + +def args_to_work(args, arch_status=None, repo='gentoo'): + """Process |args| into a list of work itmes (ebuild/arches to update)""" + work = [] + todo_arches = [] + last_todo_arches = None + + for arg in args: + if arg.endswith('.ebuild'): + if not todo_arches: + todo_arches = last_todo_arches + if not todo_arches: + raise ValueError('missing arches to process for %s' % arg) + work.append([arg, todo_arches]) + last_todo_arches = todo_arches + todo_arches = [] + else: + op = arg_to_op(arg) + if not arch_status or op.arch in arch_status: + todo_arches.append(op) + else: + raise ValueError('unknown arch/argument: %s' % arg) + + if todo_arches: + raise ValueError('missing ebuilds to process!') + + return work + + +def get_parser(): + """Return an argument parser for ekeyword""" + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('-n', '--dry-run', default=False, action='store_true', + help='Show what would be changed, but do not commit') + parser.add_argument('-v', '--verbose', default=False, action='store_true', + help='Be verbose while processing things') + parser.add_argument('-q', '--quiet', default=False, action='store_true', + help='Be quiet while processing things (only show errors)') + parser.add_argument('--format', default='auto', + choices=('auto', 'color-inline', 'inline', 'short-multi', 'long-multi'), + help='Selet output format for showing differences') + parser.add_argument('-V', '--version', default=False, action='store_true', + help='Show version information') + return parser + + +def main(argv): + if argv is None: + argv = sys.argv[1:] + + # Extract the args ourselves. This is to allow things like -hppa + # without tripping over the -h/--help flags. We can't use the + # parse_known_args function either. + # This sucks and really wish we didn't need to do this ... + parse_args = [] + work_args = [] + while argv: + arg = argv.pop(0) + if arg.startswith('--'): + if arg == '--': + work_args += argv + break + else: + parse_args.append(arg) + # Handle flags that take arguments. + if arg in ('--format',): + if argv: + parse_args.append(argv.pop(0)) + elif arg[0] == '-' and len(arg) == 2: + parse_args.append(arg) + else: + work_args.append(arg) + + parser = get_parser() + opts = parser.parse_args(parse_args) + if opts.version: + print('version: %s' % VERSION) + return os.EX_OK + if not work_args: + parser.error('need arches/ebuilds to process') + + if opts.format == 'auto': + if not portage.db['/']['vartree'].settings.get('NOCOLOR', 'false').lower() in ('no', 'false'): + nocolor() + opts.format = 'short' + else: + opts.format = 'color-inline' + + arch_status = load_profile_data() + try: + work = args_to_work(work_args, arch_status=arch_status) + except ValueError as e: + parser.error(e) + + for ebuild, ops in work: + process_ebuild(ebuild, ops, arch_status=arch_status, + verbose=opts.verbose, quiet=opts.quiet, + dry_run=opts.dry_run, format=opts.format) + + return os.EX_OK + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/src/ekeyword/ekeyword_unittest.py b/src/ekeyword/ekeyword_unittest.py new file mode 100755 index 0000000..9ccde0e --- /dev/null +++ b/src/ekeyword/ekeyword_unittest.py @@ -0,0 +1,368 @@ +#!/usr/bin/python +# Copyright 2014 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# Written by Mike Frysinger <vapier@gentoo.org> + +"""Unittests for ekeyword""" + +import os +import tempfile +import unittest + +import ekeyword + + +TESTDIR = os.path.join(os.path.dirname(__file__), 'tests') + + +class TestSortKeywords(unittest.TestCase): + """Tests for sort_keywords""" + + def _test(self, input_data, exp_data): + output_data = ekeyword.sort_keywords(input_data.split()) + self.assertEqual(exp_data.split(), output_data) + + def testNull(self): + self._test('', '') + self._test(' ', '') + + def testGlob(self): + self._test('* arm', '* arm') + self._test('arm -* x86', '-* arm x86') + self._test('hppa ~* amd64', '~* amd64 hppa') + + def testNonLinux(self): + self._test('arm-linux alpha amd64-fbsd hppa', + 'alpha hppa amd64-fbsd arm-linux') + + def testPrefixes(self): + self._test('-hppa arm ~alpha -* ~arm-linux', + '-* ~alpha arm -hppa ~arm-linux') + + +class TestDiffKeywords(unittest.TestCase): + """Tests for diff_keywords""" + + def testEmpty(self): + """Test when there is no content to diff""" + ret = ekeyword.diff_keywords([], []) + self.assertEqual(ret, '') + + def testSame(self): + """Test when there is no difference""" + ret = ekeyword.diff_keywords(['a b c'], ['a b c']) + self.assertEqual(ret, 'a b c') + + def testInsert(self): + """Test when content is simply added""" + ret = ekeyword.diff_keywords(['a'], ['~a']) + self.assertNotEqual(ret, '') + + def testDelete(self): + """Test when content is simply deleted""" + ret = ekeyword.diff_keywords(['~a'], ['a']) + self.assertNotEqual(ret, '') + + def testReplace(self): + """Test when some content replaces another""" + ret = ekeyword.diff_keywords(['~a'], ['-a']) + self.assertNotEqual(ret, '') + + def _testSmokeFormat(self, format): + return ekeyword.diff_keywords( + ['~a', 'b', '-abcde'], + ['a', '-b', '-abxde'], format=format) + + def testSmokeFormatColor(self): + """Run a full smoke test for color-inline format""" + ret = self._testSmokeFormat('color-inline') + self.assertNotEqual(ret, '') + + def testSmokeFormatNoColor(self): + """Run a full smoke test for non-color-inline format""" + self._testSmokeFormat('nocolor') + + +class TestProcessKeywords(unittest.TestCase): + """Tests for process_keywords""" + + def _test(self, keywords, ops, exp, arch_status=None): + # This func doesn't return sorted results (which is fine), + # so do so ourselves to get stable tests. + ret = ekeyword.process_keywords( + keywords.split(), ops, arch_status=arch_status) + self.assertEqual(sorted(ret), sorted(exp.split())) + + def testAdd(self): + ops = ( + ekeyword.Op(None, 'arm', None), + ekeyword.Op('~', 's390', None), + ekeyword.Op('-', 'sh', None), + ) + self._test('moo', ops, 'arm ~s390 -sh moo') + + def testModify(self): + ops = ( + ekeyword.Op(None, 'arm', None), + ekeyword.Op('~', 's390', None), + ekeyword.Op('-', 'sh', None), + ) + self._test('~arm s390 ~sh moo', ops, 'arm ~s390 -sh moo') + + def testDelete(self): + ops = ( + ekeyword.Op('^', 'arm', None), + ekeyword.Op('^', 's390', None), + ekeyword.Op('^', 'x86', None), + ) + self._test('arm -s390 ~x86 bar', ops, 'bar') + + def testSync(self): + ops = ( + ekeyword.Op('=', 'arm64', 'arm'), + ekeyword.Op('=', 'ppc64', 'ppc'), + ekeyword.Op('=', 'amd64', 'x86'), + ekeyword.Op('=', 'm68k', 'mips'), + ekeyword.Op('=', 'ia64', 'alpha'), + ekeyword.Op('=', 'sh', 'sparc'), + ekeyword.Op('=', 's390', 's390x'), + ekeyword.Op('=', 'boo', 'moo'), + ) + self._test( + 'arm64 arm ' + '~ppc64 ~ppc ' + '~amd64 x86 ' + 'm68k ~mips ' + '-ia64 alpha ' + 'sh -sparc ' + 's390 ' + 'moo ', + ops, + 'arm64 arm ~ppc64 ~ppc amd64 x86 ~m68k ~mips ia64 alpha ' + '-sh -sparc boo moo') + + def testAllNoStatus(self): + ops = ( + ekeyword.Op(None, 'all', None), + ) + self.assertRaises(ValueError, self._test, '', ops, '') + + def testAllStable(self): + ops = ( + ekeyword.Op(None, 'all', None), + ) + arch_status = { + 'alpha': None, + 'arm': 'stable', + 'arm64': 'exp', + 'm68k': 'dev', + } + self._test('* ~alpha ~arm ~arm64 ~m68k ~mips ~arm-linux', ops, + '* ~alpha arm ~arm64 ~m68k ~mips ~arm-linux', arch_status) + + def testAllUnstable(self): + ops = ( + ekeyword.Op('~', 'all', None), + ) + arch_status = { + 'alpha': None, + 'arm': 'stable', + 'arm64': 'exp', + 'm68k': 'dev', + } + self._test('alpha arm arm64 m68k mips arm-linux', ops, + '~alpha ~arm ~arm64 ~m68k ~mips ~arm-linux', arch_status) + + def testAllMultiUnstableStable(self): + ops = ( + ekeyword.Op('~', 'all', None), + ekeyword.Op(None, 'all', None), + ) + arch_status = { + 'alpha': None, + 'arm': 'stable', + 'arm64': 'exp', + 'm68k': 'dev', + } + self._test('alpha arm arm64 m68k', ops, + '~alpha arm ~arm64 ~m68k', arch_status) + + +class TestProcessContent(unittest.TestCase): + """Tests for process_content""" + + def _testKeywords(self, line): + ops = ( + ekeyword.Op(None, 'arm', None), + ekeyword.Op('~', 'sparc', None), + ) + return ekeyword.process_content( + 'file', ['%s\n' % line], ops, quiet=True) + + def testKeywords(self): + """Basic KEYWORDS mod""" + updated, ret = self._testKeywords('KEYWORDS=""') + self.assertTrue(updated) + self.assertEqual(ret, ['KEYWORDS="arm ~sparc"\n']) + + def testKeywordsIndented(self): + """Test KEYWORDS indented by space""" + updated, ret = self._testKeywords(' KEYWORDS=""') + self.assertTrue(updated) + self.assertEqual(ret, [' KEYWORDS="arm ~sparc"\n']) + + def testKeywordsSingleQuote(self): + """Test single quoted KEYWORDS""" + updated, ret = self._testKeywords("KEYWORDS=' '") + self.assertTrue(updated) + self.assertEqual(ret, ['KEYWORDS="arm ~sparc"\n']) + + def testKeywordsComment(self): + """Test commented out KEYWORDS""" + updated, ret = self._testKeywords('# KEYWORDS=""') + self.assertFalse(updated) + self.assertEqual(ret, ['# KEYWORDS=""\n']) + + def testKeywordsCode(self): + """Test code leading KEYWORDS""" + updated, ret = self._testKeywords('[[ ${PV} ]] && KEYWORDS=""') + self.assertTrue(updated) + self.assertEqual(ret, ['[[ ${PV} ]] && KEYWORDS="arm ~sparc"\n']) + + def testKeywordsEmpty(self): + """Test KEYWORDS not set at all""" + updated, ret = self._testKeywords(' KEYWORDS=') + self.assertFalse(updated) + self.assertEqual(ret, [' KEYWORDS=\n']) + + def _testSmoke(self, format='color-inline', verbose=False, quiet=False): + ops = ( + ekeyword.Op(None, 'arm', None), + ekeyword.Op('~', 'sparc', None), + ) + ekeyword.process_content( + 'asdf', ['KEYWORDS="arm"'], ops, verbose=verbose, + quiet=quiet, format=format) + + def testSmokeQuiet(self): + """Smoke test for quiet mode""" + self._testSmoke(quiet=True) + + def testSmokeVerbose(self): + """Smoke test for verbose mode""" + self._testSmoke(verbose=True) + + def testSmokeFormatColor(self): + """Smoke test for color-inline format""" + self._testSmoke('color-inline') + + def testSmokeFormatInline(self): + """Smoke test for inline format""" + self._testSmoke('inline') + + def testSmokeFormatShortMulti(self): + """Smoke test for short-multi format""" + self._testSmoke('short-multi') + + def testSmokeFormatLongMulti(self): + """Smoke test for long-multi format""" + self._testSmoke('long-multi') + + +class TestProcessEbuild(unittest.TestCase): + """Tests for process_ebuild + + This is fairly light as most code is in process_content. + """ + + def _test(self, dry_run): + ops = ( + ekeyword.Op(None, 'arm', None), + ekeyword.Op('~', 'sparc', None), + ) + with tempfile.NamedTemporaryFile() as tmp: + with open(tmp.name, 'wb') as fw: + with open(os.path.join(TESTDIR, 'process-1.ebuild'), 'rb') as f: + orig_content = f.read() + fw.write(orig_content) + ekeyword.process_ebuild(tmp.name, ops, dry_run=dry_run) + with open(tmp.name, 'rb') as f: + new_content = f.read() + if dry_run: + self.assertEqual(orig_content, new_content) + else: + self.assertNotEqual(orig_content, new_content) + + def testSmokeNotDry(self): + self._test(False) + + def testSmokeDry(self): + self._test(True) + + +class TestLoadProfileData(unittest.TestCase): + """Tests for load_profile_data""" + + def _test(self, subdir): + portdir = os.path.join(TESTDIR, 'profiles', subdir) + return ekeyword.load_profile_data(portdir=portdir) + + def testLoadBoth(self): + """Test loading both arch.list and profiles.desc""" + ret = self._test('both') + self.assertIn('arm', ret) + self.assertEqual(ret['arm'], 'stable') + self.assertIn('arm64', ret) + self.assertEqual(ret['arm64'], 'exp') + + def testLoadArchOnly(self): + """Test loading only arch.list""" + ret = self._test('arch-only') + self.assertIn('arm', ret) + self.assertEqual(ret['arm'], None) + self.assertIn('x86-solaris', ret) + + def testLoadProfilesOnly(self): + """Test loading only profiles.desc""" + ret = self._test('profiles-only') + self.assertIn('arm', ret) + self.assertEqual(ret['arm'], 'stable') + self.assertIn('arm64', ret) + self.assertEqual(ret['arm64'], 'exp') + + def testLoadNone(self): + """Test running when neither files exists""" + ret = self._test('none') + self.assertEqual(ret, {}) + + +class TestArgToOps(unittest.TestCase): + + def _test(self, arg, op): + self.assertEqual(ekeyword.arg_to_op(arg), ekeyword.Op(*op)) + + def testStable(self): + self._test('arm', (None, 'arm', None)) + + def testUnstable(self): + self._test('~ppc64', ('~', 'ppc64', None)) + + def testDisabled(self): + self._test('-sparc', ('-', 'sparc', None)) + + def testDeleted(self): + self._test('^x86-fbsd', ('^', 'x86-fbsd', None)) + + def testSync(self): + self._test('s390=x86', (None, 's390', 'x86')) + + +class TestMain(unittest.TestCase): + + def testSmoke(self): + ekeyword.main(['arm', '--dry-run', os.path.join(TESTDIR, 'process-1.ebuild')]) + ekeyword.main(['--version', '--dry-run']) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/ekeyword/tests/process-1.ebuild b/src/ekeyword/tests/process-1.ebuild new file mode 100644 index 0000000..75168c6 --- /dev/null +++ b/src/ekeyword/tests/process-1.ebuild @@ -0,0 +1,5 @@ +# asdf + +KEYWORDS="arm ~hppa x86" + +# blah diff --git a/src/ekeyword/tests/profiles/arch-only/profiles/arch.list b/src/ekeyword/tests/profiles/arch-only/profiles/arch.list new file mode 120000 index 0000000..361ad76 --- /dev/null +++ b/src/ekeyword/tests/profiles/arch-only/profiles/arch.list @@ -0,0 +1 @@ +../../both/profiles/arch.list
\ No newline at end of file diff --git a/src/ekeyword/tests/profiles/both/profiles/arch.list b/src/ekeyword/tests/profiles/both/profiles/arch.list new file mode 100644 index 0000000..e4787c0 --- /dev/null +++ b/src/ekeyword/tests/profiles/both/profiles/arch.list @@ -0,0 +1,45 @@ +alpha +amd64 +amd64-fbsd +arm +arm64 +hppa +ia64 +m68k +mips +ppc +ppc64 +s390 +sh +sparc +sparc-fbsd +x86 +x86-fbsd + +# Prefix keywords +ppc-aix +x86-freebsd +x64-freebsd +sparc64-freebsd +hppa-hpux +ia64-hpux +x86-interix +amd64-linux +arm-linux +ia64-linux +ppc64-linux +x86-linux +ppc-macos +x86-macos +x64-macos +m68k-mint +x86-netbsd +ppc-openbsd +x86-openbsd +x64-openbsd +sparc-solaris +sparc64-solaris +x64-solaris +x86-solaris +x86-winnt +x86-cygwin diff --git a/src/ekeyword/tests/profiles/both/profiles/profiles.desc b/src/ekeyword/tests/profiles/both/profiles/profiles.desc new file mode 100644 index 0000000..be751a8 --- /dev/null +++ b/src/ekeyword/tests/profiles/both/profiles/profiles.desc @@ -0,0 +1,295 @@ +############################################# +# This is a list of valid profiles for each architecture. This file is used by +# repoman when doing a repoman scan or repoman full. +# DO NOT ADD PROFILES WITH A "die" or "exit" IN THEM OR IT KILLS REPOMAN +# +#layout: +#arch profile_directory status + +# Alpha Profiles +alpha default/linux/alpha/13.0 stable +alpha default/linux/alpha/13.0/desktop stable +alpha default/linux/alpha/13.0/desktop/gnome stable +alpha default/linux/alpha/13.0/desktop/gnome/systemd stable +alpha default/linux/alpha/13.0/desktop/kde stable +alpha default/linux/alpha/13.0/desktop/kde/systemd stable +alpha default/linux/alpha/13.0/developer stable + +# AMD64 Profiles +amd64 default/linux/amd64/13.0 stable +amd64 default/linux/amd64/13.0/selinux dev +amd64 default/linux/amd64/13.0/desktop stable +amd64 default/linux/amd64/13.0/desktop/gnome stable +amd64 default/linux/amd64/13.0/desktop/gnome/systemd stable +amd64 default/linux/amd64/13.0/desktop/kde stable +amd64 default/linux/amd64/13.0/desktop/kde/systemd stable +amd64 default/linux/amd64/13.0/developer stable +amd64 default/linux/amd64/13.0/no-multilib dev +amd64 default/linux/amd64/13.0/x32 dev + +# ARM Profiles +arm default/linux/arm/13.0 stable +arm default/linux/arm/13.0/desktop dev +arm default/linux/arm/13.0/desktop/gnome dev +arm default/linux/arm/13.0/desktop/gnome/systemd dev +arm default/linux/arm/13.0/desktop/kde dev +arm default/linux/arm/13.0/desktop/kde/systemd dev +arm default/linux/arm/13.0/developer dev +arm default/linux/arm/13.0/armv4 dev +arm default/linux/arm/13.0/armv4/desktop dev +arm default/linux/arm/13.0/armv4/desktop/gnome dev +arm default/linux/arm/13.0/armv4/desktop/kde dev +arm default/linux/arm/13.0/armv4/developer dev +arm default/linux/arm/13.0/armv4t dev +arm default/linux/arm/13.0/armv4t/desktop dev +arm default/linux/arm/13.0/armv4t/desktop/gnome dev +arm default/linux/arm/13.0/armv4t/desktop/kde dev +arm default/linux/arm/13.0/armv4t/developer dev +arm default/linux/arm/13.0/armv5te dev +arm default/linux/arm/13.0/armv5te/desktop dev +arm default/linux/arm/13.0/armv5te/desktop/gnome dev +arm default/linux/arm/13.0/armv5te/desktop/kde dev +arm default/linux/arm/13.0/armv5te/developer dev +arm default/linux/arm/13.0/armv6j dev +arm default/linux/arm/13.0/armv6j/desktop dev +arm default/linux/arm/13.0/armv6j/desktop/gnome dev +arm default/linux/arm/13.0/armv6j/desktop/kde dev +arm default/linux/arm/13.0/armv6j/developer dev +arm default/linux/arm/13.0/armv7a dev +arm default/linux/arm/13.0/armv7a/desktop dev +arm default/linux/arm/13.0/armv7a/desktop/gnome dev +arm default/linux/arm/13.0/armv7a/desktop/kde dev +arm default/linux/arm/13.0/armv7a/developer dev + +# ARM64 Profiles +arm64 default/linux/arm64/13.0 exp +arm64 default/linux/arm64/13.0/desktop exp +arm64 default/linux/arm64/13.0/developer exp + +# HPPA Profiles +hppa default/linux/hppa/13.0 stable +hppa default/linux/hppa/13.0/desktop dev +hppa default/linux/hppa/13.0/developer dev + +# IA64 Profiles +ia64 default/linux/ia64/13.0 stable +ia64 default/linux/ia64/13.0/desktop stable +ia64 default/linux/ia64/13.0/desktop/gnome stable +ia64 default/linux/ia64/13.0/desktop/gnome/systemd stable +ia64 default/linux/ia64/13.0/desktop/kde stable +ia64 default/linux/ia64/13.0/desktop/kde/systemd stable +ia64 default/linux/ia64/13.0/developer stable + +# M68K Profiles +m68k default/linux/m68k/13.0 dev +m68k default/linux/m68k/13.0/desktop dev +m68k default/linux/m68k/13.0/desktop/gnome dev +m68k default/linux/m68k/13.0/desktop/kde dev +m68k default/linux/m68k/13.0/developer dev + +# MIPS Profiles +mips default/linux/mips/13.0 dev +mips default/linux/mips/13.0/n32 dev +mips default/linux/mips/13.0/n64 exp +mips default/linux/mips/13.0/multilib dev +mips default/linux/mips/13.0/multilib/n32 dev +mips default/linux/mips/13.0/multilib/n64 exp +mips default/linux/mips/13.0/mipsel dev +mips default/linux/mips/13.0/mipsel/n32 dev +mips default/linux/mips/13.0/mipsel/n64 exp +mips default/linux/mips/13.0/mipsel/multilib dev +mips default/linux/mips/13.0/mipsel/multilib/n32 dev +mips default/linux/mips/13.0/mipsel/multilib/n64 exp + +# PPC32 Profiles +ppc default/linux/powerpc/ppc32/13.0 stable +ppc default/linux/powerpc/ppc32/13.0/desktop stable +ppc default/linux/powerpc/ppc32/13.0/desktop/gnome stable +ppc default/linux/powerpc/ppc32/13.0/desktop/gnome/systemd stable +ppc default/linux/powerpc/ppc32/13.0/desktop/kde stable +ppc default/linux/powerpc/ppc32/13.0/desktop/kde/systemd stable +ppc default/linux/powerpc/ppc32/13.0/developer stable + +# PPC64 Profiles +ppc default/linux/powerpc/ppc64/13.0/32bit-userland stable +ppc default/linux/powerpc/ppc64/13.0/32bit-userland/desktop stable +ppc default/linux/powerpc/ppc64/13.0/32bit-userland/desktop/gnome stable +ppc default/linux/powerpc/ppc64/13.0/32bit-userland/desktop/gnome/systemd stable +ppc default/linux/powerpc/ppc64/13.0/32bit-userland/desktop/kde stable +ppc default/linux/powerpc/ppc64/13.0/32bit-userland/desktop/kde/systemd stable +ppc default/linux/powerpc/ppc64/13.0/32bit-userland/developer stable +ppc64 default/linux/powerpc/ppc64/13.0/64bit-userland stable +ppc64 default/linux/powerpc/ppc64/13.0/64bit-userland/desktop stable +ppc64 default/linux/powerpc/ppc64/13.0/64bit-userland/desktop/gnome stable +ppc64 default/linux/powerpc/ppc64/13.0/64bit-userland/desktop/gnome/systemd stable +ppc64 default/linux/powerpc/ppc64/13.0/64bit-userland/desktop/kde stable +ppc64 default/linux/powerpc/ppc64/13.0/64bit-userland/desktop/kde/systemd stable +ppc64 default/linux/powerpc/ppc64/13.0/64bit-userland/developer stable + +# S390 Profiles +s390 default/linux/s390/13.0 dev +s390 default/linux/s390/13.0/s390x dev + +# SH Profiles +sh default/linux/sh/13.0 dev +sh default/linux/sh/13.0/desktop dev +sh default/linux/sh/13.0/desktop/gnome dev +sh default/linux/sh/13.0/desktop/kde dev +sh default/linux/sh/13.0/developer dev + +# SPARC Profiles +sparc default/linux/sparc/13.0 stable +sparc default/linux/sparc/13.0/desktop stable +sparc default/linux/sparc/13.0/desktop/gnome stable +sparc default/linux/sparc/13.0/desktop/kde stable +sparc default/linux/sparc/13.0/developer stable + +# x86 Profiles +x86 default/linux/x86/13.0 stable +x86 default/linux/x86/13.0/selinux dev +x86 default/linux/x86/13.0/desktop stable +x86 default/linux/x86/13.0/desktop/gnome stable +x86 default/linux/x86/13.0/desktop/gnome/systemd stable +x86 default/linux/x86/13.0/desktop/kde stable +x86 default/linux/x86/13.0/desktop/kde/systemd stable +x86 default/linux/x86/13.0/developer stable + +# Gentoo/FreeBSD Profiles +amd64-fbsd default/bsd/fbsd/amd64/9.1 stable +amd64-fbsd default/bsd/fbsd/amd64/9.2 dev +amd64-fbsd default/bsd/fbsd/amd64/9.1/clang exp +amd64-fbsd default/bsd/fbsd/amd64/9.2/clang exp +sparc-fbsd default/bsd/fbsd/sparc/8.2 exp +x86-fbsd default/bsd/fbsd/x86/9.1 dev +x86-fbsd default/bsd/fbsd/x86/9.2 dev + +# Hardened Profiles +amd64 hardened/linux/amd64 stable +amd64 hardened/linux/amd64/selinux stable +amd64 hardened/linux/amd64/no-multilib stable +amd64 hardened/linux/amd64/no-multilib/selinux stable +amd64 hardened/linux/amd64/x32 dev +amd64 hardened/linux/uclibc/amd64 dev +arm hardened/linux/arm/armv7a dev +arm hardened/linux/arm/armv6j dev +arm hardened/linux/uclibc/arm/armv7a dev +ia64 hardened/linux/ia64 dev +mips hardened/linux/uclibc/mips exp +mips hardened/linux/uclibc/mips/mipsel exp +ppc hardened/linux/powerpc/ppc32 dev +ppc hardened/linux/powerpc/ppc64/32bit-userland dev +ppc64 hardened/linux/powerpc/ppc64/64bit-userland dev +x86 hardened/linux/x86 stable +x86 hardened/linux/x86/selinux stable +x86 hardened/linux/uclibc/x86 dev + +# uclibc/embedded multiarch profiles +#amd64 uclibc/amd64 dev +#arm uclibc/arm dev +#arm uclibc/arm/2.4 dev +#mips uclibc/mips dev +#mips uclibc/mips/hardened dev +#ppc uclibc/ppc dev +#ppc uclibc/ppc/2.4 dev +#ppc uclibc/ppc/hardened dev +#ppc uclibc/ppc/hardened/2.4 dev +#sh uclibc/sh dev +#sh uclibc/sh/2.4 dev +#x86 uclibc/x86 dev +#x86 uclibc/x86/2.4 dev +#x86 uclibc/x86/2005.1 dev +#x86 uclibc/x86/2005.1/2.4 dev +#x86 uclibc/x86/hardened dev +#x86 uclibc/x86/hardened/2.4 dev + + +# These are Gentoo Prefix profiles, maintained by the Prefix team + +# Linux Profiles +amd64-linux prefix/linux/amd64 exp +arm-linux prefix/linux/arm exp +ia64-linux prefix/linux/ia64 exp +ppc64-linux prefix/linux/ppc64 exp +x86-linux prefix/linux/x86 exp + +# Mac OS X Profiles +ppc-macos prefix/darwin/macos/10.4/ppc exp +x86-macos prefix/darwin/macos/10.4/x86 exp +ppc-macos prefix/darwin/macos/10.5/ppc exp +x86-macos prefix/darwin/macos/10.5/x86 exp +x64-macos prefix/darwin/macos/10.5/x64 exp +x86-macos prefix/darwin/macos/10.6/x86 exp +x64-macos prefix/darwin/macos/10.6/x64 exp +x86-macos prefix/darwin/macos/10.7/x86 exp +x64-macos prefix/darwin/macos/10.7/x64 exp +x86-macos prefix/darwin/macos/10.8/x86 exp +x64-macos prefix/darwin/macos/10.8/x64 exp +x86-macos prefix/darwin/macos/10.9/x86 exp +x64-macos prefix/darwin/macos/10.9/x64 exp + +# Solaris Profiles +sparc-solaris prefix/sunos/solaris/5.9/sparc exp +sparc-solaris prefix/sunos/solaris/5.10/sparc exp +sparc64-solaris prefix/sunos/solaris/5.10/sparc64 exp +x86-solaris prefix/sunos/solaris/5.10/x86 exp +x64-solaris prefix/sunos/solaris/5.10/x64 exp +sparc-solaris prefix/sunos/solaris/5.11/sparc exp +sparc64-solaris prefix/sunos/solaris/5.11/sparc64 exp +x86-solaris prefix/sunos/solaris/5.11/x86 exp +x64-solaris prefix/sunos/solaris/5.11/x64 exp + +# AIX Profiles +ppc-aix prefix/aix/5.2.0.0/ppc exp +ppc-aix prefix/aix/5.3.0.0/ppc exp +ppc-aix prefix/aix/6.1.0.0/ppc exp + +# Interix Profiles +x86-interix prefix/windows/interix/3.5/x86 exp +x86-interix prefix/windows/interix/5.2/x86 exp +x86-interix prefix/windows/interix/6.0/x86 exp +x86-interix prefix/windows/interix/6.1/x86 exp + +# Windows Profiles +x86-winnt prefix/windows/winnt/3.5/x86 exp +x86-winnt prefix/windows/winnt/5.2/x86 exp +x86-winnt prefix/windows/winnt/6.0/x86 exp +x86-winnt prefix/windows/winnt/6.1/x86 exp + +# Cygwin Profiles +x86-cygwin prefix/windows/cygwin/1.7/x86 exp + +# HP-UX Profiles +ia64-hpux prefix/hpux/B.11.23/ia64 exp +hppa-hpux prefix/hpux/B.11.31/hppa2.0 exp +ia64-hpux prefix/hpux/B.11.31/ia64 exp + +# FreeBSD Profiles +x86-freebsd prefix/bsd/freebsd/7.1/x86 exp +x64-freebsd prefix/bsd/freebsd/7.1/x64 exp +x86-freebsd prefix/bsd/freebsd/7.2/x86 exp +x64-freebsd prefix/bsd/freebsd/7.2/x64 exp +x86-freebsd prefix/bsd/freebsd/8.0/x86 exp +x64-freebsd prefix/bsd/freebsd/8.0/x64 exp +x86-freebsd prefix/bsd/freebsd/8.1/x86 exp +x64-freebsd prefix/bsd/freebsd/8.1/x64 exp +sparc64-freebsd prefix/bsd/freebsd/8.1/sparc64 exp +x86-freebsd prefix/bsd/freebsd/8.2/x86 exp +x64-freebsd prefix/bsd/freebsd/8.2/x64 exp +x86-freebsd prefix/bsd/freebsd/9.0/x86 exp +x64-freebsd prefix/bsd/freebsd/9.0/x64 exp +x86-freebsd prefix/bsd/freebsd/9.1/x86 exp +x64-freebsd prefix/bsd/freebsd/9.1/x64 exp + + +# OpenBSD Profiles +ppc-openbsd prefix/bsd/openbsd/4.2/ppc exp +x86-openbsd prefix/bsd/openbsd/4.2/x86 exp +x64-openbsd prefix/bsd/openbsd/4.2/x64 exp + +# NetBSD Profiles +x86-netbsd prefix/bsd/netbsd/4.0/x86 exp + +# FreeMiNT +m68k-mint prefix/mint/m68k exp + +# vim: set ts=8: diff --git a/src/ekeyword/tests/profiles/none/profiles/.keep b/src/ekeyword/tests/profiles/none/profiles/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ekeyword/tests/profiles/none/profiles/.keep diff --git a/src/ekeyword/tests/profiles/profiles-only/profiles/profiles.desc b/src/ekeyword/tests/profiles/profiles-only/profiles/profiles.desc new file mode 120000 index 0000000..04f8005 --- /dev/null +++ b/src/ekeyword/tests/profiles/profiles-only/profiles/profiles.desc @@ -0,0 +1 @@ +../../both/profiles/profiles.desc
\ No newline at end of file diff --git a/src/ekeyword2/ekeyword2 b/src/ekeyword2/ekeyword2 deleted file mode 100755 index ce8842d..0000000 --- a/src/ekeyword2/ekeyword2 +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/python - -# Output like: -# setuptools-0.6_rc9.ebuild -# < KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~sparc-fbsd -x86 ~x86-fbsd" -# --- -# > KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~sparc-fbsd x86 ~x86-fbsd" - -from __future__ import with_statement -from sys import argv -from fnmatch import fnmatch -from shutil import copyfile -from os import environ as env - -import re -import string - -from portage import settings - -STABLE_KEYWORDS = frozenset(settings["PORTAGE_ARCHLIST"].split()) -BROKEN_KEYWORDS = frozenset(['-*'] + ['-'+k for k in STABLE_KEYWORDS]) -TEST_KEYWORDS = frozenset(['~'+k for k in STABLE_KEYWORDS]) -KNOWN_KEYWORDS = STABLE_KEYWORDS | TEST_KEYWORDS | BROKEN_KEYWORDS - -argv = set(argv[1:]) -kw_re = re.compile(r'KEYWORDS="([^"]*)"') -ebuilds = frozenset([x for x in argv if fnmatch(x, '*.ebuild')]) -pretend = bool(argv.intersection(('-p', '--pretend',))) -keywords = argv.difference(('-p', '--pretend',)) - ebuilds - -if not ebuilds: - print 'usage: ekeyword [-p|--pretend] [^|~|-][all] [[^|~|-]arch [[^|~|-]arch]...] ebuild [ebuild...]' - -for e in ebuilds: - # TODO: error handling for file I/O - kw = set(keywords) - if not pretend: - try: - copyfile(e, e+'.orig') - except IOError: - print "Can't copy file %s. Check permissions." % e - exit(1) - try: - with open(e) as c: - ebuild = c.read() - except IOError: - print "Can't open file %s. Aborting." % e - exit(1) - - orig = kw_re.search(ebuild) - curkw = set(orig.groups()[0].split()) - - # ^ or ^all by itself means remove all keywords - # (however, other keywords established in the same args still get set.) - if kw.intersection(('^', '^all',)): - kw -= set(('^', '^all',)) - curkw = set() - - # ~ or ~all by itself means set ~keyword for all keywords - # since ~ expands to "$HOME" in the shell, assume the user meant ~ if we see - # the expansion of "$HOME". (Hope there's no user named 'all'.) - if kw.intersection(('~', '~all', env['HOME'],)): - kw -= set(('~', '~all', env['HOME'],)) - curkw = set(['~'+k if k in STABLE_KEYWORDS else k for k in curkw]) - - for k in kw: - # Remove keywords starting with ^ - if k[0] == '^': - curkw -= set((k[1:], '-'+k[1:], '~'+k[1:], )) - # Set ~ and - keywords to TEST and BROKEN, respectively - elif k[0] == '~' or k[0] == '-': - curkw -= set((k[1:], '-'+k[1:], '~'+k[1:], )) - curkw |= set((k,)) - # Set remaining keywords to STABLE - else: - curkw -= set(('~'+k,)) - curkw |= set((k,)) - - # Sort by arch, then OS (Luckily, this makes -* show up first if it's there) - result = 'KEYWORDS="%s"' % ' '.join(sorted(curkw, - key=lambda x: x.strip(string.punctuation).lower())) - - if not pretend: - try: - with open(e, 'w') as rebuild: - rebuild.write(kw_re.sub(result, ebuild)) - except IOError: - print "Can't write file %s. Aborting." % e - exit(1) - - unknown_keywords = curkw - KNOWN_KEYWORDS - if unknown_keywords: - print "\nWarning: Unknown keywords '%s'.\n" % ', '.join(sorted(unknown_keywords)) - - print '<<< %s' % orig.group() - print '>>> %s' % result |