Skip to content

Instantly share code, notes, and snippets.

@dinigo
Last active February 3, 2017 09:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dinigo/066eb7fc053d9fd48be1e9a1b932121c to your computer and use it in GitHub Desktop.
Save dinigo/066eb7fc053d9fd48be1e9a1b932121c to your computer and use it in GitHub Desktop.
Script para calcular altas y bajas para el DMP
#!/usr/bin/env Rscript
args = commandArgs(trailingOnly=TRUE)
base_file <- paste0(getwd(),'/',args[1])
delta_file <- paste0(getwd(),'/',args[2])
altas_file <- paste0(getwd(),'/',args[3])
bajas_file <- paste0(getwd(),'/',args[4])
cat('cargando base... \n');
base <- read.csv(base_file,sep=',',header=FALSE)
base <- t(base)
cat('cargando delta... \n');
delta <- read.csv(delta_file,sep=',',header=FALSE)
delta <- t(delta)
cat('calculando bajas... \n')
bajas <- base[!base%in%delta]
cat('calculando altas.. \n')
altas <- delta[!delta%in%base]
cat('escribiendo bajas... \n');
write.csv(altas, file = altas_file,row.names=FALSE,quote=FALSE)
cat('escribiendo altas... \n');
write.csv(bajas, file = bajas_file,row.names=FALSE,quote=FALSE)
#!/bin/bash
# setopt shwordsplit
# Script para calcular las altas y bajas en cada mes entre dos archivos
#===================================================================#
# #
# Define las varaibles y flags necesarios para almacenar la #
# configuracion del programa #
# #
#===================================================================#
# Flags
VERBOSE=true # flag de verbose
CLEAN=true # flag para limpiar los archivos cuando acaba el script
LOWER=false # flag para lowercase
COMPRESS=false # flag para comprimir
UPLOAD=false # flag para subir los archivos tras transformarlos
HASH=false # flag para calcular el hash de los ids
BAD_PARAMS=false # flag para mostrar la ayuda despues de parsear los params
DEBUG=false # flag para mostrar información de debug
# Archivos
BASE="" # archivo base sobre el que se aplican incrementos
DELTA="" # archivo incremental
OUTPUT="" # nombre del archivo de salida (opcioneal)
LOG_FILE=log.html # archivo de log por defecto
# Config
SCRIPT_NAME="$0" # nombre del script
ARGS="$@" # todos los argumentos con que se llamo al script
TRAITS="" # array de traits que añadir a las altas
EXECUTE="" # array de traits para ejecutar
REMOVE_TRAITS=() # array de id de traits que eliminar de las bajas
TEMP_FILES="" # lista de archivos temporales genrados por el script
COMMAND="" # comando que pasar al programa de encriptacion
ROW="" # columna en que se encuentra el id a encruptar
SECONDS=$(date +%s) # fecha en segundos en que se comenzó a ejecutar el script
PARAMS=$# # numero de parametros con que se invoco el script
GIST_URL="https://api.github.com/gists/066eb7fc053d9fd48be1e9a1b932121c"
DEPENDENCIES="coreutils r jq wget curl" # dependencias de la aplicacion
# Analitica
TRACKING_ID="UA-69106054-6" # propiedad de google analytics
APP_VERSION="12" # version de la app, tambien se usa para update
APP_NAME="DMP Upload" # nombre de la app
APP_ID="dmp-upload:shell" # nombre descriptivo de la app
APP_PATH="" # variable acumulador path para el estado actual
# Alias
# Si estamos en mac usamos gdate en lugar de date
if [[ $(uname) -eq 'Darwin' ]]; then
date () { gdate "$@"; }
fi
#===================================================================#
# #
# Define las functiones y demas utilidades que se usaran durante #
# la ejecucion del programa. Siempre manteniendo la filosofia #
# kiss y burrito code #
# #
#===================================================================#
# Elimina todos los archivos en la lista de temporales
cleanup(){
if [[ $CLEAN ]]; then
for file in $TEMP_FILES; do
[ -f $file ] && rm $file
done
fi
}
# Comprueba que se cumplen las dependencias del programa y las instala
check_dependencies(){
print dark_gray "Comprobando dependencias"
if [[ ! -f $LOG_FILE ]]; then
print dark_gray "Descargando plantilla de log"
local gist=$(curl -s $GIST_URL)
local log_url=$(echo $gist | jq -r '.files.log_template.raw_url')
curl -s -o $LOG_FILE $log_url
fi
if [[ ! -f difference ]]; then
print dark_gray "Descargando script para cruzar altas y bajas"
local gist=$(curl -s $GIST_URL)
local dif_url=$(echo $gist | jq -r '.files.difference.raw_url')
curl -s -o difference $dif_url
chmod +x difference
fi
if ! command -v brew >/dev/null 2>&1; then
print grey "---------------------------"
print white " Instalando gestor de paquetes"
event "install" "start" "dependency" "brew"
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
event "install" "finished" "dependency" "brew"
else
$DEBUG && print grey " Brew instalado"
fi
for dep in $DEPENDENCIES;do
if ! brew list $dep >/dev/null 2>&1; then
print white " Instalando dependencia: $dep"
event "install" "start" "dependency" "$dep"
case $dep in
r)
brew tap homebrew/science
brew install Caskroom/cask/xquartz
;;
coreutils)
brew tap homebrew/dupes
;;
esac
brew install $dep --with-default-names
event "install" "finished" "dependency" "$dep"
else
$DEBUG && print grey " Dependencia satisfecha: $dep"
fi
done
}
# Muestra una animación y el tiempo que lleva ejecutándose el último proceso
spinner(){
local pid=$1
local delay=0.1
local start_time=$(date +%s)
local end_time=''
local seconds=''
local elapsed=''
while [ $(ps -eo pid | grep $pid) ]; do
end_time=$(date +%s)
seconds=$(($end_time - $start_time))
elapsed=$(date -u -d @${seconds} +"%T")
for i in \| / - \\; do
printf ' procesando %s [%c]\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b' $elapsed $i
sleep $delay
done
done
printf '\b\b\b\b \n'
}
# Comprueba si hay aactualizaciones, las descarga y actualiza
check_upgrade(){
event "function" "run" "check_upgrade"
log dark_gray "Comprobando actualizaciones"
local gist=$(curl -s $GIST_URL)
local latest=$(echo $gist | jq -r '.files.version.content')
local script_url=$(echo $gist | jq -r '.files.dmp_upload.raw_url')
local log_url=$(echo $gist | jq -r '.files.log_template.raw_url')
local difference_url=$(echo $gist | jq -r '.files.difference.raw_url')
if [[ $latest -gt $APP_VERSION ]]; then
event "update" "start" "script" "$latest"
log green "Actualizando de la version $APP_VERSION a la $latest"
curl -s -o dmp_upload $script_url
mv $LOG_FILE back_$LOG_FILE
curl -s -o $LOG_FILE $log_url
event "update" "finished" "script" "$latest"
log green "Ejecutando la nueva version"
chmod +x dmp_upload
./dmp_upload $ARGS
exit 0
fi
}
# Procesa el mensaje a loguear
log(){
local code=$1
local message=$2
case $code in
error)
event "function" "error" "log" "$message"
print red "$message";;
error)
event "function" "warning" "log" "$message"
print orange "$message";;
open)
event "function" "open" "log"
open_log;;
*)
append_log $code "$message"
$VERBOSE && print $code "$message"
;;
esac
}
# Crea los tags necesarios para el log
open_log(){
event "function" "run" "open_log"
# agrega el indice
local title="$(date +"%y-%m-%d %H:%M")"
local id=entry-$SECONDS
local entry="<li><a href=\"#$id\">$title</a></li>"
local entry_tag="ul"
local pre="<pre id=\"$id\"><span>$title</span></pre>"
local pre_tag="body div div"
append_html "$entry" "$entry_tag"
append_html "$pre" "$pre_tag"
}
# Agrega un log
append_log(){
local color=$1
local message=$2
local text="<span style=\"color:$color\">$message</span>"
local selector="div div pre"
append_html "$text" "$selector"
}
# Agrega texto al html justo al final de cierta etiqueta
append_html(){
local content=$1
local tags=$2
local closer=""
for tag in $tags;do
closer="</$tag>\s*$closer"
done
content="${content//$'\n'/\\n}" #sustituye nuevas lineas por el caracter
sed -r -i -e "s|(\s*)($closer)|\n\1$content\1\2|g" $LOG_FILE
}
# Imprime por terminal el mensaje desseado a color
print(){
# extrae los parametros
local color=$1
local message="$2"
# tabla de colores
local blue="\033[0;34m"
local red="\033[0;31m"
local error="\033[0;31m"
local light_red="\033[1;31m"
local white="\033[1;37m"
local black="\033[0;30m"
local dark_gray="\033[1;30m"
local green="\033[0;32m"
local light_green="\033[1;32m"
local orange="\033[0;33m"
local warning="\033[0;33m"
local yellow="\033[1;33m"
local light_blue="\033[1;34m"
local purple="\033[0;35m"
local light_purple="\033[1;35m"
local cyan="\033[0;36m"
local light_cyan="\033[1;36m"
local grey="\033[0;37m"
local COLOR=${!color}
echo -e "\033[${COLOR}${message}\033[0m"
}
# Pregunta si los datos son correctos para continuar el programa
ask(){
event "function" "run" "ask" "$message"
while true; do
echo "Son correctos estos datos? (s|n):"
read yn
case $yn in
[Ss]* ) break;;
[Nn]* ) exit 0;;
* ) echo "Contesta con 's' o 'n'.";;
esac
done
}
# Imprime la ayuda del programa
help(){
event "function" "run" "help"
echo "./prepare-dmp.sh [argumentos]"
echo " -a, --datasource: id del datasource a usar en el archivo de salida"
echo " -b, --base: ruta al archivo base"
echo " -c, --compress: comprime el archivo de salida"
echo " -d, --delta: ruta al archivo incremental"
echo " -e, --encrypt: encripta los id\'s"
echo " -h, --help: imprime esta ayuda"
echo " -k, --keep: mantiene los archivos temporales"
echo " -l, --lower: pasa el archivo de salida a minuscula"
echo " -o, --output: (opcional) nombre del archivo de salida"
echo " -t, --trait traits que actualizar (agregar en altas, elimiar en bajas)"
echo " -u, --upload: sube los archivos al ftp"
echo " -v, --verbose: activa el modo verbose"
echo " -w, --row: fila en que se encuentra el msisdn"
echo " -x, --execute: cadena a enviar para hacer match"
echo " -m, --md5: calcula el hash md5 de los IDs"
echo " -u, --debug: modo debug"
echo ""
echo " Ejemplo de uso:"
echo " $./prepare-upload.sh \\"
echo " --verbose \\"
echo " --encrypt \\"
echo " --compress \\"
echo " --lower \\"
echo " --base test-base.csv \\"
echo " --delta test-deelta.dat \\"
echo " --trait 1234 --trait 4321 \\"
echo " --execute '\"my_trait\"=\"yes\"'"
}
# Almacena y obtiene un id a modo de cookie
get_uuid() {
local client_id_file=${1:-$HOME/.uuid}
local client_id=""
if [[ -f $client_id_file ]]; then
client_id=$(cat $client_id_file)
else
client_id=$(od -x /dev/urandom | head -1 | awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}')
echo "$client_id" > $client_id_file
fi
echo $client_id
}
# Envia analitica a google
analytics() {
DOMAIN="www.google-analytics.com"
$DEBUG && ANALYTICS_PATH="debug/collect" || ANALYTICS_PATH="collect"
PAYLOAD="v=1&cid=$(get_uuid)"
while [[ $# > 0 ]] ; do
case "$1" in
-t|--t|--type)
shift
PAYLOAD+="&t=$1"
;;
--tid|--tracking-id)
shift
PAYLOAD+="&tid=$1"
;;
--dh|--document-hostname)
shift
PAYLOAD+="&dh=$1"
;;
--dp|--document-path)
shift
PAYLOAD+="&dp=$1"
;;
--dt|--document-title)
shift
PAYLOAD+="&dt=$1"
;;
--ec|--event-category)
shift
PAYLOAD+="&ec=$1"
;;
--ea|--event-action)
shift
PAYLOAD+="&ea=$1"
;;
--el|--event-label)
shift
PAYLOAD+="&el=$1"
;;
--ev|--event-value)
shift
PAYLOAD+="&ev=$1"
;;
--av|--app-version)
shift
PAYLOAD+="&av=$1"
;;
--aid|--app-id)
shift
PAYLOAD+="&aid=$1"
;;
--an|--app-name)
shift
PAYLOAD+="&an=$1"
;;
esac
shift
done
URL="https://$DOMAIN/$ANALYTICS_PATH?$PAYLOAD"
if $DEBUG; then
curl -X POST --data "$PAYLOAD" $URL
else
curl -s -X POST --data "$PAYLOAD" $URL > /dev/null&
fi
}
# Abstrae la llamada a la vista de pagina
pageview(){
local step=$1
APP_PATH+="/$step"
analytics \
--type pageview \
--tracking-id $TRACKING_ID \
--document-hostname "dmp-upload" \
--document-path "$APP_PATH" \
--document-title "$step" \
--app-version $APP_VERSION \
--app-name $APP_NAME \
--app-id $APP_ID
}
# Abstre la llamada a un evento
event(){
local command="--t event --tid $TRACKING_ID --an $APP_NAME --av $APP_VERSION --aid $APP_ID"
[[ -n $1 ]] && command+=" --ec $1"
[[ -n $2 ]] && command+=" --ea $2"
[[ -n $3 ]] && command+=" --el $3"
[[ -n $4 ]] && command+=" --ev $4"
analytics $command
}
#===================================================================#
# #
# Bloque de inicialización y configuracion #
# #
#===================================================================#
trap cleanup SIGHUP SIGINT SIGTERM
check_dependencies
log open
pageview "start"
check_upgrade
VERBOSE=false
#===================================================================#
# #
# Parse a los parametros de entrada para construir la config #
# #
#===================================================================#
# parsea los parametros que se pasan al script
while [[ $# > 0 ]] ; do
case "$1" in
# imprime la ayuda
-h|--help)
help
;;
# flag que activa el modo verbose
-v|--verbose)
VERBOSE=true
log dark_gray "Modo verbose"
;;
# flag para encriptar los ids
-e|--encrypt)
COMMAND+=" --encrypt"
log dark_gray "Encriptar los IDs"
;;
# flag para calcular el hash de los ids
-m|--md5)
COMMAND+=" --md5"
log dark_gray "Hashear los IDs"
;;
# nombre del datasource al que pertenecen los traits
-a|--datasource)
shift
OUTPUT=ftp_dpm_$1_$SECONDS.sync
log dark_gray "Archivo de salida $OUTPUT"
;;
# flag para comprimir el archivo al terminar de procesarlo
-c|--compress)
COMPRESS=true
log dark_gray "Comprime el archivo de salida"
;;
# flag hace que se pasen a minuscula los resultados de encriptar
-l|--lower)
COMMAND+=" --lowercase"
LOWER=true
log dark_gray "Convertir a minusculas"
;;
# aunque parezca confuso este comando toma como id la COLUMNA dada
-w|--row)
shift
log dark_gray "Columna $1"
COMMAND+=" --row $1"
;;
# nombre del archivo base
-b|--base)
shift
BASE=$1
log dark_gray "Archivo base: $BASE"
;;
# nombre del archivo incremental
-d|--delta)
shift
DELTA=$1
log dark_gray "Archivo incremental: $DELTA"
;;
# configuracion especial para el programa msisdn
-x|--execute)
shift
EXECUTE+=" $1"
log dark_gray "Ejecuta la variable $1"
;;
# trait que agregar a las altas
-t|--trait)
shift
TRAITS+=" d_sid=$1"
REMOVE_TRAITS+=" d_unsid=$1"
log dark_gray "Actualizar trait: $1"
;;
# archivo de salida
-o|--output)
shift
OUTPUT=$1
log dark_gray "Archivo de salida: $1"
;;
# flag que desactiva la limpieza
-k|--keep)
CLEAN=false
log dark_gray "Muestra informacion del proceso"
;;
# flag para subir automaticamente el archivo al terminar de procesarlo
-u|--upload)
UPLOAD=true
VERBOSE=true
COMPRESS=true # si se va a subir es necesario comprimirlo
log dark_gray "Sube los archivos al ftp"
;;
-u|--debug)
DEBUG=true
log dark_gray "Modo debug activado"
;;
esac
shift
done
#===================================================================#
# #
# Realiza las comprobaciones basadas en los parametros antes de #
# iniciar la ejecucion del programa y avisa de posibles errores #
# #
#===================================================================#
# si no se ha podido determinar el nombre de archivo de salida por el datasource o explicito
if [ -z $OUTPUT ]; then
log error "Debe especificar un archivo de salida por medio de el id del datasource o explicito"
BAD_PARAMS=true
fi
# comprueba que hay un archivo sobre el que operar y que existe
if [ -z $BASE ]; then
log error "No hay archivo sobre el que operar: $BASE"
BAD_PARAMS=true
elif [ ! -f $BASE ]; then
log error "La ruta especificada no es un archivo: $BASE"
BAD_PARAMS=true
fi
# comprueba que, si hay un archivo delta, existe
if [[ -n $DELTA && ! -f $DELTA ]]; then
log error "No existe el archivo especificado: $DELTA"
BAD_PARAMS=true
fi
# comprueba que se han pasado parametros al programa
if [ $PARAMS -eq 0 ]; then
log warning "No se han introucido ningun parametro: $@"
BAD_PARAMS=true
fi
# comprueba que se han configurado bien los parametros ftp si se selecona subida
if [[ $UPLOAD && ( -z $FTP_HOME || -z $FTP_USER || -z $FTP_PASS ) ]]; then
log error "Se ha seleccionado subida al FTP pero no está configurada"
BAD_PARAMS=true
fi
# imprime la ayuda y termina el programa si ocurrió algún error grave
if $BAD_PARAMS; then
help
exit 1
fi
#===================================================================#
# #
# Ejecuta el programa perse: #
# Si solo hay archivo base opera con el #
# Si hay archivo delta calcula las altas y bajas #
# Procesa altas y bajas #
# Pasa a minuscula o no #
# Comprime el archivo y limpia #
# Sube el archivo al DMP #
# #
#===================================================================#
# Si no hay archivo delta trata el archivo base solamente
if [ -z $DELTA ]; then
pageview "prepare-single-file"
log grey "---------------------------"
log white " Encripta el archivo de entrada con los traits"
(java -jar msisdn.jar \
$COMMAND \
--input $BASE \
--output $OUTPUT \
$REMOVE_TRAITS \
$TRAITS \
$EXECUTE) &
spinner $!
log white " Ejemplo de linea encriptada:"
log green "$(head -n 4 $OUTPUT)"
$UPLOAD && ask
else
pageview "prepare-multi-file"
log grey "---------------------------"
#1 Extrae las bajas
log white " Extrae altas y bajas"
(./difference $BASE $DELTA altas.csv bajas.csv) &
spinner $!
TEMP_FILES+=" bajas.csv altas.csv"
log cyan " Altas: $(cat altas.csv | wc -l), Bajas: $(cat bajas.csv | wc -l)"
#2 Encripta las bajas con los id de trait que eliminar
pageview "extract-unscribers"
log grey "---------------------------"
log white " Procesa las bajas con los traits a desabilitar"
(java -jar msisdn.jar $COMMAND -o bajas-encrypted.csv -i bajas.csv $REMOVE_TRAITS) &
spinner $!
pageview "process-unscribers"
log white " Ejemplo de bajas encriptadas:"
log green "$(head -n 4 bajas-encrypted.csv)"
mv bajas-encrypted.csv bajas.csv
$UPLOAD && ask
#4 Encripta las altas
pageview "process-subscribers"
log grey "---------------------------"
log white " Procesa las altas"
(java -jar msisdn.jar $COMMAND -i altas.csv -o altas-encrypted.csv $TRAITS $EXECUTE $EXECUTE) &
spinner $!
log white " Ejemplo de altas encriptadas:"
log green "$(head -n 4 altas-encrypted.csv)"
$UPLOAD && ask
mv altas-encrypted.csv altas.csv
log grey "---------------------------"
#6 Concatena los archivos de altas y bajas listos
pageview "join-files"
log white " Concatena las altas y bajas"
cat bajas.csv altas.csv > $OUTPUT
log cyan " Archivo de salida: $OUTPUT"
log cyan " Total: $(cat $OUTPUT | wc -l)"
fi
if $LOWER; then
pageview "lowercase"
log grey "---------------------------"
log white " Pasa a minuscula"
tr A-Z a-z < $OUTPUT > lower_$OUTPUT
mv lower_$OUTPUT $OUTPUT
fi
if $COMPRESS; then
pageview "compress"
zip -9 $OUTPUT.zip $OUTPUT
TEMP_FILES+=" $OUTPUT"
OUTPUT=$OUTPUT.zip
fi
# Limpia los archivos temporales si esta activado
if $CLEAN; then
pageview "clean"
log grey "---------------------------"
log white " Elimina archivos temporales"
echo $TEMP_FILES
cleanup
fi
if $UPLOAD; then
pageview "upload"
log grey "---------------------------"
log white " Subida de archivos"
log white " Comprueba que las muestras de archivo tienen sentido"
ask
echo "
verbose
open $FTP_HOME
user $FTP_USER $FTP_PASS
put $OUTPUT
bye" | ftp -n > ftp_$$.log
fi
<!DOCTYPE html>
<html>
<head>
<style>
* {
font-family: "Arial", Helvetica, sans-serif;
}
body {
margin:0;
}
pre {
padding:4em;
margin:1em;
padding:1em;
background:#444;
border-radius: 3px;
display: inline-block;
margin: 1rem;
position: relative;
transition: box-shadow 0.3s cubic-bezier(.25,.8,.25,1);
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
}
pre:hover {
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
}
pre, pre>span {
font-family: "Lucida Console", Monaco, monospace;
}
pre>span:first-of-type {
font-weight: bolder;
color: grey;
}
a {
color: #00ACD6;
}
footer {background: #00ACD6;color:white;}
ul {
list-style-type: none;
padding: 0;
}
li {
margin: 20px;
}
ul a {
text-decoration: none;
margin: 10px;
padding: 10px;
}
ul a:hover {
background-color: #444;
color: white;
}
#wrapper {
width: 100%;
background-color: #fff;
}
#top-nav {
position: fixed;
left: 0;
right: 0;
top: 0;
height: 5em;
width: 100%;
text-align: center;
background-color: black;
color:white;
}
#side-nav {
position: fixed;
width: 13em
height:100vh;
left: 0;
top: 5em;
overflow: auto;
background-color: white;
}
#content-wrapper {
overflow: auto;
position: fixed;
left: 13em;
right: 0;
top: 5em;
height:100vh;
background: #e2e1e0;
}
</style>
</head>
<body>
<div id="wrapper">
<div id="top-nav">
<h1>Logs del proceso de archivos de CRM</h1>
</div>
<div id="side-nav">
<ul>
<li><a href="#inicio">Inicio</a></li>
</ul>
</div>
<div id="content-wrapper">
<pre id="inicio"><span>Inicio de los logs</span></pre></div></div></body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment