Chandra

 view release on metacpan or  search on metacpan

examples/pack_example/pack.pl  view on Meta::CPAN

#!/usr/bin/env perl
#
# pack.pl - Pack the example Chandra app into a distributable bundle
#
# Usage:
#   cd examples/pack_example
#   perl pack.pl                       # builds for current platform
#   perl pack.pl --platform=linux      # cross-target
#   perl pack.pl --distribute          # build + sign/notarize/DMG (macOS) or AppImage (Linux)
#
# For distribution on macOS, configure signing credentials first:
#   Chandra::Pack->config(
#       identity  => 'Developer ID Application: ...',
#       apple_id  => 'your@email.com',
#       team_id   => 'TEAM123',
#   );
# Or via environment: CHANDRA_IDENTITY, CHANDRA_APPLE_ID, CHANDRA_TEAM_ID
#
use strict;
use warnings;
use FindBin;

lib/Chandra/Pack.pm  view on Meta::CPAN

sub _save_config {
    my $file = _config_file();
    my $dir = file_dirname($file);
    file_mkpath($dir) unless file_is_dir($dir);
    my $content = "# Chandra::Pack configuration\n";
    for my $key (sort keys %CONFIG) {
        next unless defined $CONFIG{$key};
        $content .= "$key = $CONFIG{$key}\n";
    }
    file_spew($file, $content);
    chmod 0600, $file;  # Protect credentials
}

# Load config on module load
_load_config();

sub new {
    my ($class, %args) = @_;
    Carp::croak("'script' is required") unless $args{script};
    Carp::croak("Script '$args{script}' not found") unless file_exists($args{script});
    Carp::croak("Script '$args{script}' is not a file") unless file_is_file($args{script});

lib/Chandra/Pack.pm  view on Meta::CPAN

=encoding utf8

=head1 NAME

Chandra::Pack - Bundle Chandra apps into distributable packages

=head1 SYNOPSIS

    use Chandra::Pack;

    # Configure credentials (once, persists to ~/.chandra/pack.conf)
    Chandra::Pack->config(
        identity    => 'Developer ID Application: Your Name',
        apple_id    => 'you@example.com',
        team_id     => 'ABCD1234',
        save        => 1,
    );

    my $packer = Chandra::Pack->new(
        script     => 'app.pl',
        name       => 'My App',

lib/Chandra/Pack.pm  view on Meta::CPAN

=item * B<Linux>: AppImage (via appimagetool)

=item * B<Windows>: Directory build (installer support planned)

=back

=head1 CLASS METHODS

=head2 config(%args)

Configure credentials for signing and notarization. Call once before
building. Settings can be persisted to C<~/.chandra/pack.conf>.

    Chandra::Pack->config(
        # macOS signing/notarization
        identity         => 'Developer ID Application: ...',
        apple_id         => 'your@email.com',
        team_id          => 'ABCD1234',
        notary_keychain  => 'notary-profile',  # from notarytool store-credentials
        
        # Persist to disk
        save             => 1,
    );

Environment variables are used as fallbacks:

    CHANDRA_IDENTITY
    CHANDRA_APPLE_ID
    CHANDRA_TEAM_ID

lib/Chandra/Pack.pm  view on Meta::CPAN

=head1 DISTRIBUTION DETAILS

=head2 macOS Code Signing

Uses hardened runtime with entitlements for JIT and unsigned memory
(required for Perl). Ad-hoc signing (C<identity =E<gt> '-'>) skips
notarization but still works locally.

=head2 macOS Notarization

Requires Apple Developer account. Store credentials once with:

    xcrun notarytool store-credentials notary-profile \
        --apple-id your@email.com \
        --team-id ABCD1234 \
        --password your-app-specific-password

Then configure:

    Chandra::Pack->config(notary_keychain => 'notary-profile');

=head2 Linux AppImage

t/97_pack.t  view on Meta::CPAN

    my $signed = $dist->build;
    ok($signed->{success}, 'an ad hoc signed build with a disk image succeeds') or diag($signed->{error});
    ok($signed->{signed} && -f $signed->{dmg_path}, 'signed, with the image written');

    like($dist->_codesign_macos("$out/nothing.app", '-')->{error}, qr/codesign failed/, 'signing a missing app fails');
    like($dist->_create_dmg_macos("$out/nothing.app")->{error}, qr/DMG creation failed/, 'imaging a missing app fails');
    my $note = $dist->_notarize_macos("$out/nothing.app");
    like($note->{error}, qr/Failed to create ZIP|Notarization failed/, 'notarising a missing app fails');
    Chandra::Pack->config(notary_keychain => 'profile');
    $note = $dist->_notarize_macos("$out/DistApp.app");
    like($note->{error}, qr/Notarization failed/, 'and notarising without credentials fails after the zip');
    Chandra::Pack->config(notary_keychain => undef);

    Chandra::Pack->config(identity => 'Not A Real Identity', apple_id => 'a', team_id => 't');
    my $bad = Chandra::Pack->new(script => $script, name => 'Bad Sign', output => $out, distribute => 1)->build;
    ok(!$bad->{success}, 'a signing identity that does not exist fails the distribution');
    Chandra::Pack->config(identity => undef, apple_id => undef, team_id => undef);

    my $nocc = Chandra::Pack->new(script => $script, name => 'No Compile', output => "$dir/icon.png");
    eval { $nocc->build };
    like($@, qr/Failed to compile macOS launcher|cannot|Not a directory|exists/i, 'a launcher that cannot be written dies');



( run in 2.057 seconds using v1.01-cache-2.11-cpan-3f962061493 )