File: unzip.rakumod

package info (click to toggle)
raku-zef 0.13.8-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 664 kB
  • sloc: perl: 22; makefile: 8
file content (127 lines) | stat: -rw-r--r-- 4,714 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use Zef;
use Zef::Service::Shell::PowerShell;

class Zef::Service::Shell::PowerShell::unzip is Zef::Service::Shell::PowerShell does Extractor does Messenger {

    =begin pod

    =title class Zef::Service::Shell::unzip

    =subtitle A PowerShell unzip based implementation of the Extractor interface

    =head1 Synopsis

    =begin code :lang<raku>

        use Zef;
        use Zef::Service::Shell::PowerShell::unzip;

        my $unzip = Zef::Service::Shell::PowerShell::unzip.new;

        # Assuming a zef-master.zip file is in the cwd...
        my $source       = $*HOME.child("zef-master.zip");
        my $extract-to   = $*TMPDIR.child(time);
        my $extracted-to = $unzip.extract($source, $extract-to);

        die "Something went wrong" unless $extracted-to;
        say "Zef META6 from HEAD: ";
        say $extracted-to.child("zef-master/META6.json").slurp;

    =end code

    =head1 Description

    C<Extractor> class for handling file based URIs ending in .zip using the C<unzip> command.

    C<Extractor> class for handling file based URIs ending in .zip using PowerShell to launch a thin wrapper found
    in C<resources/scripts/win32unzip.ps1>.

    You probably never want to use this unless its indirectly through C<Zef::Extract>;
    handling files and spawning processes will generally be easier using core language functionality. This
    class exists to provide the means for fetching a file using the C<Extractor> interfaces that the e.g. git/tar
    adapters use.

    =head1 Methods

    =head2 method probe

        method probe(--> Bool:D)

    Returns C<True> if this module can successfully launch C<powershell>.

    =head2 method extract-matcher

        method extract-matcher(Str() $uri --> Bool:D) 

    Returns C<True> if this module knows how to extract C<$uri>, which it decides based on if C<$uri> is
    an existing local file and ends with C<.zip>.

    =head2 method extract

        method extract(IO() $archive-file, IO() $extract-to --> IO::Path)

    Extracts the files in C<$archive-file> to C<$save-to> via a PowerShell script C<%?RESOURCES{"scripts/win32unzip.ps1"}>.

    On success it returns the C<IO::Path> where the data was actually extracted to. On failure it returns C<Nil>.

    =head2 method ls-files

        method ls-files(IO() $archive-file --> Array[Str])

    On success it returns an C<Array> of relative paths that are available to be extracted from C<$archive-file>.

    =end pod


    # Delegate to parent class Zef::Service::Shell::PowerShell probe; Returns true if powershell is available
    method probe(--> Bool:D) { nextsame }

    # Return true if this Fetcher understands the given uri/path
    method extract-matcher(Str() $uri --> Bool:D) {
        return so $uri.IO.extension.lc eq 'zip';
    }

    # Extract the given $archive-file
    method extract(IO() $archive-file, IO() $extract-to --> IO::Path) {
        die "archive file does not exist: {$archive-file.absolute}"
            unless $archive-file.e && $archive-file.f;
        die "target extraction directory {$extract-to.absolute} does not exist and could not be created"
            unless ($extract-to.e && $extract-to.d) || mkdir($extract-to);

        my $passed;
        react {
            my $cwd := $archive-file.IO.parent;
            my $ENV := %*ENV;
            my $script := %?RESOURCES<scripts/win32unzip.ps1>.IO.absolute;
            my $proc = Zef::zrun-async(|@.ps-invocation, $script, $archive-file.basename, '"' ~ $extract-to.absolute ~ '"');
            whenever $proc.stdout(:bin) { }
            whenever $proc.stderr(:bin) { }
            whenever $proc.start(:$ENV, :$cwd) { $passed = $_.so }
        }

        return $passed ?? $extract-to !! Nil;
    }

    # Returns an array of strings, where each string is a relative path representing a file that can be extracted from the given $archive-file
    method ls-files(IO() $archive-file --> Array[Str]) {
        die "archive file does not exist: {$archive-file.absolute}"
            unless $archive-file.e && $archive-file.f;

        my $passed;
        my $output = Buf.new;
        react {
            my $cwd := $archive-file.parent;
            my $ENV := %*ENV;
            my $script := %?RESOURCES<scripts/win32unzip.ps1>.IO.absolute;
            my $proc = Zef::zrun-async(|@.ps-invocation, $script, $archive-file.basename);
            whenever $proc.stdout(:bin) { $output.append($_) }
            whenever $proc.stderr(:bin) { }
            whenever $proc.start(:$ENV, :$cwd) { $passed = $_.so }
        }

        my @extracted-paths = $output.decode.lines;

        my Str @results = $passed ?? @extracted-paths.grep(*.defined) !! ();
        return @results;
    }
}