Input: Summary of the licenses included by the softwares of the project . It is in the form of : ... This product bundles python 2 . 7 . 9 which is available under a Python License . For details see : / opt / opscode / LICENSES / python - LICENSE ... [CODESPLIT] def components_license_summary out = "\n\n" license_map . keys . sort . each do | name | license = license_map [ name ] [ :license ] license_files = license_map [ name ] [ :license_files ] version = license_map [ name ] [ :version ] out << "This product bundles #{name} #{version},\n" out << "which is available under a \"#{license}\" License.\n" if ! license_files . empty? out << "For details, see:\n" license_files . each do | license_file | out << "#{license_package_location(name, license_file)}\n" end end out << "\n" end out end


Input: Summary of the licenses of the transitive dependencies of the project . It is in the form of : ... This product includes inifile 3 . 0 . 0 which is a ruby_bundler dependency of chef and which is available under a MIT License . For details see : / opt / opscode / LICENSES / ruby_bundler - inifile - 3 . 0 . 0 - README . md ... [CODESPLIT] def dependencies_license_summary out = "\n\n" dep_license_map . each do | dep_mgr_name , data | data . each do | dep_name , data | data . each do | dep_version , dep_data | projects = dep_data [ "dependency_of" ] . sort . map { | p | "'#{p}'" } . join ( ", " ) files = dep_data [ "license_files" ] . map { | f | File . join ( output_dir , f ) } out << "This product includes #{dep_name} #{dep_version}\n" out << "which is a '#{dep_mgr_name}' dependency of #{projects},\n" out << "and which is available under a '#{dep_data["license"]}' License.\n" out << "For details, see:\n" out << files . join ( "\n" ) out << "\n\n" end end end out end


Input: Map that collects information about the licenses of the softwares included in the project . [CODESPLIT] def license_map @license_map ||= begin map = { } project . library . each do | component | # Some of the components do not bundle any software but contain # some logic that we use during the build. These components are # covered under the project's license and they do not need specific # license files. next if component . license == :project_license map [ component . name ] = { license : component . license , license_files : component . license_files , version : component . version , project_dir : component . project_dir , } end map end end


Input: Returns the location where the license file should reside in the package . License file is named as <project_name > - <license_file_name > and created under the output licenses directory . [CODESPLIT] def license_package_location ( component_name , where ) if local? ( where ) File . join ( output_dir , "#{component_name}-#{File.split(where).last}" ) else u = URI ( where ) File . join ( output_dir , "#{component_name}-#{File.basename(u.path)}" ) end end


Input: 0 . Translate all transitive dependency licensing issues into omnibus warnings 1 . Parse all the licensing information for all software from cache_dir 2 . Merge and drop the duplicates 3 . Add these licenses to the main manifest to be merged with the main licensing information from software definitions . [CODESPLIT] def process_transitive_dependency_licensing_info Dir . glob ( "#{cache_dir}/*/*-dependency-licenses.json" ) . each do | license_manifest_path | license_manifest_data = FFI_Yajl :: Parser . parse ( File . read ( license_manifest_path ) ) project_name = license_manifest_data [ "project_name" ] dependency_license_dir = File . dirname ( license_manifest_path ) license_manifest_data [ "dependency_managers" ] . each do | dep_mgr_name , dependencies | dep_license_map [ dep_mgr_name ] ||= { } dependencies . each do | dependency | # Copy dependency files dependency [ "license_files" ] . each do | f | license_path = File . join ( dependency_license_dir , f ) output_path = File . join ( output_dir , f ) FileUtils . cp ( license_path , output_path ) end dep_name = dependency [ "name" ] dep_version = dependency [ "version" ] # If we already have this dependency we do not need to add it again. if dep_license_map [ dep_mgr_name ] [ dep_name ] && dep_license_map [ dep_mgr_name ] [ dep_name ] [ dep_version ] dep_license_map [ dep_mgr_name ] [ dep_name ] [ dep_version ] [ "dependency_of" ] << project_name else dep_license_map [ dep_mgr_name ] [ dep_name ] ||= { } dep_license_map [ dep_mgr_name ] [ dep_name ] [ dep_version ] = { "license" => dependency [ "license" ] , "license_files" => dependency [ "license_files" ] , "dependency_of" => [ project_name ] , } end end end end FileUtils . rm_rf ( cache_dir ) end


Input:
Uses license_scout to collect the licenses for transitive dependencies into # { output_dir } / license - cache / # { software . name } [CODESPLIT] def collect_transitive_dependency_licenses_for ( software ) # We collect the licenses of the transitive dependencies of this software # with LicenseScout. We place these files under # /opt/project-name/license-cache for them to be cached in git_cache. Once # the build completes we will process these license files but we need to # perform this step after build, before git_cache to be able to operate # correctly with the git_cache. collector = LicenseScout :: Collector . new ( software . name , software . project_dir , license_output_dir ( software ) , LicenseScout :: Options . new ( environment : software . with_embedded_path , ruby_bin : software . embedded_bin ( "ruby" ) , manual_licenses : software . dependency_licenses ) ) begin # We do not automatically collect dependency licensing information when # skip_transitive_dependency_licensing is set on the software. collector . run rescue LicenseScout :: Exceptions :: UnsupportedProjectType => e # Looks like this project is not supported by LicenseScout. Either the # language and the dependency manager used by the project is not # supported, or the software definition does not have any transitive # dependencies.  In the latter case software definition should set # 'skip_transitive_dependency_licensing' to 'true' to correct this # error. transitive_dependency_licensing_warning ( <<-EOH ) #{ software . name } \
 \
 \
 \
 EOH # If we got here, we need to fail now so we don't take a git # cache snapshot, or else the software build could be restored # from cache without fixing the license issue. raise_if_warnings_fatal! rescue LicenseScout :: Exceptions :: Error => e transitive_dependency_licensing_warning ( <<-EOH ) #{ software . name } \
 #{ e } EOH # If we got here, we need to fail now so we don't take a git # cache snapshot, or else the software build could be restored # from cache without fixing the license issue. raise_if_warnings_fatal! rescue Exception => e # This catch all exception handling is here in order not to fail builds # until license_scout gets more stable. As we are adding support for more # and more dependency managers we discover unhandled edge cases which # requires us to have this. Remove this once license_scout is stable. transitive_dependency_licensing_warning ( <<-EOH ) #{ software . name } #{ e } EOH # If we got here, we need to fail now so we don't take a git # cache snapshot, or else the software build could be restored # from cache without fixing the license issue. raise_if_warnings_fatal! end end


Input: Checks transitive dependency licensing errors for the given software [CODESPLIT] def check_transitive_dependency_licensing_errors_for ( software ) reporter = LicenseScout :: Reporter . new ( license_output_dir ( software ) ) begin reporter . report . each { | i | transitive_dependency_licensing_warning ( i ) } rescue LicenseScout :: Exceptions :: InvalidOutputReport => e transitive_dependency_licensing_warning ( <<-EOH ) #{ license_output_dir ( software ) } #{ e } EOH end raise_if_warnings_fatal! end


Input: Collect the license files for the software . [CODESPLIT] def collect_licenses_for ( software ) return nil if software . license == :project_license software_name = software . name license_data = license_map [ software_name ] license_files = license_data [ :license_files ] license_files . each do | license_file | if license_file output_file = license_package_location ( software_name , license_file ) if local? ( license_file ) input_file = File . expand_path ( license_file , license_data [ :project_dir ] ) if File . exist? ( input_file ) FileUtils . cp ( input_file , output_file ) File . chmod 0644 , output_file unless windows? else licensing_warning ( "License file '#{input_file}' does not exist for software '#{software_name}'." ) # If we got here, we need to fail now so we don't take a git # cache snapshot, or else the software build could be restored # from cache without fixing the license issue. raise_if_warnings_fatal! end else begin download_file! ( license_file , output_file , enable_progress_bar : false ) File . chmod 0644 , output_file unless windows? rescue SocketError , Errno :: ECONNREFUSED , Errno :: ECONNRESET , Errno :: ENETUNREACH , Timeout :: Error , OpenURI :: HTTPError , OpenSSL :: SSL :: SSLError licensing_warning ( "Can not download license file '#{license_file}' for software '#{software_name}'." ) # If we got here, we need to fail now so we don't take a git # cache snapshot, or else the software build could be restored # from cache without fixing the license issue. raise_if_warnings_fatal! end end end end end


Input: Copy all scripts in { Project#package_scripts_path } to the control directory of this repo . [CODESPLIT] def write_scripts SCRIPT_MAP . each do | source , destination | source_path = File . join ( project . package_scripts_path , source . to_s ) next unless File . file? ( source_path ) destination_path = staging_dir_path ( destination ) log . debug ( log_key ) { "Adding script `#{source}' to `#{destination_path}'" } copy_file ( source_path , destination_path ) end end


Input: Generate a Prototype file for solaris build [CODESPLIT] def write_prototype_file shellout! "cd #{install_dirname} && find #{install_basename} -print > #{staging_dir_path('files')}" File . open staging_dir_path ( "files.clean" ) , "w+" do | fout | File . open staging_dir_path ( "files" ) do | fin | fin . each_line do | line | if line . chomp =~ / \s / log . warn ( log_key ) { "Skipping packaging '#{line}' file due to whitespace in filename" } else fout . write ( line ) end end end end # generate list of control files File . open staging_dir_path ( "Prototype" ) , "w+" do | f | f . write <<-EOF . gsub ( / / , "" ) EOF end # generate the prototype's file list shellout! "cd #{install_dirname} && pkgproto < #{staging_dir_path('files.clean')} > #{staging_dir_path('Prototype.files')}" # fix up the user and group in the file list to root shellout! "awk '{ $5 = \"root\"; $6 = \"root\"; print }' < #{staging_dir_path('Prototype.files')} >> #{staging_dir_path('Prototype')}" end


Input: Generate a pkginfo file for solaris build [CODESPLIT] def write_pkginfo_file hostname = Socket . gethostname # http://docs.oracle.com/cd/E19683-01/816-0219/6m6njqbat/index.html pkginfo_content = <<-EOF . gsub ( / / , "" ) #{ install_dirname } #{ project . package_name } #{ project . package_name } #{ safe_architecture } #{ pkgmk_version } #{ project . description } #{ project . maintainer } #{ project . maintainer } #{ hostname } #{ Time . now . utc . iso8601 } EOF File . open staging_dir_path ( "pkginfo" ) , "w+" do | f | f . write pkginfo_content end end


Input: The actual contents of the package . [CODESPLIT] def content @content ||= IO . read ( path ) rescue Errno :: ENOENT raise NoPackageFile . new ( path ) end


Input: Validate the presence of the required components for the package . [CODESPLIT] def validate! unless File . exist? ( path ) raise NoPackageFile . new ( path ) end unless File . exist? ( metadata . path ) raise NoPackageMetadataFile . new ( metadata . path ) end true end


Input: The unique upload key for this package . The additional stuff is postfixed to the end of the path . [CODESPLIT] def key_for ( package , * stuff ) File . join ( Config . s3_publish_pattern % package . metadata , stuff ) end


Input: Create a new BuildVersion [CODESPLIT] def semver build_tag = version_tag # PRERELEASE VERSION if prerelease_version? # ensure all dashes are dots per precedence rules (#12) in Semver # 2.0.0-rc.1 prerelease = prerelease_tag . tr ( "-" , "." ) build_tag << "-" << prerelease end # BUILD VERSION # Follows SemVer conventions and the build version begins with a '+'. build_version_items = [ ] # By default we will append a timestamp to every build. This behavior can # be overriden by setting the OMNIBUS_APPEND_TIMESTAMP environment # variable to a 'falsey' value (ie false, f, no, n or 0). # # format: YYYYMMDDHHMMSS example: 20130131123345 if Config . append_timestamp build_version_items << build_start_time end # We'll append the git describe information unless we are sitting right # on an annotated tag. # # format: git.COMMITS_SINCE_TAG.GIT_SHA example: git.207.694b062 unless commits_since_tag == 0 build_version_items << [ "git" , commits_since_tag , git_sha_tag ] . join ( "." ) end unless build_version_items . empty? build_tag << "+" << build_version_items . join ( "." ) end build_tag end


Input: We ll attempt to retrieve the timestamp from the Jenkin s set BUILD_TIMESTAMP or fall back to BUILD_ID environment variable . This will ensure platform specfic packages for the same build will share the same timestamp . [CODESPLIT] def build_start_time @build_start_time ||= begin if ENV [ "BUILD_TIMESTAMP" ] begin Time . strptime ( ENV [ "BUILD_TIMESTAMP" ] , "%Y-%m-%d_%H-%M-%S" ) rescue ArgumentError error_message = "BUILD_TIMESTAMP environment variable " error_message << "should be in YYYY-MM-DD_hh-mm-ss " error_message << "format." raise ArgumentError , error_message end elsif ENV [ "BUILD_ID" ] begin Time . strptime ( ENV [ "BUILD_ID" ] , "%Y-%m-%d_%H-%M-%S" ) rescue ArgumentError error_message = "BUILD_ID environment variable " error_message << "should be in YYYY-MM-DD_hh-mm-ss " error_message << "format." raise ArgumentError , error_message end else Time . now . utc end end . strftime ( TIMESTAMP_FORMAT ) end


Input: Generates a version string by running { https : // www . kernel . org / pub / software / scm / git / docs / git - describe . html git describe } in the root of the Omnibus project . [CODESPLIT] def git_describe @git_describe ||= begin cmd = shellout ( "git describe --tags" , cwd : @path ) if cmd . exitstatus == 0 cmd . stdout . chomp else log . warn ( log_key ) do "Could not extract version information from 'git describe'! " "Setting version to 0.0.0." end "0.0.0" end end end


Input: Save the file to disk . [CODESPLIT] def save File . open ( path , "w+" ) do | f | f . write ( FFI_Yajl :: Encoder . encode ( to_hash , pretty : true ) ) end true end


Input: Set or return the vendor who made this package . [CODESPLIT] def vendor ( val = NULL ) if null? ( val ) @vendor || "Omnibus <omnibus@getchef.com>" else unless val . is_a? ( String ) raise InvalidValue . new ( :vendor , "be a String" ) end @vendor = val end end


Input: Set or return the license for this package . [CODESPLIT] def license ( val = NULL ) if null? ( val ) @license || project . license else unless val . is_a? ( String ) raise InvalidValue . new ( :license , "be a String" ) end @license = val end end


Input: Mark filesystem directories with ownership and permissions specified in the filesystem package https : // git . fedorahosted . org / cgit / filesystem . git / plain / filesystem . spec [CODESPLIT] def mark_filesystem_directories ( fsdir ) if fsdir . eql? ( "/" ) || fsdir . eql? ( "/usr/lib" ) || fsdir . eql? ( "/usr/share/empty" ) "%dir %attr(0555,root,root) #{fsdir}" elsif filesystem_directories . include? ( fsdir ) "%dir %attr(0755,root,root) #{fsdir}" else "%dir #{fsdir}" end end


Input: Render an rpm spec file in + SPECS / # { name } . spec + using the supplied ERB template . [CODESPLIT] def write_rpm_spec # Create a map of scripts that exist and their contents scripts = SCRIPT_MAP . inject ( { } ) do | hash , ( source , destination ) | path = File . join ( project . package_scripts_path , source . to_s ) if File . file? ( path ) hash [ destination ] = File . read ( path ) end hash end # Get a list of all files files = FileSyncer . glob ( "#{build_dir}/**/*" ) . map { | path | build_filepath ( path ) } render_template ( resource_path ( "spec.erb" ) , destination : spec_file , variables : { name : safe_base_package_name , version : safe_version , iteration : safe_build_iteration , vendor : vendor , license : license , dist_tag : dist_tag , maintainer : project . maintainer , homepage : project . homepage , description : project . description , priority : priority , category : category , conflicts : project . conflicts , replaces : project . replaces , dependencies : project . runtime_dependencies , user : project . package_user , group : project . package_group , scripts : scripts , config_files : config_files , files : files , build_dir : build_dir , platform_family : Ohai [ "platform_family" ] , compression : compression , } ) end


Input: Generate the RPM file using + rpmbuild + . Unlike debian the + fakeroot + command is not required for the package to be owned by + root : root + . The rpmuser specified in the spec file dictates this . [CODESPLIT] def create_rpm_file command = %{rpmbuild} command << %{ --target #{safe_architecture}} command << %{ -bb} command << %{ --buildroot #{staging_dir}/BUILD} command << %{ --define '_topdir #{staging_dir}'} if signing_passphrase log . info ( log_key ) { "Signing enabled for .rpm file" } if File . exist? ( "#{ENV['HOME']}/.rpmmacros" ) log . info ( log_key ) { "Detected .rpmmacros file at `#{ENV['HOME']}'" } home = ENV [ "HOME" ] else log . info ( log_key ) { "Using default .rpmmacros file from Omnibus" } # Generate a temporary home directory home = Dir . mktmpdir render_template ( resource_path ( "rpmmacros.erb" ) , destination : "#{home}/.rpmmacros" , variables : { gpg_name : project . maintainer , gpg_path : "#{ENV['HOME']}/.gnupg" , # TODO: Make this configurable } ) end command << " --sign" command << " #{spec_file}" with_rpm_signing do | signing_script | log . info ( log_key ) { "Creating .rpm file" } shellout! ( "#{signing_script} \"#{command}\"" , environment : { "HOME" => home } ) end else log . info ( log_key ) { "Creating .rpm file" } command << " #{spec_file}" shellout! ( "#{command}" ) end FileSyncer . glob ( "#{staging_dir}/RPMS/**/*.rpm" ) . each do | rpm | copy_file ( rpm , Config . package_dir ) end end


Input: Convert the path of a file in the staging directory to an entry for use in the spec file . [CODESPLIT] def build_filepath ( path ) filepath = rpm_safe ( "/" + path . gsub ( "#{build_dir}/" , "" ) ) return if config_files . include? ( filepath ) full_path = build_dir + filepath . gsub ( "[%]" , "%" ) # FileSyncer.glob quotes pathnames that contain spaces, which is a problem on el7 full_path . delete! ( '"' ) # Mark directories with the %dir directive to prevent rpmbuild from counting their contents twice. return mark_filesystem_directories ( filepath ) if ! File . symlink? ( full_path ) && File . directory? ( full_path ) filepath end


Input: Render the rpm signing script with secure permissions call the given block with the path to the script and ensure deletion of the script from disk since it contains sensitive information . [CODESPLIT] def with_rpm_signing ( & block ) directory = Dir . mktmpdir destination = "#{directory}/sign-rpm" render_template ( resource_path ( "signing.erb" ) , destination : destination , mode : 0700 , variables : { passphrase : signing_passphrase , } ) # Yield the destination to the block yield ( destination ) ensure remove_file ( destination ) remove_directory ( directory ) end


Input: Generate an RPM - safe name from the given string doing the following : [CODESPLIT] def rpm_safe ( string ) string = "\"#{string}\"" if string [ / \s / ] string . dup . gsub ( "[" , "[\\[]" ) . gsub ( "*" , "[*]" ) . gsub ( "?" , "[?]" ) . gsub ( "%" , "[%]" ) end


Input: Shortcut method for executing a publisher . [CODESPLIT] def publish ( klass , pattern , options ) if options [ :platform_mappings ] options [ :platform_mappings ] = FFI_Yajl :: Parser . parse ( File . read ( File . expand_path ( options [ :platform_mappings ] ) ) ) end klass . publish ( pattern , options ) do | package | say ( "Published '#{package.name}' for #{package.metadata[:platform]}-#{package.metadata[:platform_version]}" , :green ) end end


Input: ** [ Required ] ** Set or retrieve the path at which the project should be installed by the generated package . [CODESPLIT] def install_dir ( val = NULL ) if null? ( val ) @install_dir || raise ( MissingRequiredAttribute . new ( self , :install_dir , "/opt/chef" ) ) else @install_dir = val . tr ( '\\' , "/" ) . squeeze ( "/" ) . chomp ( "/" ) end end


Input: Set or retrieve the version of the project . [CODESPLIT] def build_version ( val = NULL , & block ) if block && ! null? ( val ) raise Error , "You cannot specify additional parameters to " "#build_version when a block is given!" end if block @build_version_dsl = BuildVersionDSL . new ( block ) else if null? ( val ) @build_version_dsl . build_version else @build_version_dsl = BuildVersionDSL . new ( val ) end end end


Input: Add or override a customization for the packager with the given + id + . When given multiple blocks with the same + id + they are evaluated _in order_ so the last block evaluated will take precedence over the previous ones . [CODESPLIT] def package ( id , & block ) unless block raise InvalidValue . new ( :package , "have a block" ) end packagers [ id ] << block end


Input: Add or override a customization for the compressor with the given + id + . When given multiple blocks with the same + id + they are evaluated _in order_ so the last block evaluated will take precedence over the previous ones . [CODESPLIT] def compress ( id , & block ) if block compressors [ id ] << block else compressors [ id ] << Proc . new { } end end


Input: Set or retrieve the overrides hash for one piece of software being overridden . Calling it as a setter does not merge hash entries and it will set all the overrides for a given software definition . [CODESPLIT] def override ( name , val = NULL ) if null? ( val ) overrides [ name . to_sym ] else overrides [ name . to_sym ] = val end end


Input: Location of license file that omnibus will create and that will contain the information about the license of the project plus the details about the licenses of the software components included in the project . [CODESPLIT] def license_file_path ( path = NULL ) if null? ( path ) @license_file_path || File . join ( install_dir , "LICENSE" ) else @license_file_path = File . join ( install_dir , path ) end end


Input: Indicates whether the given + software + is defined as a software component of this project . [CODESPLIT] def dependency? ( software ) name = software . is_a? ( Software ) ? software . name : software dependencies . include? ( name ) end


Input: Generate a version manifest of the loaded software sources . [CODESPLIT] def built_manifest log . info ( log_key ) { "Building version manifest" } m = Omnibus :: Manifest . new ( build_version , build_git_revision , license ) softwares . each do | software | m . add ( software . name , software . manifest_entry ) end m end


Input: Writes a text manifest to the text_manifest_path . This uses the same method as the version - manifest software definition in omnibus - software . [CODESPLIT] def write_text_manifest File . open ( text_manifest_path , "w" ) do | f | f . puts "#{name} #{build_version}" f . puts "" f . puts Omnibus :: Reports . pretty_version_map ( self ) end end


Input: Compression level ( 1 - 9 ) to use ( - Z ) . [CODESPLIT] def compression_level ( val = NULL ) if null? ( val ) @compression_level || 9 else unless val . is_a? ( Integer ) && 1 <= val && 9 >= val raise InvalidValue . new ( :compression_level , "be an Integer between 1 and 9" ) end @compression_level = val end end


Input: Compression strategy to use ( - Z ) . For gzip : : filtered : huffman : rle or : fixed ; for xz : : extreme ( nil means parameter will not be passsed to dpkg - deb ) [CODESPLIT] def compression_strategy ( val = NULL ) if null? ( val ) @compression_strategy else unless val . is_a? ( Symbol ) && [ :filtered , :huffman , :rle , :fixed , :extreme ] . member? ( val ) raise InvalidValue . new ( :compression_strategy , "be a Symbol (:filtered, " ":huffman, :rle, :fixed, or :extreme)" ) end @compression_strategy = val end end


Input: Render a control file in + # { debian_dir } / control + using the supplied ERB template . [CODESPLIT] def write_control_file render_template ( resource_path ( "control.erb" ) , destination : File . join ( debian_dir , "control" ) , variables : { name : safe_base_package_name , version : safe_version , iteration : safe_build_iteration , vendor : vendor , license : license , architecture : safe_architecture , maintainer : project . maintainer , installed_size : package_size , homepage : project . homepage , description : project . description , priority : priority , section : section , conflicts : project . conflicts , replaces : project . replaces , dependencies : project . runtime_dependencies , } ) end


Input: Render the list of config files into the conffile . [CODESPLIT] def write_conffiles_file return if project . config_files . empty? render_template ( resource_path ( "conffiles.erb" ) , destination : File . join ( debian_dir , "conffiles" ) , variables : { config_files : project . config_files , } ) end


Input: Copy all scripts in { Project#package_scripts_path } to the control directory of this repo . [CODESPLIT] def write_scripts %w{ preinst postinst prerm postrm } . each do | script | path = File . join ( project . package_scripts_path , script ) if File . file? ( path ) log . debug ( log_key ) { "Adding script `#{script}' to `#{debian_dir}' from #{path}" } copy_file ( path , debian_dir ) log . debug ( log_key ) { "SCRIPT FILE:  #{debian_dir}/#{script}" } FileUtils . chmod ( 0755 , File . join ( debian_dir , script ) ) end end end


Input: Generate a list of the md5 sums of every file in the package and write it to + # { debian_dir } / control / md5sums + . [CODESPLIT] def write_md5_sums path = "#{staging_dir}/**/*" hash = FileSyncer . glob ( path ) . inject ( { } ) do | hash , path | if File . file? ( path ) && ! File . symlink? ( path ) && ! ( File . dirname ( path ) == debian_dir ) relative_path = path . gsub ( "#{staging_dir}/" , "" ) hash [ relative_path ] = digest ( path , :md5 ) end hash end render_template ( resource_path ( "md5sums.erb" ) , destination : File . join ( debian_dir , "md5sums" ) , variables : { md5sums : hash , } ) end


Input: Sign the + . deb + file with gpg . This has to be done as separate steps from creating the + . deb + file . See + debsigs + source for behavior replicated here . + https : // gitlab . com / debsigs / debsigs / blob / master / debsigs . txt#L103 - 124 + [CODESPLIT] def sign_deb_file if ! signing_passphrase log . info ( log_key ) { "Signing not enabled for .deb file" } return end log . info ( log_key ) { "Signing enabled for .deb file" } # Check our dependencies and determine command for GnuPG. +Omnibus.which+ returns the path, or nil. gpg = nil if Omnibus . which ( "gpg2" ) gpg = "gpg2" elsif Omnibus . which ( "gpg" ) gpg = "gpg" end if gpg && Omnibus . which ( "ar" ) # Create a directory that will be cleaned when we leave the block Dir . mktmpdir do | tmp_dir | Dir . chdir ( tmp_dir ) do # Extract the deb file contents shellout! ( "ar x #{Config.package_dir}/#{package_name}" ) # Concatenate contents, in order per +debsigs+ documentation. shellout! ( "cat debian-binary control.tar.* data.tar.* > complete" ) # Create signature (as +root+) gpg_command = "#{gpg} --armor --sign --detach-sign" gpg_command << " --local-user '#{project.maintainer}'" gpg_command << " --homedir #{ENV['HOME']}/.gnupg" # TODO: Make this configurable ## pass the +signing_passphrase+ via +STDIN+ gpg_command << " --batch --no-tty" ## Check `gpg` for the compatibility/need of pinentry-mode # - We're calling gpg with the +--pinentry-mode+ argument, and +STDIN+ of +/dev/null+ # - This _will_ fail with exit code 2 no matter what. We want to check the +STDERR+ #   for the error message about the parameter. If it is _not present_ in the #   output, then we _do_ want to add it. (If +grep -q+ is +1+, add parameter) if shellout ( "#{gpg} --pinentry-mode loopback </dev/null 2>&1 | grep -q pinentry-mode" ) . exitstatus == 1 gpg_command << " --pinentry-mode loopback" end gpg_command << " --passphrase-fd 0" gpg_command << " -o _gpgorigin complete" shellout! ( "fakeroot #{gpg_command}" , input : signing_passphrase ) # Append +_gpgorigin+ to the +.deb+ file (as +root+) shellout! ( "fakeroot ar rc #{Config.package_dir}/#{package_name} _gpgorigin" ) end end else log . info ( log_key ) { "Signing not possible. Ensure that GnuPG and GNU AR are available" } end end


Input: The size of this Debian package . This is dynamically calculated . [CODESPLIT] def package_size @package_size ||= begin path = "#{project.install_dir}/**/*" total = FileSyncer . glob ( path ) . inject ( 0 ) do | size , path | unless File . directory? ( path ) || File . symlink? ( path ) size += File . size ( path ) end size end # Per http://www.debian.org/doc/debian-policy/ch-controlfields.html, the # disk space is given as the integer value of the estimated installed # size in bytes, divided by 1024 and rounded up. total / 1024 end end


Input: Return the Debian - ready base package name converting any invalid characters to dashes ( + - + ) . [CODESPLIT] def safe_base_package_name if project . package_name =~ / \A \. \+ \- \z / project . package_name . dup else converted = project . package_name . downcase . gsub ( / \. \+ \- / , "-" ) log . warn ( log_key ) do "The `name' component of Debian package names can only include " "lower case alphabetical characters (a-z), numbers (0-9), dots (.), " "plus signs (+), and dashes (-). Converting `#{project.package_name}' to " "`#{converted}'." end converted end end


Input: Return the Debian - ready version replacing all dashes ( + - + ) with tildes ( + ~ + ) and converting any invalid characters to underscores ( + _ + ) . [CODESPLIT] def safe_version version = project . build_version . dup if version =~ / \- / converted = version . tr ( "-" , "~" ) log . warn ( log_key ) do "Dashes hold special significance in the Debian package versions. " "Versions that contain a dash and should be considered an earlier " "version (e.g. pre-releases) may actually be ordered as later " "(e.g. 12.0.0-rc.6 > 12.0.0). We'll work around this by replacing " "dashes (-) with tildes (~). Converting `#{project.build_version}' " "to `#{converted}'." end version = converted end if version =~ / \A \. \+ \: \~ \z / version else converted = version . gsub ( / \. \+ \: \~ / , "_" ) log . warn ( log_key ) do "The `version' component of Debian package names can only include " "alphabetical characters (a-z, A-Z), numbers (0-9), dots (.), " "plus signs (+), dashes (-), tildes (~) and colons (:). Converting " "`#{project.build_version}' to `#{converted}'." end converted end end


Input: Fetch ( clone ) or update ( fetch ) the remote git repository . [CODESPLIT] def fetch log . info ( log_key ) { "Fetching from `#{source_url}'" } create_required_directories if cloned? git_fetch else force_recreate_project_dir! unless dir_empty? ( project_dir ) git_clone end end


Input: Determine if a directory is empty [CODESPLIT] def dir_empty? ( dir ) Dir . entries ( dir ) . reject { | d | [ "." , ".." ] . include? ( d ) } . empty? end


Input: Forcibly remove and recreate the project directory [CODESPLIT] def force_recreate_project_dir! log . warn ( log_key ) { "Removing existing directory #{project_dir} before cloning" } FileUtils . rm_rf ( project_dir ) Dir . mkdir ( project_dir ) end


Input: The current revision for the cloned checkout . [CODESPLIT] def current_revision cmd = git ( "rev-parse HEAD" ) cmd . stdout . strip rescue CommandFailed log . debug ( log_key ) { "unable to determine current revision" } nil end


Input: Check if the current clone has the requested commit id . [CODESPLIT] def contains_revision? ( rev ) cmd = git ( "cat-file -t #{rev}" ) cmd . stdout . strip == "commit" rescue CommandFailed log . debug ( log_key ) { "unable to determine presence of commit #{rev}" } false end


Input: Converts a BN object to a string . The format used is that which is required by the SSH2 protocol . [CODESPLIT] def to_ssh if zero? return [ 0 ] . pack ( "N" ) else buf = to_s ( 2 ) if buf . getbyte ( 0 ) [ 7 ] == 1 return [ buf . length + 1 , 0 , buf ] . pack ( "NCA*" ) else return [ buf . length , buf ] . pack ( "NA*" ) end end end


Input: Compute the number of bits needed for the given number of bytes . [CODESPLIT] def compute_need_bits # for Compatibility: OpenSSH requires (need_bits * 2 + 1) length of parameter need_bits = data [ :need_bytes ] * 8 * 2 + 1 data [ :minimum_dh_bits ] ||= MINIMUM_BITS if need_bits < data [ :minimum_dh_bits ] need_bits = data [ :minimum_dh_bits ] elsif need_bits > MAXIMUM_BITS need_bits = MAXIMUM_BITS end data [ :need_bits ] = need_bits data [ :need_bytes ] = need_bits / 8 end


Input: Returns the DH key parameters for the given session . [CODESPLIT] def get_parameters compute_need_bits # request the DH key parameters for the given number of bits. buffer = Net :: SSH :: Buffer . from ( :byte , KEXDH_GEX_REQUEST , :long , data [ :minimum_dh_bits ] , :long , data [ :need_bits ] , :long , MAXIMUM_BITS ) connection . send_message ( buffer ) buffer = connection . next_message raise Net :: SSH :: Exception , "expected KEXDH_GEX_GROUP, got #{buffer.type}" unless buffer . type == KEXDH_GEX_GROUP p = buffer . read_bignum g = buffer . read_bignum [ p , g ] end


Input: Build the signature buffer to use when verifying a signature from the server . [CODESPLIT] def build_signature_buffer ( result ) response = Net :: SSH :: Buffer . new response . write_string data [ :client_version_string ] , data [ :server_version_string ] , data [ :client_algorithm_packet ] , data [ :server_algorithm_packet ] , result [ :key_blob ] response . write_long MINIMUM_BITS , data [ :need_bits ] , MAXIMUM_BITS response . write_bignum dh . p , dh . g , dh . pub_key , result [ :server_dh_pubkey ] , result [ :shared_secret ] response end


Input: Executes the given block after the page is loaded . [CODESPLIT] def when_loaded # Get original loaded value, in case we are nested # inside another when_loaded block. previously_loaded = loaded # Within the block, check (and cache) loaded?, to see whether the # page has indeed loaded according to the rules defined by the user. self . loaded = loaded? # If the page hasn't loaded. Then crash and return the error message. # If one isn't defined, just return the Error code. raise SitePrism :: FailedLoadValidationError , load_error unless loaded # Return the yield value of the block if one was supplied. yield self if block_given? ensure self . loaded = previously_loaded end


Input: If any load validations from page subclasses returns false immediately return false . [CODESPLIT] def load_validations_pass? self . class . load_validations . all? do | validation | passed , message = instance_eval ( validation ) self . load_error = message if message && ! passed passed end end


Input: Prevent users from calling methods with blocks when they shouldn t be . [CODESPLIT] def raise_if_block ( obj , name , has_block , type ) return unless has_block SitePrism . logger . debug ( "Type passed in: #{type}" ) SitePrism . logger . warn ( 'section / iFrame can only accept blocks.' ) SitePrism . logger . error ( "#{obj.class}##{name} does not accept blocks" ) raise SitePrism :: UnsupportedBlockError end


Input: Sanitize method called before calling any SitePrism DSL method or meta - programmed method . This ensures that the Capybara query is correct . [CODESPLIT] def merge_args ( find_args , runtime_args , visibility_args = { } ) find_args = find_args . dup runtime_args = runtime_args . dup options = visibility_args . dup SitePrism . logger . debug ( "Initial args: #{find_args}, #{runtime_args}." ) recombine_args ( find_args , runtime_args , options ) return [ find_args , runtime_args ] if options . empty? [ find_args , runtime_args , options ] end


Input: Options re - combiner . This takes the original inputs and combines them such that there is only one hash passed as a final argument to Capybara . [CODESPLIT] def recombine_args ( find_args , runtime_args , options ) options . merge! ( find_args . pop ) if find_args . last . is_a? Hash options . merge! ( runtime_args . pop ) if runtime_args . last . is_a? Hash options [ :wait ] = wait_time unless wait_key_present? ( options ) end


Input: Runnable in the scope of any SitePrism :: Page or Section . Returns + true + when every item that is being checked is present within the current scope . See #elements_to_check for how the definition of every item is derived . [CODESPLIT] def all_there? ( recursion : 'none' ) SitePrism . logger . info ( 'Setting for recursion is being ignored for now.' ) if %w[ none one ] . include? ( recursion ) elements_to_check . all? { | item_name | there? ( item_name ) } else SitePrism . logger . error ( 'Invalid recursion setting, Will not run.' ) end end


Input: If the page or section has expected_items set return expected_items that are mapped ; otherwise just return the list of all mapped_items [CODESPLIT] def elements_to_check if _expected_items SitePrism . logger . debug ( 'Expected Items has been set.' ) _mapped_items . select { | item_name | _expected_items . include? ( item_name ) } else _mapped_items end end


Input: Loads the page . @param expansion_or_html @param block [ &block ] An optional block to run once the page is loaded . The page will yield the block if defined . [CODESPLIT] def load ( expansion_or_html = { } , & block ) self . loaded = false SitePrism . logger . debug ( "Reset loaded state on #{self.class}." ) return_yield = if expansion_or_html . is_a? ( String ) load_html_string ( expansion_or_html , block ) else load_html_website ( expansion_or_html , block ) end # Ensure that we represent that the page we loaded is now indeed loaded! # This ensures that future calls to #loaded? do not perform the # instance evaluations against all load validations procs another time. self . loaded = true SitePrism . logger . info ( "#{self.class} loaded." ) # Return the yield from the block if there was one, otherwise return true return_yield || true end


Input: Determine whether URL matches our pattern and optionally whether the extracted mappings match a hash of expected values . You can specify values as strings numbers or regular expressions . [CODESPLIT] def matches? ( url , expected_mappings = { } ) actual_mappings = mappings ( url ) return false unless actual_mappings expected_mappings . empty? || all_expected_mappings_match? ( expected_mappings , actual_mappings ) end


Input: Returns empty hash if the template omits the component or a set of substitutions if the provided URI component matches the template component or nil if the match fails . [CODESPLIT] def component_matches ( component , uri ) component_template = component_templates [ component ] return { } unless component_template component_url = uri . public_send ( component ) . to_s mappings = component_template . extract ( component_url ) return mappings if mappings # to support Addressable's expansion of queries # ensure it's parsing the fragment as appropriate (e.g. {?params*}) prefix = component_prefixes [ component ] return nil unless prefix component_template . extract ( prefix + component_url ) end


Input: Convert the pattern into an Addressable URI by substituting the template slugs with nonsense strings . [CODESPLIT] def to_substituted_uri url = pattern substitutions . each_pair { | slug , value | url = url . sub ( slug , value ) } begin Addressable :: URI . parse ( url ) rescue Addressable :: URI :: InvalidURIError SitePrism . logger . warn ( "Ensure you don't use templated port numbers." ) raise SitePrism :: InvalidUrlMatcherError end end


Input: Generate a repeatable 5 character uniform alphabetical nonsense string to allow parsing as a URI [CODESPLIT] def substitution_value ( index ) sha = Digest :: SHA1 . digest ( index . to_s ) Base64 . urlsafe_encode64 ( sha ) . gsub ( / / , '' ) [ 0 .. 5 ] end


Input: Builds Enumerator objects that iterates N times and yields number starting from zero . [CODESPLIT] def build_times_enumerator ( number , cursor : ) raise ArgumentError , "First argument must be an Integer" unless number . is_a? ( Integer ) wrap ( self , build_array_enumerator ( number . times . to_a , cursor : cursor ) ) end


Input: Builds Enumerator object from a given array using + cursor + as an offset . [CODESPLIT] def build_array_enumerator ( enumerable , cursor : ) unless enumerable . is_a? ( Array ) raise ArgumentError , "enumerable must be an Array" end if enumerable . any? { | i | defined? ( ActiveRecord ) && i . is_a? ( ActiveRecord :: Base ) } raise ArgumentError , "array cannot contain ActiveRecord objects" end drop = if cursor . nil? 0 else cursor + 1 end wrap ( self , enumerable . each_with_index . drop ( drop ) . to_enum { enumerable . size } ) end


Input: Builds Enumerator from a lock queue instance that belongs to a job . The helper is only to be used from jobs that use LockQueue module . [CODESPLIT] def build_lock_queue_enumerator ( lock_queue , at_most_once : ) unless lock_queue . is_a? ( BackgroundQueue :: LockQueue :: RedisQueue ) || lock_queue . is_a? ( BackgroundQueue :: LockQueue :: RolloutRedisQueue ) raise ArgumentError , "an argument to #build_lock_queue_enumerator must be a LockQueue" end wrap ( self , BackgroundQueue :: LockQueueEnumerator . new ( lock_queue , at_most_once : at_most_once ) . to_enum ) end


Input: Builds Enumerator from Active Record Relation . Each Enumerator tick moves the cursor one row forward . [CODESPLIT] def build_active_record_enumerator_on_records ( scope , cursor : , ** args ) enum = build_active_record_enumerator ( scope , cursor : cursor , ** args ) . records wrap ( self , enum ) end


Input: Builds Enumerator from Active Record Relation and enumerates on batches . Each Enumerator tick moves the cursor + batch_size + rows forward . [CODESPLIT] def build_active_record_enumerator_on_batches ( scope , cursor : , ** args ) enum = build_active_record_enumerator ( scope , cursor : cursor , ** args ) . batches wrap ( self , enum ) end


Input: Constructs a enumerator on batches of CSV rows [CODESPLIT] def batches ( batch_size : , cursor : ) @csv . lazy . each_slice ( batch_size ) . each_with_index . drop ( cursor . to_i ) . to_enum { ( count_rows_in_file . to_f / batch_size ) . ceil } end


Input: Restore the item from this version . [CODESPLIT] def reify ( options = { } ) unless self . class . column_names . include? "object" raise "reify can't be called without an object column" end return nil if object . nil? :: PaperTrail :: Reifier . reify ( self , options ) end


Input: Enforces the version_limit if set . Default : no limit . [CODESPLIT] def enforce_version_limit! limit = version_limit return unless limit . is_a? Numeric previous_versions = sibling_versions . not_creates . order ( self . class . timestamp_sort_order ( "asc" ) ) return unless previous_versions . size > limit excess_versions = previous_versions - previous_versions . last ( limit ) excess_versions . map ( :destroy ) end


Input: See docs section 2 . e . Limiting the Number of Versions Created . The version limit can be global or per - model . [CODESPLIT] def version_limit if self . class . item_subtype_column_present? klass = ( item_subtype || item_type ) . constantize if klass &. paper_trail_options &. key? ( :limit ) return klass . paper_trail_options [ :limit ] end end PaperTrail . config . version_limit end


Input: Returns [CODESPLIT] def sequence if @version_class . primary_key_is_int? @versions . select ( primary_key ) . order ( primary_key . asc ) else @versions . select ( [ table [ :created_at ] , primary_key ] ) . order ( @version_class . timestamp_sort_order ) end end


Input: Destroys all but the most recent version ( s ) for items on a given date ( or on all dates ) . Useful for deleting drafts . [CODESPLIT] def clean_versions! ( options = { } ) options = { keeping : 1 , date : :all } . merge ( options ) gather_versions ( options [ :item_id ] , options [ :date ] ) . each do | _item_id , item_versions | group_versions_by_date ( item_versions ) . each do | _date , date_versions | # Remove the number of versions we wish to keep from the collection # of versions prior to destruction. date_versions . pop ( options [ :keeping ] ) date_versions . map ( :destroy ) end end end


Input: Returns a hash of versions grouped by the item_id attribute formatted like this : { : item_id = > PaperTrail :: Version } . If item_id or date is set versions will be narrowed to those pointing at items with those ids that were created on specified date . Versions are returned in chronological order . [CODESPLIT] def gather_versions ( item_id = nil , date = :all ) unless date == :all || date . respond_to? ( :to_date ) raise ArgumentError , "Expected date to be a Timestamp or :all" end versions = item_id ? PaperTrail :: Version . where ( item_id : item_id ) : PaperTrail :: Version versions = versions . order ( PaperTrail :: Version . timestamp_sort_order ) versions = versions . between ( date . to_date , date . to_date + 1 . day ) unless date == :all # If `versions` has not been converted to an ActiveRecord::Relation yet, # do so now. versions = PaperTrail :: Version . all if versions == PaperTrail :: Version versions . group_by ( :item_id ) end


Input: Adds a callback that records a version after a create event . [CODESPLIT] def on_create @model_class . after_create { | r | r . paper_trail . record_create if r . paper_trail . save_version? } return if @model_class . paper_trail_options [ :on ] . include? ( :create ) @model_class . paper_trail_options [ :on ] << :create end


Input: Adds a callback that records a version before or after a destroy event . [CODESPLIT] def on_destroy ( recording_order = "before" ) unless %w[ after before ] . include? ( recording_order . to_s ) raise ArgumentError , 'recording order can only be "after" or "before"' end if recording_order . to_s == "after" && cannot_record_after_destroy? raise E_CANNOT_RECORD_AFTER_DESTROY end @model_class . send ( "#{recording_order}_destroy" , lambda do | r | return unless r . paper_trail . save_version? r . paper_trail . record_destroy ( recording_order ) end ) return if @model_class . paper_trail_options [ :on ] . include? ( :destroy ) @model_class . paper_trail_options [ :on ] << :destroy end


Input: Adds a callback that records a version after an update event . [CODESPLIT] def on_update @model_class . before_save { | r | r . paper_trail . reset_timestamp_attrs_for_update_if_needed } @model_class . after_update { | r | if r . paper_trail . save_version? r . paper_trail . record_update ( force : false , in_after_callback : true , is_touch : false ) end } @model_class . after_update { | r | r . paper_trail . clear_version_instance } return if @model_class . paper_trail_options [ :on ] . include? ( :update ) @model_class . paper_trail_options [ :on ] << :update end


Input: Adds a callback that records a version after a touch event . [CODESPLIT] def on_touch @model_class . after_touch { | r | r . paper_trail . record_update ( force : true , in_after_callback : true , is_touch : true ) } end


Input: Set up [CODESPLIT] def setup ( options = { } ) options [ :on ] ||= %i[ create update destroy touch ] options [ :on ] = Array ( options [ :on ] ) # Support single symbol @model_class . send :include , :: PaperTrail :: Model :: InstanceMethods setup_options ( options ) setup_associations ( options ) check_presence_of_item_subtype_column ( options ) @model_class . after_rollback { paper_trail . clear_rolled_back_versions } setup_callbacks_from_options options [ :on ] end


Input: Some options require the presence of the item_subtype column . Currently only limit but in the future there may be others . [CODESPLIT] def check_presence_of_item_subtype_column ( options ) return unless options . key? ( :limit ) return if version_class . item_subtype_column_present? raise format ( E_MODEL_LIMIT_REQUIRES_ITEM_SUBTYPE , @model_class . name ) end


Input: recording_order is after or before . See ModelConfig#on_destroy . [CODESPLIT] def record_destroy ( recording_order ) return unless enabled? && ! @record . new_record? in_after_callback = recording_order == "after" event = Events :: Destroy . new ( @record , in_after_callback ) # Merge data from `Event` with data from PT-AT. We no longer use # `data_for_destroy` but PT-AT still does. data = event . data . merge ( data_for_destroy ) version = @record . class . paper_trail . version_class . create ( data ) if version . errors . any? log_version_errors ( version , :destroy ) else assign_and_reset_version_association ( version ) version end end


Input: AR callback . [CODESPLIT] def save_version? if_condition = @record . paper_trail_options [ :if ] unless_condition = @record . paper_trail_options [ :unless ] ( if_condition . blank? || if_condition . call ( @record ) ) && ! unless_condition . try ( :call , @record ) end


Input: Save and create a version record regardless of options such as : on : if or : unless . [CODESPLIT] def save_with_version ( * args ) :: PaperTrail . request ( enabled : false ) do @record . save ( args ) end record_update ( force : true , in_after_callback : false , is_touch : false ) end


Input: Like the update_columns method from ActiveRecord :: Persistence but also creates a version to record those changes . [CODESPLIT] def update_columns ( attributes ) # `@record.update_columns` skips dirty-tracking, so we can't just use # `@record.changes` or @record.saved_changes` from `ActiveModel::Dirty`. # We need to build our own hash with the changes that will be made # directly to the database. changes = { } attributes . each do | k , v | changes [ k ] = [ @record [ k ] , v ] end @record . update_columns ( attributes ) record_update_columns ( changes ) end


Input: Returns the object ( not a Version ) as it was at the given timestamp . [CODESPLIT] def version_at ( timestamp , reify_options = { } ) # Because a version stores how its object looked *before* the change, # we need to look for the first version created *after* the timestamp. v = versions . subsequent ( timestamp , true ) . first return v . reify ( reify_options ) if v @record unless @record . destroyed? end


Input: Returns the objects ( not Versions ) as they were between the given times . [CODESPLIT] def versions_between ( start_time , end_time ) versions = send ( @record . class . versions_association_name ) . between ( start_time , end_time ) versions . collect { | version | version_at ( version . created_at ) } end


Input: Invalidate some part of the snapshot / record ( dir file subtree etc . ) [CODESPLIT] def invalidate ( type , rel_path , options ) watched_dir = Pathname . new ( record . root ) change = options [ :change ] cookie = options [ :cookie ] if ! cookie && config . silenced? ( rel_path , type ) Listen :: Logger . debug { "(silenced): #{rel_path.inspect}" } return end path = watched_dir + rel_path Listen :: Logger . debug do log_details = options [ :silence ] && 'recording' || change || 'unknown' "#{log_details}: #{type}:#{path} (#{options.inspect})" end if change options = cookie ? { cookie : cookie } : { } config . queue ( type , change , watched_dir , rel_path , options ) elsif type == :dir # NOTE: POSSIBLE RECURSION # TODO: fix - use a queue instead Directory . scan ( self , rel_path , options ) else change = File . change ( record , rel_path ) return if ! change || options [ :silence ] config . queue ( :file , change , watched_dir , rel_path ) end rescue RuntimeError => ex msg = format ( '%s#%s crashed %s:%s' , self . class , __method__ , exinspect , ex . backtrace * "\n" ) Listen :: Logger . error ( msg ) raise end


Input: Note : relative_path is temporarily expected to be a relative Pathname to make refactoring easier ( ideally it would take a string ) TODO : switch type and path places - and verify [CODESPLIT] def silenced? ( relative_path , type ) path = relative_path . to_s if only_patterns && type == :file return true unless only_patterns . any? { | pattern | path =~ pattern } end ignore_patterns . any? { | pattern | path =~ pattern } end


Input: groups changes into the expected structure expected by clients [CODESPLIT] def _squash_changes ( changes ) # We combine here for backward compatibility # Newer clients should receive dir and path separately changes = changes . map { | change , dir , path | [ change , dir + path ] } actions = changes . group_by ( :last ) . map do | path , action_list | [ _logical_action_for ( path , action_list . map ( :first ) ) , path . to_s ] end config . debug ( "listen: raw changes: #{actions.inspect}" ) { modified : [ ] , added : [ ] , removed : [ ] } . tap do | squashed | actions . each do | type , path | squashed [ type ] << path unless type . nil? end config . debug ( "listen: final changes: #{squashed.inspect}" ) end end


Input: remove extraneous rb - inotify events keeping them only if it s a possible editor rename () call ( e . g . Kate and Sublime ) [CODESPLIT] def _reinterpret_related_changes ( cookies ) table = { moved_to : :added , moved_from : :removed } cookies . flat_map do | _ , changes | data = _detect_possible_editor_save ( changes ) if data to_dir , to_file = data [ [ :modified , to_dir , to_file ] ] else not_silenced = changes . reject do | type , _ , _ , path , _ | config . silenced? ( Pathname ( path ) , type ) end not_silenced . map do | _ , change , dir , path , _ | [ table . fetch ( change , change ) , dir , path ] end end end end


Input: Fetch tree node if necessary [CODESPLIT] def to_node object if object . is_a? ( self . ancestry_base_class ) then object else unscoped_where { | scope | scope . find object } end end


Input: Scope on relative depth options [CODESPLIT] def scope_depth depth_options , depth depth_options . inject ( self . ancestry_base_class ) do | scope , option | scope_name , relative_depth = option if [ :before_depth , :to_depth , :at_depth , :from_depth , :after_depth ] . include? scope_name scope . send scope_name , depth + relative_depth else raise Ancestry :: AncestryException . new ( "Unknown depth option: #{scope_name}." ) end end end


Input: Orphan strategy writer [CODESPLIT] def orphan_strategy = orphan_strategy # Check value of orphan strategy, only rootify, adopt, restrict or destroy is allowed if [ :rootify , :adopt , :restrict , :destroy ] . include? orphan_strategy class_variable_set :@@orphan_strategy , orphan_strategy else raise Ancestry :: AncestryException . new ( "Invalid orphan strategy, valid ones are :rootify,:adopt, :restrict and :destroy." ) end end


Input: Get all nodes and sorting them into an empty hash [CODESPLIT] def arrange options = { } if ( order = options . delete ( :order ) ) arrange_nodes self . ancestry_base_class . order ( order ) . where ( options ) else arrange_nodes self . ancestry_base_class . where ( options ) end end


Input: Arrange array of nodes into a nested hash of the form { node = > children } where children = {} if the node has no children If a node s parent is not included the node will be included as if it is a top level node [CODESPLIT] def arrange_nodes ( nodes ) node_ids = Set . new ( nodes . map ( :id ) ) index = Hash . new { | h , k | h [ k ] = { } } nodes . each_with_object ( { } ) do | node , arranged | children = index [ node . id ] index [ node . parent_id ] [ node ] = children arranged [ node ] = children unless node_ids . include? ( node . parent_id ) end end


Input: Arrangement to nested array [CODESPLIT] def arrange_serializable options = { } , nodes = nil , & block nodes = arrange ( options ) if nodes . nil? nodes . map do | parent , children | if block_given? yield parent , arrange_serializable ( options , children , block ) else parent . serializable_hash . merge 'children' => arrange_serializable ( options , children ) end end end


Input: Pseudo - preordered array of nodes . Children will always follow parents for ordering nodes within a rank provide block eg . Node . sort_by_ancestry ( Node . all ) { |a b| a . rank < = > b . rank } . [CODESPLIT] def sort_by_ancestry ( nodes , & block ) arranged = nodes if nodes . is_a? ( Hash ) unless arranged presorted_nodes = nodes . sort do | a , b | a_cestry , b_cestry = a . ancestry || '0' , b . ancestry || '0' if block_given? && a_cestry == b_cestry yield a , b else a_cestry <=> b_cestry end end arranged = arrange_nodes ( presorted_nodes ) end arranged . inject ( [ ] ) do | sorted_nodes , pair | node , children = pair sorted_nodes << node sorted_nodes += sort_by_ancestry ( children , block ) unless children . blank? sorted_nodes end end


Input: Integrity checking [CODESPLIT] def check_ancestry_integrity! options = { } parents = { } exceptions = [ ] if options [ :report ] == :list unscoped_where do | scope | # For each node ... scope . find_each do | node | begin # ... check validity of ancestry column if ! node . valid? and ! node . errors [ node . class . ancestry_column ] . blank? raise Ancestry :: AncestryIntegrityException . new ( "Invalid format for ancestry column of node #{node.id}: #{node.read_attribute node.ancestry_column}." ) end # ... check that all ancestors exist node . ancestor_ids . each do | ancestor_id | unless exists? ancestor_id raise Ancestry :: AncestryIntegrityException . new ( "Reference to non-existent node in node #{node.id}: #{ancestor_id}." ) end end # ... check that all node parents are consistent with values observed earlier node . path_ids . zip ( [ nil ] + node . path_ids ) . each do | node_id , parent_id | parents [ node_id ] = parent_id unless parents . has_key? node_id unless parents [ node_id ] == parent_id raise Ancestry :: AncestryIntegrityException . new ( "Conflicting parent id found in node #{node.id}: #{parent_id || 'nil'} for node #{node_id} while expecting #{parents[node_id] || 'nil'}" ) end end rescue Ancestry :: AncestryIntegrityException => integrity_exception case options [ :report ] when :list then exceptions << integrity_exception when :echo then puts integrity_exception else raise integrity_exception end end end end exceptions if options [ :report ] == :list end


Input: Integrity restoration [CODESPLIT] def restore_ancestry_integrity! parents = { } # Wrap the whole thing in a transaction ... self . ancestry_base_class . transaction do unscoped_where do | scope | # For each node ... scope . find_each do | node | # ... set its ancestry to nil if invalid if ! node . valid? and ! node . errors [ node . class . ancestry_column ] . blank? node . without_ancestry_callbacks do node . update_attribute node . ancestry_column , nil end end # ... save parent of this node in parents array if it exists parents [ node . id ] = node . parent_id if exists? node . parent_id # Reset parent id in array to nil if it introduces a cycle parent = parents [ node . id ] until parent . nil? || parent == node . id parent = parents [ parent ] end parents [ node . id ] = nil if parent == node . id end # For each node ... scope . find_each do | node | # ... rebuild ancestry from parents array ancestry , parent = nil , parents [ node . id ] until parent . nil? ancestry , parent = if ancestry . nil? then parent else "#{parent}/#{ancestry}" end , parents [ parent ] end node . without_ancestry_callbacks do node . update_attribute node . ancestry_column , ancestry end end end end end


Input: Build ancestry from parent id s for migration purposes [CODESPLIT] def build_ancestry_from_parent_ids! parent_id = nil , ancestry = nil unscoped_where do | scope | scope . where ( :parent_id => parent_id ) . find_each do | node | node . without_ancestry_callbacks do node . update_attribute ancestry_column , ancestry end build_ancestry_from_parent_ids! node . id , if ancestry . nil? then "#{node.id}" else "#{ancestry}/#{node.id}" end end end end


Input: Rebuild depth cache if it got corrupted or if depth caching was just turned on [CODESPLIT] def rebuild_depth_cache! raise Ancestry :: AncestryException . new ( "Cannot rebuild depth cache for model without depth caching." ) unless respond_to? :depth_cache_column self . ancestry_base_class . transaction do unscoped_where do | scope | scope . find_each do | node | node . update_attribute depth_cache_column , node . depth end end end end


Input: Update descendants with new ancestry ( before save ) [CODESPLIT] def update_descendants_with_new_ancestry # If enabled and node is existing and ancestry was updated and the new ancestry is sane ... if ! ancestry_callbacks_disabled? && ! new_record? && ancestry_changed? && sane_ancestry? # ... for each descendant ... unscoped_descendants . each do | descendant | # ... replace old ancestry with new ancestry descendant . without_ancestry_callbacks do descendant . update_attribute ( self . ancestry_base_class . ancestry_column , descendant . read_attribute ( descendant . class . ancestry_column ) . gsub ( # child_ancestry_was / #{ self . child_ancestry } / , # future child_ancestry if ancestors? then "#{read_attribute self.class.ancestry_column }/#{id}" else id . to_s end ) ) end end end end


Input: Apply orphan strategy ( before destroy - no changes ) [CODESPLIT] def apply_orphan_strategy if ! ancestry_callbacks_disabled? && ! new_record? case self . ancestry_base_class . orphan_strategy when :rootify # make all children root if orphan strategy is rootify unscoped_descendants . each do | descendant | descendant . without_ancestry_callbacks do new_ancestry = if descendant . ancestry == child_ancestry nil else # child_ancestry did not change so child_ancestry_was will work here descendant . ancestry . gsub ( / #{ child_ancestry } \/ / , '' ) end descendant . update_attribute descendant . class . ancestry_column , new_ancestry end end when :destroy # destroy all descendants if orphan strategy is destroy unscoped_descendants . each do | descendant | descendant . without_ancestry_callbacks do descendant . destroy end end when :adopt # make child elements of this node, child of its parent descendants . each do | descendant | descendant . without_ancestry_callbacks do new_ancestry = descendant . ancestor_ids . delete_if { | x | x == self . id } . join ( "/" ) # check for empty string if it's then set to nil new_ancestry = nil if new_ancestry . empty? descendant . update_attribute descendant . class . ancestry_column , new_ancestry || nil end end when :restrict # throw an exception if it has children raise Ancestry :: AncestryException . new ( 'Cannot delete record because it has descendants.' ) unless is_childless? end end end


Input: Touch each of this record s ancestors ( after save ) [CODESPLIT] def touch_ancestors_callback if ! ancestry_callbacks_disabled? && self . ancestry_base_class . touch_ancestors # Touch each of the old *and* new ancestors unscoped_current_and_previous_ancestors . each do | ancestor | ancestor . without_ancestry_callbacks do ancestor . touch end end end end


Input: The ancestry value for this record s children ( before save ) This is technically child_ancestry_was [CODESPLIT] def child_ancestry # New records cannot have children raise Ancestry :: AncestryException . new ( 'No child ancestry for new record. Save record before performing tree operations.' ) if new_record? if self . send ( "#{self.ancestry_base_class.ancestry_column}#{IN_DATABASE_SUFFIX}" ) . blank? id . to_s else "#{self.send "#{self.ancestry_base_class.ancestry_column}#{IN_DATABASE_SUFFIX}"}/#{id}" end end


Input: indirect = anyone who is a descendant but not a child [CODESPLIT] def indirect_conditions ( object ) t = arel_table node = to_node ( object ) # rails has case sensitive matching. if ActiveRecord :: VERSION :: MAJOR >= 5 t [ ancestry_column ] . matches ( "#{node.child_ancestry}/%" , nil , true ) else t [ ancestry_column ] . matches ( "#{node.child_ancestry}/%" ) end end


Input: increment_failure_of [CODESPLIT] def increment_failure_of ( setting_name ) self [ setting_name ] [ :failures ] += 1 Sail . reset ( setting_name ) if self [ setting_name ] [ :failures ] > Sail . configuration . failures_until_reset end


Input: rubocop : disable AbcSize [CODESPLIT] def index @settings = Setting . by_query ( s_params [ :query ] ) . ordered_by ( s_params [ :order_field ] ) @number_of_pages = ( @settings . count . to_f / settings_per_page ) . ceil @settings = @settings . paginated ( s_params [ :page ] , settings_per_page ) fresh_when ( @settings ) end


Input: rubocop : enable AbcSize [CODESPLIT] def update respond_to do | format | @setting , @successful_update = Setting . set ( s_params [ :name ] , s_params [ :value ] ) format . js { } format . json { @successful_update ? head ( :ok ) : head ( :conflict ) } end end


Input: Checks the response code for common errors . Returns parsed response for successful requests . [CODESPLIT] def validate ( response ) error_klass = Error :: STATUS_MAPPINGS [ response . code ] raise error_klass , response if error_klass parsed = response . parsed_response parsed . client = self if parsed . respond_to? ( :client= ) parsed . parse_headers! ( response . headers ) if parsed . respond_to? ( :parse_headers! ) parsed end


Input: Sets a base_uri and default_params for requests . [CODESPLIT] def request_defaults ( sudo = nil ) self . class . default_params sudo : sudo raise Error :: MissingCredentials , 'Please set an endpoint to API' unless @endpoint self . class . default_params . delete ( :sudo ) if sudo . nil? end


Input: Creates a hash of options and their values . [CODESPLIT] def options VALID_OPTIONS_KEYS . inject ( { } ) do | option , key | option . merge! ( key => send ( key ) ) end end


Input: Resets all configuration options to the defaults . [CODESPLIT] def reset self . endpoint = ENV [ 'GITLAB_API_ENDPOINT' ] self . private_token = ENV [ 'GITLAB_API_PRIVATE_TOKEN' ] || ENV [ 'GITLAB_API_AUTH_TOKEN' ] self . httparty = get_httparty_config ( ENV [ 'GITLAB_API_HTTPARTY_OPTIONS' ] ) self . sudo = nil self . user_agent = DEFAULT_USER_AGENT end


Input: Allows HTTParty config to be specified in ENV using YAML hash . [CODESPLIT] def get_httparty_config ( options ) return if options . nil? httparty = Gitlab :: CLI :: Helpers . yaml_load ( options ) raise ArgumentError , 'HTTParty config should be a Hash.' unless httparty . is_a? Hash Gitlab :: CLI :: Helpers . symbolize_keys httparty end


Input: Start a timer in the included object [CODESPLIT] def start_timer ( timer = DEFAULT_TIMER . new ) raise Socketry :: InternalError , "timer already started" if defined? ( @timer ) raise Socketry :: InternalError , "deadline already set" if defined? ( @deadline ) @deadline = nil @timer = timer @timer . start true end


Input: Set a timeout . Only one timeout may be active at a given time for a given object . [CODESPLIT] def set_timeout ( timeout ) raise Socketry :: InternalError , "deadline already set" if @deadline return unless timeout raise Socketry :: TimeoutError , "time expired" if timeout < 0 @deadline = lifetime + timeout end


Input: Calculate number of seconds remaining until we hit the timeout [CODESPLIT] def time_remaining ( timeout ) return unless timeout raise Socketry :: InternalError , "no deadline set" unless @deadline remaining = @deadline - lifetime raise Socketry :: TimeoutError , "time expired" if remaining <= 0 remaining end


Input: Run a simple true / false validation of data against a schema [CODESPLIT] def validate @base_schema . validate ( @data , [ ] , self , @validation_options ) if @options [ :record_errors ] if @options [ :errors_as_objects ] @errors . map { | e | e . to_hash } else @errors . map { | e | e . to_string } end else true end ensure if @validation_options [ :clear_cache ] == true self . class . clear_cache end if @validation_options [ :insert_defaults ] self . class . merge_missing_values ( @data , @original_data ) end end


Input: Build all schemas with IDs mapping out the namespace [CODESPLIT] def build_schemas ( parent_schema ) schema = parent_schema . schema # Build ref schemas if they exist if schema [ "$ref" ] load_ref_schema ( parent_schema , schema [ "$ref" ] ) end case schema [ "extends" ] when String load_ref_schema ( parent_schema , schema [ "extends" ] ) when Array schema [ 'extends' ] . each do | type | handle_schema ( parent_schema , type ) end end # Check for schemas in union types [ "type" , "disallow" ] . each do | key | if schema [ key ] . is_a? ( Array ) schema [ key ] . each do | type | if type . is_a? ( Hash ) handle_schema ( parent_schema , type ) end end end end # Schema properties whose values are objects, the values of which # are themselves schemas. %w[ definitions properties patternProperties ] . each do | key | next unless value = schema [ key ] value . each do | k , inner_schema | handle_schema ( parent_schema , inner_schema ) end end # Schema properties whose values are themselves schemas. %w[ additionalProperties additionalItems dependencies extends ] . each do | key | next unless schema [ key ] . is_a? ( Hash ) handle_schema ( parent_schema , schema [ key ] ) end # Schema properties whose values may be an array of schemas. %w[ allOf anyOf oneOf not ] . each do | key | next unless value = schema [ key ] Array ( value ) . each do | inner_schema | handle_schema ( parent_schema , inner_schema ) end end # Items are always schemas if schema [ "items" ] items = schema [ "items" ] . clone items = [ items ] unless items . is_a? ( Array ) items . each do | item | handle_schema ( parent_schema , item ) end end # Convert enum to a ArraySet if schema [ "enum" ] . is_a? ( Array ) schema [ "enum" ] = ArraySet . new ( schema [ "enum" ] ) end end


Input: Either load a reference schema or create a new schema [CODESPLIT] def handle_schema ( parent_schema , obj ) if obj . is_a? ( Hash ) schema_uri = parent_schema . uri . dup schema = JSON :: Schema . new ( obj , schema_uri , parent_schema . validator ) if obj [ 'id' ] self . class . add_schema ( schema ) end build_schemas ( schema ) end end


Input: Returns a Hash containing as keys all local branches that have upstream branches and as values a brief description of each branch s status relative to its upstream branch ( up to date or ahead / behind ) [CODESPLIT] def get_upstream_branches command_to_a ( "git branch -vv" ) . map do | line | line . gsub! ( LEADING_STAR_REGEX , "" ) branch_name = line . split ( BRANCH_NAME_REGEX ) [ 0 ] remote_info = line [ REMOTE_INFO_REGEX , 1 ] if remote_info . nil? nil else comparison_raw = remote_info . split ( ":" ) comparison = if comparison_raw . length < 2 "Up to date" else comparison_raw [ 1 ] . strip . capitalize end [ branch_name , comparison ] end end . compact . to_h end


Input: Matches the block or conditions hash [CODESPLIT] def matches_conditions? ( action , subject , extra_args ) if @match_all call_block_with_all ( action , subject , extra_args ) elsif @block && ! subject_class? ( subject ) @block . call ( subject , extra_args ) elsif @conditions . kind_of? ( Hash ) && subject . class == Hash nested_subject_matches_conditions? ( subject ) elsif @conditions . kind_of? ( Hash ) && ! subject_class? ( subject ) matches_conditions_hash? ( subject ) else # Don't stop at "cannot" definitions when there are conditions. @conditions . empty? ? true : @base_behavior end end


Input: Checks if the given subject matches the given conditions hash . This behavior can be overriden by a model adapter by defining two class methods : override_matching_for_conditions? ( subject conditions ) and matches_conditions_hash? ( subject conditions ) [CODESPLIT] def matches_conditions_hash? ( subject , conditions = @conditions ) if conditions . empty? true else if model_adapter ( subject ) . override_conditions_hash_matching? subject , conditions model_adapter ( subject ) . matches_conditions_hash? subject , conditions else conditions . all? do | name , value | if model_adapter ( subject ) . override_condition_matching? subject , name , value model_adapter ( subject ) . matches_condition? subject , name , value else attribute = subject . send ( name ) if value . kind_of? ( Hash ) if attribute . kind_of? Array attribute . any? { | element | matches_conditions_hash? element , value } else ! attribute . nil? && matches_conditions_hash? ( attribute , value ) end elsif ! value . is_a? ( String ) && value . kind_of? ( Enumerable ) value . include? attribute else attribute == value end end end end end end


Input: Alias one or more actions into another one . [CODESPLIT] def alias_action ( * args ) target = args . pop [ :to ] validate_target ( target ) aliased_actions [ target ] ||= [ ] aliased_actions [ target ] += args end


Input: See ControllerAdditions#authorize! for documentation . [CODESPLIT] def authorize! ( action , subject , * args ) message = nil if args . last . kind_of? ( Hash ) && args . last . has_key? ( :message ) message = args . pop [ :message ] end if cannot? ( action , subject , args ) message ||= unauthorized_message ( action , subject ) raise AccessDenied . new ( message , action , subject ) end subject end


Input: Accepts an array of actions and returns an array of actions which match . This should be called before matches? and other checking methods since they rely on the actions to be expanded . [CODESPLIT] def expand_actions ( actions ) actions . map do | action | aliased_actions [ action ] ? [ action , expand_actions ( aliased_actions [ action ] ) ] : action end . flatten end


Input: Given an action it will try to find all of the actions which are aliased to it . This does the opposite kind of lookup as expand_actions . [CODESPLIT] def aliases_for_action ( action ) results = [ action ] aliased_actions . each do | aliased_action , actions | results += aliases_for_action ( aliased_action ) if actions . include? action end results end


Input: Returns an array of Rule instances which match the action and subject This does not take into consideration any hash conditions or block statements [CODESPLIT] def relevant_rules ( action , subject ) rules . reverse . select do | rule | rule . expanded_actions = expand_actions ( rule . actions ) rule . relevant? action , subject end end


Input: : nodoc : [CODESPLIT] def load_resource_instance if parent? @controller . send :association_chain @controller . instance_variable_get ( "@#{instance_name}" ) elsif new_actions . include? @params [ :action ] . to_sym resource = @controller . send :build_resource assign_attributes ( resource ) else @controller . send :resource end end


Input: Returns the class used for this resource . This can be overriden by the : class option . If + false + is passed in it will use the resource name as a symbol in which case it should only be used for authorization not loading since there s no class to load through . [CODESPLIT] def resource_class case @options [ :class ] when false then name . to_sym when nil then namespaced_name . to_s . camelize . constantize when String then @options [ :class ] . constantize else @options [ :class ] end end


Input: The object that methods ( such as find new or build ) are called on . If the : through option is passed it will go through an association on that instance . If the : shallow option is passed it will use the resource_class if there s no parent If the : singleton option is passed it won t use the association because it needs to be handled later . [CODESPLIT] def resource_base if @options [ :through ] if parent_resource @options [ :singleton ] ? resource_class : parent_resource . send ( @options [ :through_association ] || name . to_s . pluralize ) elsif @options [ :shallow ] resource_class else raise AccessDenied . new ( nil , authorization_action , resource_class ) # maybe this should be a record not found error instead? end else resource_class end end


Input: Create a missing file if the path is valid . [CODESPLIT] def create_missing_file raise Errno :: EISDIR , path . to_s if File . directory? ( @path ) return if File . exist? ( @path ) # Unnecessary check, probably. dirname = RealFile . dirname @path unless dirname == '.' dir = FileSystem . find dirname raise Errno :: ENOENT , path . to_s unless dir . is_a? FakeDir end @file = FileSystem . add ( path , FakeFile . new ) end


Input: Return a pathname which is substituted by String#sub . [CODESPLIT] def sub ( pattern , * rest , & block ) path = if block @path . sub ( pattern , rest ) do | * args | begin old = Thread . current [ :pathname_sub_matchdata ] Thread . current [ :pathname_sub_matchdata ] = $~ # TODO: rewrite without using eval eval ( '$~ = Thread.current[:pathname_sub_matchdata]' , block . binding , __FILE__ , __LINE__ - 3 ) ensure Thread . current [ :pathname_sub_matchdata ] = old end yield ( args ) end else @path . sub ( pattern , rest ) end self . class . new ( path ) end


Input: #mountpoint? returns + true + if <tt > self< / tt > points to a mountpoint . [CODESPLIT] def mountpoint? stat1 = lstat begin stat2 = parent . lstat stat1 . dev == stat2 . dev && stat1 . ino == stat2 . ino || stat1 . dev != stat2 . dev rescue Errno :: ENOENT false end end


Input: Iterates over each component of the path . [CODESPLIT] def each_filename # :yield: filename return to_enum ( __method__ ) unless block_given? _prefix , names = split_names ( @path ) names . each { | filename | yield filename } nil end


Input: Iterates over and yields a new Pathname object for each element in the given path in descending order . [CODESPLIT] def descend vs = [ ] ascend { | v | vs << v } vs . reverse_each { | v | yield v } nil end


Input: Iterates over and yields a new Pathname object for each element in the given path in ascending order . [CODESPLIT] def ascend path = @path yield self while ( r = chop_basename ( path ) ) path , _name = r break if path . empty? yield self . class . new ( del_trailing_separator ( path ) ) end end


Input: Pathname# + appends a pathname fragment to this one to produce a new Pathname object . [CODESPLIT] def + ( other ) other = Pathname . new ( other ) unless other . is_a? ( Pathname ) Pathname . new ( plus ( @path , other . to_s ) ) end


Input: Pathname#join joins pathnames . [CODESPLIT] def join ( * args ) args . unshift self result = args . pop result = Pathname . new ( result ) unless result . is_a? ( Pathname ) return result if result . absolute? args . reverse_each do | arg | arg = Pathname . new ( arg ) unless arg . is_a? ( Pathname ) result = arg + result return result if result . absolute? end result end


Input: Returns the children of the directory ( files and subdirectories not recursive ) as an array of Pathname objects . By default the returned pathnames will have enough information to access the files . If you set + with_directory + to + false + then the returned pathnames will contain the filename only . [CODESPLIT] def children ( with_directory = true ) with_directory = false if @path == '.' result = [ ] Dir . foreach ( @path ) do | e | next if [ '.' , '..' ] . include? ( e ) result << if with_directory self . class . new ( File . join ( @path , e ) ) else self . class . new ( e ) end end result end


Input: #relative_path_from returns a relative path from the argument to the receiver . If + self + is absolute the argument must be absolute too . If + self + is relative the argument must be relative too . [CODESPLIT] def relative_path_from ( base_directory ) dest_directory = cleanpath . to_s base_directory = base_directory . cleanpath . to_s dest_prefix = dest_directory dest_names = [ ] while ( r = chop_basename ( dest_prefix ) ) dest_prefix , basename = r dest_names . unshift basename if basename != '.' end base_prefix = base_directory base_names = [ ] while ( r = chop_basename ( base_prefix ) ) base_prefix , basename = r base_names . unshift basename if basename != '.' end unless SAME_PATHS [ dest_prefix , base_prefix ] raise ArgumentError , "different prefix: #{dest_prefix.inspect} " "and #{base_directory.inspect}" end while ! dest_names . empty? && ! base_names . empty? && SAME_PATHS [ dest_names . first , base_names . first ] dest_names . shift base_names . shift end if base_names . include? '..' raise ArgumentError , "base_directory has ..: #{base_directory.inspect}" end base_names . fill ( '..' ) relpath_names = base_names + dest_names if relpath_names . empty? Pathname . new ( '.' ) else Pathname . new ( File . join ( relpath_names ) ) end end


Input: chop_basename ( path ) - > [ pre - basename basename ] or nil [CODESPLIT] def chop_basename ( path ) base = File . basename ( path ) if / \A #{ SEPARATOR_PAT } \z /o =~ base return nil else return path [ 0 , path . rindex ( base ) ] , base end end


Input: split_names ( path ) - > prefix [ name ... ] [CODESPLIT] def split_names ( path ) names = [ ] while ( r = chop_basename ( path ) ) path , basename = r names . unshift basename end [ path , names ] end


Input: Clean the path simply by resolving and removing excess . and .. entries . Nothing more nothing less . [CODESPLIT] def cleanpath_aggressive path = @path names = [ ] pre = path while ( r = chop_basename ( pre ) ) pre , base = r case base when '.' # rubocop:disable Lint/EmptyWhen when '..' names . unshift base else if names [ 0 ] == '..' names . shift else names . unshift base end end end if / #{ SEPARATOR_PAT } /o =~ File . basename ( pre ) names . shift while names [ 0 ] == '..' end self . class . new ( prepend_prefix ( pre , File . join ( names ) ) ) end


Input: trailing_separator? ( path ) - > bool [CODESPLIT] def trailing_separator? ( path ) if ( r = chop_basename ( path ) ) pre , basename = r pre . length + basename . length < path . length else false end end


Input: * IO * [CODESPLIT] def each_line ( * args , & block ) # :yield: line if block_given? File . open ( @path , 'r' ) do | io | io . each_line ( args , block ) end else enum_for ( :each_line , args ) end end


Input: See <tt > File . write< / tt > . Returns the number of bytes written . [CODESPLIT] def write ( string , * args ) offset = args [ 0 ] open_args = args [ 1 ] File . open ( @path , open_args || 'w' ) do | file | file . seek ( offset ) if offset return file . write ( string ) end end


Input: * Find * [CODESPLIT] def find ( * ) # :yield: pathname require 'find' if @path == '.' Find . find ( @path ) { | f | yield self . class . new ( f . sub ( %r{ \A \. } , '' ) ) } else Find . find ( @path ) { | f | yield self . class . new ( f ) } end end


Input: Calculates the C checksum based on checksum_values [CODESPLIT] def c_checksum sum = 0 checksum_values . each_with_index do | value , index | sum += ( ( index % 20 ) + 1 ) * value end sum % 47 end


Input: Calculates the K checksum based on checksum_values_with_c_checksum [CODESPLIT] def k_checksum sum = 0 checksum_values_with_c_checksum . each_with_index do | value , index | sum += ( ( index % 15 ) + 1 ) * value end sum % 47 end


Input: Returns an instance of Magick :: Image [CODESPLIT] def to_image ( opts = { } ) with_options opts do canvas = Magick :: Image . new ( full_width , full_height ) bars = Magick :: Draw . new x1 = margin y1 = margin if barcode . two_dimensional? encoding . each do | line | line . split ( / / ) . map { | c | c == '1' } . each do | bar | if bar x2 = x1 + ( xdim - 1 ) y2 = y1 + ( ydim - 1 ) # For single pixels use point if x1 == x2 && y1 == y2 bars . point ( x1 , y1 ) else bars . rectangle ( x1 , y1 , x2 , y2 ) end end x1 += xdim end x1 = margin y1 += ydim end else booleans . each do | bar | if bar x2 = x1 + ( xdim - 1 ) y2 = y1 + ( height - 1 ) bars . rectangle ( x1 , y1 , x2 , y2 ) end x1 += xdim end end bars . draw ( canvas ) canvas end end


Input: Annotate a PDFWriter document with the barcode [CODESPLIT] def annotate_pdf ( pdf , options = { } ) with_options options do xpos , ypos = x , y orig_xpos = xpos if barcode . two_dimensional? boolean_groups . reverse_each do | groups | groups . each do | bar , amount | if bar pdf . move_to ( xpos , ypos ) . line_to ( xpos , ypos + xdim ) . line_to ( xpos + ( xdim amount ) , ypos + xdim ) . line_to ( xpos + ( xdim amount ) , ypos ) . line_to ( xpos , ypos ) . fill end xpos += ( xdim amount ) end xpos = orig_xpos ypos += xdim end else boolean_groups . each do | bar , amount | if bar pdf . move_to ( xpos , ypos ) . line_to ( xpos , ypos + height ) . line_to ( xpos + ( xdim amount ) , ypos + height ) . line_to ( xpos + ( xdim amount ) , ypos ) . line_to ( xpos , ypos ) . fill end xpos += ( xdim amount ) end end end pdf end


Input: Converts the barcode s encoding ( a string containing 1s and 0s ) to true and false values ( 1 == true == black bar ) [CODESPLIT] def booleans ( reload = false ) #:doc: if two_dimensional? encoding ( reload ) . map { | l | l . split ( / / ) . map { | c | c == '1' } } else encoding ( reload ) . split ( / / ) . map { | c | c == '1' } end end


Input: Collects continuous groups of bars and spaces ( 1 and 0 ) into arrays where the first item is true or false ( 1 or 0 ) and the second is the size of the group [CODESPLIT] def boolean_groups ( reload = false ) if two_dimensional? encoding ( reload ) . map do | line | line . scan ( / / ) . map do | group | [ group [ 0 , 1 ] == '1' , group . size ] end end else encoding ( reload ) . scan ( / / ) . map do | group | [ group [ 0 , 1 ] == '1' , group . size ] end end end


Input: Takes a hash and temporarily sets properties on self ( the outputter object ) corresponding with the keys to their values . When the block exits the properties are reset to their original values . Returns whatever the block returns . [CODESPLIT] def with_options ( options = { } ) original_options = options . inject ( { } ) do | origs , pair | if respond_to? ( pair . first ) && respond_to? ( "#{pair.first}=" ) origs [ pair . first ] = send ( pair . first ) send ( "#{pair.first}=" , pair . last ) end origs end rv = yield original_options . each do | attribute , value | send ( "#{attribute}=" , value ) end rv end


Input: Returns the encodable characters . If extended mode is enabled each character will first be replaced by two characters from the encodable charset [CODESPLIT] def characters chars = raw_characters extended ? chars . map { | c | EXTENDED_ENCODINGS [ c ] . split ( / / ) } . flatten : chars end


Input: Takes an array of WIDE / NARROW values and returns the string representation for those bars and spaces using wide_width and narrow_width [CODESPLIT] def encoding_for_bars ( * bars_and_spaces ) bar = false bars_and_spaces . flatten . map do | width | bar = ! bar ( bar ? '1' : '0' ) * ( width == WIDE ? wide_width : narrow_width ) end . join end


Input: Creates a PNG :: Canvas object and renders the barcode on it [CODESPLIT] def to_image ( opts = { } ) with_options opts do canvas = ChunkyPNG :: Image . new ( full_width , full_height , ChunkyPNG :: Color :: WHITE ) if barcode . two_dimensional? x , y = margin , margin booleans . each do | line | line . each do | bar | if bar x . upto ( x + ( xdim - 1 ) ) do | xx | y . upto y + ( ydim - 1 ) do | yy | canvas [ xx , yy ] = ChunkyPNG :: Color :: BLACK end end end x += xdim end y += ydim x = margin end else x , y = margin , margin booleans . each do | bar | if bar x . upto ( x + ( xdim - 1 ) ) do | xx | y . upto y + ( height - 1 ) do | yy | canvas [ xx , yy ] = ChunkyPNG :: Color :: BLACK end end end x += xdim end end canvas end end


Input: Create a ChunkyPNG :: Datastream containing the barcode image [CODESPLIT] def to_datastream ( * a ) constraints = a . first && a . first [ :constraints ] ? [ a . first [ :constraints ] ] : [ ] to_image ( a ) . to_datastream ( constraints ) end


Input: Set the data for this barcode . If the barcode changes character set an extra will be created . [CODESPLIT] def data = ( data ) data , * extra = data . split ( / #{ CODEA + CODEB + CODEC } /n ) @data = data || '' self . extra = extra . join unless extra . empty? end


Input: Set the extra for this barcode . The argument is a string starting with the change character set symbol . The string may contain several character sets in which case the extra will itself have an extra . [CODESPLIT] def extra = ( extra ) raise ArgumentError , "Extra must begin with \\305, \\306 or \\307" unless extra =~ / #{ CODEA + CODEB + CODEC } /n type , data = extra [ 0 , 1 ] , extra [ 1 .. - 1 ] @extra = class_for ( type ) . new ( data ) end


Input: Get an array of the individual characters for this barcode . Special characters like FNC1 will be present . Characters from extras are not present . [CODESPLIT] def characters chars = data . split ( / /n ) if type == 'C' result = [ ] count = 0 while count < chars . size if chars [ count ] =~ / \d / #If encountering a digit, next char/byte *must* be second digit in pair. I.e. if chars[count] is 5, #chars[count+1] must be /[0-9]/, otherwise it's not valid result << "#{chars[count]}#{chars[count+1]}" count += 2 else result << chars [ count ] count += 1 end end result else chars end end


Input: Calculate the checksum for the data in this barcode . The data includes data from extras . [CODESPLIT] def checksum pos = 0 ( numbers + extra_numbers ) . inject ( start_num ) do | sum , number | pos += 1 sum + ( number * pos ) end % 103 end


Input: Generate encoding for an array of W N [CODESPLIT] def encoding_for_bars ( * bars ) wide , narrow , space = wide_encoding , narrow_encoding , space_encoding bars . flatten . inject '' do | enc , bar | enc + ( bar == WIDE ? wide : narrow ) + space end end


Input: Mod10 [CODESPLIT] def checksum evens , odds = even_and_odd_digits sum = odds . inject ( 0 ) { | s , d | s + d } + evens . inject ( 0 ) { | s , d | s + ( d 3 ) } sum %= 10 sum . zero? ? 0 : 10 - sum end


Input: Render the barcode onto a Cairo context [CODESPLIT] def render_to_cairo_context ( context , options = { } ) if context . respond_to? ( :have_current_point? ) and context . have_current_point? current_x , current_y = context . current_point else current_x = x ( options ) || margin ( options ) current_y = y ( options ) || margin ( options ) end _xdim = xdim ( options ) _height = height ( options ) original_current_x = current_x context . save do context . set_source_color ( :black ) context . fill do if barcode . two_dimensional? boolean_groups . each do | groups | groups . each do | bar , amount | current_width = _xdim * amount if bar context . rectangle ( current_x , current_y , current_width , _xdim ) end current_x += current_width end current_x = original_current_x current_y += _xdim end else boolean_groups . each do | bar , amount | current_width = _xdim * amount if bar context . rectangle ( current_x , current_y , current_width , _height ) end current_x += current_width end end end end context end


Input: Render the barcode to a PNG image [CODESPLIT] def to_png ( options = { } ) output_to_string_io do | io | Cairo :: ImageSurface . new ( options [ :format ] , full_width ( options ) , full_height ( options ) ) do | surface | render ( surface , options ) surface . write_to_png ( io ) end end end


Input: Render the barcode to a PS document [CODESPLIT] def to_ps ( options = { } ) output_to_string_io do | io | Cairo :: PSSurface . new ( io , full_width ( options ) , full_height ( options ) ) do | surface | surface . eps = options [ :eps ] if surface . respond_to? ( :eps= ) render ( surface , options ) end end end


Input: Render the barcode to a PDF document [CODESPLIT] def to_pdf ( options = { } ) output_to_string_io do | io | Cairo :: PDFSurface . new ( io , full_width ( options ) , full_height ( options ) ) do | surface | render ( surface , options ) end end end


Input: Render the barcode to an SVG document [CODESPLIT] def to_svg ( options = { } ) output_to_string_io do | io | Cairo :: SVGSurface . new ( io , full_width ( options ) , full_height ( options ) ) do | surface | render ( surface , options ) end end end


Input: Encodes an array of interleaved W or N bars and spaces ex : [ W N W W N N ] = > 111011100010 [CODESPLIT] def encoding_for_interleaved ( * bars_and_spaces ) bar = false #starts with bar bars_and_spaces . flatten . inject '' do | enc , bar_or_space | bar = ! bar enc << ( bar ? '1' : '0' ) * ( bar_or_space == WIDE ? wide_width : narrow_width ) end end


Input: @param [ Hash ] params [CODESPLIT] def request_params ( params = { } ) default_request_params . merge ( params ) do | key , oldval , newval | key == :headers ? oldval . merge ( newval ) : newval end end


Input: @param [ String ] xpath @param [ Regexp ] pattern @param [ Typhoeus :: Response String ] page [CODESPLIT] def xpath_pattern_from_page ( xpath , pattern , page = nil ) page = NS :: Browser . get ( url ( page ) ) unless page . is_a? ( Typhoeus :: Response ) matches = [ ] page . html . xpath ( xpath ) . each do | node | next unless node . text . strip =~ pattern yield Regexp . last_match , node if block_given? matches << [ Regexp . last_match , node ] end matches end


Input: @param [ Regexp ] pattern @param [ Typhoeus :: Response String ] page [CODESPLIT] def comments_from_page ( pattern , page = nil ) xpath_pattern_from_page ( '//comment()' , pattern , page ) do | match , node | yield match , node if block_given? end end


Input: @param [ Regexp ] pattern @param [ Typhoeus :: Response String ] page [CODESPLIT] def javascripts_from_page ( pattern , page = nil ) xpath_pattern_from_page ( '//script' , pattern , page ) do | match , node | yield match , node if block_given? end end


Input: @param [ Typhoeus :: Response String ] page @param [ String ] xpath [CODESPLIT] def uris_from_page ( page = nil , xpath = '//@href|//@src|//@data-src' ) page = NS :: Browser . get ( url ( page ) ) unless page . is_a? ( Typhoeus :: Response ) found = [ ] page . html . xpath ( xpath ) . each do | node | attr_value = node . text . to_s next unless attr_value && ! attr_value . empty? node_uri = begin uri . join ( attr_value . strip ) rescue StandardError # Skip potential malformed URLs etc. next end next unless node_uri . host yield node_uri , node . parent if block_given? && ! found . include? ( node_uri ) found << node_uri end found . uniq end


Input: @param [ String Addressable :: URI ] url An absolute URL or URI [CODESPLIT] def in_scope? ( url_or_uri ) url_or_uri = Addressable :: URI . parse ( url_or_uri . strip ) unless url_or_uri . is_a? ( Addressable :: URI ) scope . include? ( url_or_uri . host ) rescue StandardError false end


Input: @param [ Typhoeus :: Response ] res @param [ String ] xpath [CODESPLIT] def in_scope_uris ( res , xpath = '//@href|//@src|//@data-src' ) found = [ ] uris_from_page ( res , xpath ) do | uri , tag | next unless in_scope? ( uri ) yield uri , tag if block_given? found << uri end found end


Input: Similar to Target#url_pattern but considering the in scope domains as well [CODESPLIT] def scope_url_pattern return @scope_url_pattern if @scope_url_pattern domains = [ uri . host + uri . path ] domains += if scope . domains . empty? [ scope . invalid_domains [ 1 .. - 1 ] ] else [ scope . domains [ 1 .. - 1 ] ] . map ( :to_s ) + scope . invalid_domains end domains . map! { | d | Regexp . escape ( d . gsub ( %r{ } , '' ) ) . gsub ( '\*' , '.*' ) . gsub ( '/' , '\\\\\?/' ) } domains [ 0 ] . gsub! ( Regexp . escape ( uri . host ) , Regexp . escape ( uri . host ) + '(?::\\d+)?' ) if uri . port @scope_url_pattern = %r{ \\ \\ #{ domains . join ( '|' ) } \\ }i end


Input: For Sanity [CODESPLIT] def match ( pattern ) pattern = PublicSuffix . parse ( pattern ) unless pattern . is_a? ( PublicSuffix :: Domain ) return name == pattern . name unless pattern . trd return false unless tld == pattern . tld && sld == pattern . sld matching_pattern? ( pattern ) end


Input: @param [ Controller :: Base ] controller [CODESPLIT] def << ( controller ) options = controller . cli_options unless include? ( controller ) option_parser . add ( options ) if options super ( controller ) end self end


Input: Set the threads attribute and update hydra accordinly If the throttle attribute is > 0 max_threads will be forced to 1 [CODESPLIT] def max_threads = ( number ) @max_threads = number . to_i . positive? && throttle . zero? ? number . to_i : 1 hydra . max_concurrency = @max_threads end


Input: Hook to be able to have an exit code returned depending on the findings / errors : nocov : [CODESPLIT] def exit_hook # Avoid hooking the exit when rspec is running, otherwise it will always return 0 # and Travis won't detect failed builds. Couldn't find a better way, even though # some people managed to https://github.com/rspec/rspec-core/pull/410 return if defined? ( RSpec ) at_exit do exit ( run_error_exit_code ) if run_error # The parsed_option[:url] must be checked to avoid raising erros when only -h/-v are given exit ( NS :: ExitCode :: VULNERABLE ) if NS :: ParsedCli . url && controllers . first . target . vulnerable? exit ( NS :: ExitCode :: OK ) end end


Input: : nocov : [CODESPLIT] def run_error_exit_code return NS :: ExitCode :: CLI_OPTION_ERROR if run_error . is_a? ( OptParseValidator :: Error ) || run_error . is_a? ( OptionParser :: ParseError ) return NS :: ExitCode :: INTERRUPTED if run_error . is_a? ( Interrupt ) return NS :: ExitCode :: ERROR if run_error . is_a? ( NS :: Error :: Standard ) || run_error . is_a? ( CMSScanner :: Error :: Standard ) NS :: ExitCode :: EXCEPTION end


Input: Checks if the remote website is up . [CODESPLIT] def online? ( path = nil ) NS :: Browser . get ( url ( path ) ) . code . nonzero? ? true : false end


Input: @param [ String ] url [CODESPLIT] def redirection ( url = nil ) url ||= @uri . to_s return unless [ 301 , 302 ] . include? ( NS :: Browser . get ( url ) . code ) res = NS :: Browser . get ( url , followlocation : true ) res . effective_url == url ? nil : res . effective_url end


Input: Perform a HEAD request to the path provided then if its response code is in the array of codes given a GET is done and the response returned . Otherwise the HEAD response is returned . [CODESPLIT] def head_and_get ( path , codes = [ 200 ] , params = { } ) url_to_get = url ( path ) head_params = ( params [ :head ] || { } ) . merge ( head_or_get_params ) head_res = NS :: Browser . forge_request ( url_to_get , head_params ) . run codes . include? ( head_res . code ) ? NS :: Browser . get ( url_to_get , params [ :get ] || { } ) : head_res end


Input: Get a connection to the database [CODESPLIT] def db return @db unless @db . nil? Sequel . single_threaded = true @db = Sequel . connect ( config ( :sql_url ) , :encoding => 'utf8' ) #@db.loggers << Logger.new(STDOUT) if @db . tables . empty? dir = File . join ( File . dirname ( __FILE__ ) , 'migrations' ) puts "Database empty, running migrations from #{dir}" Sequel . extension :migration Sequel :: Migrator . apply ( @db , dir ) end @db end


Input: Make sure a commit exists [CODESPLIT] def ensure_commit ( repo , sha , user , comments = true ) ensure_repo ( user , repo ) c = retrieve_commit ( repo , sha , user ) if c . nil? warn "Commit #{user}/#{repo} -> #{sha} does not exist" return end stored = store_commit ( c , repo , user ) ensure_parents ( c ) if not c [ 'commit' ] [ 'comment_count' ] . nil? and c [ 'commit' ] [ 'comment_count' ] > 0 ensure_commit_comments ( user , repo , sha ) if comments end ensure_repo_commit ( user , repo , sha ) stored end