### Complete deployment example Source: https://context7.com/eserte/doit/llms.txt This comprehensive example illustrates a full application deployment process using multiple Doit features. It covers installing dependencies, setting up directories, downloading releases, and deploying to local or remote servers via SSH. ```perl #!/usr/bin/perl use strict; use warnings; use Doit; use Doit::Util qw(in_directory get_sudo_cmd); sub deploy_to_server { my($doit, $version) = @_; my $release_dir = "/opt/app/releases/$version"; $doit->make_path($release_dir); $doit->system('tar', '-xzf', "/tmp/app-$version.tar.gz", '-C', $release_dir); in_directory { $doit->system('npm', 'install', '--production'); } $release_dir; $doit->ln_nsf($release_dir, '/opt/app/current'); $doit->system('systemctl', 'restart', 'myapp'); return "Deployed $version successfully"; } return 1 if caller; my $doit = Doit->init; $doit->add_component('deb'); $doit->add_component('git'); $doit->add_component('lwp'); # Install system dependencies my $sudo = $doit->do_sudo; $sudo->deb_install_packages(qw(nginx nodejs npm)); # Setup application directories $sudo->make_path('/opt/app/releases', '/opt/app/shared/log'); $sudo->chown('deploy', 'deploy', '/opt/app'); # Download release my $version = '2.0.0'; $doit->lwp_mirror( "https://releases.example.com/app-$version.tar.gz", "/tmp/app-$version.tar.gz" ); # Deploy to local or remote server if (my $remote_host = $ENV{DEPLOY_HOST}) { my $ssh = $doit->do_ssh_connect($remote_host, as => 'deploy'); $ssh->call_with_runner('deploy_to_server', $version); } else { deploy_to_server($doit, $version); } print "Deployment complete!\n"; ``` -------------------------------- ### Manage FreeBSD Packages with Perl Source: https://context7.com/eserte/doit/llms.txt Installs and checks for missing packages on FreeBSD systems. Requires root privileges for package management. ```perl use Doit; my $doit = Doit->init; $doit->add_component('fbsdpkg'); # Install packages $doit->fbsdpkg_install_packages(qw(nginx postgresql15-server redis)); # Check missing packages my @missing = $doit->fbsdpkg_missing_packages(qw(nginx postgresql15-server)); ``` -------------------------------- ### Manage Debian Packages with Perl Source: https://context7.com/eserte/doit/llms.txt Installs, checks for missing, and lists upgradeable Debian packages. Also handles GPG key installation and repository addition. Requires root privileges for package management operations. ```perl use Doit; my $doit = Doit->init; $doit->add_component('deb'); # Install packages (idempotent - only installs if missing) $doit->deb_install_packages(qw(nginx postgresql-14 redis-server)); # Check which packages need installation my @missing = $doit->deb_missing_packages(qw(nginx postgresql redis)); if (@missing) { print "Missing packages: @missing\n"; } # Check for available upgrades my @upgradeable = $doit->deb_upgradeable_packages(); if (@upgradeable) { print "Packages with updates: @upgradeable\n"; $doit->system('apt-get', '-y', 'upgrade'); } # Add GPG key for third-party repository $doit->deb_install_packages(qw(curl gnupg)); $doit->deb_install_key( url => 'https://packages.example.com/gpg.key', key => '0123456789ABCDEF0123456789ABCDEF01234567', file => '/etc/apt/keyrings/example.gpg' ); # Add repository $doit->deb_add_repository('example', <<'EOF', update => 1); Types: deb URIs: https://packages.example.com/debian Suites: stable Components: main Signed-By: /etc/apt/keyrings/example.gpg EOF ``` -------------------------------- ### Manage RPM Packages with Perl Source: https://context7.com/eserte/doit/llms.txt Installs and checks for missing RPM packages. Can also enable repositories and trigger updates. Requires root privileges for package management. ```perl use Doit; my $doit = Doit->init; $doit->add_component('rpm'); # Install packages $doit->rpm_install_packages(qw(nginx postgresql-server redis)); # Check missing packages my @missing = $doit->rpm_missing_packages(qw(nginx postgresql-server)); print "Need to install: @missing\n" if @missing; # Enable repository my $changed = $doit->rpm_enable_repo('epel', update => 1); ``` -------------------------------- ### Manage Python Pip Packages with Perl Source: https://context7.com/eserte/doit/llms.txt Installs and checks for missing Python packages using pip3. Includes checks for pip availability and functionality. Does not require root privileges if using virtual environments. ```perl use Doit; my $doit = Doit->init; $doit->add_component('pip'); # Check if pip is available if ($doit->can_pip && $doit->pip_is_functional) { # Install Python packages $doit->pip_install_packages(qw(requests flask gunicorn)); # Check missing packages my @missing = $doit->pip_missing_packages(qw(django celery)); print "Missing Python packages: @missing\n" if @missing; } ``` -------------------------------- ### Create Directories (mkdir, make_path) Source: https://context7.com/eserte/doit/llms.txt Creates directories using mkdir for single directories and make_path for directory trees. Both commands support specifying permissions and make_path can create all intermediate directories as needed. File::Path options can also be passed. ```perl use Doit; my $doit = Doit->init; # Create single directory $doit->mkdir('/var/log/myapp'); # Create with specific permissions (only applied to new directories) $doit->mkdir('/var/run/myapp', 0755); # Create directory tree including all intermediate directories $doit->make_path('/opt/app/shared/log', '/opt/app/shared/tmp', '/opt/app/shared/pids'); # Create with File::Path options $doit->make_path('/opt/secure/data', { mode => 0700 }); ``` -------------------------------- ### HTTP Downloads and Mirroring with LWP in Perl Source: https://context7.com/eserte/doit/llms.txt Downloads files from the web using LWP::UserAgent or HTTP::Tiny. Supports mirroring with conditional downloads based on modification time or digest. Allows specifying refresh behavior and custom user agents. ```perl use Doit; my $doit = Doit->init; $doit->add_component('lwp'); # Mirror file (uses If-Modified-Since for efficiency) $doit->lwp_mirror('https://example.com/latest-release.tar.gz', '/tmp/release.tar.gz'); # Download only once, never refresh $doit->lwp_mirror('https://example.com/static-data.json', '/opt/data/static.json', refresh => 'never' ); # Always download (ignore cache) $doit->lwp_mirror('https://example.com/config.yml', '/etc/app/config.yml', refresh => 'unconditionally' ); # Verify by digest before downloading $doit->lwp_mirror('https://example.com/binary.tar.gz', '/tmp/binary.tar.gz', refresh => ['digest', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e'] ); # Use HTTP::Tiny instead of LWP::UserAgent use HTTP::Tiny; $doit->lwp_mirror('https://example.com/file.txt', '/tmp/file.txt', ua => HTTP::Tiny->new ); ``` -------------------------------- ### Create Symbolic Links (symlink, ln_nsf) Source: https://context7.com/eserte/doit/llms.txt Creates symbolic links using symlink and ln_nsf. symlink fails if the target file exists and points elsewhere, while ln_nsf replaces an existing symlink if necessary, facilitating atomic deployment patterns. ```perl use Doit; my $doit = Doit->init; # Create symlink (fails if newfile exists and points elsewhere) $doit->symlink('/opt/app-v2.0', '/opt/app-current'); # Create symlink, replacing existing symlink if necessary $doit->ln_nsf('/opt/app-v2.0', '/opt/app-current'); # Atomic deployment pattern $doit->ln_nsf("/opt/releases/release-$timestamp", '/opt/app/current'); ``` -------------------------------- ### Capture System Command Output with Doit Source: https://context7.com/eserte/doit/llms.txt Captures the standard output of system commands and provides exception handling. It can also retrieve exit status information. The `info_qx` function is suitable for commands that should run in dry-run mode. ```perl use Doit; my $doit = Doit->init; # Capture stdout my $hostname = $doit->qx('hostname', '-f'); chomp $hostname; # Get exit status information my %status; my $output = $doit->qx({statusref => \%status}, 'git', 'status', '--porcelain'); if ($status{exitcode} == 0 && $output eq '') { print "Working directory clean\n"; } # info_qx runs in dry-run mode my $kernel = $doit->info_qx('uname', '-r'); ``` -------------------------------- ### Manage user accounts Source: https://context7.com/eserte/doit/llms.txt This section covers user management operations using the 'Doit' framework. It includes creating user accounts with detailed configurations, adding users to groups, removing users, and executing code as a specific user. ```perl use Doit; my $doit = Doit->init; $doit->add_component('user'); # Create user account with full configuration my $sudo = $doit->do_sudo; $sudo->user_account( username => 'appuser', ensure => 'present', uid => 1001, home => '/home/appuser', shell => '/bin/bash', groups => ['docker', 'www-data'], ssh_keys => [ 'ssh-rsa AAAAB3... user@example.com', ] ); # Add user to additional group $sudo->user_add_user_to_group( username => 'appuser', group => 'sudo' ); # Remove user $sudo->user_account( username => 'olduser', ensure => 'absent' ); # Run code as different user (requires root) use Doit::User qw(as_user); as_user { # This code runs as 'appuser' print "Running as: " . getpwuid($<) . "\n"; system('touch', '/home/appuser/test.txt'); } 'appuser'; ``` -------------------------------- ### Utility functions for common tasks Source: https://context7.com/eserte/doit/llms.txt This snippet showcases various utility functions provided by the 'Doit::Util' module. It includes temporarily changing directories, registering cleanup actions, copying file attributes, retrieving sudo commands, and fetching OS release information. ```perl use Doit; use Doit::Util qw(in_directory new_scope_cleanup copy_stat get_sudo_cmd get_os_release); my $doit = Doit->init; # Temporarily change directory in_directory { $doit->system('make', 'install'); $doit->system('ldconfig'); } '/opt/src/myproject'; # Previous directory automatically restored # Register cleanup code { my $cleanup = new_scope_cleanup(sub { print "Cleaning up temporary files...\n"; unlink '/tmp/lockfile'; }); # Do work... $doit->system('process-data.pl'); # Cleanup runs automatically when leaving scope } # Copy file attributes (ownership, permissions, timestamps) copy_stat('/etc/nginx/nginx.conf.orig', '/etc/nginx/nginx.conf'); copy_stat('/src/file', '/dest/file', { mode => 1, ownership => 1, time => 0 }); # Get sudo command if needed my @sudo = get_sudo_cmd(); # Returns ('sudo') if not root, () if root $doit->system(@sudo, 'apt-get', 'update'); # Get OS release information my $os = get_os_release(); if ($os) { print "OS: $os->{ID} $os->{VERSION_ID}\n"; # e.g., "ubuntu 22.04" or "debian 12" } ``` -------------------------------- ### Execute Commands with Input/Output Capture using Doit Source: https://context7.com/eserte/doit/llms.txt Allows execution of commands, providing standard input and capturing both standard output and standard error. Useful for interactive commands or when detailed error information is needed. ```perl use Doit; my $doit = Doit->init; # Provide input and capture output my $encrypted = $doit->open2({instr => "secret data\n"}, 'openssl', 'enc', '-aes-256-cbc', '-pass', 'pass:mykey'); # Capture both stdout and stderr my $stderr; my %status; my $stdout = $doit->open3({ errref => \$stderr, statusref => \%status, instr => "SELECT * FROM users;\n" }, 'mysql', '-u', 'root', 'mydb'); if ($status{exitcode} != 0) { warn "MySQL error: $stderr"; } ``` -------------------------------- ### Git Repository Management with Doit Source: https://context7.com/eserte/doit/llms.txt Manage Git repositories including cloning, updating, checking status, and configuring settings. Supports shallow clones and retrieving commit information. ```perl use Doit; my $doit = Doit->init; $doit->add_component('git'); # Clone or update repository $doit->git_repo_update( repository => 'https://github.com/user/project.git', directory => '/opt/project', branch => 'main', clone_opts => ['--depth=1'] # shallow clone ); # Get repository information my $root = $doit->git_root(directory => '/opt/project'); my $sha1 = $doit->git_get_commit_hash(directory => '/opt/project'); my $branch = $doit->git_current_branch(directory => '/opt/project'); my @changed = $doit->git_get_changed_files(directory => '/opt/project'); print "Repository root: $root\n"; print "Current commit: $sha1\n"; print "Current branch: $branch\n"; print "Changed files: @changed\n" if @changed; # Check repository status my $status = $doit->git_short_status(directory => '/opt/project'); # Status values: '' (in sync), '<' (local ahead), '>' (remote ahead), '<>' (diverged) if ($status =~ /<git_config( directory => '/opt/project', key => 'user.email', val => 'deploy@example.com' ); ``` -------------------------------- ### Execute System Commands with Doit Source: https://context7.com/eserte/doit/llms.txt Executes system commands with integrated logging and exception handling. Supports basic command execution, commands with arguments (list form preferred to avoid shell interpretation), and quiet modes. Includes `info_system` for read-only commands that run even in dry-run mode. ```perl use Doit; my $doit = Doit->init; # Basic command execution $doit->system('nginx', '-t'); # Command with arguments (list form avoids shell) $doit->system('rsync', '-avz', '--delete', '/src/', '/dest/'); # Show current working directory in log $doit->system({show_cwd => 1}, 'make', 'install'); # Quiet mode (no logging) $doit->system({quiet => 1}, 'cleanup-script.sh'); # info_system runs even in dry-run mode (for read-only commands) $doit->info_system('df', '-h'); ``` -------------------------------- ### Environment Variable Management with Doit Source: https://context7.com/eserte/doit/llms.txt Idempotently set and unset environment variables. Also includes a utility to find executable paths. ```perl use Doit; my $doit = Doit->init; # Set environment variable $doit->setenv('APP_ENV', 'production'); $doit->setenv('DATABASE_URL', 'postgres://localhost/myapp'); # Unset environment variable $doit->unsetenv('DEBUG'); # Verify with which command my $ruby_path = $doit->which('ruby'); print "Ruby found at: $ruby_path\n" if $ruby_path; ``` -------------------------------- ### Write Binary File Content Atomically with Doit Source: https://context7.com/eserte/doit/llms.txt Writes file content atomically, with automatic diff display. Supports UTF-8 encoding and options for quiet operation or disabling atomicity. Useful for configuration files and binary data. ```perl use Doit; my $doit = Doit->init; # Write configuration file my $config_content = <<'EOF'; server { listen 80; server_name example.com; root /var/www/html; } EOF $doit->write_binary('/etc/nginx/sites-available/example.conf', $config_content); # Write with encoding use Encode; $doit->write_binary('/etc/myapp/message.txt', Encode::encode_utf8("Hello, World!\n")); # Write without showing diff (quiet=1) or without any logging (quiet=2) $doit->write_binary({quiet => 1}, '/tmp/data.bin', $binary_data); # Non-atomic write (use when atomic rename would cause issues) $doit->write_binary({atomic => 0}, '/proc/sys/net/ipv4/ip_forward', "1\n"); ``` -------------------------------- ### Sudo Execution with Doit Source: https://context7.com/eserte/doit/llms.txt Execute commands as different users using sudo. Allows running system commands and calling functions with elevated privileges or as specific users. ```perl use Doit; sub install_packages { my($doit, @packages) = @_; $doit->system('apt-get', '-y', 'install', @packages); } sub create_app_user { my($doit) = @_; $doit->system('useradd', '-m', '-s', '/bin/bash', 'appuser'); } return 1 if caller; my $doit = Doit->init; # Get sudo runner (runs as root by default) my $sudo = $doit->do_sudo; # Execute system commands as root $sudo->system('apt-get', 'update'); $sudo->call_with_runner('install_packages', 'nginx', 'postgresql'); $sudo->call_with_runner('create_app_user'); # Change file permissions as root $sudo->chown('appuser', 'appuser', '/opt/app'); $sudo->chmod(0755, '/opt/app'); # Sudo as different user my $app_sudo = $doit->do_sudo(sudo_opts => ['-u', 'appuser']); $app_sudo->system('whoami'); # outputs: appuser $sudo->exit; ``` -------------------------------- ### Write File Atomically in Perl Source: https://context7.com/eserte/doit/llms.txt Atomically writes content to a file using a callback. Supports change detection, custom temporary directories, and digest checking. Dependencies include Perl's built-in file handling and potentially LWP::UserAgent for digest verification. ```perl use Doit; my $doit = Doit->init; # Write file atomically $doit->file_atomic_write('/etc/nginx/sites-available/myapp', sub { my($fh, $tmpfile) = @_; print $fh "server {\n"; print $fh " listen 80;\n"; print $fh " server_name example.com;\n"; print $fh "}\n"; }); # Write with change detection (returns false if file unchanged) my $changed = $doit->file_atomic_write('/etc/cron.d/backup', sub { my $fh = shift; print $fh "0 2 * * * root /opt/scripts/backup.sh\n"; }, check_change => 1, mode => 0644); if ($changed) { $doit->system('systemctl', 'restart', 'cron'); } # Use custom temp directory and suffix $doit->file_atomic_write('/etc/apt/sources.list.d/custom.list', sub { my $fh = shift; print $fh "deb http://repo.example.com stable main\n"; }, tmpdir => '/tmp', tmpsuffix => '.dpkg-tmp', show_diff => 1); # Check file digest my $matches = $doit->file_digest_matches('/path/to/file', 'abc123...', 'SHA-256'); ``` -------------------------------- ### Execute Complex Pipelines with Doit's run Source: https://context7.com/eserte/doit/llms.txt Enables the execution of complex command pipelines, including redirects, using the `run` method. This is particularly useful for chaining multiple commands together for sophisticated data processing tasks. ```perl use Doit; my $doit = Doit->init; # Pipeline with redirects $doit->run( ['grep', 'ERROR', '/var/log/app.log'], '|', ['sort'], '|', ['uniq', '-c'], '>', '/tmp/error-summary.txt' ); # Complex data processing $doit->run( ['cat', 'data.json'], '|', ['jq', '.users[]'], '|', ['sort', '-k2'], '>', 'sorted-users.txt' ); ``` -------------------------------- ### Atomic File Writing with Doit Source: https://context7.com/eserte/doit/llms.txt Atomically write content to files, with options for change detection. Ensures that file updates are safe and reliable. ```perl use Doit; my $doit = Doit->init; $doit->add_component('file'); # Example usage would go here, e.g.: # $doit->file_atomic_write(path => '/tmp/myfile.txt', content => 'new content'); ``` -------------------------------- ### Delete Files and Touch Timestamps (unlink, touch) Source: https://context7.com/eserte/doit/llms.txt Deletes files using unlink, which is idempotent and does not error if files are already deleted. touch creates an empty file or updates existing file timestamps. create_file_if_nonexisting creates a file only if it does not already exist. ```perl use Doit; my $doit = Doit->init; # Delete files (idempotent - no error if already deleted) $doit->unlink('/tmp/lockfile', '/var/run/myapp.pid'); # Create empty file or update timestamps $doit->touch('/var/log/myapp/access.log'); # Create marker file only if it doesn't exist $doit->create_file_if_nonexisting('/opt/app/.initialized'); ``` -------------------------------- ### Conditional Execution with doit Source: https://context7.com/eserte/doit/llms.txt Execute commands conditionally based on a check. Supports running unless a condition is true or creating a file if it doesn't exist. Uses IPC::Run-style redirects for output. ```perl use Doit; my $doit = Doit->init; # Run unless condition is true $doit->cond_run( unless => sub { system('pgrep -x nginx') == 0 }, cmd => ['systemctl', 'start', 'nginx'] ); # With IPC::Run-style redirects $doit->cond_run( creates => '/tmp/report.txt', cmd => [['generate-report.pl'], '>', '/tmp/report.txt'] ); ``` -------------------------------- ### Forked Process Execution with Doit Source: https://context7.com/eserte/doit/llms.txt Run code in separate processes with IPC communication. Useful for offloading heavy computations or long-running tasks. ```perl use Doit; use Doit::Log; sub heavy_computation { my($doit, $data) = @_; # Simulate expensive operation sleep 2; return { pid => $$, result => length($data) * 2 }; } return 1 if caller; my $doit = Doit->init; $doit->add_component('fork'); # Create forked worker my $fork = $doit->do_fork; # Call function in forked process my $result = $fork->call_with_runner('heavy_computation', 'test data'); info "Worker PID $result->{pid} returned: $result->{result}"; # Clean up - worker process exits undef $fork; # Check exit information info "Worker exit: $Doit::Fork::last_exits[-1]->{msg}"; ``` -------------------------------- ### Initialize Doit Runner Object Source: https://context7.com/eserte/doit/llms.txt Initializes a Doit runner object, automatically handling dry-run mode detection and providing access to all Doit commands. It supports standard Perl options like --dry-run and -n, as well as custom options like --verbose and --config. ```perl use Doit; use Getopt::Long; my $doit = Doit->init; # automatically handles --dry-run and -n options GetOptions( 'verbose' => \my $verbose, 'config=s' => \my $config_file, ) or die "usage: $0 [--dry-run] [--verbose] [--config FILE]\n"; # Run script in dry-run mode: # $ ./script.pl --dry-run # Run script in real mode: # $ ./script.pl ``` -------------------------------- ### Copy Files (copy) Source: https://context7.com/eserte/doit/llms.txt Copies files idempotently using the copy command, skipping the operation if the source and destination contents are identical. It supports an option to suppress diff logging and returns 1 if a copy was performed, 0 otherwise. ```perl use Doit; my $doit = Doit->init; # Copy configuration file (shows diff if destination exists and differs) $doit->copy('templates/nginx.conf', '/etc/nginx/sites-available/myapp'); # Copy without showing diff $doit->copy({quiet => 1}, 'defaults.yml', 'config.yml'); # Returns 1 if copy was performed, 0 if files were identical my $copied = $doit->copy('new-version.txt', 'current-version.txt'); if ($copied) { print "Configuration updated\n"; } ``` -------------------------------- ### Modify Files with Pattern-Based Rules using Doit Source: https://context7.com/eserte/doit/llms.txt Modifies existing files based on pattern matching. Supports adding lines if missing, adding lines after a pattern, replacing matching lines, deleting matching lines, and executing custom actions on matches. Includes validation capabilities. ```perl use Doit; my $doit = Doit->init; # Add line if missing $doit->change_file('/etc/hosts', { add_if_missing => '127.0.0.1 myapp.local' } ); # Add line after a matching pattern $doit->change_file('/etc/ssh/sshd_config', { add_if_missing => 'PermitRootLogin no', add_after => qr/^#?\s*PermitRootLogin/ } ); # Replace matching lines $doit->change_file('/etc/myapp/config.ini', { match => qr/^max_connections\s*=/, replace => 'max_connections = 100' } ); # Delete matching lines $doit->change_file('/etc/crontab', { match => qr/old-backup-script/, delete => 1 } ); # Custom action on matching lines $doit->change_file('/etc/passwd', { match => qr/^myuser:/, action => sub { $_[0] =~ s{\/bin\/sh}{\/bin\/bash} } } ); # Multiple changes with validation my $changes = $doit->change_file({debug => 1, check => sub { my $file = shift; system("nginx -t -c $file") == 0 or die "Invalid nginx config"; }}, '/etc/nginx/nginx.conf', { match => 'worker_processes auto;', replace => 'worker_processes 4;' }, { add_if_missing => 'include \/etc\/nginx\/conf.d\/*.conf;', add_before => qr/^}/ } ); ``` -------------------------------- ### Conditionally Execute Commands with Doit Source: https://context7.com/eserte/doit/llms.txt Executes commands based on specified conditions, such as file existence or custom subroutines. This allows for more dynamic task execution, ensuring commands only run when necessary or appropriate. ```perl use Doit; my $doit = Doit->init; # Run only if file doesn't exist (creates option) $doit->cond_run( creates => '/opt/app/node_modules/.package-lock.json', cmd => ['npm', 'install'] ); # Run with custom condition $doit->cond_run( if => sub { ! -e '/var/run/myapp.pid' }, cmd => ['systemctl', 'start', 'myapp'] ); ``` -------------------------------- ### Remove Directories (rmdir, remove_tree) Source: https://context7.com/eserte/doit/llms.txt Removes directories using rmdir for empty directories and remove_tree for recursive deletion of directory trees. remove_tree is analogous to `rm -rf` and is useful for cleanup operations before deployments. ```perl use Doit; my $doit = Doit->init; # Remove empty directory $doit->rmdir('/tmp/build-artifacts'); # Remove directory tree recursively (like rm -rf) $doit->remove_tree('/tmp/old-cache', '/var/tmp/session-data'); # Cleanup before fresh deployment $doit->remove_tree('/opt/app/releases/old-release'); $doit->make_path('/opt/app/releases/new-release'); ``` -------------------------------- ### Remote SSH Execution with Doit Source: https://context7.com/eserte/doit/llms.txt Execute commands on remote servers via SSH. Supports various connection options and allows calling Doit functions remotely. ```perl use Doit; sub deploy_app { my($doit, $version) = @_; $doit->system('tar', '-xzf', "/tmp/app-$version.tar.gz", '-C', '/opt/app'); $doit->symlink("/opt/app/releases/$version", '/opt/app/current'); $doit->system('systemctl', 'restart', 'myapp'); return "Deployed version $version"; } return 1 if caller; my $doit = Doit->init; # Connect to remote server my $ssh = $doit->do_ssh_connect('deploy@production.example.com', forward_agent => 1, master_opts => ['-o', 'ConnectTimeout=10'] ); # Execute Doit commands remotely $ssh->mkdir('/opt/app/releases'); $ssh->system('curl', '-o', '/tmp/app-2.0.tar.gz', 'https://releases.example.com/app-2.0.tar.gz'); # Call function on remote server my $result = $ssh->call_with_runner('deploy_app', '2.0'); print "Remote result: $result\n"; # Connect as root on remote my $root_ssh = $doit->do_ssh_connect('admin@production.example.com', as => 'root', tty => 1 # needed for password prompts ); $root_ssh->system('apt-get', 'update'); ``` -------------------------------- ### Modify INI file with callback Source: https://context7.com/eserte/doit/llms.txt This snippet demonstrates how to change values in an INI file using a callback function. It requires the 'Config::IniFiles' implementation and modifies specific settings like memory limit and upload file size. ```perl $doit->ini_set_implementation('Config::IniFiles'); $doit->ini_change('/etc/php/7.4/fpm/php.ini', sub { my $self = shift; $self->confobj->setval('PHP', 'memory_limit', '256M'); $self->confobj->setval('PHP', 'upload_max_filesize', '50M'); }); ``` -------------------------------- ### Modify INI Files with Perl Source: https://context7.com/eserte/doit/llms.txt Modifies values within INI configuration files and reads their content. Supports changing multiple key-value pairs and retrieving configuration as a hash of hashes. No external dependencies beyond standard Perl modules. ```perl use Doit; my $doit = Doit->init; $doit->add_component('ini'); # Change values in INI file (simple mode) $doit->ini_change('/etc/myapp/config.ini', 'database.host' => 'localhost', 'database.port' => '5432', 'cache.enabled' => 'true' ); # Read INI file contents my $config = $doit->ini_info_as_HoH('/etc/myapp/config.ini'); print "Database host: $config->{database}{host}\n"; ``` -------------------------------- ### Move and Rename Files with Doit Source: https://context7.com/eserte/doit/llms.txt Performs file move and rename operations. The 'move' function works across filesystems and can optionally show diffs if the destination exists. 'rename' is faster but restricted to the same filesystem. ```perl use Doit; my $doit = Doit->init; # Move file (works across filesystems) $doit->move('/tmp/downloaded-config.yml', '/etc/myapp/config.yml'); # Move with diff output if destination exists $doit->move({show_diff => 1}, 'new-config.yml', 'config.yml'); # Rename within same filesystem (faster but doesn't work across filesystems) $doit->rename('app.log', 'app.log.bak'); ``` -------------------------------- ### Change File Ownership (chown) Source: https://context7.com/eserte/doit/llms.txt Changes file ownership and group using the chown command. It supports specifying ownership by username/groupname or by uid/gid. Unchanged ownership can be preserved by using -1 or undef for the respective parameter. ```perl use Doit; my $doit = Doit->init; # Change owner and group by name $doit->chown('www-data', 'www-data', '/var/www/app/'); # Change only owner (leave group unchanged with -1 or undef) $doit->chown('deploy', -1, '/opt/releases/current'); # Change by uid/gid $doit->chown(1000, 1000, '/home/appuser/.config'); ``` -------------------------------- ### Set File Permissions (chmod) Source: https://context7.com/eserte/doit/llms.txt Sets file permissions idempotently using the chmod command. It supports setting permissions by octal mode and can operate on multiple files or specific configurations. The function returns the number of files actually changed. ```perl use Doit; my $doit = Doit->init; # Set executable permission on scripts $doit->chmod(0755, 'bin/deploy.pl', 'bin/backup.pl'); # Set restrictive permissions on config files (quiet mode suppresses logging) $doit->chmod({quiet => 1}, 0600, '/etc/app/secrets.conf'); # Returns number of files actually changed my $changed = $doit->chmod(0644, glob('lib/*.pm')); print "Changed $changed files\n"; ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.