X-Recipient: archive-cygwin AT delorie DOT com DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:content-type:message-id:mime-version :subject:date:references:to:in-reply-to; q=dns; s=default; b=CzU BQ9kgQ3JVhZ9HjWSEW3xvWEWRFkDNrWrkNMURVhYL0kjONWU/I1CX5HhFQOMnCjD hFFq++QWALqT9of26HOiMtZHfTAFjOnBkg4nZ/CnNHsJG1VMMiU7eWPe1wY5hjzS 0FODLcHaPPAG7Yyf6BpjlJGJcfgw7CQUDbUUbzoY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:content-type:message-id:mime-version :subject:date:references:to:in-reply-to; s=default; bh=PzBUdJF9g srd32sdq0Z4O5CxbWQ=; b=IYzANFJQtX/Uagfy8bzPXWjBgDMNBdI9Q1Be7rctV VYxN+4S+pE4ZK6gmHPRE1rf7/OtEeh+y1VLDpORHfKf6y5YBECC7DWZCX5S80MQ7 FU1tMPiidpleoaV2LVOji8k/ia4bqte3Qf7JLYUqTxYRp9LG+4gD7ikagOBz4UaE bk= Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.8 required=5.0 tests=AWL,BAYES_00,KAM_LAZY_DOMAIN_SECURITY,RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=Hx-languages-length:772, H*c:HHHH, H*c:HHHHHHHH, H*r:envelope-sender X-HELO: etr-usa.com From: Warren Young Content-Type: multipart/mixed; boundary="Apple-Mail=_B1AFA8F9-4A69-45BD-B7C8-F67D3A77E067" Message-Id: <5B19C9A7-3200-4841-A300-D48C600623DA@etr-usa.com> Mime-Version: 1.0 (Mac OS X Mail 9.3 \(3124\)) Subject: Re: Anecdotal: Rebase and Visual Studio 2015 and /etc Date: Tue, 5 Jul 2016 23:17:41 -0600 References: <693uFCmXF1392S07 DOT 1467203045 AT web07 DOT cms DOT usa DOT net> <3334CBDB-BF42-4CDA-83B5-CCA5B251A746 AT etr-usa DOT com> <98C319EE-D0EF-48CD-85D7-3384DA5051A9 AT etr-usa DOT com> <44F329F2-C5FE-47D9-BCC5-BF7F9D85F68F AT etr-usa DOT com> To: The Cygwin Mailing List In-Reply-To: X-IsSubscribed: yes --Apple-Mail=_B1AFA8F9-4A69-45BD-B7C8-F67D3A77E067 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=windows-1252 On Jul 3, 2016, at 8:02 AM, Ken Brown wrote: >=20 > it doesn't take dependency loops into account I=92ve fixed that using your proposed =93Dependency order=94 solution. I h= aven=92t analyzed the output, but it is a bit longer than the last time, so= I assume it has saved me from dropping all packages in a loop. If this is also found to be insufficient, I think I=92d have to build the d= ependency graph from setup.ini and learn to walk it, rather than continue w= ith this present linear algorithm. > if the mirror was used for both an x86 and x86_64 installation, it always= uses the x86 setup.ini, regardless of the current architecture. Good catch! The script now uses the output of uname -m to select the mirro= r subdirectory. --Apple-Mail=_B1AFA8F9-4A69-45BD-B7C8-F67D3A77E067 Content-Disposition: attachment; filename=find-cyg-roots Content-Type: application/octet-stream; name="find-cyg-roots" Content-Transfer-Encoding: 7bit #!/usr/bin/perl use strict; use warnings; use URI::Escape; my $prgname = $0; #### find_setup_ini_file ############################################### # Parse Cygwin's setup.rc file to find the last setup.ini file it used. sub find_setup_ini_file { open my $rc, '<', '/etc/setup/setup.rc' or usage("could not read setup.rc file: $!"); my ($path, $mirror); while (<$rc>) { chomp; if ($_ eq 'last-cache') { $path = <$rc>; chomp $path; $path =~ s/^\s+//; open my $cp, '-|', "cygpath -u '$path'"; $path = <$cp>; chomp $path; close $cp; } elsif ($_ eq 'last-mirror') { $mirror = <$rc>; chomp $mirror; $mirror =~ s/^\s+//; $mirror = uri_escape($mirror); } } close $rc; usage("could not find last Cygwin cache dir") unless $path; usage("could not find last Cygwin DL mirror") unless $mirror; open my $uname, '-|', 'uname -m' or die "uname -m failed: $!\n"; my $plat = <$uname>; chomp $plat; close $uname; $path .= "/$mirror/$plat/setup.ini"; usage("could not find setup.ini") unless -r $path; return $path; } #### get_dependency_order ############################################## # Return a hash mapping package names to their index on the "Dependency # order" line written to /var/log/setup.log.full by setup.exe. Lower # numbers mean they're farther to the left and hence more depended-upon, # so the index of "base-cygwin" is 0, "cygwin" is 1, etc. sub get_dependency_order { open my $log, '<', '/var/log/setup.log.full' or usage("failed to read setup log: $!"); my @lines = grep { /^Dependency order/ } <$log>; usage("no dependency order line in setup log") if @lines == 0; usage("multiple dependency order lines found") unless @lines == 1; my ($preamble, $deporder) = split ':', $lines[0]; my @packages = split ' ', $deporder; my $i = 0; my %deps; for my $p (@packages) { $deps{$p} = $i++; } return \%deps; } #### get_installed_package_list ######################################## # Return a list of names of installed packages sub get_installed_package_list { open my $db, '<', '/etc/setup/installed.db' or usage("failed to read installed package DB file: $!"); my $header = <$db>; my @pkgnames; while (<$db>) { my ($name) = split; push @pkgnames, $name; } return \@pkgnames; } #### parse_cygwin_setup_ini_file ####################################### # Extract dependency info from the Cygwin setup.ini file. sub parse_cygwin_setup_ini_file { my ($inifile, $piref) = @_; open my $ini, '<', $inifile or die "Cannot read INI file $inifile: $!\n"; # Skip to first package entry while (<$ini>) { last if /^@/; } # Parse package entries my %deps; while (defined $_) { chomp; my $p = substr $_, 2; my $obs = 0; while (<$ini>) { if (/^@/) { # Found next package entry; restart outer loop last; } elsif (/^category: Base$/) { # Mark this one as a special sort of root package: one # we're going to install regardless of user selection, # so we need not list it in our output. $piref->{$p} = 2; } elsif (/^category: _obsolete$/) { # Select this package's replacement instead below. $piref->{$p} = 0; $obs = 1; } elsif (/^requires:/) { # Save this package's requirements as its dependents list. my ($junk, @deps) = split; $deps{$p} = \@deps; # If this package was marked obsolete above, select its # replacement as provisionally to-be-installed. That # package still might end up removed from our output list # if it in turn is a dependent of one of the packages we # consider a "root" package at the end. $piref->{$deps[0]} = 1 if $obs; } } } close $ini; return \%deps; } #### usage ############################################################# # Print usage message plus optional error string, then exit sub usage { my ($error) = @_; print "ERROR: $error\n\n" if length($error); print <<"USAGE"; usage: $prgname Finds the last-used Cygwin setup.ini file, then uses the package dependency info found within it to pare the list of currently-installed Cygwin packages down to a "root" set, being those that will implicitly install all of the others as dependencies. The output is a list suitable for passing to setup.exe -P. USAGE exit ($error ? 1 : 0); } #### main ############################################################## my $inifile = find_setup_ini_file; # Convert package list to a hash so we can mark them non-root by name my $pkgnames = get_installed_package_list; my %packages = map { $_ => 1 } @$pkgnames; my $deps = parse_cygwin_setup_ini_file($inifile, \%packages); my $deporder = get_dependency_order; # For each installed package, mark all of its dependencies as non-root # since those will be installed if the requiring package is installed. for my $p (@$pkgnames) { my $pdref = $deps->{$p}; for my $d (@$pdref) { # Package $p depends on $d, but only mark it as non-root if $p # was to the right of $d in the dependency order list written by # setup.exe on the last install. Otherwise, setup.exe is saying # $p is more depended-upon than $d, which means we're looking at # a dependency graph cycle. That means we always call the least # depended-upon package in that loop as the "root," but that # choice is not important. What that matters is that we avoid # marking all packages in that loop as non-root, since then none # of them get installed. $packages{$d} = 0 if $deporder->{$p} > $deporder->{$d}; } } # Collect list of root packages and print it out print join ',', sort(grep { $packages{$_} == 1 } @$pkgnames); --Apple-Mail=_B1AFA8F9-4A69-45BD-B7C8-F67D3A77E067 Content-Type: text/plain; charset=us-ascii -- Problem reports: http://cygwin.com/problems.html FAQ: http://cygwin.com/faq/ Documentation: http://cygwin.com/docs.html Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple --Apple-Mail=_B1AFA8F9-4A69-45BD-B7C8-F67D3A77E067--