Skip to content

Commit 914b197

Browse files
Bue PetersenPraqma
Bue Petersen
authored and
Praqma
committed
Squashed commit of the following:
commit f5b6d24f68c393a8aa14a5e607248820d2a32b52 Author: Bue Petersen <[email protected]> Date: Fri Sep 16 13:23:00 2016 +0200 #2 do cppcheck wrapper script, and script in misc missed before commit 4364ebf963d62f95b9b049729ed1cbe9cbf40d65 Author: Bue Petersen <[email protected]> Date: Fri Sep 16 13:12:41 2016 +0200 #2 setversion scripts added commit ce7e73dc24d4a111e1304ac2a65f490cb82fe09f Author: Bue Petersen <[email protected]> Date: Fri Sep 16 10:22:08 2016 +0200 #2 first two misc scripts
1 parent e7301d0 commit 914b197

13 files changed

+934
-1
lines changed

README.md

+32-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,39 @@ Continuous Delivery utilities - small scripts and concepts used in continuous de
44
Instead we all keep reinventing the same small concepts and scripts again and again we should share them.
55
This repository is for sharing all the small nice little scripts used on daily basis for continuous integrations, continous delivery, builds, artifact management or what-ever is needed for you to get the build and delivery pipeline up and running.
66

7+
Many of the added scripts and snippets are quite old, added during a clean-up. They might serve as inspiration, rather than production useable scripts. Some of the thigns might also be done in another way today.
8+
79
## Utils available
810

11+
### Misc-folder
12+
13+
Contains different small scripts.
14+
15+
__[misc/checkFileSyncModified.sh](misc/checkFileSyncModified.sh)__: Bash script to check if one file in a list of files have been modified since last time, without the other being updated. And old praqmatic solution to keeping files in sync that could be reused. Used in a Jenkins job, that failed if one of the files being changed without the others being chagned as well. Don't check if the changes are relevant.
16+
17+
__[misc/jenkins-createUniqueArtifact.rb](misc/jenkins-createUniqueArtifact.rb)__: can create unique files with some traceability content in a Jenkins job, that can be archived and fingerprinted to create traces between Jenkins job. The created unique artifacts, could also be stored to show important information with artifacts.
18+
19+
__[misc/createStagingNo.rb](misc/createStagingNo.rb)__: Modulo 10 a build number from Jenkins, to create round robin deploy or staging folders.
20+
21+
__[misc/](misc/)__:
22+
__[misc/](misc/)__:
23+
__[misc/](misc/)__:
24+
__[misc/](misc/)__:
25+
__[misc/](misc/)__:
26+
27+
28+
### Set version in C/C++ files
29+
30+
A simple conceptual script that can stamp build version into C/C++ application. Can be re-used for other things.
31+
Basically works on headerfiles, that needs to be included.
32+
33+
See the [setversion/](setversion/) folder for the script, in Bash and Ruby, and related template files.
34+
35+
### doCppCheck
36+
37+
A Ruby wraper script around running CppCheck, and some configuration files to adjust the way it analyses the code.
38+
Wrapper script was mostly used to gather relevant files to include in analysis, and try to find header files to include for the analysis to be more correct.
39+
940
### Pretested Integration
1041

1142
The well established concept of pretested integration, made available first as the [Jenkins Pretested Integration Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Pretested+Integration+Plugin) is also available in several flavors not related to Jenkins.
@@ -79,7 +110,7 @@ Let's see how this evolves.
79110

80111
## Testing
81112

82-
You should have some testing alongside your scripts.
113+
You should have some testing alongside your scripts.
83114
An old idea is described in the testing-idea folder, see [testing-idea/readme.md](testing-idea/readme.md)
84115

85116
You chose any way to test your scripts.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/ruby
2+
3+
module CppcheckSettings
4+
5+
#############################
6+
# do_cppcheck configuration #
7+
#############################
8+
# Should this script fail with an error if cppcheck reports it can not
9+
# find every header file during analysis?
10+
# This mean the scripts abort if the following error is found in the results:
11+
# "error id="missingInclude" severity="style" msg="Cppcheck cannot find all the include files (use --check-config for details)"
12+
FAIL_ON_MISSING_HEADER_FILES = true
13+
# fail script if errors from commands are reported?
14+
FAIL_ON_STDERR_MSG = true
15+
16+
###############################################################################
17+
# Sources
18+
###############################################################################
19+
### Searching for source files configuration ###
20+
# Search recursively from this lists of paths (regexp or string).
21+
# Current path . (period) is allowed.
22+
SRC_SEARCH_PATH = [ "." ]
23+
# Find file matching this regexp:
24+
SRC_FILE_SEARCH_REGEXP = /^[a-zA-Z0-9_]+.cpp/ # might also use /^[a-zA-Z0-9_]+.cpp$/
25+
26+
### Filtering sources and excluding sources ###
27+
# Whitelist of filename suffixes - regexp or string
28+
# MUST include the . (period)
29+
# This list can be empty, if SRC_FILE_SEARCH_REGEXP only find exactly those file
30+
# with correct ending.
31+
SRC_SUFFIX_LIST = [ /\.cpp$/ ]
32+
33+
# Exclude all files and directories containing one of these string
34+
# or matching one the regexp.
35+
SRC_BLACKLIST_PATTERNS = [ /\.\/include\/msg_bus*/, "host", "vendor", "docs", "examples", "test", "tools", /\/moc_*/, /Adaptor.cpp$/, /Proxy.cpp$/ ]
36+
37+
###############################################################################
38+
# Headers - settings follows same conventions as the sources above
39+
###############################################################################
40+
HEADER_SEARCH_PATH = [ "." ]
41+
HEADER_FILE_SEARCH_REGEXP = /^[a-zA-Z0-9_]+.\.h$/
42+
HEADER_SUFFIX_LIST = [ ]
43+
44+
HEADER_BLACKLIST_PATTERNS = [ /\.\/host\//, /\.\/docs\//, /\.\/examples\//, /\.\/tools\//, /\.\/test\// ]
45+
46+
# Append these headers manually to Cppcheck. Eg. if they can not be found automatically.
47+
# The will be given to cppcheck with the prefix -I (for include dirs)
48+
HEADER_APPEND_DIR_LIST = [ "./msgbus_applications/view/include", "/usr/include/qt4/QtCore" ]
49+
50+
51+
##########################
52+
# Cppcheck configuration #
53+
##########################
54+
# Cppcheck executeable name
55+
CPPCHECK_EXEC="cppcheck"
56+
57+
# Currently we execute cppcheck this way, first with --check-config then with --enable=all for the real analysis
58+
# cppcheck --enable=all" + " --file-list=cppcheckSourceFiles.lst" + " --includes-file=cppcheckHeaderFiles.lst"
59+
# The real check also have " --xml 2> cppcheck-results.xml" added for output to a file.
60+
# To check possible parameters, run cppcheck --help.
61+
# For example you could add -DQT_DEPRECATED -DQT3_SUPPORT to avoid checking those configurations.
62+
CPPCHECK_ADDITIONAL_PARAMETERS = [ "-DQT3_support", "-DQT_DEPRECATED" ]
63+
64+
# Note on threads: do_cppcheck.rb script will automatically look for env. var. CPPCHECK_THREAD_COUNT and use that
65+
# as -j $CPPCHECK_THREAD_COUNT for using more jobs in parallel when checking. It is not part of the additional
66+
# parameter above, as optimal thread count will differ from build host to build host, thus it better selecting it
67+
# automatically.
68+
69+
# Reference to file with errors to whitelist
70+
# Read the file for how to suppress warnings from Cppcheck.
71+
# It it does not exist, a template should be available with the script
72+
# Comment out if not used!
73+
CPPCHECK_SUPPRESSION_FILE = "do_cppcheck-suppressions.lst"
74+
75+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Cppcheck states in it's help the following way to whitelist error.
2+
// This can be used for error we either acknowledge is okay, or that we can not
3+
// fix due to third party code etc.
4+
// Cppcheck uses the following syntax.
5+
// -suppress=<spec> Suppress warnings that match <spec>. The format of
6+
// <spec> is:
7+
// [error id]:[filename]:[line]
8+
// The [filename] and [line] are optional. If [error id]
9+
// is a wildcard '*', all error ids match.
10+
// --suppressions-list=<file>
11+
// Suppress warnings listed in the file. Each suppression
12+
// is in the same format as <spec> above.
13+
14+
// This file is included, through the --suppression-list paramter, if configured in
15+
// the do_cppcheck-settings.rb file.
16+
//
17+
// Do not use linenumber - but always id and file. Note it supresses alle the warnings with the same id.
18+
//
19+
// This it QT error, we can not fix
20+
//<error file="/usr/include/qt4/QtCore/qglobal.h" line="268" id="preprocessorErrorDirective" severity="error" msg="&quot;Qt has not been ported to this OS - talk to [email protected]&quot;"/>
21+
//<error file="/usr/include/qt4/QtCore/qglobal.h" line="786" id="preprocessorErrorDirective" severity="error" msg="&quot;Qt has not been tested with this compiler - talk to [email protected]&quot;"/>
22+
//<error file="/usr/include/qt4/QtCore/qglobal.h" line="268" id="preprocessorErrorDirective" severity="error" msg="#error &quot;Qt has not been ported to this OS - talk to [email protected]&quot;"/>
23+
// We will exclude everything regarding gt4 stuff
24+
*:/usr/include/qt4*
25+
26+
// You can also exclude less like just:
27+
// preprocessorErrorDirective:/usr/include/qt4/QtCore/qglobal.h
28+
29+
30+
// We do not have control over msgbus_applications/view/ViewMachine.h thus excluding this file also
31+
*:msgbus_applications/view/ViewMachine.h

doCppCheck/do_cppcheck.rb

+228
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
#!/usr/bin/ruby
2+
3+
# This program run the static analysis tool Cppcheck.
4+
# It takes a configuration file (also in Ruby) as mandatory parameter.
5+
#
6+
# Call as shown in usage below, or just try executing it without parameters.
7+
#
8+
# NOtES about design:
9+
# - if cppcheck offers a solution, eg. excluding or including files, it is used (eg. using suppression list parameter over cleaning the output afterwards with the script)
10+
# - every confiuration, both cppcheck parameters, exclude files etc., is defined in a file under revision control
11+
# - it supposed not to clean up it temporary files, as these might be need later for further debugging
12+
# - the out-file name is hardcoded by choice, to avoid developers changing it easily and therefore
13+
# requiring automated build configuration changes. We will avoid this as it makes it more difficult to
14+
# automatically build old revision without changing build job defintions.
15+
16+
17+
require "find"
18+
require "fileutils"
19+
require "open3"
20+
21+
# Parse input paramenter:
22+
# one mandatory settings file in ruby (not validating the file)
23+
if ARGV.length() != 1 then
24+
puts <<-EOF
25+
Please provide a settings file as only parameter
26+
27+
Usage:
28+
do_cppcheck.rb cppcheck_settings.rb
29+
EOF
30+
abort("Wrong input parameters")
31+
else
32+
# assume file is in correct format and load it
33+
puts "Using settingsfile: " + ARGV[0]
34+
load ARGV[0]
35+
end
36+
37+
38+
# Cross-platform way of finding an executable in the $PATH.
39+
#
40+
# which('ruby') #=> /usr/bin/ruby
41+
def which(cmd)
42+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
43+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
44+
exts.each { |ext|
45+
exe = "#{path}/#{cmd}#{ext}"
46+
return exe if File.executable? exe
47+
}
48+
end
49+
return nil
50+
end
51+
52+
53+
# Searches each directory in the dirlist recursively for file basenames
54+
# matching string or regular expression name.
55+
# For example find all .cpp files with the regexp like:
56+
# /^[a-zA-Z0-9_]+.cpp$/
57+
# Note the dolar sign in the end for looking for suffixes
58+
# Params:
59+
# +dirlist+:: list of directories (current directory is accepted)
60+
# +name+:: a string or regexp to match against the file basename
61+
# Returns:
62+
# +list+:: a list of files with path relative to the searched directory
63+
def find_files(dirlist, name, suffix)
64+
list = []
65+
dirlist.each{|dir|
66+
Find.find(dir) do |path|
67+
case name
68+
when String
69+
list << path if File.basename(path) == name
70+
when Regexp
71+
list << path if File.basename(path) =~ name
72+
else
73+
raise ArgumentError
74+
end
75+
end
76+
}
77+
if suffix.length() == 0 then
78+
return list
79+
else
80+
list_suffix_filtered = [ ]
81+
suffix.each{|suffix|
82+
case suffix
83+
when String
84+
list_suffix_filtered.concat( list.select { |file| File.extname(file).eql?(suffix) } )
85+
when Regexp
86+
list_suffix_filtered.concat( list.select { |file| suffix.match(File.extname(file)) } )
87+
else
88+
raise ArgumentError
89+
end
90+
}
91+
return list_suffix_filtered
92+
end
93+
end
94+
95+
# Filters a list of strings from a blacklist strings or regexps.
96+
# Params:
97+
# +inlist+:: list of strings (supposely file names)
98+
# +blacklist+:: list of strings or regexp used to filter out matches in the inlist
99+
def filter_list(inlist, blacklist)
100+
blacklist.each{|bitem|
101+
case bitem
102+
when String
103+
inlist.delete_if { |item| item.include?(bitem) }
104+
when Regexp
105+
inlist.delete_if { |item| bitem.match(item) }
106+
else
107+
raise ArgumentError
108+
end
109+
}
110+
end
111+
112+
# is the string in the list a file?
113+
def sanitize_filelist(listOfFiles)
114+
listOfFiles.each{|fileString|
115+
listOfFiles.delete_if { |fileString| !File.file?(fileString) }
116+
}
117+
end
118+
119+
def backup_existing_file(filename)
120+
# Safety check - will not overwrite existing file - renames old
121+
if File.exists?(filename) then
122+
FileUtils.cp(filename, filename + ".bak")
123+
puts "Filename '" + filename + "' to write already exist - saved old with '.bak' suffix"
124+
end
125+
end
126+
127+
128+
def write_filelist(listOfFiles, filename, sanitize=false)
129+
if sanitize then
130+
sanitize_filelist(listOfFiles)
131+
end
132+
# Safety check - will not overwrite existing file - renames old
133+
backup_existing_file(filename)
134+
135+
File.open(filename, 'w') do |f|
136+
listOfFiles.each{|file|
137+
f << file << "\n"
138+
}
139+
end
140+
end
141+
142+
def extract_unique_dir(listOfFiles)
143+
listOfFiles.map! { |file| File.dirname(file) }
144+
listOfFiles.uniq!
145+
end
146+
147+
148+
def run_command(command, failIfstdError=false)
149+
# FIXME We should upgrade to Ruby 1.9.3 soon, to be able to user newer version
150+
# of Open3, that can check exit status and other nice stuff.
151+
puts "\n\n\n================================================================================"
152+
puts "Running Cppcheck command now: " + command
153+
stdin, stdout, stderr = Open3.popen3(command)
154+
result = 0 # to be used later when Open3 can return this
155+
output = stdout.read
156+
errors = stderr.read
157+
puts "================================================================================"
158+
puts "Output (stdout) was:"
159+
puts output
160+
if !(errors.empty?) then
161+
puts "================================================================================"
162+
puts "There is errors, stderr) not empty:"
163+
puts errors
164+
if failIfstdError then
165+
abort("Command returned messages to stderr, asuming errors and failing")
166+
end
167+
end
168+
return output, errors, result, command
169+
end
170+
171+
172+
source_files = find_files(CppcheckSettings::SRC_SEARCH_PATH, CppcheckSettings::SRC_FILE_SEARCH_REGEXP, CppcheckSettings::SRC_SUFFIX_LIST)
173+
filter_list(source_files, CppcheckSettings::SRC_BLACKLIST_PATTERNS)
174+
write_filelist(source_files, "cppcheckSourceFiles.lst", true)
175+
176+
header_files = find_files(CppcheckSettings::HEADER_SEARCH_PATH, CppcheckSettings::HEADER_FILE_SEARCH_REGEXP, CppcheckSettings::HEADER_SUFFIX_LIST)
177+
filter_list(header_files, CppcheckSettings::HEADER_BLACKLIST_PATTERNS)
178+
179+
extract_unique_dir(header_files)
180+
header_files.concat CppcheckSettings::HEADER_APPEND_DIR_LIST
181+
write_filelist(header_files, "cppcheckHeaderFiles.lst")
182+
183+
puts which('cppcheck')
184+
185+
# It is my intention to hard-code the cppcheck result xm-file, and NOT letting
186+
# the user decide the name. We will use that specific file in the Jenkins CI
187+
# server job configuration, thus is "someone" decides to change it, job
188+
# configuration need to be changes as well.
189+
# - this is a problem as it can go unotised if old file exist
190+
# - it also give problems if one like to make historical build and not
191+
# changing the job configuration
192+
cppcheckResultFile = "cppcheck-results.xml"
193+
194+
# Check if using suppression list for cppcheck warnings and prepare the list for cppcheck
195+
# We will like comments in the file, but cppcheck can not handle that, so we remove them
196+
suppressions_list_parameter = ""
197+
if (defined? CppcheckSettings::CPPCHECK_SUPPRESSION_FILE) then
198+
suppressions_list_parameter = "--suppressions-list=" + CppcheckSettings::CPPCHECK_SUPPRESSION_FILE
199+
end
200+
201+
cppcheck_common_params = " " + CppcheckSettings::CPPCHECK_ADDITIONAL_PARAMETERS.map! { |p| p}.join(" ") + " " + suppressions_list_parameter + " --file-list=cppcheckSourceFiles.lst" + " --includes-file=cppcheckHeaderFiles.lst"
202+
203+
# To support threads, job numbers, of cppcheck, we check an environment variable and if set we use that numbers of jobs parameter to cppcheck
204+
if ENV['CPPCHECK_THREAD_COUNT'] then
205+
jobs_parameter = "-j " + ENV['CPPCHECK_THREAD_COUNT']
206+
puts "do_cppcheck script found env. var. CPPCHECK_THREAD_COUNT so using job parameter: " + jobs_parameter
207+
cppcheck_common_params = " " + jobs_parameter + " " + cppcheck_common_params
208+
end
209+
210+
run_command(CppcheckSettings::CPPCHECK_EXEC + " --version")
211+
run_command(CppcheckSettings::CPPCHECK_EXEC + " --check-config" + cppcheck_common_params, CppcheckSettings::FAIL_ON_STDERR_MSG)
212+
backup_existing_file(cppcheckResultFile)
213+
run_command(CppcheckSettings::CPPCHECK_EXEC + " --enable=all" + cppcheck_common_params + " --xml 2> " + cppcheckResultFile, CppcheckSettings::FAIL_ON_STDERR_MSG)
214+
215+
216+
if CppcheckSettings::FAIL_ON_MISSING_HEADER_FILES then
217+
missing_includes = [ ]
218+
File.open( 'cppcheck-results.xml' ).each do |line|
219+
if line =~ /.+Cppcheck cannot find all the include files.*/ then
220+
puts "cppcheck found errors that is so important that we must fail!: \n" + line + "\n\n" + missing_includes.map! { |l| l}.join("")
221+
# okay here, because cppcheck add this line last!
222+
abort("Cppcheck found errors that means we did not analyse everything - fix it checking the results in cppcheck-results.xml")
223+
elsif line =~ /.+id="missingInclude".*/ then
224+
missing_includes << line
225+
end
226+
227+
end
228+
end

0 commit comments

Comments
 (0)