delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2016/07/06/01:17:55

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: <cygwin.cygwin.com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
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 <wyml AT etr-usa DOT com>
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> <d83f0551-1a48-b723-f50e-9949bd395823 AT cornell DOT edu>
To: The Cygwin Mailing List <cygwin AT cygwin DOT com>
In-Reply-To: <d83f0551-1a48-b723-f50e-9949bd395823@cornell.edu>
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--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019