public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
From: Warren Young <wyml@etr-usa.com>
To: The Cygwin Mailing List <cygwin@cygwin.com>
Subject: Re: Anecdotal: Rebase and Visual Studio 2015 and /etc
Date: Fri, 01 Jul 2016 23:38:00 -0000	[thread overview]
Message-ID: <44F329F2-C5FE-47D9-BCC5-BF7F9D85F68F@etr-usa.com> (raw)
In-Reply-To: <98C319EE-D0EF-48CD-85D7-3384DA5051A9@etr-usa.com>

[-- Attachment #1: Type: text/plain, Size: 409 bytes --]

On Jul 1, 2016, at 4:40 PM, Warren Young wrote:
> 
> I’ve written a script to do that automatically.

I’ve improved the script so that it no longer requires any parameters.  It finds the last-used setup.ini file and extracts the list of currently-installed packages, all on its own.

Thus, calling this script is now as simple as:

    $ /path/to/setup*.exe -P $(/path/to/find-cyg-roots) ...



[-- Attachment #2: find-cyg-roots --]
[-- Type: application/octet-stream, Size: 4087 bytes --]

#!/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;

	for my $parent (glob("$path/$mirror/x86*")) {
		my $path = "$parent/setup.ini";
		return $path if -r $path;
	}
	
	usage("could not find setup.ini");
	return;
}


#### 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);

# For each given package name, mark any of its dependencies also found
# on the command line as as non-root.
for my $p (@$pkgnames) {
	my $pdref = $deps->{$p};
	for my $d (@$pdref) {
		$packages{$d} = 0;
	}
}

# Collect list of root packages and print it out
print join ',', sort(grep { $packages{$_} == 1 } @$pkgnames);


[-- Attachment #3: Type: text/plain, Size: 218 bytes --]

--
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

  reply	other threads:[~2016-07-01 23:38 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-06-29 13:21 KARL BOTTS
2016-06-29 13:36 ` Eliot Moss
2016-07-01  6:35 ` Andrey Repin
2016-07-01 19:35 ` Warren Young
2016-07-01 22:40   ` Warren Young
2016-07-01 23:38     ` Warren Young [this message]
2016-07-03 14:02       ` Ken Brown
2016-07-05 13:59         ` Ken Brown
2016-07-05 20:09           ` Ken Brown
2016-07-06  5:17         ` Warren Young
2016-07-06 11:44           ` Vlado
2016-07-06 12:39           ` Vlado
2016-07-01 22:13 KARL BOTTS
2016-07-01 22:47 ` Warren Young
2016-07-05 12:12 KARL BOTTS
2016-07-05 12:27 ` Achim Gratz
2016-07-05 23:13 ` Warren Young

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=44F329F2-C5FE-47D9-BCC5-BF7F9D85F68F@etr-usa.com \
    --to=wyml@etr-usa.com \
    --cc=cygwin@cygwin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).