How to get package changes before update in zypper - package

does a counterpart for apt-listchanges functionality from debian/ubuntu exists for zypper?
at the moment I have to do following manually for each updated package: 1) install with zypper, 2) check the changes with rpm -q --changelog PACKAGE_NAME and it is far away from the convenient way it is done by apt-listchanges. And most important for me, how to get changes before the installation (with possibility to abort)?

not with zypper but if you can download both rpms (old and new versions), you may use pkgdiff to check the differences.

I couldn't find a way to see changes made to an individual package without downloading it. OpenSUSE collects packages in "patches" since bugs often need changes to several packages. To see what's in a patch:
Get the name/ID of the available patches with zypper list-patches
Get the info about a patch set using zypper info -t patch $ID where $ID is the ID from the output of the previous command.
If you want to look at a certain package, you can use zypper download to download it without installing. After that, you can use rpm -q --changelog -p $PATH to see the changelog of the downloaded file at $PATH.

(I don't know what apt-listchanges outputs)
The main problem is to get output that is easily parsable from zypper. This isn't perfect, but it may get you on the way:
First get the plain names of the patches from zypper output, omitting header and trailer lines:
zypper -t lp | awk -F'|' '/^---/ { OK=1; next } OK && NF == 7 { gsub(" ", "", $2); print $2 }'
For example you could get:
openSUSE-2018-172
openSUSE-2018-175
openSUSE-2018-176
openSUSE-2018-178
Then feed that output into zypper again, like this:
zypper patch-info $(zypper -t lp | awk -F'|' '/^---/ { OK=1; next } OK && NF == 7 { gsub(" ", "", $2); print $2 }')
Output would include information like this (truncated for brevity):
Summary : Security update for ffmpeg
Description :
This update for ffmpeg fixes the following issues:
Updated ffmpeg to new bugfix release 3.4.2
* Fix integer overflows, multiplication overflows, undefined
shifts, and verify buffer lengths.

Related

How to merge duplicate entries that produced by for loop

Following my previous question which got closed— basically I have a script that check availability of packages on target server, the target server and the packages have been stored to an array.
declare -a prog=("gdebi" "firefox" "chromium-browser" "thunar")
declare -a snap=("beer2" "beer3")
# checkvar=$(
for f in "${prog[#]}"; do
for connect in "${snap[#]}"; do
ssh lg#"$connect" /bin/bash <<- EOF
if dpkg --get-selections | grep -qE "(^|\s)"$f"(\$|\s)"; then
status="[INSTALLED] [$connect]"
else
status=""
fi
printf '%s %s\n' "$f" "\$status"
EOF
done
done
With the help of fellow member here, I've made several fix to original script, script ran pretty well— except there's one problem, the output contain duplicate entries.
gdebi [INSTALLED] [beer2]
gdebi
firefox [INSTALLED] [beer2]
firefox [INSTALLED] [beer3]
chromium-browser [INSTALLED] [beer2]
chromium-browser [INSTALLED] [beer3]
thunar
thunar
I know it this is normal behavior, as for pass multiple server from snap array, making ssh travel to all the two server.
Considering that the script checks same package for two server, I want the output to be merged.
If beer2 have firefox packages, but beer3 doesn't.
firefox [INSTALLED] [beer2]
If beer3 have firefox packages, but beer2 doesn't.
firefox [INSTALLED] [beer3]
If both beer2 and beer3 have the packages.
firefox [INSTALLED] [beer2, beer3]
or
firefox [INSTALLED] [beer2] [beer3]
If both beer2 and beer3 doesn't have the package, it will return without extra parameter.
firefox
Sound like an easy task, but for the love of god I can't find how to achieve this, here's list of things I have tried.
Try to manipulate the for loops.
Try putting return value after one successful loops (exit code).
Try nested if.
All of the above doesn't seem to work, I haven't tried changing/manipulate the return string as I'm not really experienced with some text processing such as: awk, sed, tr and many others.
Can anyone shows how It's done ? Would really mean the world to me.
Pure Bash 4+ solution using associative array to store hosts the program is installed on:
#!/usr/bin/env bash
declare -A hosts_with_package=(["gdebi"]="" ["firefox"]="" ["chromium-browser"]="" ["thunar"]="")
declare -a hosts=("beer2" "beer3")
# Collect installed status
# Iterate all hosts
for host in "${hosts[#]}"; do
# Read the output of dpkg --get-selections with searched packages
while IFS=$' \t' read -r package status; do
# Test weather package is installed on host
if [ "$status" = "install" ]; then
# If no host listed for package, create first entry
if [ -z "${hosts_with_package[$package]}" ]; then
# Record the first host having the package installed
hosts_with_package["$package"]="$host"
else
# Additional hosts are concatenated as CSV
hosts_with_package["$package"]="${hosts_with_package[$package]}, $host"
fi
fi
# Feed the whole loop with the output of the dpkg --get-selections for packages names
# Packages names are the index of the hosts_with_package array
done < <(ssh "lg#$host" dpkg --get-selections "${!hosts_with_package[#]}")
done
# Output results
# Iterate the package name keys
for package in "${!hosts_with_package[#]}"; do
# Print package name without newline
printf '%s' "$package"
# If package is installed on some hosts
if [ -n "${hosts_with_package[$package]}" ]; then
# Continue the line with installed hosts
printf ' [INSTALLED] [%s]' "${hosts_with_package[$package]}"
fi
# End with a newline
echo
done
Instead of making several ssh connections in nested loops consider this change
prog=( mysql-server apache2 php ufw )
snap=( localhost )
for connect in ${snap[#]}; do
ssh $connect "
progs=( ${prog[#]} )
for prog in \${progs[#]}; do
dpkg -l | grep -q \$prog && echo \"\$prog [INSTALLED]\" || echo \"\$prog\"
done
"
done
Based on #Ivan answer
#!/bin/bash
prog=( "gdebi" "firefox" "chromium-browser" "thunar" )
snap=( "beer2" "beer3" )
# First, retrieve the list on installed program for each host
for connect in ${snap[#]}; do
ssh lg#"$connect" /bin/bash >/tmp/installed.${connect} <<- EOF
progs=( "${prog[#]}" )
for prog in \${progs[#]}; do
dpkg --get-selections | awk -v pkg=\$prog '\$1 == pkg && \$NF ~ /install/ {print \$1}'
done
EOF
done
# Filter the previous results to format the output as you need
awk '{
f = FILENAME;
gsub(/.*\./,"",f);
a[$1] = a[$1] "," f
}
END {
for (i in a)
print i ":[" substr(a[i],2) "]"
}' /tmp/installed.*
rm /tmp/installed.*
Example of output :
# With prog=( bash cat sed tail something firefox-esr )
firefox-esr:[localhost]
bash:[localhost,localhost2]
sed:[localhost,localhost2]

How to view apps packageName with ADB commands? [duplicate]

I need to get the package name of an Android APK. I have tried to unzip the APK and read the contents of the AndroidManifest.xml file but it seems that it's not a text file.
How can I extract the APK's package name?
aapt dump badging <path-to-apk> | grep package:\ name
Install the apk on your Android device. Then
you can launch adb shell and execute pm list packages -f, which shows the package name for each installed apk.
This is taken from
Find package name for Android apps to use Intent to launch Market app from web.
Based on #hackbod answer ... but related to windows.
aapt command is located on Android\SDK\build-tools\version.
If you need more info about what is appt command (Android Asset Packaging Tool) read this https://stackoverflow.com/a/28234956/812915
The dump sub-command of aapt is used to display the values of individual elements or parts of a package:
aapt dump badging <path-to-apk>
If you want see only the line with package: name info, use findstr
aapt dump badging <path-to-apk> | findstr -n "package: name" | findstr "1:"
Hope it help other windows user!
If you are looking at google play and want to know its package name then you can look at url or address bar. You will get package name. Here com.landshark.yaum is the package name
https://play.google.com/store/apps/details?id=com.landshark.yaum&feature=search_result#?t=W251bGwsMSwyLDEsImNvbS5sYW5kc2hhcmsueWF1bSJd
The following bash script will display the package name and the main activity name:
apk_package.sh
package=$(aapt dump badging "$*" | awk '/package/{gsub("name=|'"'"'",""); print $2}')
activity=$(aapt dump badging "$*" | awk '/activity/{gsub("name=|'"'"'",""); print $2}')
echo
echo " file : $1"
echo "package : $package"
echo "activity: $activity"
run it like so:
apk_package.sh /path/to/my.apk
If you open the AndroidManifest.xml using MS Notepad, search for phrase package and you'll find following:
package manifest $xxx.xxxxxxx.xxxxxxx |
where xxx.xxxxxxx.xxxxxxx is your package name, just written with a space after each character.
It's useful way when you don't have any specific tools installed.
Since its mentioned in Android documentation that AAPT has been deprecated, getting the package name using AAPT2 command in Linux is as follows:
./aapt2 dump packagename <path_to_apk>
Since I am using an older version of Gradle build, I had to download a newer version of AAPT2 as mentioned here :
Download AAPT2 from Google Maven
Using the build-tools in my sdk - 25.0.3, 26.0.1 and 27.0.3, executing the aapt2 command shows an error: Unable to open 'packagename': No such file or directory. That's why I went for the newer versions of AAPT2.
I used 3.3.0-5013011 for linux.
A Programmatic Answer
If you need to do this programmatically, it's a little more involved than just getting the answer into your brain. I have a script that I use to sign all of our apps, but each use a different key. Here are 2 ways to get just the Package Name as output so you can put it in a variable or do whatever you need with it.
Example output: com.example.appname (and nothing more)
Requirements
aapt - Android Asset Packaging Tool, part of the SDK Tools download
Solution 1
Using awk specify ' as the Field Separator, search for a line with package: name=, and print only the 2nd "field" in the line:
aapt dump badging /path/to/file.apk | awk -v FS="'" '/package: name=/{print $2}'
A weakness of this method is that it relies on aapt to output the package information fields in the same order:
package: name='com.example.appname' versionCode='3461' versionName='2.2.4' platformBuildVersionName='4.2.2-1425461'
We have no commitments from the developers to maintain this format.
Solution 2
Using awk specify " as the Field Separator, search for a line with package=, and print only the 2nd "field" in the line:
aapt list -a /path/to/file.apk | awk -v FS='"' '/package=/{print $2}'
A weakness of this method is that it relies on aapt to output package= only in the Android Manifest: section of the output. We have no commitments from the developers to maintain this format.
Solution 3
Expand the apk file with apktool d and read the AndroidManifest.xml.
This would be the best method, but the AndroidManifest.xml is a binary file and all the SO answers I see for converting it to text do not work. (Using apktool d instead of a simple unzip is supposed to do this for you, but it does not.) Please comment if you have an solution to this issue
A simple solution would be Open Android Studio -> Build -> Analyze Apk... browse and select the APK now you can find the package name and pretty much you can read.
You can use Analyze APK... from the Build menu in Android Studio, it will display the package name at the top of new window.
If you don't have the Android SDK installed, like in some test scenarios, you can get the package name using the following bash method:
getAppIdFromApk() {
local apk_path="$1"
# regular expression (required)
local re="^\"L.*/MainActivity;"
# sed substitute expression
local se="s:^\"L\(.*\)/MainActivity;:\1:p"
# tr expression
local te=' / .';
local app_id="$(unzip -p $apk_path classes.dex | strings | grep -Eo $re | sed -n -e $se | tr $te)"
echo "$app_id"
}
Tested on a mac. 'strings' and 'unzip' are standard on most linux's, so should work on linux too.
A very simple method is to use apkanalyzer.
apkanalyzer manifest application-id "${_path_to_apk}"
On Mac:
Way 1:
zgong$ /Users/zgong/Library/Android/sdk/build-tools/29.0.3/aapt dump badging ~/Downloads/NonSIMCC-151-app-release-signed.apk
package: name='com.A.B' versionCode='2020111801' versionName='1.0.40' compileSdkVersion='29' compileSdkVersionCodename='10'
sdkVersion:'24'
targetSdkVersion:'29'
......
Way 2:
/Users/zgong/Library/Android/sdk/build-tools/29.0.3/aapt2 dump packagename ~/Downloads/NonSIMCC-151-app-release-signed.apk
com.A.B
If you just want to know package name, run adb logcat, launch the activity you want , you will get a hint on the package name.
Another solution is to use aapt list and use sed to parse through that:
aapt list -a $PATH_TO_YOUR_APK | sed -n "/^Package Group[^s]/s/.*name=//p"
I think the best and simplest way to extract only the package name in Linux is
aapt dump badging <APK_path> | grep package | sed -r "s/package: name='([a-z0-9.]*)'.*/\1/"
Explanation:
AAPT extracts the APK information
Grep "package" to keep only the line about the package information
Make sed replace the whole line with the package name only using the following regex: package: name='([a-z0-9.]*)'.* and replacing with the first (and only) matching group.
There's a very simple way if you got your APK allready on your Smartphone. Just use one of these APPs:
Package Name Viewer Apps
To use this in batch scripting it's handy to have the script return just the package name (e.g. for uninstalling an app when you have the APK).
Here's the script I use:
# extract the android package id from a built apk file
# usage ./getPackageName.sh <path-to-apk>
line=`aapt dump badging "$1" | grep package:\ name`
# above returns:
# package: name='com.calvium.myapp' versionCode='1' versionName='1.0'
if [[ $line =~ name=\'(.+)\'\ versionCode ]]; then
echo ${BASH_REMATCH[1]}
else
echo "Failed to find package name"
exit 1
fi
available on gist
So you could write:
adb uninstall `./getPackageName.sh file.apk`
You can extract AndroidManifest.xml from the APK, remove all NULL bytes, skip everything until after the string 'manifest', and then you are at a length byte followed by the package name (and what comes after it). For the difficult task I use the great GEMA tool, so the command looks like this:
7z e -so MyApp.apk AndroidManifest.xml | gema '\x00=' | gema -match 'manifest<U1><U>=#substring{0;#char-int{$1};$2}'
Of course, you can use any other tool to do the filtering.
For Windows following worked for me:
:: // Initializing variables
SET adb="C:\Users\<User name>\AppData\Local\Android\Sdk\platform-tools\adb"
SET aapt="C:\Users\<User name>\AppData\Local\Android\Sdk\build-tools\22.0.0\aapt"
SET APKPath=C:\Users\<User name>\Desktop\APK\Instant_Instal\
CD %APKPath%
:: // Searching for apk file and storing it
FOR /F "delims=" %%f IN ('dir /S /B *.apk') DO SET "APKFullPath=%%f"
SET apk=%APKFullPath%
:: // Command adb install apk, run apk
%adb% install %apk%
:: // Fetching package name from apk
%aapt% dump badging %APKFullPath% | FIND "package: name=" > temp.txt
FOR /F "tokens=2 delims='" %%s IN (temp.txt) DO SET pkgName=%%s
del temp.txt
:: // Launching apk
%adb% shell monkey -p %pkgName% -c android.intent.category.LAUNCHER 1
pause
Note
Please edit the paths of adb, aapt, APKPath according to the paths of adb, aapt, and the apk location in your system.
Working:
Here I have added the apk in a folder on Desktop "\Desktop\APK\Instant_Instal\".
The command %adb% install %apk% installs the application if the device is connected.
This %aapt% dump badging %APKFullPath% | FIND "package: name=" > temp.txt fetches package name and a few other details like version etc. of the apk and stores in a temp.txt file in same location as that of the apk.
FOR /F "tokens=2 delims='" %%s IN (temp.txt) DO SET pkgName=%%sextracts the package name and assigns topkgName` variable
Finally %adb% shell monkey -p %pkgName% -c android.intent.category.LAUNCHER 1 launches the app.
In essence the above code installs the apk from given location in desktop "Desktop\APK\Instant_Instal\" to the device and launches the application.
You can get the package name programmatically by :
packageManager.getPackageArchiveInfo(apkFilePath, 0)?.packageName
you can instal Package_Name_Viewer.apk on your emulator and next you can see package name of all instaled app on your emulator.
I also tried the de-compilation thing, it works but recently I found the easiest way:
Download and install Appium from Appium website
Open Appium->Android setting, choose the target apk file. And then you get everything you want, the package info, activity info.
As I don't was able to find the package name in the .apk file with editor (like suggested above), I have checked the functions in the App "ES Datei Explorer" / "ES File Explorer" (free version) that I had installed already.
In this tool, the package name is showed properly.
As I think a good file explorer should not be missing on a phone, I suggest to use this tool (if you already have installed the apk on an mobile and have to know the package name).
If you want to read the package name of a typical APK file in your app, there's an easy way to analyze the PackageInfo:
fun getAPKPackageName(apkFile: File?): String? {
if (apkFile == null || !apkFile.isFile || !apkFile.exists()) return null
val apkFilePath = apkFile.absolutePath
if (apkFilePath.isNullOrEmpty()) return null
val packageManager = App.context.packageManager ?: return null
val packageInfo = packageManager.getPackageArchiveInfo(apkFilePath, 0) ?: return null
return packageInfo.packageName
}

How to post review for multiple clearcase files in review board

Old File : /vobs/code1/dir1/file1.c##/main/branch1/4 .
New File : /vobs/code1/dir1/file1.c##/main/branch1/mybranch/1
$ diff -q /vobs/code1/dir1/file1.c##/main/branch1/4 /vobs/code1/dir1/file1.c##/main/branch1/mybranch/1
Files /vobs/code1/dir1/file1.c##/main/branch1/4 and /vobs/code1/dir1/file1.c##/main/branch1/mybranch/1 differ
$ post-review --server http://reviewserver.oursite.com --revision-range='/vobs/code1/dir1/file1.c##/main/branch1/4:/vobs/code1/dir1/file1.c##/main/branch1/mybranch/1'
There don't seem to be any diffs!
$
Why i am getting above message when there are difference in files ?
Generate unified diffs of all files using option -U of GNU diff command:
diff -U 100000 file1.c##/main/4 file1.c##/main/10 > uni_diffs
diff -U 100000 file2.c##/main/br1/3 file2.c##/main/branch2/4 >> uni_diffs
diff -U 100000 file3.c##/main/abc/4 file3.c##/main/30 >> uni_diffs
....
Note 100000 is passed so that complete file can also be viewed on review board.
Assuming file length is less than 1000000.
Post the above unified diff file to review board :
post-review --diff-filename=uni_diffs ....
Deepak
In many RBTool versions there is a mistake in class ClearCaseClient, function diff_between_revisions.
Problematic part in postreview.py looks like this:
revision_range = revision_range.split(';')
Two ways to handle this issue if staying with current version of Review Board and RBTools:
1) Changing semicolon to colon in the postreview.py code
2) Using semicolon as delimiter in the command line argument.
Choose the preferred solution and use it. ;-)

File churn in CVS

I'm looking to find the number of times that each file has changed on a particular branch in our cvs repository. I'm particularly looking for all the files which have changed the most. A "top 40" list would be good enough.
This was added as an edit by the original asker, I have converted it to a community wiki answer because it should be an answer, not an edit.
In this case, the branch has been in use for about 6 months. If I set to the latest in that branch ("cvs -z9 co -r r80m-1 ..."), it looks like the last number of the revision is the number of changes in the current branch -- if the file has been changed in the past 180 days, then it's on this branch. I'm using linux, so I eventually did it this way:
for file in `find . \! \( -name CVS -prune \) -type f -mtime -180`
do
cvs status "$file" | grep Working.revision | gawk -v FNAME=$file '{ print FNAME gensub(/(\.)([0-9]*)$/, "\\1\\2 churn:\\2 ", 1) }' >> cvs_churn.txt
done
sort -k3 -t: -n cvs_churn.txt | uniq
So, for each line in "cvs status" output like:
Working revision: 1.2.34
The gawk command changes it to:
./path/file.c Working revision: 1.2.34 churn:34
and I can then sort on ":34".
This works, but it's pretty crude. I'm hoping others may be able to answer with better approaches.
I've seen in some other questions eg: Free CVS reporting tools people have mentioned statCVS. It sounds interesting (more than I need, but some of the other info might also be useful). However, it says it only works on the "default" branch. The documentation was a little unclear -- can I set to the branch of interest, and use it for this?

Moving things in terminal based on their name

Edit: I think this has been answered successfully, but I can't check 'til later. I've reformatted it as suggested though.
The question: I have a series of files, each with a name of the form XXXXNAME, where XXXX is some number. I want to move them all to separate folders called XXXX and have them called NAME. I can do this manually, but I was hoping that by naming them XXXXNAME there'd be some way I could tell Terminal (I think that's the right name, but not really sure) to move them there. Something like
mv *NAME */NAME
but where it takes whatever * was in the first case and regurgitates it to the path.
This is on some form of Linux, with a bash shell.
In the real life case, the files are 0000GNUmakefile, with sequential numbering. I'm having to make lots of similar-but-slightly-altered versions of a program to compile and run on a cluster as part of my research. It would probably have been quicker to write a program to edit all the files and put in the right place in the first place, but I didn't.
This is probably extremely simple, and I should be able to find an answer myself, if I knew the right words. Thing is, I have no formal training in programming, so I don't know what to call things to search for them. So hopefully this will result in me getting an answer, and maybe knowing how to find out the answer for similar things myself next time. With the basic programming I've picked up, I'm sure I could write a program to do this for me, but I'm hoping there's a simple way to do it just using functionality already in Terminal. I probably shouldn't be allowed to play with these things.
Thanks for any help! I can actually program in C and Python a fair amount, but that's through trial and error largely, and I still don't know what I can do and can't do in Terminal.
SO many ways to achieve this.
I find that the old standbys sed and awk are often the most powerful.
ls | sed -rne 's:^([0-9]{4})(NAME)$:mv -iv & \1/\2:p'
If you're satisfied that the commands look right, pipe the command line through a shell:
ls | sed -rne 's:^([0-9]{4})(NAME)$:mv -iv & \1/\2:p' | sh
I put NAME in brackets and used \2 so that if it varies more than your example indicates, you can come up with a regular expression to handle your filenames better.
To do the same thing in gawk (GNU awk, the variant found in most GNU/Linux distros):
ls | gawk '/^[0-9]{4}NAME$/ {printf("mv -iv %s %s/%s\n", $1, substr($0,0,4), substr($0,5))}'
As with the first sample, this produces commands which, if they make sense to you, can be piped through a shell by appending | sh to the end of the line.
Note that with all these mv commands, I've added the -i and -v options. This is for your protection. Read the man page for mv (by typing man mv in your Linux terminal) to see if you should be comfortable leaving them out.
Also, I'm assuming with these lines that all your directories already exist. You didn't mention if they do. If they don't, here's a one-liner to create the directories.
ls | sed -rne 's:^([0-9]{4})(NAME)$:mkdir -p \1:p' | sort -u
As with the others, append | sh to run the commands.
I should mention that it is generally recommended to use constructs like for (in Tim's answer) or find instead of parsing the output of ls. That said, when your filename format is as simple as /[0-9]{4}word/, I find the quick sed one-liner to be the way to go.
Lastly, if by NAME you actually mean "any string of characters" rather than the literal string "NAME", then in all my examples above, replace NAME with .*.
The following script will do this for you. Copy the script into a file on the remote machine (we'll call it sortfiles.sh).
#!/bin/bash
# Get all files in current directory having names XXXXsomename, where X is an integer
files=$(find . -name '[0-9][0-9][0-9][0-9]*')
# Build a list of the XXXX patterns found in the list of files
dirs=
for name in ${files}; do
dirs="${dirs} $(echo ${name} | cut -c 3-6)"
done
# Remove redundant entries from the list of XXXX patterns
dirs=$(echo ${dirs} | uniq)
# Create any XXXX directories that are not already present
for name in ${dirs}; do
if [[ ! -d ${name} ]]; then
mkdir ${name}
fi
done
# Move each of the XXXXsomename files to the appropriate directory
for name in ${files}; do
mv ${name} $(echo ${name} | cut -c 3-6)
done
# Return from script with normal status
exit 0
From the command line, do chmod +x sortfiles.sh
Execute the script with ./sortfiles.sh
Just open the Terminal application, cd into the directory that contains the files you want moved/renamed, and copy and paste these commands into the command line.
for file in [0-9][0-9][0-9][0-9]*; do
dirName="${file%%*([^0-9])}"
mkdir -p "$dirName"
mv "$file" "$dirName/${file##*([0-9])}"
done
This assumes all the files that you want to rename and move are in the same directory. The file globbing also assumes that there are at least four digits at the start of the filename. If there are more than four numbers, it will still be caught, but not if there are less than four. If there are less than four, take off the appropriate number of [0-9]s from the first line.
It does not handle the case where "NAME" (i.e. the name of the new file you want) starts with a number.
See this site for more information about string manipulation in bash.

Resources