From 1d658bbf0064c8bcd43fe36e4b926b0b44ca4f90 Mon Sep 17 00:00:00 2001 From: Judah Sotomayor Date: Sat, 15 Nov 2025 02:51:17 -0500 Subject: [PATCH 1/5] refactor: Migrate jiujitsu to plain jj. Long script name is not really useful. --- bin/jiujitsu | 13 ------------- bin/jj | 4 +++- 2 files changed, 3 insertions(+), 14 deletions(-) delete mode 100755 bin/jiujitsu mode change 120000 => 100755 bin/jj diff --git a/bin/jiujitsu b/bin/jiujitsu deleted file mode 100755 index e0dd12d..0000000 --- a/bin/jiujitsu +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env perl - -## no critic -BEGIN { - our @path = split( m{/bin/(?:jj|jiujitsu)}xms, __FILE__ ); -} - -use lib "$path[0]/lib"; - -## yes critic - -use LUCCDC::Jiujitsu; -LUCCDC::Jiujitsu->run; diff --git a/bin/jj b/bin/jj deleted file mode 120000 index c10671b..0000000 --- a/bin/jj +++ /dev/null @@ -1 +0,0 @@ -jiujitsu \ No newline at end of file diff --git a/bin/jj b/bin/jj new file mode 100755 index 0000000..1bbc4b5 --- /dev/null +++ b/bin/jj @@ -0,0 +1,3 @@ +#!/usr/bin/env perl +use LUCCDC::Jiujitsu; +LUCCDC::Jiujitsu->run; From 777f0e687a53af6c27922cf23d893c9708b68ddb Mon Sep 17 00:00:00 2001 From: Judah Sotomayor Date: Sat, 15 Nov 2025 02:51:52 -0500 Subject: [PATCH 2/5] refactor: Remove vendored strictures. --- lib/strictures.pm | 561 ---------------------------------------------- 1 file changed, 561 deletions(-) delete mode 100644 lib/strictures.pm diff --git a/lib/strictures.pm b/lib/strictures.pm deleted file mode 100644 index 889700e..0000000 --- a/lib/strictures.pm +++ /dev/null @@ -1,561 +0,0 @@ -package strictures; - -use strict; -use warnings FATAL => 'all'; - -BEGIN { - *_PERL_LT_5_8_4 = ( "$]" < 5.008004 ) ? sub() { 1 } : sub() { 0 }; - - # goto &UNIVERSAL::VERSION usually works on 5.8, but fails on some ARM - # machines. Seems to always work on 5.10 though. - *_CAN_GOTO_VERSION = ( "$]" >= 5.010000 ) ? sub() { 1 } : sub() { 0 }; -} - -our $VERSION = '2.000006'; -$VERSION =~ tr/_//d; - -our @WARNING_CATEGORIES = grep { exists $warnings::Offsets{$_} } qw( - closure - chmod - deprecated - exiting - experimental - experimental::alpha_assertions - experimental::autoderef - experimental::bitwise - experimental::const_attr - experimental::declared_refs - experimental::lexical_subs - experimental::lexical_topic - experimental::postderef - experimental::private_use - experimental::re_strict - experimental::refaliasing - experimental::regex_sets - experimental::script_run - experimental::signatures - experimental::smartmatch - experimental::win32_perlio - glob - imprecision - io - closed - exec - layer - newline - pipe - syscalls - unopened - locale - misc - missing - numeric - once - overflow - pack - portable - recursion - redefine - redundant - regexp - severe - debugging - inplace - internal - malloc - shadow - signal - substr - syntax - ambiguous - bareword - digit - illegalproto - parenthesis - precedence - printf - prototype - qw - reserved - semicolon - taint - threads - uninitialized - umask - unpack - untie - utf8 - non_unicode - nonchar - surrogate - void - void_unusual - y2k -); - -sub VERSION { - { - no warnings; - local $@; - if ( defined $_[1] && eval { &UNIVERSAL::VERSION; 1 } ) { - $^H |= 0x20000 - unless _PERL_LT_5_8_4; - $^H{strictures_enable} = int $_[1]; - } - } - _CAN_GOTO_VERSION ? goto &UNIVERSAL::VERSION : &UNIVERSAL::VERSION; -} - -our %extra_load_states; - -our $Smells_Like_VCS; - -sub import { - my $class = shift; - my %opts = @_ == 1 ? %{ $_[0] } : @_; - if ( !exists $opts{version} ) { - $opts{version} = - exists $^H{strictures_enable} - ? delete $^H{strictures_enable} - : int $VERSION; - } - $opts{file} = (caller)[1]; - $class->_enable( \%opts ); -} - -sub _enable { - my ( $class, $opts ) = @_; - my $version = $opts->{version}; - $version = 'undef' - if !defined $version; - my $method = "_enable_$version"; - if ( !$class->can($method) ) { - require Carp; - Carp::croak("Major version specified as $version - not supported!"); - } - $class->$method($opts); -} - -sub _enable_1 { - my ( $class, $opts ) = @_; - strict->import; - warnings->import( FATAL => 'all' ); - - if ( _want_extra( $opts->{file} ) ) { - _load_extras(qw(indirect multidimensional bareword::filehandles)); - indirect->unimport(':fatal') - if $extra_load_states{indirect}; - multidimensional->unimport - if $extra_load_states{multidimensional}; - bareword::filehandles->unimport - if $extra_load_states{'bareword::filehandles'}; - } -} - -our @V2_NONFATAL = grep { exists $warnings::Offsets{$_} } ( - 'exec', # not safe to catch - 'recursion', # will be caught by other mechanisms - 'internal', # not safe to catch - 'malloc', # not safe to catch - 'newline', # stat on nonexistent file with a newline in it - 'experimental', # no reason for these to be fatal - 'deprecated', # unfortunately can't make these fatal - 'portable', # everything worked fine here, just may not elsewhere -); -our @V2_DISABLE = grep { exists $warnings::Offsets{$_} } ( - 'once' # triggers inconsistently, can't be fatalized -); - -sub _enable_2 { - my ( $class, $opts ) = @_; - strict->import; - warnings->import; - warnings->import( FATAL => @WARNING_CATEGORIES ); - warnings->unimport( FATAL => @V2_NONFATAL ); - warnings->import(@V2_NONFATAL); - warnings->unimport(@V2_DISABLE); - - if ( _want_extra( $opts->{file} ) ) { - _load_extras(qw(indirect multidimensional bareword::filehandles)); - indirect->unimport(':fatal') - if $extra_load_states{indirect}; - multidimensional->unimport - if $extra_load_states{multidimensional}; - bareword::filehandles->unimport - if $extra_load_states{'bareword::filehandles'}; - } -} - -sub _want_extra_env { - if ( exists $ENV{PERL_STRICTURES_EXTRA} ) { - if ( _PERL_LT_5_8_4 and $ENV{PERL_STRICTURES_EXTRA} ) { - die 'PERL_STRICTURES_EXTRA checks are not available on perls older' - . "than 5.8.4: please unset \$ENV{PERL_STRICTURES_EXTRA}\n"; - } - return $ENV{PERL_STRICTURES_EXTRA} ? 1 : 0; - } - return undef; -} - -sub _want_extra { - my $file = shift; - my $want_env = _want_extra_env(); - return $want_env - if defined $want_env; - return ( - !_PERL_LT_5_8_4 - and $file =~ /^(?:t|xt|lib|blib)[\\\/]/ - and defined $Smells_Like_VCS - ? $Smells_Like_VCS - : ( - $Smells_Like_VCS = !!( - -e '.git' || -e '.svn' || -e '.hg' - || -e '.bzr' - || ( - -e '../../dist.ini' - && ( -e '../../.git' - || -e '../../.svn' - || -e '../../.hg' - || -e '../../.bzr' ) - ) - ) - ) - ); -} - -sub _load_extras { - my @extras = @_; - my @failed; - foreach my $mod (@extras) { - next - if exists $extra_load_states{$mod}; - - $extra_load_states{$mod} = eval "require $mod; 1;" or do { - push @failed, $mod; - - #work around 5.8 require bug - ( my $file = $mod ) =~ s|::|/|g; - delete $INC{"${file}.pm"}; - }; - } - - if (@failed) { - my $failed = join ' ', @failed; - my $extras = join ' ', @extras; - print STDERR < 'all'; - use warnings NONFATAL => qw( - exec - recursion - internal - malloc - newline - experimental - deprecated - portable - ); - no warnings 'once'; - -except when called from a file which matches: - - (caller)[1] =~ /^(?:t|xt|lib|blib)[\\\/]/ - -and when either C<.git>, C<.svn>, C<.hg>, or C<.bzr> is present in the current -directory (with the intention of only forcing extra tests on the author side) --- or when C<.git>, C<.svn>, C<.hg>, or C<.bzr> is present two directories up -along with C (which would indicate we are in a C operation, -via L) -- or when the C environment variable -is set, in which case it also does the equivalent of - - no indirect 'fatal'; - no multidimensional; - no bareword::filehandles; - -Note that C may at some point add even more tests, with -only a minor version increase, but any changes to the effect of C in normal mode will involve a major version bump. - -If any of the extra testing modules are not present, L will -complain loudly, once, via C, and then shut up. But you really -should consider installing them, they're all great anti-footgun tools. - -=head1 DESCRIPTION - -I've been writing the equivalent of this module at the top of my code for -about a year now. I figured it was time to make it shorter. - -Things like the importer in C don't help me because they turn -warnings on but don't make them fatal -- which from my point of view is -useless because I want an exception to tell me my code isn't warnings-clean. - -Any time I see a warning from my code, that indicates a mistake. - -Any time my code encounters a mistake, I want a crash -- not spew to STDERR -and then unknown (and probably undesired) subsequent behaviour. - -I also want to ensure that obvious coding mistakes, like indirect object -syntax (and not so obvious mistakes that cause things to accidentally compile -as such) get caught, but not at the cost of an XS dependency and not at the -cost of blowing things up on another machine. - -Therefore, L turns on additional checking, but only when it thinks -it's running in a test file in a VCS checkout -- although if this causes -undesired behaviour this can be overridden by setting the -C environment variable. - -If additional useful author side checks come to mind, I'll add them to the -C code path only -- this will result in a minor version -increase (e.g. 1.000000 to 1.001000 (1.1.0) or similar). Any fixes only to the -mechanism of this code will result in a sub-version increase (e.g. 1.000000 to -1.000001 (1.0.1)). - -=head1 CATEGORY SELECTIONS - -strictures does not enable fatal warnings for all categories. - -=over 4 - -=item exec - -Includes a warning that can cause your program to continue running -unintentionally after an internal fork. Not safe to fatalize. - -=item recursion - -Infinite recursion will end up overflowing the stack eventually anyway. - -=item internal - -Triggers deep within perl, in places that are not safe to trap. - -=item malloc - -Triggers deep within perl, in places that are not safe to trap. - -=item newline - -Includes a warning for using stat on a valid but suspect filename, ending in a -newline. - -=item experimental - -Experimental features are used intentionally. - -=item deprecated - -Deprecations will inherently be added to in the future in unexpected ways, -so making them fatal won't be reliable. - -=item portable - -Doesn't indicate an actual problem with the program, only that it may not -behave properly if run on a different machine. - -=item once - -Can't be fatalized. Also triggers very inconsistently, so we just disable it. - -=back - -=head1 VERSIONS - -Depending on the version of strictures requested, different warnings will be -enabled. If no specific version is requested, the current version's behavior -will be used. Versions can be requested using perl's standard mechanism: - - use strictures 2; - -Or, by passing in a C option: - - use strictures version => 2; - -=head2 VERSION 2 - -Equivalent to: - - use strict; - use warnings FATAL => 'all'; - use warnings NONFATAL => qw( - exec - recursion - internal - malloc - newline - experimental - deprecated - portable - ); - no warnings 'once'; - - # and if in dev mode: - no indirect 'fatal'; - no multidimensional; - no bareword::filehandles; - -Additionally, any warnings created by modules using L or -C will not be fatalized. - -=head2 VERSION 1 - -Equivalent to: - - use strict; - use warnings FATAL => 'all'; - # and if in dev mode: - no indirect 'fatal'; - no multidimensional; - no bareword::filehandles; - -=head1 METHODS - -=head2 import - -This method does the setup work described above in L. Optionally -accepts a C option to request a specific version's behavior. - -=head2 VERSION - -This method traps the C<< strictures->VERSION(1) >> call produced by a use line -with a version number on it and does the version check. - -=head1 EXTRA TESTING RATIONALE - -Every so often, somebody complains that they're deploying via C -and that they don't want L to enable itself in this case -- and that -setting C to 0 isn't acceptable (additional ways to -disable extra testing would be welcome but the discussion never seems to get -that far). - -In order to allow us to skip a couple of stages and get straight to a -productive conversation, here's my current rationale for turning the -extra testing on via a heuristic: - -The extra testing is all stuff that only ever blows up at compile time; -this is intentional. So the oft-raised concern that it's different code being -tested is only sort of the case -- none of the modules involved affect the -final optree to my knowledge, so the author gets some additional compile -time crashes which he/she then fixes, and the rest of the testing is -completely valid for all environments. - -The point of the extra testing -- especially C -- is to catch -mistakes that newbie users won't even realise are mistakes without -help. For example, - - foo { ... }; - -where foo is an & prototyped sub that you forgot to import -- this is -pernicious to track down since all I fine until it gets called -and you get a crash. Worse still, you can fail to have imported it due -to a circular require, at which point you have a load order dependent -bug which I've seen before now I show up in production due to tiny -differences between the production and the development environment. I wrote -L to explain -this particular problem before L itself existed. - -As such, in my experience so far L' extra testing has -I production versus development differences, not caused them. - -Additionally, L' policy is very much "try and provide as much -protection as possible for newbies -- who won't think about whether there's -an option to turn on or not" -- so having only the environment variable -is not sufficient to achieve that (I get to explain that you need to add -C at least once a week on freenode #perl -- newbies sometimes -completely skip steps because they don't understand that that step -is important). - -I make no claims that the heuristic is perfect -- it's already been evolved -significantly over time, especially for 1.004 where we changed things to -ensure it only fires on files in your checkout (rather than L-using -modules you happened to have installed, which was just silly). However, I -hope the above clarifies why a heuristic approach is not only necessary but -desirable from a point of view of providing new users with as much safety as -possible, and will allow any future discussion on the subject to focus on "how -do we minimise annoyance to people deploying from checkouts intentionally". - -=head1 SEE ALSO - -=over 4 - -=item * - -L - -=item * - -L - -=item * - -L - -=back - -=head1 COMMUNITY AND SUPPORT - -=head2 IRC channel - -irc.perl.org #toolchain - -(or bug 'mst' in query on there or freenode) - -=head2 Git repository - -Gitweb is on http://git.shadowcat.co.uk/ and the clone URL is: - - git clone git://git.shadowcat.co.uk/p5sagit/strictures.git - -The web interface to the repository is at: - - http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/strictures.git - -=head1 AUTHOR - -mst - Matt S. Trout (cpan:MSTROUT) - -=head1 CONTRIBUTORS - -Karen Etheridge (cpan:ETHER) - -Mithaldu - Christian Walde (cpan:MITHALDU) - -haarg - Graham Knop (cpan:HAARG) - -=head1 COPYRIGHT - -Copyright (c) 2010 the strictures L and L -as listed above. - -=head1 LICENSE - -This library is free software and may be distributed under the same terms -as perl itself. - -=cut From 0590249de719cb773600983f1e84c60be0897b72 Mon Sep 17 00:00:00 2001 From: Judah Sotomayor Date: Sat, 15 Nov 2025 03:00:35 -0500 Subject: [PATCH 3/5] feat: Add basic build infrastructure. This commit is obviously very large, this is because it ties together both a solid build system and the means to run builds using nix. The build system is Actually Portable Perl, which is very nice. Nix must be taught to run APPerl, but I've got it working. --- .gitignore | 6 ++ apperl-project.json | 25 ++++++++ flake.lock | 29 ++++++++- flake.nix | 153 +++++++++++++++++++++++++++++++++----------- nix/perl.nix | 63 ++++++++---------- 5 files changed, 201 insertions(+), 75 deletions(-) create mode 100644 apperl-project.json diff --git a/.gitignore b/.gitignore index 6f26811..e49dde4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,11 @@ *.log tmp/ +result/ +result .direnv/ .vagrant/ + +*.com* +*.tgz +.apperl/ diff --git a/apperl-project.json b/apperl-project.json new file mode 100644 index 0000000..569ca0e --- /dev/null +++ b/apperl-project.json @@ -0,0 +1,25 @@ +{ + "apperl_configs" : { + "jiujitsu" : { + "dest" : "jj.com", + "desc" : "description of this config", + "base" : "full", + "install_modules": [ + ".apperl/nix-links/Module-Path-0.19.tar.gz", + ".apperl/nix-links/File-Grep-0.02.tar.gz", + ".apperl/nix-links/strictures-2.000006.tar.gz" + ], + "zip_extra_files" : { + "__perllib__/LUCCDC" : [ + "lib/LUCCDC/Jiujitsu.pm", + "lib/LUCCDC/Jiujitsu/" + ], + "bin" : [ + "bin/jj" + ] + }, + "default_script" : "/zip/bin/jj" + } + }, + "defaultconfig" : "jiujitsu" +} diff --git a/flake.lock b/flake.lock index e540b82..edf3f3f 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,18 @@ { "nodes": { + "cosmo": { + "flake": false, + "locked": { + "lastModified": 1716786888, + "narHash": "sha256-Ljyc0Jr7luKbLT7SEzm7lOhMm4gmJTfPHvYn5AhHCm8=", + "type": "tarball", + "url": "https://cosmo.zip/pub/cosmocc/cosmocc-3.3.10.zip" + }, + "original": { + "type": "tarball", + "url": "https://cosmo.zip/pub/cosmocc/cosmocc-3.3.10.zip" + } + }, "flake-parts": { "inputs": { "nixpkgs-lib": "nixpkgs-lib" @@ -49,10 +62,24 @@ "type": "github" } }, + "perlSrc": { + "flake": false, + "locked": { + "narHash": "sha256-V8a6oHgn1cR70Hznn5znKMRb6gwOLE3z9WdSWYKH+E4=", + "type": "file", + "url": "https://github.com/Perl/perl5/archive/refs/tags/v5.36.3.tar.gz" + }, + "original": { + "type": "file", + "url": "https://github.com/Perl/perl5/archive/refs/tags/v5.36.3.tar.gz" + } + }, "root": { "inputs": { + "cosmo": "cosmo", "flake-parts": "flake-parts", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs", + "perlSrc": "perlSrc" } } }, diff --git a/flake.nix b/flake.nix index 9e52e37..bee15e0 100644 --- a/flake.nix +++ b/flake.nix @@ -4,59 +4,138 @@ inputs = { flake-parts.url = "github:hercules-ci/flake-parts"; nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + + cosmo = { + url = "https://cosmo.zip/pub/cosmocc/cosmocc-3.3.10.zip"; + flake = false; + }; + + perlSrc = { + url = "file+https://github.com/Perl/perl5/archive/refs/tags/v5.36.3.tar.gz"; + flake = false; + }; }; - outputs = inputs@{ flake-parts, self, ...}: + outputs = inputs@{ flake-parts, self, perlSrc, cosmo, ...}: flake-parts.lib.mkFlake { inherit inputs; } { - imports = [ - # To import a flake module - # 1. Add foo to inputs - # 2. Add foo as a parameter to the outputs function - # 3. Add here: foo.flakeModule - ]; - - - # Systems supported - systems = [ "x86_64-linux" "aarch64-linux" ]; - - perSystem = { config, pkgs, lib, system, ... }: { - _module.args.pkgs = import self.inputs.nixpkgs { - inherit system; - config.allowUnfreePredicate = pkg: - builtins.elem (lib.getName pkg) [ - "vagrant" - ]; - }; - - devShells.default = - let - generatedPerlPackages = import ./nix/perl.nix {inherit pkgs lib;}; + imports = []; + + systems = [ "x86_64-linux" ]; + + perSystem = { config, pkgs, lib, system, ... }: + let + generatedPerlPackages = import ./nix/perl.nix {inherit pkgs lib;}; + + perlDeps = with pkgs.perl540Packages; [ + ModulePath + FileGrep + strictures + ]; + + apperl-link = pkgs.writeShellScriptBin "apperl-link" '' +rm -fr ./.apperl/nix-links && echo "Removing previous links directory..." +mkdir -p ./.apperl/nix-links && echo "Creating links directory..." +echo -e "Creating links to CPAN sources...\ninstall_modules entries:" +${lib.concatMapStringsSep "\n" (p: ''ln -s ${toString p.out.src} ./.apperl/nix-links/${p.pname}-${p.version}.tar.gz + echo -e '\t".apperl/nix-links/${p.pname}-${p.version}.tar.gz"','') perlDeps} +''; + + jiujitsu = let + perlUrl = "file+https://github.com/Perl/perl5/archive/refs/tags/v5.36.3.tar.gz"; + apperl-project = lib.recursiveUpdate (lib.importJSON ./apperl-project.json) { + apperl_configs.jiujitsu = { + perl_url = perlUrl; + }; + }; + + apperl-site.cosmocc = "${cosmo}"; in - pkgs.mkShell { + pkgs.stdenv.mkDerivation rec { + pname = "jiujitsu"; + src = ./.; + version = "0.1.0"; + + buildInputs = [ + apperl-link + pkgs.perl + generatedPerlPackages.PerlDistAPPerl + ]; + nativeBuildInputs = perlDeps; + + outputs = ["out"]; + + HOME = "./fake-home"; + + dontFixup = true; + + preConfigure = '' + mkdir -p $HOME/.config/apperl/ .apperl/o + cp ${(pkgs.writers.writeJSON "apperl-project.json" apperl-project)} ./apperl-project.json + cp ${(pkgs.writers.writeJSON "site.json" apperl-site)} $HOME/.config/apperl/site.json + cp ${perlSrc} .apperl/o/${baseNameOf apperl-project.apperl_configs.jiujitsu.perl_url} + apperl-link + ''; + + configurePhase = '' + runHook preConfigure + apperlm configure + ''; + + buildPhase = '' + apperlm build + ''; + + installPhase = '' + mkdir -p $out/bin + cp ./${apperl-project.apperl_configs.jiujitsu.dest} $out/bin + cp ./${apperl-project.apperl_configs.jiujitsu.dest}.dbg $out/bin + ''; + }; + + in + { + _module.args.pkgs = import self.inputs.nixpkgs { + inherit system; + config.allowUnfreePredicate = pkg: + builtins.elem (lib.getName pkg) [ + "vagrant" + ]; + }; + + packages = { + inherit jiujitsu; + }; + + devShells.default = pkgs.mkShell { name = "jiujitsu"; buildInputs = with pkgs; [ vagrant + + # CLI Tools perl - (pkgs.perl540.withPackages (p-pkgs: with p-pkgs; [ - PLS - TryTiny - ModulePath - CPANPLUS - FileGrep + perl540Packages.PerlCritic + perl540Packages.PLS + generatedPerlPackages.PerlDistAPPerl + apperl-link + + # Needed for the CPAN generator script + (perl540.withPackages(p-pkgs: with p-pkgs; [ AppFatPacker GetoptLongDescriptive LogLog4perl - perlcritic + Readonly + CPANPLUS ])) - ] ++ generatedPerlPackages; + + ] ++ perlDeps; # Local dev demands we extend PERL5LIB to include our local library. - # Will not work for flake builds. - # TODO Determine robust path-setting for final build. + # apperl-link ensures we can also run local builds. shellHook = '' export PERL5LIB="$(pwd)/lib/:$PERL5LIB" - ''; + apperl-link +''; }; - }; + }; }; } diff --git a/nix/perl.nix b/nix/perl.nix index c02cbaa..aa8cf79 100644 --- a/nix/perl.nix +++ b/nix/perl.nix @@ -24,34 +24,6 @@ let }; }; - MooseXApp = buildPerlPackage { - pname = "MooseX-App"; - version = "1.43"; - src = fetchurl { - url = "mirror://cpan/authors/id/M/MA/MAROS/MooseX-App-1.43.tar.gz"; - hash = "sha256-w0YP6wM6R9V7PHbWZUfrf05ncjEnmMfoAp5qq6pnhIc="; - }; - buildInputs = [ - (withPackages (p-pkgs: with p-pkgs; [ - TestDifferences - TestException - TestWarn - TestDeep - TestMost TestNoWarnings - ])) - ]; - propagatedBuildInputs = [ - (withPackages (p-pkgs: with p-pkgs; [ - IOInteractive - ConfigAny Moose PodElemental namespaceautoclean - ])) - ]; - meta = { - description = "Write user-friendly command line apps with even less suffering"; - license = with lib.licenses; [ artistic1 gpl1Plus ]; - }; - }; - LinuxSystemd = buildPerlModule { pname = "Linux-Systemd"; version = "1.201600"; @@ -144,14 +116,31 @@ let }; }; + PerlDistAPPerl = buildPerlPackage { + pname = "Perl-Dist-APPerl"; + version = "0.6.1"; + src = fetchurl { + url = "mirror://cpan/authors/id/G/GA/GAHAYES/Perl-Dist-APPerl-v0.6.1.tar.gz"; + hash = "sha256-H455GwzKbVHpIJ2THq50rIBLPidkVrYMfYDRtZ0687M="; + }; + buildInputs = [ perl540Packages.FileShareDirInstall ]; + propagatedBuildInputs = [ pkgs.cosmocc pkgs.wget pkgs.zip perl540Packages.FileShareDir ]; + meta = { + homepage = "https://computoid.com/APPerl"; + description = "Actually Portable Perl"; + license = with lib.licenses; [ artistic1 gpl1Plus ]; + }; + }; + in -[ - GetoptEuclid - MooseXApp - LinuxSystemd - indirect - multidimensional - barewordfilehandles - NetDBus -] +{ + inherit + GetoptEuclid + LinuxSystemd + indirect + multidimensional + barewordfilehandles + NetDBus + PerlDistAPPerl; +} From a525b13f2b7f3bd291fb24e22485119ef8d0f093 Mon Sep 17 00:00:00 2001 From: Judah Sotomayor Date: Sat, 15 Nov 2025 03:04:23 -0500 Subject: [PATCH 4/5] feat: Change github action to run nix build. I am once again stealing good things from Andrew at 3AM. --- .github/workflows/release.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7b8863e..d6f9a4b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,21 +1,22 @@ name: Release -run-name: Creating release tarball... on: push: tags: - "v*.*.*" jobs: - Create-Tarball: - runs-on: ubuntu-latest + build: + runs-on: ubuntu-22.04 + permissions: + id-token: "write" + contents: "write" steps: - - name: Checkout code - uses: actions/checkout@v5 - - name: Create tarball - run: git archive --format=tar.gz --prefix=jj/ -o jj.tgz HEAD + - uses: actions/checkout@v4 + - uses: DeterminateSystems/nix-installer-action@main + - uses: DeterminateSystems/magic-nix-cache-action@main + - name: Run `nix build` + run: nix build .#jiujitsu - name: Create release uses: softprops/action-gh-release@v2 with: - files: jj.tgz -permissions: - contents: write + files: result/bin/jj.com From ca775073c15c015ea74b9b4c8d59c03d68607594 Mon Sep 17 00:00:00 2001 From: Judah Sotomayor Date: Sat, 15 Nov 2025 03:31:08 -0500 Subject: [PATCH 5/5] docs: Add much better docs for contributing. --- README.md | 67 ++++++++++++++++++++++++++++++++++++++++++++++--------- flake.nix | 6 +++++ 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 32ddacc..5ba8104 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,49 @@ -# How to run while testing -Assuming you have all the perl dependencies installed, use: -`perl -I ./lib/ bin/jiujitsu` from the repository root. +# How to Use +```bash +wget https://github.com/luccdc/jj/releases/latest/download/jj.tgz +# OR +curl -LO https://github.com/luccdc/jj/releases/latest/download/jj.tgz +``` + +```bash +jj.com # Runs jiujitsu + +# Run as perl +cp jj.com perl +./perl + +# Run as perldoc +cp jj.com perldoc +./perldoc +``` + +# How to Develop +You'll need to have Nix installed to work on this. +If you're on Windows, either WSL or a virtual machine work perfectly. +Once you've got Linux, please: +1. [Install nix](https://nixos.org/download/) +2. Enable flakes by adding this line in `~/.config/nix/nix.conf`: + `experimental-features = nix-command flakes` +3. Reload the nix daemon with `systemctl`. + +Next, clone this repository: +(Make sure you're in an appropriate directory!) +``` shell +git clone git@github.com:luccdc/jj.git +cd jj +``` +From inside the repo, running `nix develop` should bring you into the nix development environment. +The first time you do this it may take a few minutes to load, that is normal. + +You can run intermediate work using `./bin/jj` from the repository root. + +## Producing Builds +While developing, you can run the builder with `apperlm configure && apperlm build`. +Note that these builds are _not_ produced cleanly. They will install cosmocc and perl separately the first time you run them. +In order to produce a release build, run `nix build .#jiujitsu`. In 45 minutes or so, **boom!** `jj.com` will appear in `result/bin/`. + +## Where to get dependencies from -# Where to get dependencies from Q: I need a library that does foo, don't want to write it myself. Where can I find it? A: CPAN! Check this list of high-quality tools: @@ -10,14 +51,21 @@ A: CPAN! Check this list of high-quality tools: Or search for it: - https://metacpan.org -# How to add a new Perl package to Nix +Once you have a good dependency in mind, [add it to nix](#how-to-add-a-new-perl-package-to-nix). + +## How to add a new Perl package to Nix 1. Find the package you want to add on [CPAN](https://metacpan.org/search) -2. Search [nixpkgs](https://search.nixos.org/packages?channel=unstable) for a matching perl540Package to add inside the `perl540.withPackages` expression. +2. Search [nixpkgs](https://search.nixos.org/packages?channel=unstable) for a matching perl540Package. 3. No dice? Generate the package with the `./nix/nix-generate-from-cpan.pl` script: `nix-generate-from-cpan.pl ` -4. Add the resulting expression into the `let`-expression in `nix/perl.nix`, and add the name to the final list. + - Add the resulting expression into the `let`-expression in `nix/perl.nix`, and add the name to the final object. +4. Add your package to the perlDeps list. + If you got it from nixpkgs, just the name please. + If you generated it, prefix the name with `generatedPerlPackages`. # Argument Parsing +**NOTICE: This crappy argparser will shortly be replaced with something better.** + Argument parsing uses the [Arguments](./lib/LUCCDC/jiujitsu/Util/Arguments.pm) module. A parser is a closure that can be called on a string representing the command-line. Each parser takes two arguments: @@ -48,6 +96,5 @@ The above exemplifies the creation and use of a parser. A parser closure will return a hash of the arguments, keyed to the names of options. If it encounters a subcommand, it will run that command and exit instead of returning. -# Packaging Options -- https://metacpan.org/pod/App::FatPacker -- https://metacpan.org/pod/pp +# Related Projects +Check out [jj-rs](https://github.com/luccdc/jj-rs/), our sister project and sometime-competing implementation, written by the legendary Andrew Rioux. diff --git a/flake.nix b/flake.nix index bee15e0..e65fa45 100644 --- a/flake.nix +++ b/flake.nix @@ -26,6 +26,12 @@ let generatedPerlPackages = import ./nix/perl.nix {inherit pkgs lib;}; + # + # NOTE: ADD NEW PERL PACKAGES HERE + # + # In nixpkgs? Just the name: `ModulePath` + # Generated from CPAN? Use `generatedPerlPackages.ModulePath` + # Obviously replace `ModulePath` with the name of your package. perlDeps = with pkgs.perl540Packages; [ ModulePath FileGrep