CPAN-Maker-Bootstrapper

 view release on metacpan or  search on metacpan

lib/CPAN/Maker/Bootstrapper/ConfigReader.pm  view on Meta::CPAN

=item C<perlcriticrc>

Path to a F<.perlcriticrc> configuration file. When set, enables
C<perlcritic> checking in the build system pattern rules.

=item C<llm-api-key-helper>

A shell command whose output is used as the LLM API key. Executed when
no key is passed directly and C<LLM_API_KEY> is not set in the environment.
The command should print the key and nothing else. The file it reads should
be chmod 600.

Example: cat ~/.ssh/anthropic-api-key

=back

=head1 METHODS

=head2 new

  my $reader = CPAN::Maker::ConfigReader->new;

lib/CPAN/Maker/Bootstrapper/Role/Installer.pm  view on Meta::CPAN

  foreach (@manifest) {
    die "ERROR: MANIFEST contains corrupted entry ($_)\n"
      if $_ !~ m{\A[[:alnum:]][[:alnum:]._-]*(?:/[[:alnum:]][[:alnum:]._-]*)*\z}xsm;

    die "ERROR: $_ is not found in the distribution. MANIFEST may be corrupted.\n"
      if !-e "$dist_dir/$_";

    if (/[.]mk$/xsm) {
      die "ERROR: could not copy $dist_dir/$_ to $installdir/.includes/$_\n"
        if !copy( "$dist_dir/$_", "$installdir/.includes/$_" );
      chmod 0444, "$installdir/.includes/$_";
    }
    else {
      die "ERROR: could not copy $dist_dir/$_ to $installdir/$_\n"
        if !copy( "$dist_dir/$_", "$installdir/$_" );
    }
  }

  # no need to check file existence, copy will fail above or rename will fail and be caught
  rename "$installdir/Makefile.txt", "$installdir/Makefile"
    or die "ERROR: error renaming $installdir/Makefile.txt to $installdir/Makefile: $OS_ERROR\n";

  chmod 0444, "$installdir/Makefile";
  chmod 0555, "$installdir/builder";

  rename "$installdir/gitignore", "$installdir/.gitignore"
    or die "ERROR: error renaming $installdir/gitignore to $installdir/.gitignore: $OS_ERROR\n";

  return;
}

########################################################################
sub _import_files {
########################################################################

lib/CPAN/Maker/Bootstrapper/Role/Installer.pm  view on Meta::CPAN

    close $fh;

    # copy scripts to bin
    foreach my $s ( @{$scripts} ) {
      my $dest = sprintf '%s/bin/%s.in', $installdir, basename($s);
      $self->get_logger->debug( sprintf 'copying %s => %s', $s, $dest );

      die "ERROR: error copying $s to $dest\n"
        if !copy( $s, $dest );

      chmod 0644, $dest;  # remove -x
    }
  }

  # copy tests to t
  foreach my $t ( @{$tests} ) {
    my $dest = sprintf '%s/t/%s', $installdir, basename($t);
    $self->get_logger->debug( sprintf 'copying %s => %s', $t, $dest );

    die "ERROR: error copying $t to $dest\n"
      if !copy( $t, $dest );

    chmod 0644, $dest;  # make sure they are writable
  }

  # create sub directories and copy packages
  foreach my $p ( keys %{$packages} ) {

    my $primary = $self->_find_primary_package( $p, $packages->{$p} );

    if ( !$primary ) {
      warn "WARNING: could not determine primary package for $p...skipping.\n";
      next;

lib/CPAN/Maker/Bootstrapper/Role/Installer.pm  view on Meta::CPAN


    my $lib_path = sprintf '%s/lib/%s', $installdir, dirname($path);

    make_path($lib_path);
    die "ERROR: could not create $lib_path\n" if !-d $lib_path;

    my $dest = sprintf '%s/%s.in', $lib_path, basename($p);
    die "ERROR: could not copy $p to $dest\n"
      if !copy( $p, $dest );

    chmod 0644, $dest;  # make sure they are writable
  }

  return;
}

########################################################################
sub _create_resources_file {
########################################################################
  my ( $self, $module_name, $installdir ) = @_;

release-notes.md  view on Meta::CPAN

```bash
update_available=$(current="..." cpan="..." perl -Mversion -e \
  'print version->parse($ENV{cpan}) > version->parse($ENV{current});')
```

**`make update` left managed files writable**

The `update` target was setting files writable before copying but
never restoring them to read-only afterward, leaving `Makefile` and
`.includes/*` writable after every update. The target now explicitly
runs `chmod -w` after all copies complete. The `post-update` loop also
applies `chmod -w` immediately after each file is copied rather than
before.

**`_install_files` not enforcing immutability**

The `bootstrapper` initializer set `.includes/*.mk` files to `0644`
(writable by owner), making it easy to accidentally edit a managed
file. Files are now installed as:

- `.includes/*.mk` - `0444` (read-only)
- `Makefile` - `0444` (read-only)

share/Makefile.txt  view on Meta::CPAN


.DEFAULT_GOAL := all

all: update-available $(TARBALL) ## builds distribution tarball and dependencies

include .includes/perl.mk

bin/%.sh: bin/%.sh.in
	$(NO_ECHO)sed -e 's/[@]PACKAGE_VERSION[@]/$(VERSION)/' \
	    -e 's/[@]MODULE_NAME[@]/$(MODULE_NAME)/' < $< > $@; \
	chmod +x $@

bin/%: bin/%.in
	$(NO_ECHO)sed -e 's/[@]PACKAGE_VERSION[@]/$(VERSION)/' \
	    -e 's/[@]MODULE_NAME[@]/$(MODULE_NAME)/' < $< > $@; \
	chmod +x $@

.PHONY: quick
quick: ## quick build, turns off scanning, perltidy, perlcritic
	$(NO_ECHO)$(MAKE) SCAN=off LINT=off

cpanfile: requires test-requires 
	$(NO_ECHO)if [[ -e requires ]] && [[ -e test-requires ]]; then \
	  all_requires=$$(mktemp); trap 'rm -f $$all_requires' EXIT; \
	  cp requires $$all_requires; \
	  cat test-requires >>$$all_requires; \

share/Makefile.txt  view on Meta::CPAN

    ChangeLog

$(TARBALL): $(DEPS) \
    $(if $(tidy_on), $(PERL_MODULES:%=%.tdy) $(PERL_BIN_FILES:%=%.tdy)) \
    $(if $(critic_on), $(PERL_MODULES:%=%.crit) $(PERL_BIN_FILES:%=%.crit))
	$(MAKE_CPAN_DIST) -l $(LOG_LEVEL) -b $<

module.pm.tmpl:
	$(NO_ECHO)if [[ -n "$(STUB)" ]]; then \
	  cp --preserve=all --update=none $(STUB) $@; \
	  chmod +w $@; \
	else \
	  touch $@; \
	fi; \

$(MODULE_PATH).in: | module.pm.tmpl
	$(NO_ECHO)mkdir -p $$(dirname $@); \
	test -e $@ || sed -e 's/[@]MODULE_NAME[@]/$(MODULE_NAME)/' \
	    -e 's/[@]GIT_NAME[@]/$(GIT_NAME)/' \
	    -e 's/[@]GIT_EMAIL[@]/$(GIT_EMAIL)/' < module.pm.tmpl > $@

test.t.tmpl:
	$(NO_ECHO)template=$$(perl -MFile::ShareDir=dist_file -e 'print dist_file(q{CPAN-Maker-Bootstrapper}, q{$@});' 2>/dev/null || true); \
	if [[ -n "$$template" ]]; then \
	  cp $$template $@; \
	else \
	  touch $@; \
	fi; \
	chmod 0644 $@

$(UNIT_TEST_NAME): | test.t.tmpl
	$(NO_ECHO)sed -e 's/[@]MODULE_NAME[@]/$(MODULE_NAME)/' < test.t.tmpl > $@

ifeq ($(wildcard README.md.in),)
# If README.md.in does NOT exist, use POD2MARKDOWN on the module
README.md: $(MODULE_PATH)
	$(NO_ECHO)tmpfile=$$(mktemp); \
	trap 'rm -f $$tmpfile' EXIT; \
	echo "@TOC@" > $$tmpfile; \

share/Makefile.txt  view on Meta::CPAN

ChangeLog:
	$(NO_ECHO)test -e $@ || touch $@

buildspec.yml.tmpl:
	$(NO_ECHO)template=$$(perl -MFile::ShareDir=dist_file -e 'print dist_file(q{CPAN-Maker-Bootstrapper}, q{$@});' 2>/dev/null || true); \
	if [[ -n "$$template" ]]; then \
	  cp $$template $@; \
	else \
	  touch $@; \
	fi; \
	chmod 0644 $@

buildspec.yml: | buildspec.yml.tmpl
	$(NO_ECHO)buildspec=$$(mktemp); \
	specfile="$(PROJECT_NAME)"; \
	specfile="$${specfile,,}.yml"; \
	if [[ -e "$$specfile" ]]; then \
	  share_files="    - $$specfile\n"; \
	fi; \
	trap 'rm -f $$buildspec' EXIT; \
	sed -e 's/[@]MODULE_NAME[@]/$(MODULE_NAME)/g' \

share/Makefile.txt  view on Meta::CPAN


.PHONY: workflow
workflow:
	$(NO_ECHO)dist_dir=$$(perl -MFile::ShareDir=dist_dir -e 'print dist_dir(q{CPAN-Maker-Bootstrapper});' 2>/dev/null || true); \
	if [[ -z "$$dist_dir" ]]; then \
	  echo >&2 "ERROR: could not determine CPAN::Maker::Bootstrapper share directory"; \
	  exit 1; \
	fi; \
	pwd=$$(pwd); \
	cp $$dist_dir/builder $$pwd; \
	chmod +x $$pwd/builder; \
	build_requires="$$(mktemp)"; trap 'rm -f $$build_requires' EXIT; \
	test -e build-requires || touch build-requires; \
	cp build-requires $$build_requires; \
	cat $$dist_dir/build-requires >>$$build_requires; \
	sort -u $$build_requires > build-requires; \
	mkdir -p $$pwd/.github/workflows; \
	project_name="$(PROJECT_NAME)"; \
	project_name="$${project_name,,}"; \
	sed -e 's/CPAN::Maker::Bootstrapper/$(PROJECT_NAME)/' \
	    -e "s/cpan-maker-bootstrapper/$$project_name/" $$dist_dir/build.yml > $$pwd/.github/workflows/build.yml; \

share/perl.mk  view on Meta::CPAN


%.pm: %.pm.in
	$(NO_ECHO)module_tmp="$$(mktemp)"; \
	local_cleanfiles="$$module_tmp"; \
	trap 'rm -f $$local_cleanfiles' EXIT; \
	sed -e 's/[@]PACKAGE_VERSION[@]/$(VERSION)/' \
	    -e 's/[@]MODULE_NAME[@]/$(MODULE_NAME)/' $< > "$$module_tmp"; \
	$(run_podextract); \
	rm -f "$@"; \
	cp "$$module_tmp" "$@"; \
	chmod -w "$@"; \
	$(if $(syntax_on),$(check_syntax_pm))

%.pl: %.pl.in
	$(NO_ECHO)rm -f "$@"; \
	sed -e 's/[@]PACKAGE_VERSION[@]/$(VERSION)/' \
	    -e 's/[@]MODULE_NAME[@]/$(MODULE_NAME)/' $< > "$@"; \
	chmod +x "$@"; \
	chmod -w "$@"; \
	$(if $(syntax_on),$(check_syntax_pl))

# ------------------------------------------------------------------
# convenience targets
# ------------------------------------------------------------------

.PHONY: tidy critic lint

tidy: ## run perltidy on all source files
	$(NO_ECHO)if [[ -z "$(PERLTIDYRC)" ]]; then \

share/update.mk  view on Meta::CPAN


INCLUDES_DIR = .includes

.PHONY: post-update
post-update: 
	@mkdir -p $(INCLUDES_DIR); \
	for f in $(MANAGED_FILES); do \
	  src="$(BOOTSTRAPPER_DIST_DIR)/$$f"; \
	  test -e "$$src" || continue; \
	  cp "$$src" "$(INCLUDES_DIR)/$$f"; \
	  chmod -w "$(INCLUDES_DIR)/$$f"; \
	done; \
	echo "Files updated. Review changes with: git diff"

.PHONY: update  ## update managed project files from the installed bootstrapper
update:
	@if [[ -e builder ]]; then \
	  chmod +w builder; \
	  cp $(BOOTSTRAPPER_DIST_DIR)/builder builder; \
	  chmod 0555 builder; \
	fi; \
	chmod +w Makefile; \
	cp $(BOOTSTRAPPER_DIST_DIR)/Makefile.txt Makefile; \
	chmod +w .includes/*; \
	cp $(BOOTSTRAPPER_DIST_DIR)/update.mk .includes/; \
	cp $(BOOTSTRAPPER_DIST_DIR)/upgrade.mk .includes/; \
	$(MAKE) post-update; \
	chmod -w Makefile .includes/*

.PHONY: update-available
update-available:
	@if [[ -n "$(BOOTSTRAPPER_VERSION)" && "$(PROJECT_NAME)" != "CPAN-Maker-Bootstrapper" ]]; then \
	  dist=$$(cpanm --info -l /dev/null 2>/dev/null CPAN::Maker::Bootstrapper || true); \
	  if [[ "$$dist" =~ -([0-9.]+)\.tar\.gz$$ ]]; then \
	    version="$${BASH_REMATCH[1]}"; \
	    update_available=$$(current="$(BOOTSTRAPPER_VERSION)" cpan="$$version" perl -Mversion -e 'print version->parse($$ENV{cpan}) > version->parse($$ENV{current});'); \
	    if [[ -z "$$update_available" ]]; then \
	      echo "CPAN::Maker::Bootstrapper $$version is up-to-date."; \



( run in 0.662 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )