phablet-tools-1.2+16.04.20160317/0000755000015600001650000000000012672632126016504 5ustar pbuserpbgroup00000000000000phablet-tools-1.2+16.04.20160317/citrain0000755000015600001650000001161612672627760020100 0ustar pbuserpbgroup00000000000000#!/bin/sh -e # This program is free software: you can redistribute it and/or modify it # under the terms of the the GNU General Public License version 3, as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranties of # MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR # PURPOSE. See the applicable version of the GNU General Public # License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Copyright (C) 2014 Canonical, Ltd. usage () { cat </tmp/askpass.sh" loudly chmod +x /tmp/askpass.sh loudly SUDO_ASKPASS=/tmp/askpass.sh sudo -A touch /userdata/.adb_onlock loudly SUDO_ASKPASS=/tmp/askpass.sh sudo -A mount -o remount,rw / # Stable images have stable-snapshot PPA but sometimes we need to pull deps from overlay: loudly SUDO_ASKPASS=/tmp/askpass.sh sudo -A add-apt-repository -y "$PPA/$DISTRO/stable-phone-overlay" loudly SUDO_ASKPASS=/tmp/askpass.sh sudo -A add-apt-repository -y "$PPA/$DISTRO/$SILO" loudly "test -e /usr/sbin/policy-rc.d && cp /usr/sbin/policy-rc.d /tmp/policy-rc.d" loudly "echo 'exit 101' | SUDO_ASKPASS=/tmp/askpass.sh sudo -A tee /usr/sbin/policy-rc.d" loudly SUDO_ASKPASS=/tmp/askpass.sh sudo -A chmod +x /usr/sbin/policy-rc.d loudly "echo -e 'Package: *\nPin: release o=*$SILO*\nPin-Priority: 1100\n\nPackage: *\nPin: release a=$SERIES*\nPin-Priority: 50' | SUDO_ASKPASS=/tmp/askpass.sh sudo -A tee /etc/apt/preferences.d/extra-ppas.pref" loudly SUDO_ASKPASS=/tmp/askpass.sh sudo -A apt-get update # We need to put lxc-android-config on hold here as it's the only # package which must be upgrade by hand through the recovery. See # https://wiki.ubuntu.com/Touch/Testing/lxc-android-config for details. loudly SUDO_ASKPASS=/tmp/askpass.sh sudo -A apt-mark hold lxc-android-config loudly SUDO_ASKPASS=/tmp/askpass.sh sudo -A apt-get dist-upgrade --yes --force-yes loudly SUDO_ASKPASS=/tmp/askpass.sh sudo -A apt-get autoremove --yes --force-yes loudly "test ! -e /tmp/policy-rc.d && SUDO_ASKPASS=/tmp/askpass.sh sudo -A rm /usr/sbin/policy-rc.d" loudly "test -e /tmp/policy-rc.d && SUDO_ASKPASS=/tmp/askpass.sh sudo -A mv /tmp/policy-rc.d /usr/sbin/policy-rc.d" loudly SUDO_ASKPASS=/tmp/askpass.sh sudo -A apt-mark unhold lxc-android-config loudly SUDO_ASKPASS=/tmp/askpass.sh sudo -A reboot ;; host-purge) set -x sudo ppa-purge "$PPA/$SILO" ;; device-purge) echo "Unfortunately purging from the device is unsupported because" echo "ppa-purge is not installed by default in the images." echo "However, the silo packages go away next time you flash the device." ;; *) usage "Unknown COMMAND." ;; esac phablet-tools-1.2+16.04.20160317/tests/0000755000015600001650000000000012672632126017646 5ustar pbuserpbgroup00000000000000phablet-tools-1.2+16.04.20160317/tests/test_cdimage.py0000644000015600001650000000424112672627760022661 0ustar pbuserpbgroup00000000000000# Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Unit tests for phabletutils.environment.""" from mock import patch from phabletutils import cdimage from testtools import TestCase from testtools.matchers import Equals @patch('subprocess.check_output') class TestCdimageLinks(TestCase): def setUp(self): super(TestCdimageLinks, self).setUp() self.cdimage_uri = 'http://cdimage.ubuntu.com/ubuntu-touch/daily-build' self.rsync_uri_part = 'rsync://cdimage.ubuntu.com/cdimage/' \ 'ubuntu-touch/daily-build' self.rsync_call = ['rsync', '-l'] def testCurrent(self, process_mock): """Given a cdimage uri return the linked build for current.""" # given target_build = '20130714' process_mock.return_value = target_build self.rsync_call.append('%s/current' % self.rsync_uri_part) # when build = cdimage.get_build(self.cdimage_uri) # then self.assertThat(build, Equals(target_build)) process_mock.assert_called_once_with(self.rsync_call) def testPending(self, process_mock): """Given a cdimage uri return the linked build for current.""" # given target_build = '20130714.1' process_mock.return_value = target_build self.rsync_call.append('%s/pending' % self.rsync_uri_part) # when build = cdimage.get_build(self.cdimage_uri, pending=True) # then self.assertThat(build, Equals(target_build)) process_mock.assert_called_once_with(self.rsync_call) phablet-tools-1.2+16.04.20160317/tests/__init__.py0000644000015600001650000000000012672627760021755 0ustar pbuserpbgroup00000000000000phablet-tools-1.2+16.04.20160317/tests/index.json0000644000015600001650000006122312672627760021664 0ustar pbuserpbgroup00000000000000{ "global": { "generated_at": "Wed Aug 07 11:30:01 UTC 2013" }, "images": [ { "description": "20130731.3", "files": [ { "checksum": "7c9ce28bb751e25e80e5cee540ef1bdc929e97801528a14f066516f3ae2343d1", "order": 0, "path": "/daily/ubuntu/ubuntu-20130731.3.full.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130731.3.full.tar.xz.asc", "size": 264081876 }, { "checksum": "22ee6ded6902004e341a83c284218510a2b3a92c537a86140aa0daa76b7852f4", "order": 1, "path": "/daily/mako/mako-20130731.3.full.tar.xz", "signature": "/daily/mako/mako-20130731.3.full.tar.xz.asc", "size": 37335764 }, { "checksum": "4181ff7e4f6f6262f5eb231e65735c277abf5a13993d68abb200ca9cd8136c4e", "order": 2, "path": "/daily/mako/version-20130733.tar.xz", "signature": "/daily/mako/version-20130733.tar.xz.asc", "size": 196 } ], "type": "full", "version": 20130733 }, { "base": 20130732, "description": "20130731.3", "files": [ { "checksum": "002c10476be7a4db9d2fda3b9583eb67c2873b82c5f95483f6df7b253d7a8171", "order": 0, "path": "/daily/ubuntu/ubuntu-20130731.3.delta-20130731.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130731.3.delta-20130731.tar.xz.asc", "size": 14993132 }, { "checksum": "e557a50f29ecfe6265c405cbc35621f18e2b01225f9d9bfea01e30ddca752f43", "order": 1, "path": "/daily/mako/mako-20130731.3.delta-20130730.tar.xz", "signature": "/daily/mako/mako-20130731.3.delta-20130730.tar.xz.asc", "size": 34903260 }, { "checksum": "4181ff7e4f6f6262f5eb231e65735c277abf5a13993d68abb200ca9cd8136c4e", "order": 2, "path": "/daily/mako/version-20130733.tar.xz", "signature": "/daily/mako/version-20130733.tar.xz.asc", "size": 196 } ], "type": "delta", "version": 20130733 }, { "description": "20130801", "files": [ { "checksum": "963c3bf9367450ab17c47f670f91db1d15f0ef6bdcf194481b5f458379129d7e", "order": 0, "path": "/daily/ubuntu/ubuntu-20130801.full.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130801.full.tar.xz.asc", "size": 264000016 }, { "checksum": "eb2160d8e37b9e5af34a8cb8b9e6cc63105f759a953d928c896741feef7eed01", "order": 1, "path": "/daily/mako/mako-20130801.full.tar.xz", "signature": "/daily/mako/mako-20130801.full.tar.xz.asc", "size": 37335924 }, { "checksum": "11da343b235e14a10a2537620e0dc397f4a23e8d5fc6f81e7fa86dcc9e80fa6a", "order": 2, "path": "/daily/mako/version-20130800.tar.xz", "signature": "/daily/mako/version-20130800.tar.xz.asc", "size": 192 } ], "type": "full", "version": 20130800 }, { "base": 20130733, "description": "20130801", "files": [ { "checksum": "f81a98769b92a9ba2c61b75ee83aa7fa7417767788f518553ae195e0a846768f", "order": 0, "path": "/daily/ubuntu/ubuntu-20130801.delta-20130731.3.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130801.delta-20130731.3.tar.xz.asc", "size": 18625000 }, { "checksum": "e907a5a4740881080bb997e494df69e4b317ae938a2a689d0aa5cf7a086ea6a4", "order": 1, "path": "/daily/mako/mako-20130801.delta-20130731.3.tar.xz", "signature": "/daily/mako/mako-20130801.delta-20130731.3.tar.xz.asc", "size": 34903248 }, { "checksum": "11da343b235e14a10a2537620e0dc397f4a23e8d5fc6f81e7fa86dcc9e80fa6a", "order": 2, "path": "/daily/mako/version-20130800.tar.xz", "signature": "/daily/mako/version-20130800.tar.xz.asc", "size": 192 } ], "type": "delta", "version": 20130800 }, { "description": "20130802.1", "files": [ { "checksum": "05969428a0502d021ee91945f28bfd9884f774f406fe7e0578b09e26f521b171", "order": 0, "path": "/daily/ubuntu/ubuntu-20130802.1.full.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130802.1.full.tar.xz.asc", "size": 264078540 }, { "checksum": "269a33c87c6a995f068293776aa10f4a74d0cbb8101a236e0fedb375aff1df63", "order": 1, "path": "/daily/mako/mako-20130802.1.full.tar.xz", "signature": "/daily/mako/mako-20130802.1.full.tar.xz.asc", "size": 37342212 }, { "checksum": "b2f4f1b04add4d47209598acb78137e3eb31ef1997aa92f67b17fcba8ea2911c", "order": 2, "path": "/daily/mako/version-20130801.tar.xz", "signature": "/daily/mako/version-20130801.tar.xz.asc", "size": 192 } ], "type": "full", "version": 20130801 }, { "base": 20130800, "description": "20130802.1", "files": [ { "checksum": "d3c80a6144159933d037a605052b1c56ad4edae05ba31c73841c4bc80df59f6e", "order": 0, "path": "/daily/ubuntu/ubuntu-20130802.1.delta-20130801.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130802.1.delta-20130801.tar.xz.asc", "size": 18381112 }, { "checksum": "0fe99c8d57cda68dc757bb10d039f26895c822d7e5d6efb96f9456efd65c384f", "order": 1, "path": "/daily/mako/mako-20130802.1.delta-20130801.tar.xz", "signature": "/daily/mako/mako-20130802.1.delta-20130801.tar.xz.asc", "size": 37098756 }, { "checksum": "b2f4f1b04add4d47209598acb78137e3eb31ef1997aa92f67b17fcba8ea2911c", "order": 2, "path": "/daily/mako/version-20130801.tar.xz", "signature": "/daily/mako/version-20130801.tar.xz.asc", "size": 192 } ], "type": "delta", "version": 20130801 }, { "description": "20130802.2", "files": [ { "checksum": "253139a135389d920ce446d258e4b0c779c51780c1ad747641a6cb11a3331634", "order": 0, "path": "/daily/ubuntu/ubuntu-20130802.2.full.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130802.2.full.tar.xz.asc", "size": 264050500 }, { "checksum": "490fc1586ea46d98719f2d53ae3044c31ef065d7d353071aed9ca4af43e37ceb", "order": 1, "path": "/daily/mako/mako-20130802.2.full.tar.xz", "signature": "/daily/mako/mako-20130802.2.full.tar.xz.asc", "size": 37335972 }, { "checksum": "64fbb613532c31d2ee0d6141a2cba656c3247f39a257b8eed67fa1d18f481983", "order": 2, "path": "/daily/mako/version-20130802.tar.xz", "signature": "/daily/mako/version-20130802.tar.xz.asc", "size": 192 } ], "type": "full", "version": 20130802 }, { "base": 20130801, "description": "20130802.2", "files": [ { "checksum": "193fde8008c63009397cb5d470c0d81c3547583ea5a28e1c1dc0c7be57ab59cc", "order": 0, "path": "/daily/ubuntu/ubuntu-20130802.2.delta-20130802.1.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130802.2.delta-20130802.1.tar.xz.asc", "size": 19171116 }, { "checksum": "8f3747431d40a45e52c780116f92939ac4cd071d63a80d0c9031b1da6b6241ac", "order": 1, "path": "/daily/mako/mako-20130802.2.delta-20130802.1.tar.xz", "signature": "/daily/mako/mako-20130802.2.delta-20130802.1.tar.xz.asc", "size": 34996120 }, { "checksum": "64fbb613532c31d2ee0d6141a2cba656c3247f39a257b8eed67fa1d18f481983", "order": 2, "path": "/daily/mako/version-20130802.tar.xz", "signature": "/daily/mako/version-20130802.tar.xz.asc", "size": 192 } ], "type": "delta", "version": 20130802 }, { "description": "20130803", "files": [ { "checksum": "c0bc116b31adcb88b4587f8db0af9dcc6c6a2be839ea6013c5bd970bf9625467", "order": 0, "path": "/daily/ubuntu/ubuntu-20130803.full.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130803.full.tar.xz.asc", "size": 264111912 }, { "checksum": "02730cefdb71d35ce971f9494b0fedb775e1fd08cb65a8826fd74b3ebdba55d0", "order": 1, "path": "/daily/mako/mako-20130803.full.tar.xz", "signature": "/daily/mako/mako-20130803.full.tar.xz.asc", "size": 37344168 }, { "checksum": "3b4f2fdce15f5f3ececdc73b2b58f512717da37abadd50d9ac08fff4dcafad00", "order": 2, "path": "/daily/mako/version-20130803.tar.xz", "signature": "/daily/mako/version-20130803.tar.xz.asc", "size": 196 } ], "type": "full", "version": 20130803 }, { "base": 20130802, "description": "20130803", "files": [ { "checksum": "fd11b3944464bde87f7d187979eef556ce33a3f5f6fff00808bffeaea906b0ee", "order": 0, "path": "/daily/ubuntu/ubuntu-20130803.delta-20130802.2.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130803.delta-20130802.2.tar.xz.asc", "size": 14519416 }, { "checksum": "60f988ece3a4a092e0f05aa326feb655d67b68e2a53736bd4aa6717a3e0d26db", "order": 1, "path": "/daily/mako/mako-20130803.delta-20130802.2.tar.xz", "signature": "/daily/mako/mako-20130803.delta-20130802.2.tar.xz.asc", "size": 34918944 }, { "checksum": "3b4f2fdce15f5f3ececdc73b2b58f512717da37abadd50d9ac08fff4dcafad00", "order": 2, "path": "/daily/mako/version-20130803.tar.xz", "signature": "/daily/mako/version-20130803.tar.xz.asc", "size": 196 } ], "type": "delta", "version": 20130803 }, { "description": "20130804", "files": [ { "checksum": "f3c1273666c71cb3fd74d9762783c016794cf36f5aab3fa01329460966293c6c", "order": 0, "path": "/daily/ubuntu/ubuntu-20130804.full.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130804.full.tar.xz.asc", "size": 264089004 }, { "checksum": "5f49821d302631c5de2f5df838b168b2c8290c0a9a4a510533464d92e4b9b638", "order": 1, "path": "/daily/mako/mako-20130804.full.tar.xz", "signature": "/daily/mako/mako-20130804.full.tar.xz.asc", "size": 37335780 }, { "checksum": "e2619bd73b47539e23ebfbc29620baf8a6d56c3cf850141e2f9b3c8973e00342", "order": 2, "path": "/daily/mako/version-20130804.tar.xz", "signature": "/daily/mako/version-20130804.tar.xz.asc", "size": 196 } ], "type": "full", "version": 20130804 }, { "base": 20130803, "description": "20130804", "files": [ { "checksum": "80c02eb1269adfd3b641593a2a6c93a4f4c570fbce1a90020073295276a1c0ba", "order": 0, "path": "/daily/ubuntu/ubuntu-20130804.delta-20130803.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130804.delta-20130803.tar.xz.asc", "size": 16620436 }, { "checksum": "99d0eb9f2315675a427c899ed308ab2ce11694675c979a305800f1949e008083", "order": 1, "path": "/daily/mako/mako-20130804.delta-20130803.tar.xz", "signature": "/daily/mako/mako-20130804.delta-20130803.tar.xz.asc", "size": 34913316 }, { "checksum": "e2619bd73b47539e23ebfbc29620baf8a6d56c3cf850141e2f9b3c8973e00342", "order": 2, "path": "/daily/mako/version-20130804.tar.xz", "signature": "/daily/mako/version-20130804.tar.xz.asc", "size": 196 } ], "type": "delta", "version": 20130804 }, { "description": "20130805", "files": [ { "checksum": "6862856f1e029fd86883e1b28cc4aa959190ff3fdcaeb3c4115184c2942d21ee", "order": 0, "path": "/daily/ubuntu/ubuntu-20130805.full.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130805.full.tar.xz.asc", "size": 264023912 }, { "checksum": "c9f9b8644d5573cd73727a9a506ca46663cf22b6bae82d0dad90f3e53f43079c", "order": 1, "path": "/daily/mako/mako-20130805.full.tar.xz", "signature": "/daily/mako/mako-20130805.full.tar.xz.asc", "size": 37343256 }, { "checksum": "915f703e637a509c9947890983427ec6d44fa53ee5a45e866acbd76c5c7d2fcb", "order": 2, "path": "/daily/mako/version-20130805.tar.xz", "signature": "/daily/mako/version-20130805.tar.xz.asc", "size": 196 } ], "type": "full", "version": 20130805 }, { "base": 20130804, "description": "20130805", "files": [ { "checksum": "8d65c5deb8723db8df7e918790f98bfe4304490d7bde96af85fba0989ff04fe8", "order": 0, "path": "/daily/ubuntu/ubuntu-20130805.delta-20130804.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130805.delta-20130804.tar.xz.asc", "size": 15166336 }, { "checksum": "401400168374635c26c320218518565d567bd3c38d0a4ffc2ff750207702d070", "order": 1, "path": "/daily/mako/mako-20130805.delta-20130804.tar.xz", "signature": "/daily/mako/mako-20130805.delta-20130804.tar.xz.asc", "size": 34921568 }, { "checksum": "915f703e637a509c9947890983427ec6d44fa53ee5a45e866acbd76c5c7d2fcb", "order": 2, "path": "/daily/mako/version-20130805.tar.xz", "signature": "/daily/mako/version-20130805.tar.xz.asc", "size": 196 } ], "type": "delta", "version": 20130805 }, { "description": "20130806", "files": [ { "checksum": "cd06ae29bc3d57def4d216be24d857a0c01367f65626651459a9478c42a8d80c", "order": 0, "path": "/daily/ubuntu/ubuntu-20130806.full.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130806.full.tar.xz.asc", "size": 264142320 }, { "checksum": "db5a43ee320eac7474a98beb0bbcc43648ff17f90adf581d19200bfb5bda0dce", "order": 1, "path": "/daily/mako/mako-20130806.full.tar.xz", "signature": "/daily/mako/mako-20130806.full.tar.xz.asc", "size": 42475196 }, { "checksum": "3a17c0ae8f9a42c26aee06313ebc619f0b2a24385f7cbf3df519698ab9078acf", "order": 2, "path": "/daily/mako/version-20130806.tar.xz", "signature": "/daily/mako/version-20130806.tar.xz.asc", "size": 196 } ], "type": "full", "version": 20130806 }, { "base": 20130805, "description": "20130806", "files": [ { "checksum": "0acc8ef06a657d74117a759b7e0fff0ba7a69e332aec15f8dbc7d1716d04fbbb", "order": 0, "path": "/daily/ubuntu/ubuntu-20130806.delta-20130805.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130806.delta-20130805.tar.xz.asc", "size": 17806408 }, { "checksum": "59d1604655efc0cfc582b97bae1111344f273b49c3df259647fe6fb063448ebb", "order": 1, "path": "/daily/mako/mako-20130806.delta-20130805.tar.xz", "signature": "/daily/mako/mako-20130806.delta-20130805.tar.xz.asc", "size": 42221272 }, { "checksum": "3a17c0ae8f9a42c26aee06313ebc619f0b2a24385f7cbf3df519698ab9078acf", "order": 2, "path": "/daily/mako/version-20130806.tar.xz", "signature": "/daily/mako/version-20130806.tar.xz.asc", "size": 196 } ], "type": "delta", "version": 20130806 }, { "description": "20130806.1", "files": [ { "checksum": "b42156ae0b171c3425cb832d46cc4a86302a943beea18a29132ba3f84d978a02", "order": 0, "path": "/daily/ubuntu/ubuntu-20130806.1.full.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130806.1.full.tar.xz.asc", "size": 264114544 }, { "checksum": "6b5f8a78e94554ad59a3bb7f81550cce446d17d25d455759a77c6435d70de715", "order": 1, "path": "/daily/mako/mako-20130806.1.full.tar.xz", "signature": "/daily/mako/mako-20130806.1.full.tar.xz.asc", "size": 36869564 }, { "checksum": "aa1fbad7150d4c0a2cc23e78672678aaeeaa26ac4e57a65fb635bf62c898955c", "order": 2, "path": "/daily/mako/version-20130807.tar.xz", "signature": "/daily/mako/version-20130807.tar.xz.asc", "size": 188 } ], "type": "full", "version": 20130807 }, { "base": 20130806, "description": "20130806.1", "files": [ { "checksum": "3d6283525d795a34f98e2b996ae5bf7ce70892ca79026c776fca973b1080b30e", "order": 0, "path": "/daily/ubuntu/ubuntu-20130806.1.delta-20130806.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130806.1.delta-20130806.tar.xz.asc", "size": 14764572 }, { "checksum": "3e02f4a2ae19f47ba1bd10c2f236b46b368d012ede8003cb11fa3afbe0d7683f", "order": 1, "path": "/daily/mako/mako-20130806.1.delta-20130806.tar.xz", "signature": "/daily/mako/mako-20130806.1.delta-20130806.tar.xz.asc", "size": 34428224 }, { "checksum": "aa1fbad7150d4c0a2cc23e78672678aaeeaa26ac4e57a65fb635bf62c898955c", "order": 2, "path": "/daily/mako/version-20130807.tar.xz", "signature": "/daily/mako/version-20130807.tar.xz.asc", "size": 188 } ], "type": "delta", "version": 20130807 }, { "description": "20130807", "files": [ { "checksum": "5a615f41c92c562496e650c2ee5831a66da02c5435c5270d6b594aec6e30511d", "order": 0, "path": "/daily/ubuntu/ubuntu-20130807.full.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130807.full.tar.xz.asc", "size": 264539288 }, { "checksum": "1a39b78b220660fe0c7fd8c30febe92009ad5306610e41f7cdf838da8290c59a", "order": 1, "path": "/daily/mako/mako-20130807.full.tar.xz", "signature": "/daily/mako/mako-20130807.full.tar.xz.asc", "size": 36875496 }, { "checksum": "287eb50401487dc217f6a614fa03ae1bfb7fbead48f196692cf090667c98353f", "order": 2, "path": "/daily/mako/version-20130808.tar.xz", "signature": "/daily/mako/version-20130808.tar.xz.asc", "size": 192 } ], "type": "full", "version": 20130808 }, { "base": 20130807, "description": "20130807", "files": [ { "checksum": "1e48af06cb25e899a536301c36f212f06c0479be69785d1569d2795099485ab5", "order": 0, "path": "/daily/ubuntu/ubuntu-20130807.delta-20130806.1.tar.xz", "signature": "/daily/ubuntu/ubuntu-20130807.delta-20130806.1.tar.xz.asc", "size": 17889552 }, { "checksum": "10000fae3aa0a567bb10cc5efc6552bb01ee6ec96a689f0adf886ad3e202b0c7", "order": 1, "path": "/daily/mako/mako-20130807.delta-20130806.1.tar.xz", "signature": "/daily/mako/mako-20130807.delta-20130806.1.tar.xz.asc", "size": 34435132 }, { "checksum": "287eb50401487dc217f6a614fa03ae1bfb7fbead48f196692cf090667c98353f", "order": 2, "path": "/daily/mako/version-20130808.tar.xz", "signature": "/daily/mako/version-20130808.tar.xz.asc", "size": 192 } ], "type": "delta", "version": 20130808 } ] } phablet-tools-1.2+16.04.20160317/tests/test_community.py0000644000015600001650000001263312672627760023320 0ustar pbuserpbgroup00000000000000# Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Unit tests for phabletutils.environment.""" import json import shutil import tempfile from os import path from phabletutils import community from testtools import TestCase from testtools.matchers import Equals from testtools.matchers import Is class TestCommunityManifestLoad(TestCase): def setUp(self): super(TestCommunityManifestLoad, self).setUp() self.device_dir = tempfile.mkdtemp() def tearDown(self): super(TestCommunityManifestLoad, self).tearDown() shutil.rmtree(self.device_dir) def testSimpleDeviceManifest(self): # given manifest = {'device': 'http://somelocation.com/device.zip'} with open(path.join(self.device_dir, 'manifest.json'), 'w') as f: f.write(json.dumps(manifest)) # when loaded_manifest = community.load_manifest(self.device_dir) # then self.assertThat(loaded_manifest['device'], Equals(manifest['device'])) self.assertThat(loaded_manifest['ubuntu'], Is(None)) self.assertThat(loaded_manifest['revision'], Is(None)) self.assertThat(loaded_manifest['storage'], Equals('/sdcard/')) def testSimpleDeviceAndUbuntuManifest(self): # given manifest = {'device': 'http://somelocation.com/device.zip', 'ubuntu': 'http://somelocation.com/ubuntu.zip'} with open(path.join(self.device_dir, 'manifest.json'), 'w') as f: f.write(json.dumps(manifest)) # when loaded_manifest = community.load_manifest(self.device_dir) # then self.assertThat(loaded_manifest['device'], Equals(manifest['device'])) self.assertThat(loaded_manifest['ubuntu'], Equals(manifest['ubuntu'])) self.assertThat(loaded_manifest['revision'], Is(None)) self.assertThat(loaded_manifest['storage'], Equals('/sdcard/')) def testSimpleDeviceAndUbuntuRevisionManifest(self): # given manifest = {'device': 'http://somelocation.com/device.zip', 'ubuntu': 'http://somelocation.com/ubuntu.zip', 'revision': 'unstable'} with open(path.join(self.device_dir, 'manifest.json'), 'w') as f: f.write(json.dumps(manifest)) # when loaded_manifest = community.load_manifest(self.device_dir) # then self.assertThat(loaded_manifest['device'], Equals(manifest['device'])) self.assertThat(loaded_manifest['ubuntu'], Equals(manifest['ubuntu'])) self.assertThat(loaded_manifest['revision'], Equals(manifest['revision'])) self.assertThat(loaded_manifest['storage'], Equals('/sdcard/')) def testSimpleDeviceAndUbuntuRevisionStorageManifest(self): # given manifest = {'device': 'http://somelocation.com/device.zip', 'ubuntu': 'http://somelocation.com/ubuntu.zip', 'storage': '/emmc/', 'revision': 'unstable'} with open(path.join(self.device_dir, 'manifest.json'), 'w') as f: f.write(json.dumps(manifest)) # when loaded_manifest = community.load_manifest(self.device_dir) # then self.assertThat(loaded_manifest['device'], Equals(manifest['device'])) self.assertThat(loaded_manifest['ubuntu'], Equals(manifest['ubuntu'])) self.assertThat(loaded_manifest['revision'], Equals(manifest['revision'])) self.assertThat(loaded_manifest['storage'], Equals(manifest['storage'])) class TestCommunityFiles(TestCase): def setUp(self): super(TestCommunityFiles, self).setUp() self.download_dir = '/downloads' self.series = 'saucy' def tearDown(self): super(TestCommunityFiles, self).tearDown() def testSimpleDeviceAndUbuntu(self): # given manifest = {'device': 'http://somelocation.com/device.zip', 'ubuntu': 'http://somelocation.com/ubuntu.zip'} # when files = community.get_files(manifest, self.download_dir, self.series) # then self.assertThat(files['device'].uri, Equals(manifest['device'])) self.assertThat(files['device'].hash, Is(None)) self.assertThat(files['device'].verified, Is(False)) self.assertThat(files['device'].path, Equals(path.join(self.download_dir, path.basename(manifest['device'])))) self.assertThat(files['ubuntu'].uri, Equals(manifest['ubuntu'])) self.assertThat(files['ubuntu'].hash, Is(None)) self.assertThat(files['ubuntu'].verified, Is(False)) self.assertThat(files['ubuntu'].path, Equals(path.join(self.download_dir, path.basename(manifest['ubuntu'])))) phablet-tools-1.2+16.04.20160317/tests/test_static_checkers.py0000644000015600001650000000465012672627760024432 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Loïc Minier # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Static checkers against source files.""" import subprocess import testtools from setup import PYTHON_SCRIPTS, SH_SCRIPTS # external script which is only pyflakes-clean, not pep8-clean PEP8_EXCLUDES = ["repo", ] def has_command(command): """Returns whether a command is in the PATH or not.""" returncode = subprocess.call(['which', command], stdout=open('/dev/null', 'w')) return returncode == 0 def get_output(command): proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) return proc.communicate() class TestStaticCheckers(testtools.TestCase): @testtools.skipUnless(has_command("checkbashisms"), "checkbashisms not found") def test_bashisms(self): (stdout, stderr) = get_output(['checkbashisms', ] + SH_SCRIPTS) self.assertEquals('', stdout) self.assertEquals('', stderr) @testtools.skipUnless(has_command("pep8"), "pep8 not found") def test_pep8(self): scripts = [p for p in PYTHON_SCRIPTS if p not in PEP8_EXCLUDES] (stdout, stderr) = get_output(['pep8', '.'] + scripts) self.assertEquals('', stdout) self.assertEquals('', stderr) @testtools.skipUnless(has_command("pyflakes"), "pyflakes not found") def test_pyflakes(self): (stdout, stderr) = get_output(['pyflakes', '.'] + PYTHON_SCRIPTS) self.assertEquals('', stdout) self.assertEquals('', stderr) def test_sh_syntax(self): (stdout, stderr) = get_output(['sh', '-n'] + SH_SCRIPTS) self.assertEquals('', stdout) self.assertEquals('', stderr) phablet-tools-1.2+16.04.20160317/tests/test_ubuntuimage.py0000644000015600001650000000475012672627760023622 0ustar pbuserpbgroup00000000000000# Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Unit tests for phabletutils.environment.""" from mock import patch from phabletutils import ubuntuimage from testtools import TestCase from testtools.matchers import Equals from testtools.matchers import HasLength @patch('phabletutils.downloads.get_content') class TestUbuntuImage(TestCase): def setUp(self): super(TestUbuntuImage, self).setUp() self.device = 'mako' self.channel = 'daily' with open('tests/index.json', 'r') as f: self.json_content = f.read() def testGetLatestIndex(self, get_content_mock): # given get_content_mock.return_value = self.json_content # when json_dict = ubuntuimage.get_json_from_index(self.device, self.channel, 0, 'http://server.com') # then self.assertThat(json_dict['version'], Equals(20130808)) self.assertThat(json_dict['description'], Equals('20130807')) self.assertThat(json_dict['type'], Equals('full')) self.assertThat(json_dict['files'], HasLength(3)) def testGetPreviousIndex(self, get_content_mock): # given get_content_mock.return_value = self.json_content # when json_dict = ubuntuimage.get_json_from_index(self.device, self.channel, -1, 'http://server.com') # then self.assertThat(json_dict['version'], Equals(20130807)) self.assertThat(json_dict['description'], Equals('20130806.1')) self.assertThat(json_dict['type'], Equals('full')) self.assertThat(json_dict['files'], HasLength(3)) phablet-tools-1.2+16.04.20160317/shell-adb-common.sh0000755000015600001650000000174412672627760022202 0ustar pbuserpbgroup00000000000000#!/bin/sh # This program is free software: you can redistribute it and/or modify it # under the terms of the the GNU General Public License version 3, as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranties of # MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR # PURPOSE. See the applicable version of the GNU General Public # License for more details. #. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Copyright (C) 2014 Canonical, Ltd. check_devices() { # Quick way to make sure that we fail gracefully if more than one device # is connected and no serial is passed set +e adb wait-for-device err=$? set -e if [ $err != 0 ]; then echo "E: more than one device or emulator" adb devices exit 1 fi } phablet-tools-1.2+16.04.20160317/phablet-flash0000755000015600001650000000425512672627760021162 0ustar pbuserpbgroup00000000000000#! /usr/bin/python2.7 # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import logging import os import sys import time from phabletutils.device import (AndroidBridge, Fastboot) from phabletutils import arguments from phabletutils import license from phabletutils import settings logging.basicConfig(level=logging.INFO) log = logging.getLogger() log.name = 'phablet-flash' def accepted_pathname(): return os.path.expanduser(settings.accept_path) def main(argv): parser = arguments.get_parser() args = parser.parse_args(argv[1:]) if args.debug: log.setLevel(logging.DEBUG) if not license.has_accepted(accepted_pathname()) and \ not license.query(settings.legal_notice, accepted_pathname()): exit(1) print('\nphablet-flash is deprecated; use ubuntu-device-flash instead\n' 'provided by the ubuntu-device-flash package or\n' 'go get launchpad.net/goget-ubuntu-touch/ubuntu-device-flash\n') time.sleep(2) try: project = args.func(args) if project: fastboot = Fastboot(args.serial) adb = AndroidBridge(args.serial) adb.start() project.download() if not args.download_only: project.install(adb, fastboot) except KeyboardInterrupt: log.info('Provisioning manually interrupted. Resume by rerunning ' 'the command') exit(1) except Exception as e: log.error(e) if args.debug: log.exception(e) exit(1) if __name__ == "__main__": main(sys.argv) phablet-tools-1.2+16.04.20160317/repo0000755000015600001650000005702112672627760017414 0ustar pbuserpbgroup00000000000000#!/usr/bin/env python ## repo default configuration ## REPO_URL = 'https://gerrit.googlesource.com/git-repo' REPO_REV = 'stable' # Copyright (C) 2008 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # increment this whenever we make important changes to this script VERSION = (1, 21) # increment this if the MAINTAINER_KEYS block is modified KEYRING_VERSION = (1, 2) MAINTAINER_KEYS = """ Repo Maintainer -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.2.2 (GNU/Linux) mQGiBEj3ugERBACrLJh/ZPyVSKeClMuznFIrsQ+hpNnmJGw1a9GXKYKk8qHPhAZf WKtrBqAVMNRLhL85oSlekRz98u41H5si5zcuv+IXJDF5MJYcB8f22wAy15lUqPWi VCkk1l8qqLiuW0fo+ZkPY5qOgrvc0HW1SmdH649uNwqCbcKb6CxaTxzhOwCgj3AP xI1WfzLqdJjsm1Nq98L0cLcD/iNsILCuw44PRds3J75YP0pze7YF/6WFMB6QSFGu aUX1FsTTztKNXGms8i5b2l1B8JaLRWq/jOnZzyl1zrUJhkc0JgyZW5oNLGyWGhKD Fxp5YpHuIuMImopWEMFIRQNrvlg+YVK8t3FpdI1RY0LYqha8pPzANhEYgSfoVzOb fbfbA/4ioOrxy8ifSoga7ITyZMA+XbW8bx33WXutO9N7SPKS/AK2JpasSEVLZcON ae5hvAEGVXKxVPDjJBmIc2cOe7kOKSi3OxLzBqrjS2rnjiP4o0ekhZIe4+ocwVOg e0PLlH5avCqihGRhpoqDRsmpzSHzJIxtoeb+GgGEX8KkUsVAhbQpUmVwbyBNYWlu dGFpbmVyIDxyZXBvQGFuZHJvaWQua2VybmVsLm9yZz6IYAQTEQIAIAUCSPe6AQIb AwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEBZTDV6SD1xl1GEAn0x/OKQpy7qI 6G73NJviU0IUMtftAKCFMUhGb/0bZvQ8Rm3QCUpWHyEIu7kEDQRI97ogEBAA2wI6 5fs9y/rMwD6dkD/vK9v4C9mOn1IL5JCPYMJBVSci+9ED4ChzYvfq7wOcj9qIvaE0 GwCt2ar7Q56me5J+byhSb32Rqsw/r3Vo5cZMH80N4cjesGuSXOGyEWTe4HYoxnHv gF4EKI2LK7xfTUcxMtlyn52sUpkfKsCpUhFvdmbAiJE+jCkQZr1Z8u2KphV79Ou+ P1N5IXY/XWOlq48Qf4MWCYlJFrB07xjUjLKMPDNDnm58L5byDrP/eHysKexpbakL xCmYyfT6DV1SWLblpd2hie0sL3YejdtuBMYMS2rI7Yxb8kGuqkz+9l1qhwJtei94 5MaretDy/d/JH/pRYkRf7L+ke7dpzrP+aJmcz9P1e6gq4NJsWejaALVASBiioqNf QmtqSVzF1wkR5avZkFHuYvj6V/t1RrOZTXxkSk18KFMJRBZrdHFCWbc5qrVxUB6e N5pja0NFIUCigLBV1c6I2DwiuboMNh18VtJJh+nwWeez/RueN4ig59gRTtkcc0PR 35tX2DR8+xCCFVW/NcJ4PSePYzCuuLvp1vEDHnj41R52Fz51hgddT4rBsp0nL+5I socSOIIezw8T9vVzMY4ArCKFAVu2IVyBcahTfBS8q5EM63mONU6UVJEozfGljiMw xuQ7JwKcw0AUEKTKG7aBgBaTAgT8TOevpvlw91cAAwUP/jRkyVi/0WAb0qlEaq/S ouWxX1faR+vU3b+Y2/DGjtXQMzG0qpetaTHC/AxxHpgt/dCkWI6ljYDnxgPLwG0a Oasm94BjZc6vZwf1opFZUKsjOAAxRxNZyjUJKe4UZVuMTk6zo27Nt3LMnc0FO47v FcOjRyquvgNOS818irVHUf12waDx8gszKxQTTtFxU5/ePB2jZmhP6oXSe4K/LG5T +WBRPDrHiGPhCzJRzm9BP0lTnGCAj3o9W90STZa65RK7IaYpC8TB35JTBEbrrNCp w6lzd74LnNEp5eMlKDnXzUAgAH0yzCQeMl7t33QCdYx2hRs2wtTQSjGfAiNmj/WW Vl5Jn+2jCDnRLenKHwVRFsBX2e0BiRWt/i9Y8fjorLCXVj4z+7yW6DawdLkJorEo p3v5ILwfC7hVx4jHSnOgZ65L9s8EQdVr1ckN9243yta7rNgwfcqb60ILMFF1BRk/ 0V7wCL+68UwwiQDvyMOQuqkysKLSDCLb7BFcyA7j6KG+5hpsREstFX2wK1yKeraz 5xGrFy8tfAaeBMIQ17gvFSp/suc9DYO0ICK2BISzq+F+ZiAKsjMYOBNdH/h0zobQ HTHs37+/QLMomGEGKZMWi0dShU2J5mNRQu3Hhxl3hHDVbt5CeJBb26aQcQrFz69W zE3GNvmJosh6leayjtI9P2A6iEkEGBECAAkFAkj3uiACGwwACgkQFlMNXpIPXGWp TACbBS+Up3RpfYVfd63c1cDdlru13pQAn3NQy/SN858MkxN+zym86UBgOad2 =CMiZ -----END PGP PUBLIC KEY BLOCK----- Conley Owens -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.11 (GNU/Linux) mQENBFHRvc8BCADFg45Xx/y6QDC+T7Y/gGc7vx0ww7qfOwIKlAZ9xG3qKunMxo+S hPCnzEl3cq+6I1Ww/ndop/HB3N3toPXRCoN8Vs4/Hc7by+SnaLFnacrm+tV5/OgT V37Lzt8lhay1Kl+YfpFwHYYpIEBLFV9knyfRXS/428W2qhdzYfvB15/AasRmwmor py4NIzSs8UD/SPr1ihqNCdZM76+MQyN5HMYXW/ALZXUFG0pwluHFA7hrfPG74i8C zMiP7qvMWIl/r/jtzHioH1dRKgbod+LZsrDJ8mBaqsZaDmNJMhss9g76XvfMyLra 9DI9/iFuBpGzeqBv0hwOGQspLRrEoyTeR6n1ABEBAAG0H0NvbmxleSBPd2VucyA8 Y2NvM0BhbmRyb2lkLmNvbT6JATgEEwECACIFAlHRvc8CGwMGCwkIBwMCBhUIAgkK CwQWAgMBAh4BAheAAAoJEGe35EhpKzgsP6AIAJKJmNtn4l7hkYHKHFSo3egb6RjQ zEIP3MFTcu8HFX1kF1ZFbrp7xqurLaE53kEkKuAAvjJDAgI8mcZHP1JyplubqjQA xvv84gK+OGP3Xk+QK1ZjUQSbjOpjEiSZpRhWcHci3dgOUH4blJfByHw25hlgHowd a/2PrNKZVcJ92YienaxxGjcXEUcd0uYEG2+rwllQigFcnMFDhr9B71MfalRHjFKE fmdoypqLrri61YBc59P88Rw2/WUpTQjgNubSqa3A2+CKdaRyaRw+2fdF4TdR0h8W zbg+lbaPtJHsV+3mJC7fq26MiJDRJa5ZztpMn8su20gbLgi2ShBOaHAYDDi5AQ0E UdG9zwEIAMoOBq+QLNozAhxOOl5GL3StTStGRgPRXINfmViTsihrqGCWBBUfXlUE OytC0mYcrDUQev/8ToVoyqw+iGSwDkcSXkrEUCKFtHV/GECWtk1keyHgR10YKI1R mquSXoubWGqPeG1PAI74XWaRx8UrL8uCXUtmD8Q5J7mDjKR5NpxaXrwlA0bKsf2E Gp9tu1kKauuToZhWHMRMqYSOGikQJwWSFYKT1KdNcOXLQF6+bfoJ6sjVYdwfmNQL Ixn8QVhoTDedcqClSWB17VDEFDFa7MmqXZz2qtM3X1R/MUMHqPtegQzBGNhRdnI2 V45+1Nnx/uuCxDbeI4RbHzujnxDiq70AEQEAAYkBHwQYAQIACQUCUdG9zwIbDAAK CRBnt+RIaSs4LNVeB/0Y2pZ8I7gAAcEM0Xw8drr4omg2fUoK1J33ozlA/RxeA/lJ I3KnyCDTpXuIeBKPGkdL8uMATC9Z8DnBBajRlftNDVZS3Hz4G09G9QpMojvJkFJV By+01Flw/X+eeN8NpqSuLV4W+AjEO8at/VvgKr1AFvBRdZ7GkpI1o6DgPe7ZqX+1 dzQZt3e13W0rVBb/bUgx9iSLoeWP3aq/k+/GRGOR+S6F6BBSl0SQ2EF2+dIywb1x JuinEP+AwLAUZ1Bsx9ISC0Agpk2VeHXPL3FGhroEmoMvBzO0kTFGyoeT7PR/BfKv +H/g3HsL2LOB9uoIm8/5p2TTU5ttYCXMHhQZ81AY =AUp4 -----END PGP PUBLIC KEY BLOCK----- """ GIT = 'git' # our git command MIN_GIT_VERSION = (1, 7, 2) # minimum supported git version repodir = '.repo' # name of repo's private directory S_repo = 'repo' # special repo repository S_manifests = 'manifests' # special manifest repository REPO_MAIN = S_repo + '/main.py' # main script MIN_PYTHON_VERSION = (2, 6) # minimum supported python version import errno import optparse import os import re import stat import subprocess import sys if sys.version_info[0] == 3: import urllib.request import urllib.error else: import imp import urllib2 urllib = imp.new_module('urllib') urllib.request = urllib2 urllib.error = urllib2 def _print(*objects, **kwargs): sep = kwargs.get('sep', ' ') end = kwargs.get('end', '\n') out = kwargs.get('file', sys.stdout) out.write(sep.join(objects) + end) # Python version check ver = sys.version_info if ver[0] == 3: _print('warning: Python 3 support is currently experimental. YMMV.\n' 'Please use Python 2.6 - 2.7 instead.', file=sys.stderr) if (ver[0], ver[1]) < MIN_PYTHON_VERSION: _print('error: Python version %s unsupported.\n' 'Please use Python 2.6 - 2.7 instead.' % sys.version.split(' ')[0], file=sys.stderr) sys.exit(1) home_dot_repo = os.path.expanduser('~/.repoconfig') gpg_dir = os.path.join(home_dot_repo, 'gnupg') extra_args = [] init_optparse = optparse.OptionParser(usage="repo init -u url [options]") # Logging group = init_optparse.add_option_group('Logging options') group.add_option('-q', '--quiet', dest="quiet", action="store_true", default=False, help="be quiet") # Manifest group = init_optparse.add_option_group('Manifest options') group.add_option('-u', '--manifest-url', dest='manifest_url', help='manifest repository location', metavar='URL') group.add_option('-b', '--manifest-branch', dest='manifest_branch', help='manifest branch or revision', metavar='REVISION') group.add_option('-m', '--manifest-name', dest='manifest_name', help='initial manifest file', metavar='NAME.xml') group.add_option('--mirror', dest='mirror', action='store_true', help='create a replica of the remote repositories ' 'rather than a client working directory') group.add_option('--reference', dest='reference', help='location of mirror directory', metavar='DIR') group.add_option('--depth', type='int', default=None, dest='depth', help='create a shallow clone with given depth; see git clone') group.add_option('--archive', dest='archive', action='store_true', help='checkout an archive instead of a git repository for ' 'each project. See git archive.') group.add_option('-g', '--groups', dest='groups', default='default', help='restrict manifest projects to ones with specified ' 'group(s) [default|all|G1,G2,G3|G4,-G5,-G6]', metavar='GROUP') group.add_option('-p', '--platform', dest='platform', default="auto", help='restrict manifest projects to ones with a specified ' 'platform group [auto|all|none|linux|darwin|...]', metavar='PLATFORM') # Tool group = init_optparse.add_option_group('repo Version options') group.add_option('--repo-url', dest='repo_url', help='repo repository location', metavar='URL') group.add_option('--repo-branch', dest='repo_branch', help='repo branch or revision', metavar='REVISION') group.add_option('--no-repo-verify', dest='no_repo_verify', action='store_true', help='do not verify repo source code') # Other group = init_optparse.add_option_group('Other options') group.add_option('--config-name', dest='config_name', action="store_true", default=False, help='Always prompt for name/e-mail') class CloneFailure(Exception): """Indicate the remote clone of repo itself failed. """ def _Init(args): """Installs repo by cloning it over the network. """ opt, args = init_optparse.parse_args(args) if args: init_optparse.print_usage() sys.exit(1) url = opt.repo_url if not url: url = REPO_URL extra_args.append('--repo-url=%s' % url) branch = opt.repo_branch if not branch: branch = REPO_REV extra_args.append('--repo-branch=%s' % branch) if branch.startswith('refs/heads/'): branch = branch[len('refs/heads/'):] if branch.startswith('refs/'): _print("fatal: invalid branch name '%s'" % branch, file=sys.stderr) raise CloneFailure() try: os.mkdir(repodir) except OSError as e: if e.errno != errno.EEXIST: _print('fatal: cannot make %s directory: %s' % (repodir, e.strerror), file=sys.stderr) # Don't raise CloneFailure; that would delete the # name. Instead exit immediately. # sys.exit(1) _CheckGitVersion() try: if NeedSetupGnuPG(): can_verify = SetupGnuPG(opt.quiet) else: can_verify = True dst = os.path.abspath(os.path.join(repodir, S_repo)) _Clone(url, dst, opt.quiet) if can_verify and not opt.no_repo_verify: rev = _Verify(dst, branch, opt.quiet) else: rev = 'refs/remotes/origin/%s^0' % branch _Checkout(dst, branch, rev, opt.quiet) except CloneFailure: if opt.quiet: _print('fatal: repo init failed; run without --quiet to see why', file=sys.stderr) raise def ParseGitVersion(ver_str): if not ver_str.startswith('git version '): return None num_ver_str = ver_str[len('git version '):].strip().split('-')[0] to_tuple = [] for num_str in num_ver_str.split('.')[:3]: if num_str.isdigit(): to_tuple.append(int(num_str)) else: to_tuple.append(0) return tuple(to_tuple) def _CheckGitVersion(): cmd = [GIT, '--version'] try: proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) except OSError as e: _print(file=sys.stderr) _print("fatal: '%s' is not available" % GIT, file=sys.stderr) _print('fatal: %s' % e, file=sys.stderr) _print(file=sys.stderr) _print('Please make sure %s is installed and in your path.' % GIT, file=sys.stderr) raise CloneFailure() ver_str = proc.stdout.read().strip() proc.stdout.close() proc.wait() ver_act = ParseGitVersion(ver_str) if ver_act is None: _print('error: "%s" unsupported' % ver_str, file=sys.stderr) raise CloneFailure() if ver_act < MIN_GIT_VERSION: need = '.'.join(map(str, MIN_GIT_VERSION)) _print('fatal: git %s or later required' % need, file=sys.stderr) raise CloneFailure() def NeedSetupGnuPG(): if not os.path.isdir(home_dot_repo): return True kv = os.path.join(home_dot_repo, 'keyring-version') if not os.path.exists(kv): return True kv = open(kv).read() if not kv: return True kv = tuple(map(int, kv.split('.'))) if kv < KEYRING_VERSION: return True return False def SetupGnuPG(quiet): try: os.mkdir(home_dot_repo) except OSError as e: if e.errno != errno.EEXIST: _print('fatal: cannot make %s directory: %s' % (home_dot_repo, e.strerror), file=sys.stderr) sys.exit(1) try: os.mkdir(gpg_dir, stat.S_IRWXU) except OSError as e: if e.errno != errno.EEXIST: _print('fatal: cannot make %s directory: %s' % (gpg_dir, e.strerror), file=sys.stderr) sys.exit(1) env = os.environ.copy() env['GNUPGHOME'] = gpg_dir.encode() cmd = ['gpg', '--import'] try: proc = subprocess.Popen(cmd, env = env, stdin = subprocess.PIPE) except OSError as e: if not quiet: _print('warning: gpg (GnuPG) is not available.', file=sys.stderr) _print('warning: Installing it is strongly encouraged.', file=sys.stderr) _print(file=sys.stderr) return False proc.stdin.write(MAINTAINER_KEYS) proc.stdin.close() if proc.wait() != 0: _print('fatal: registering repo maintainer keys failed', file=sys.stderr) sys.exit(1) _print() fd = open(os.path.join(home_dot_repo, 'keyring-version'), 'w') fd.write('.'.join(map(str, KEYRING_VERSION)) + '\n') fd.close() return True def _SetConfig(local, name, value): """Set a git configuration option to the specified value. """ cmd = [GIT, 'config', name, value] if subprocess.Popen(cmd, cwd = local).wait() != 0: raise CloneFailure() def _InitHttp(): handlers = [] mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm() try: import netrc n = netrc.netrc() for host in n.hosts: p = n.hosts[host] mgr.add_password(p[1], 'http://%s/' % host, p[0], p[2]) mgr.add_password(p[1], 'https://%s/' % host, p[0], p[2]) except: pass handlers.append(urllib.request.HTTPBasicAuthHandler(mgr)) handlers.append(urllib.request.HTTPDigestAuthHandler(mgr)) if 'http_proxy' in os.environ: url = os.environ['http_proxy'] handlers.append(urllib.request.ProxyHandler({'http': url, 'https': url})) if 'REPO_CURL_VERBOSE' in os.environ: handlers.append(urllib.request.HTTPHandler(debuglevel=1)) handlers.append(urllib.request.HTTPSHandler(debuglevel=1)) urllib.request.install_opener(urllib.request.build_opener(*handlers)) def _Fetch(url, local, src, quiet): if not quiet: _print('Get %s' % url, file=sys.stderr) cmd = [GIT, 'fetch'] if quiet: cmd.append('--quiet') err = subprocess.PIPE else: err = None cmd.append(src) cmd.append('+refs/heads/*:refs/remotes/origin/*') cmd.append('refs/tags/*:refs/tags/*') proc = subprocess.Popen(cmd, cwd = local, stderr = err) if err: proc.stderr.read() proc.stderr.close() if proc.wait() != 0: raise CloneFailure() def _DownloadBundle(url, local, quiet): if not url.endswith('/'): url += '/' url += 'clone.bundle' proc = subprocess.Popen( [GIT, 'config', '--get-regexp', 'url.*.insteadof'], cwd = local, stdout = subprocess.PIPE) for line in proc.stdout: m = re.compile(r'^url\.(.*)\.insteadof (.*)$').match(line) if m: new_url = m.group(1) old_url = m.group(2) if url.startswith(old_url): url = new_url + url[len(old_url):] break proc.stdout.close() proc.wait() if not url.startswith('http:') and not url.startswith('https:'): return False dest = open(os.path.join(local, '.git', 'clone.bundle'), 'w+b') try: try: r = urllib.request.urlopen(url) except urllib.error.HTTPError as e: if e.code in [403, 404]: return False _print('fatal: Cannot get %s' % url, file=sys.stderr) _print('fatal: HTTP error %s' % e.code, file=sys.stderr) raise CloneFailure() except urllib.error.URLError as e: _print('fatal: Cannot get %s' % url, file=sys.stderr) _print('fatal: error %s' % e.reason, file=sys.stderr) raise CloneFailure() try: if not quiet: _print('Get %s' % url, file=sys.stderr) while True: buf = r.read(8192) if buf == '': return True dest.write(buf) finally: r.close() finally: dest.close() def _ImportBundle(local): path = os.path.join(local, '.git', 'clone.bundle') try: _Fetch(local, local, path, True) finally: os.remove(path) def _Clone(url, local, quiet): """Clones a git repository to a new subdirectory of repodir """ try: os.mkdir(local) except OSError as e: _print('fatal: cannot make %s directory: %s' % (local, e.strerror), file=sys.stderr) raise CloneFailure() cmd = [GIT, 'init', '--quiet'] try: proc = subprocess.Popen(cmd, cwd = local) except OSError as e: _print(file=sys.stderr) _print("fatal: '%s' is not available" % GIT, file=sys.stderr) _print('fatal: %s' % e, file=sys.stderr) _print(file=sys.stderr) _print('Please make sure %s is installed and in your path.' % GIT, file=sys.stderr) raise CloneFailure() if proc.wait() != 0: _print('fatal: could not create %s' % local, file=sys.stderr) raise CloneFailure() _InitHttp() _SetConfig(local, 'remote.origin.url', url) _SetConfig(local, 'remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*') if _DownloadBundle(url, local, quiet): _ImportBundle(local) else: _Fetch(url, local, 'origin', quiet) def _Verify(cwd, branch, quiet): """Verify the branch has been signed by a tag. """ cmd = [GIT, 'describe', 'origin/%s' % branch] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd = cwd) cur = proc.stdout.read().strip() proc.stdout.close() proc.stderr.read() proc.stderr.close() if proc.wait() != 0 or not cur: _print(file=sys.stderr) _print("fatal: branch '%s' has not been signed" % branch, file=sys.stderr) raise CloneFailure() m = re.compile(r'^(.*)-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur) if m: cur = m.group(1) if not quiet: _print(file=sys.stderr) _print("info: Ignoring branch '%s'; using tagged release '%s'" % (branch, cur), file=sys.stderr) _print(file=sys.stderr) env = os.environ.copy() env['GNUPGHOME'] = gpg_dir.encode() cmd = [GIT, 'tag', '-v', cur] proc = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.PIPE, cwd = cwd, env = env) out = proc.stdout.read() proc.stdout.close() err = proc.stderr.read() proc.stderr.close() if proc.wait() != 0: _print(file=sys.stderr) _print(out, file=sys.stderr) _print(err, file=sys.stderr) _print(file=sys.stderr) raise CloneFailure() return '%s^0' % cur def _Checkout(cwd, branch, rev, quiet): """Checkout an upstream branch into the repository and track it. """ cmd = [GIT, 'update-ref', 'refs/heads/default', rev] if subprocess.Popen(cmd, cwd = cwd).wait() != 0: raise CloneFailure() _SetConfig(cwd, 'branch.default.remote', 'origin') _SetConfig(cwd, 'branch.default.merge', 'refs/heads/%s' % branch) cmd = [GIT, 'symbolic-ref', 'HEAD', 'refs/heads/default'] if subprocess.Popen(cmd, cwd = cwd).wait() != 0: raise CloneFailure() cmd = [GIT, 'read-tree', '--reset', '-u'] if not quiet: cmd.append('-v') cmd.append('HEAD') if subprocess.Popen(cmd, cwd = cwd).wait() != 0: raise CloneFailure() def _FindRepo(): """Look for a repo installation, starting at the current directory. """ curdir = os.getcwd() repo = None olddir = None while curdir != '/' \ and curdir != olddir \ and not repo: repo = os.path.join(curdir, repodir, REPO_MAIN) if not os.path.isfile(repo): repo = None olddir = curdir curdir = os.path.dirname(curdir) return (repo, os.path.join(curdir, repodir)) class _Options: help = False def _ParseArguments(args): cmd = None opt = _Options() arg = [] for i in range(len(args)): a = args[i] if a == '-h' or a == '--help': opt.help = True elif not a.startswith('-'): cmd = a arg = args[i + 1:] break return cmd, opt, arg def _Usage(): _print( """usage: repo COMMAND [ARGS] repo is not yet installed. Use "repo init" to install it here. The most commonly used repo commands are: init Install repo in the current working directory help Display detailed help on a command For access to the full online help, install repo ("repo init"). """, file=sys.stderr) sys.exit(1) def _Help(args): if args: if args[0] == 'init': init_optparse.print_help() sys.exit(0) else: _print("error: '%s' is not a bootstrap command.\n" ' For access to online help, install repo ("repo init").' % args[0], file=sys.stderr) else: _Usage() sys.exit(1) def _NotInstalled(): _print('error: repo is not installed. Use "repo init" to install it here.', file=sys.stderr) sys.exit(1) def _NoCommands(cmd): _print("""error: command '%s' requires repo to be installed first. Use "repo init" to install it here.""" % cmd, file=sys.stderr) sys.exit(1) def _RunSelf(wrapper_path): my_dir = os.path.dirname(wrapper_path) my_main = os.path.join(my_dir, 'main.py') my_git = os.path.join(my_dir, '.git') if os.path.isfile(my_main) and os.path.isdir(my_git): for name in ['git_config.py', 'project.py', 'subcmds']: if not os.path.exists(os.path.join(my_dir, name)): return None, None return my_main, my_git return None, None def _SetDefaultsTo(gitdir): global REPO_URL global REPO_REV REPO_URL = gitdir proc = subprocess.Popen([GIT, '--git-dir=%s' % gitdir, 'symbolic-ref', 'HEAD'], stdout = subprocess.PIPE, stderr = subprocess.PIPE) REPO_REV = proc.stdout.read().strip() proc.stdout.close() proc.stderr.read() proc.stderr.close() if proc.wait() != 0: _print('fatal: %s has no current branch' % gitdir, file=sys.stderr) sys.exit(1) def main(orig_args): repo_main, rel_repo_dir = _FindRepo() cmd, opt, args = _ParseArguments(orig_args) wrapper_path = os.path.abspath(__file__) my_main, my_git = _RunSelf(wrapper_path) if not repo_main: if opt.help: _Usage() if cmd == 'help': _Help(args) if not cmd: _NotInstalled() if cmd == 'init': if my_git: _SetDefaultsTo(my_git) try: _Init(args) except CloneFailure: for root, dirs, files in os.walk(repodir, topdown=False): for name in files: os.remove(os.path.join(root, name)) for name in dirs: os.rmdir(os.path.join(root, name)) os.rmdir(repodir) sys.exit(1) repo_main, rel_repo_dir = _FindRepo() else: _NoCommands(cmd) if my_main: repo_main = my_main ver_str = '.'.join(map(str, VERSION)) me = [sys.executable, repo_main, '--repo-dir=%s' % rel_repo_dir, '--wrapper-version=%s' % ver_str, '--wrapper-path=%s' % wrapper_path, '--'] me.extend(orig_args) me.extend(extra_args) try: os.execv(sys.executable, me) except OSError as e: _print("fatal: unable to start %s" % repo_main, file=sys.stderr) _print("fatal: %s" % e, file=sys.stderr) sys.exit(148) if __name__ == '__main__': main(sys.argv[1:]) phablet-tools-1.2+16.04.20160317/click-buddy0000755000015600001650000001224312672627760020636 0ustar pbuserpbgroup00000000000000#!/bin/sh # This program is free software: you can redistribute it and/or modify it # under the terms of the the GNU General Public License version 3, as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranties of # MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR # PURPOSE. See the applicable version of the GNU General Public # License for more details. #. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Copyright (C) 2014 Canonical, Ltd. # # Author: Sergio Schvezov export LC_ALL=C usage() { cat < # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from __future__ import print_function from phabletutils.device import AndroidBridge from phabletutils.fileutils import create_temp_dir from subprocess import CalledProcessError import argparse import os import shutil import subprocess import sys import urllib import re import pipes LOCAL_SOURCE_FILE = '''deb file:/tmp/archive/ ./ ''' LOCAL_PIN_FILE = '''Package: * Pin: origin "" Pin-Priority: 1100 ''' class UbuntuDevice(AndroidBridge): def __init__(self, device=None): super(UbuntuDevice, self).__init__(device=device) def _handle_timezone(adb, args): if not args.tz: try: tz_string = open('/etc/timezone', 'r').read().strip('\n') print(tz_string) except IOError: print("/etc/timezone not found. Please pass --tz") sys.exit(1) else: tz_string = args.tz if not is_valid_tz(tz_string): print("Not a valid timezone") sys.exit(1) print("Changing timezone to %s" % tz_string) try: cmd = "gdbus call -y -d org.freedesktop.timedate1 -o " \ "/org/freedesktop/timedate1 -m " \ "org.freedesktop.timedate1.SetTimezone '%s' false" % tz_string print(cmd) adb.shell(cmd) print("Time zone successfully changed") except: print("Timezone has not been changed") sys.exit(1) def is_valid_tz(timezone): tz_path = os.path.join('/usr/share/zoneinfo/' + timezone) return os.path.isfile(tz_path) def is_valid_locale(adb, locale): phone_locales = adb.shell('ls /usr/share/locale/').split() return locale in phone_locales def _handle_locale(adb, args): if not args.lc and not args.list: print("No locale to set, exiting") sys.exit(1) if args.list: print(adb.shell('ls /usr/share/locale')) sys.exit(0) elif not is_valid_locale(adb, args.lc): print("Not a valid locale, exiting") sys.exit(1) try: cmd = "dbus-send --system --print-reply --dest="\ "org.freedesktop.Accounts /org/freedesktop/Accounts/User32011 "\ "org.freedesktop.Accounts.User.SetLanguage"\ " string:%s" % args.lc adb.shell(cmd) print("Locale set to %s, rebooting to take effect" % args.lc) adb.reboot() except: print("Locale was not changed") sys.exit(1) def is_remote_root(adb): return adb.shell("id -ru").strip() == "0" def _handle_autopilot(adb, args): if not is_remote_root(adb): dbusarg = 'false' if args.dbus_probe == 'enable': dbusarg = 'true' dbus_call = 'dbus-send --system --print-reply ' \ '--dest=com.canonical.PropertyService ' \ '/com/canonical/PropertyService ' \ 'com.canonical.PropertyService.SetProperty ' \ 'string:autopilot boolean:%s' % dbusarg adb.shell(dbus_call, False) # wait until it is done; it takes a while to start apparmor_parser, so # we need to wait a bit in advance adb.shell('sleep 5; while pidof apparmor_parser; do sleep 5; done', False) else: if args.dbus_probe == 'enable': rfile = '/usr/share/autopilot-touch/apparmor/click.rules' adb.shell('aa-clickhook -f --include=%s' % rfile) else: adb.shell('aa-clickhook -f') def sudo_shell(adb, sudocmd, cmd): output = adb.shell('%s %s' % (sudocmd, cmd), ignore_errors=False) print('%s' % output) def _handle_writable_image(adb, args): fname = '/userdata/.writable_image' try: adb.shell('test -e %s' % fname, False) except CalledProcessError as e: if not is_remote_root(adb): dbus_call = 'dbus-send --system --print-reply ' \ '--dest=com.canonical.PropertyService ' \ '/com/canonical/PropertyService ' \ 'com.canonical.PropertyService.SetProperty ' \ 'string:writable boolean:true' adb.shell(dbus_call, False) else: adb.shell('touch %s' % fname, False) adb.reboot() adb.wait_for_device() adb.wait_for_network() try: sudocmd = '' tempfile = '' if not is_remote_root(adb) and args.remotepassword: tempfile = adb.shell('mktemp -t sudo_askpass.XXXX').rstrip() adb.shell("printf '%%s\\n' '#!/bin/sh' 'echo %s' >> %s " % (args.remotepassword[0], tempfile), ignore_errors=False) adb.shell("chmod u+x %s" % tempfile) sudocmd = 'SUDO_ASKPASS=%s sudo -A' % tempfile if args.package_dir: if not is_remote_root(adb) and not args.remotepassword: print('need the remote password (-r) for package operations') sys.exit(1) tmp_archive = create_temp_dir() for package_dir in args.package_dir: # Copy all deb files under the given dir to a temp dir for root, dirs, files in os.walk(package_dir): for deb_file in files: if deb_file.endswith('.deb'): shutil.copy(os.path.join(root, deb_file), tmp_archive) # Create the Packages file current_dir = os.getcwd() os.chdir(tmp_archive) subprocess.check_call( '/usr/bin/dpkg-scanpackages . /dev/null > Packages', shell=True) os.chdir(current_dir) # Create the apt source file for the device with open(os.path.join(tmp_archive, '00localrepo.list'), 'w') as sources_file: sources_file.write(LOCAL_SOURCE_FILE) # Create the apt pin file for the device with open(os.path.join(tmp_archive, 'local-pin-1100'), 'w') as pin_file: pin_file.write(LOCAL_PIN_FILE) adb.push(tmp_archive, '/tmp/archive') sudo_shell(adb, sudocmd, 'mv /tmp/archive/00localrepo.list ' '/etc/apt/sources.list.d') sudo_shell(adb, sudocmd, 'mv /tmp/archive/local-pin-1100 ' '/etc/apt/preferences.d') if args.ppa: if not is_remote_root(adb) and not args.remotepassword: print('need the remote password (-r) for package operations') sys.exit(1) for ppa in args.ppa: sudo_shell(adb, sudocmd, 'add-apt-repository -y %s' % ppa) if args.package_dir or args.ppa or args.package: if not is_remote_root(adb) and not args.remotepassword: print('need the remote password (-r) for package operations') sys.exit(1) sudo_shell(adb, sudocmd, 'apt-get update -qq') if args.package: if not is_remote_root(adb) and not args.remotepassword: print('need the remote password (-r) for package operations') sys.exit(1) package = ' '.join(args.package) sudo_shell(adb, sudocmd, 'apt-get install -yq --force-yes %s' % package) if args.package_dir: # Remove the local archive sudo_shell(adb, sudocmd, 'rm /etc/apt/sources.list.d/00localrepo.list') sudo_shell(adb, sudocmd, 'rm /etc/apt/preferences.d/local-pin-1100') adb.shell('rm -rf /tmp/archive') adb.shell('rm -rf %s' % tempfile) except CalledProcessError as e: print(e) print(e.output) sys.exit(e.returncode) def _handle_edges_intro(adb, args): # Don't try to detect if edges are already enabled or not, since it's # actually a spectrum (some edges might have been completed, others may # not be) and rather than figure out exactly what the current state is, # just set our preferred state. setter = 'true' if args.enable else 'false' dbus_call = 'dbus-send --system --print-reply ' \ '--dest=com.canonical.PropertyService ' \ '/com/canonical/PropertyService ' \ 'com.canonical.PropertyService.SetProperty ' \ 'string:edge boolean:%s' % setter adb.shell(dbus_call, False) def _handle_welcome_wizard(adb, args): config_dir = '/home/phablet/.config/ubuntu-system-settings' ran_file = config_dir + '/wizard-has-run' enabled = adb.shell('ls %s' % ran_file).strip() != ran_file if args.enable and enabled: print('already enabled') elif not args.enable and not enabled: print('already disabled') elif args.enable: adb.shell('rm %s' % ran_file) else: adb.shell('sudo -u phablet mkdir -p %s' % config_dir) adb.shell('sudo -u phablet touch %s' % ran_file) def get_wifi(adb): '''Return (ssid, password) of current wifi connection Raise ValueError if there is no current connection. ''' out = adb.shell( 'gdbus call --system -d org.freedesktop.NetworkManager ' '-o /org/freedesktop/NetworkManager/ActiveConnection/0 ' '-m org.freedesktop.DBus.Properties.Get ' 'org.freedesktop.NetworkManager.Connection.Active Connection') m = re.search("objectpath '(.*?)'>", out) if not m: raise ValueError('no current connection') settings_path = m.group(1) # get ESSID and secret type out = adb.shell( 'gdbus call --system -d org.freedesktop.NetworkManager -o %s ' '-m org.freedesktop.NetworkManager.Settings.Connection.GetSettings' % settings_path) m = re.search("'ssid': <\[byte (.*?)\]", out) assert m, 'failed to parse SSID out of %s' % out # convert byte array to string ssid = bytearray() for b in m.group(1).split(','): ssid.append(int(b, 16)) m = re.search("'security': <'(.*?)'", out) if m: secret_type = m.group(1) out = adb.shell( 'gdbus call --system -d org.freedesktop.NetworkManager -o %s ' '-m org.freedesktop.NetworkManager.Settings.Connection.GetSecrets' ' %s' % (settings_path, secret_type)) m = re.search("{'.*?': <'(.*?)'>}", out) assert m, 'failed to parse secret out of %s' % out secret = m.group(1) else: secret = '' return (ssid, secret) def set_wifi(adb, ssid, password): '''Connect to given wifi''' out = adb.shell('nmcli device wifi connect %s password %s' % ( pipes.quote(ssid), pipes.quote(password))) print(out) if 'Error' in out: sys.exit(1) def _handle_network(adb, args): if args.read: try: (ssid, password) = get_wifi(adb) print('ssid=%s password=%s' % (urllib.quote(ssid), urllib.quote(password))) except ValueError: sys.stderr.write('No current wifi connection\n') sys.exit(1) elif args.write: m = re.match('\s*ssid=([^\s]+)\s+password=([^\s]*)\s*$', args.write) if not m: sys.stderr.write('Invalid wifi specification format\n') sys.exit(1) set_wifi(adb, urllib.unquote(m.group(1)), urllib.unquote(m.group(2))) def parse_arguments(): parser = argparse.ArgumentParser( description='Set up different configuration options on a device.') parser.add_argument('-s', '--serial', help='''Device serial. Use when more than one device is connected.''') sub = parser.add_subparsers(title='Commands', metavar='') tz = sub.add_parser('timezone', help='Configure timezone for device.') tz.add_argument('--tz', help='''Timezone to push to phone. Defaults to whatever is in hosts /etc/timezone''') tz.set_defaults(func=_handle_timezone) lc = sub.add_parser('locale', help="Configure locale for device.") lc.add_argument('--lc', help='''Locale to push to phone. See --list for valid locales''') lc.add_argument('--list', help='List available locales on device', action='store_true') lc.set_defaults(func=_handle_locale) ap = sub.add_parser('autopilot', help='Configure autopilot for device.') ap.add_argument('--dbus-probe', choices=('enable', 'disable'), required=True, help='''Allows autopilot the ability to introspect DBUS objects so that tests will work.''') ap.set_defaults(func=_handle_autopilot) dm = sub.add_parser('writable-image', help='''Enable read/write access to device partitions and optionally install extra packages.''') dm.add_argument('--ppa', action='append', help='PPA to add. Can be repeated.') dm.add_argument('--package-dir', action='append', help='''Directory containing debs to use as an on device repository. Can be repeated.''') dm.add_argument('-p', '--package', action='append', help='Package to install. Can be repeated.') dm.add_argument('-r', '--remotepassword', action='append', help='Password to use for sudo on the device.') dm.set_defaults(func=_handle_writable_image) ei = sub.add_parser('edges-intro', help='Enable/disable the edges intro.') ei.set_defaults(func=_handle_edges_intro) ei = ei.add_mutually_exclusive_group(required=True) ei.add_argument('--enable', action='store_true', required=False, help='enable edges intro') ei.add_argument('--disable', action='store_false', required=False, help='disable edges intro') ei = sub.add_parser('welcome-wizard', help='Enable/disable the welcome wizard.') ei.set_defaults(func=_handle_welcome_wizard) ei = ei.add_mutually_exclusive_group(required=True) ei.add_argument('--enable', action='store_true', required=False, help='enable welcome wizard') ei.add_argument('--disable', action='store_false', required=False, help='disable welcome wizard') nw = sub.add_parser('network', help='Read/write current wifi connection.') nw.set_defaults(func=_handle_network) nw_grp = nw.add_mutually_exclusive_group(required=True) nw_grp.add_argument('-r', '--read', action='store_true', help='Read current wifi ESSID and key in a format ' 'suitable for --write') nw_grp.add_argument('-w', '--write', metavar='WIFI_SPEC', help='Connect to given wifi ESSID and key (format ' 'from --read)') return parser.parse_args() def main(): args = parse_arguments() adb = UbuntuDevice(args.serial) adb.start() args.func(adb, args) if __name__ == '__main__': main() phablet-tools-1.2+16.04.20160317/setup.py0000644000015600001650000000165712672627760020237 0ustar pbuserpbgroup00000000000000#!/usr/bin/python from setuptools import find_packages from setuptools import setup PYTHON_SCRIPTS = [ 'phablet-click-test-setup', 'phablet-demo-setup', 'phablet-dev-bootstrap', 'phablet-flash', 'repo', 'phablet-config' ] SH_SCRIPTS = [ 'citrain', 'phablet-network', 'phablet-screenshot', 'phablet-test-run', 'click-buddy', 'phablet-bootchart', 'phablet-shell', ] DATA_FILES = [ ('/usr/share/phabletutils/', ['shell-adb-common.sh', ]), ] if __name__ == "__main__": setup( name='phablet-tools', version='0.1', description='Scripts to deploy Ubuntu on mobile devices', author='Sergio Schvezov', author_email='sergio.schvezov@canonical.com', license='GPLv3', packages=find_packages(exclude=("tests",)), scripts=PYTHON_SCRIPTS + SH_SCRIPTS, data_files=DATA_FILES, test_suite='tests', ) phablet-tools-1.2+16.04.20160317/phabletutils/0000755000015600001650000000000012672632126021204 5ustar pbuserpbgroup00000000000000phablet-tools-1.2+16.04.20160317/phabletutils/cdimage.py0000644000015600001650000001177312672627760023170 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import logging import re import requests import os.path import subprocess import urlparse from phabletutils import hashes from phabletutils import fileutils from phabletutils import resources from phabletutils import settings log = logging.getLogger() def _get_elements(uri): '''Scraps cdimage and returns a list of relevant links as elements.''' request = requests.get(uri).content html_elements = filter( lambda x: '
  • .*', x).group(0) for x in html_elements] elements_inter = [re.sub('<[^>]*>', '', i) for i in html_elements] elements = [i.strip().strip('/') for i in elements_inter] return elements def _get_releases(uri): '''Fetches the available releases for a given cdimage project URI.''' releases = [{'release': i, 'uri': '%s/%s' % (uri, i)} for i in _get_elements(uri)] log.debug('releases: %s', releases) return releases def _get_revisions(uri): '''Returns the revisions for a given release URI.''' return _get_elements(uri) def get_available_revisions(cdimage_uri): '''Returns all the releases available for a given cdimage project.''' if cdimage_uri[-1] != '/': cdimage_uri = cdimage_uri + '/' releases = _get_releases(cdimage_uri) for release in releases: release['revisions'] = _get_revisions(release['uri']) return releases def get_latest_revision(cdimage_uri): '''Returns the latest revision tagged.''' log.debug('cdimage_uri: %s', cdimage_uri) try: latest_release = _get_releases(cdimage_uri)[-1] log.debug('latest_release: %s', latest_release) latest_revision = _get_revisions(latest_release['uri'])[-1] except IndexError: raise EnvironmentError('No releases for current project. Verify ' 'by checking %s' % cdimage_uri) return latest_release['release'], latest_revision def display_revisions(revisions): '''Displays the available revisions for a give cdimage project.''' for series in revisions: print 'Available releases:' if 'revisions' in series: for rev in series['revisions']: print '\t%s/%s' % (series['release'], rev) else: print 'No releases for %s available' % rev['release'] if not revisions: print 'No revisions have been tagged for this project yet' def _get_link_target(uri): '''Returns the target for the link in the image.''' uri = urlparse.urlparse(uri) uri = 'rsync://%s/cdimage%s' % (uri.netloc, uri.path) link = subprocess.check_output(['rsync', '-l', uri]).split()[-1] return link def get_build(cdimage_uri, pending=False): '''Returns the latest build in current.''' if pending: uri = '%s/%s' % (cdimage_uri, 'pending') else: uri = '%s/%s' % (cdimage_uri, 'current') build = _get_link_target(uri) return build def get_file(file_key, series, download_dir, project='ubuntu-touch', device=None): uri = '%s/%s/daily-preinstalled' % (settings.cdimage_uri_base, project) build = get_build(uri) hash_dict = hashes.load_hash('%s/%s' % (uri, build), 'SHA256SUMS') if device: file_name = settings.files_arch_any[project][file_key] %\ (series, device) download_dir = fileutils.create_path( download_dir, os.path.join(device, build)) else: file_name = settings.files_arch_all[project][file_key] % series download_dir = fileutils.create_path( download_dir, build) log.debug('Download dir for %s set to %s' % (file_name, download_dir)) return resources.File( file_path=os.path.join(download_dir, file_name), file_uri='%s/%s/%s' % (uri, build, file_name), file_hash=hash_dict[file_name]) phablet-tools-1.2+16.04.20160317/phabletutils/__init__.py0000644000015600001650000000141212672627760023323 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright 2013 Canonical # Author: Sergio Schvezov # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License version 3, as published # by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranties of # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR # PURPOSE. See the GNU General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program. If not, see . '''Phablet tools''' phablet-tools-1.2+16.04.20160317/phabletutils/fileutils.py0000644000015600001650000000361412672627760023572 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import atexit import contextlib import logging import lzma import os.path import shutil import tarfile import tempfile log = logging.getLogger() def cleanup(directory): if os.path.exists(directory) and os.path.isdir(directory): print('Removing directory %s' % directory) shutil.rmtree(directory) def create_temp_dir(): directory = tempfile.mkdtemp() atexit.register(cleanup, directory) return directory def create_path(directory, subdir): directory = os.path.join(directory, subdir) if not os.path.exists(directory): log.debug('Creating directory %s' % directory) try: os.makedirs(directory) except OSError as e: if e.errno == 17: pass else: raise e return directory def lzma_extract_file(lzma_tarfile, file_name): log.info('Decompressing %s from %s' % (file_name, lzma_tarfile)) temp_dir = create_temp_dir() with contextlib.closing(lzma.LZMAFile(lzma_tarfile)) as xz: with tarfile.open(fileobj=xz) as tar: tar.extract(member=file_name, path=temp_dir) return os.path.join(temp_dir, file_name) phablet-tools-1.2+16.04.20160317/phabletutils/downloads.py0000644000015600001650000001236112672627760023563 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import configobj import contextlib import fcntl import hashlib import logging import os import requests import subprocess from xdg.BaseDirectory import xdg_config_home log = logging.getLogger() @contextlib.contextmanager def flocked(lockfile): lockfile += '.lock' with open(lockfile, 'w') as f: log.debug('Aquiring lock for %s', lockfile) try: fcntl.lockf(f, fcntl.LOCK_EX) yield finally: log.debug('Releasing lock for %s', lockfile) fcntl.lockf(f, fcntl.LOCK_UN) def setup_download_directory(download_dir): ''' Tries to create the download directory from XDG_DOWNLOAD_DIR or sets an alternative one. Returns path to directory ''' log.info('Download directory set to %s' % download_dir) if not os.path.exists(download_dir): log.info('Creating %s' % download_dir) try: os.makedirs(download_dir) except OSError as e: if e.errno == 17: pass else: raise e def get_full_path(subdir): try: userdirs_file = os.path.join(xdg_config_home, 'user-dirs.dirs') userdirs_config = configobj.ConfigObj(userdirs_file, encoding='utf-8') userdirs_download = os.path.expandvars( userdirs_config['XDG_DOWNLOAD_DIR']) download_dir = userdirs_download except KeyError: download_dir = os.path.expandvars('$HOME') log.warning('XDG_DOWNLOAD_DIR could not be read') directory = os.path.join(download_dir, subdir) setup_download_directory(directory) return directory def get_sha256_hash(string): return hashlib.sha256(string).hexdigest() def checksum_verify(file_path, file_hash, sum_method=hashlib.sha256): '''Returns the checksum for a file with a specified algorightm.''' file_sum = sum_method() log.debug('Verifying file: %s against: %s' % (file_path, file_hash)) if not os.path.exists(file_path): log.debug('File %s not found' % file_path) return False with open(file_path, 'rb') as f: for file_chunk in iter( lambda: f.read(file_sum.block_size * 128), b''): file_sum.update(file_chunk) if file_hash == file_sum.hexdigest(): return True else: log.debug('Calculated sum mismatch calculated %s != %s' % (file_sum.hexdigest(), file_hash)) return False def _download(uri, path): if uri.startswith('http://10.97.0.26'): subprocess.check_call(['curl', '-L', '-C', '-', uri, '-o', path]) else: subprocess.check_call(['wget', '-c', uri, '-O', path]) def download_sig(artifact): '''Downloads an artifact into target.''' log.info('Downloading %s to %s' % (artifact.sig_uri, artifact.sig_path)) with flocked(artifact._sig_path): _download(artifact.sig_uri, artifact.sig_path) def download(artifact): '''Downloads an artifact into target.''' log.info('Downloading %s to %s' % (artifact.uri, artifact.path)) with flocked(artifact._path): _download(artifact.uri, artifact.path) def get_content(uri): '''Fetches the SHA256 sum file from cdimage.''' content_request = requests.get(uri) if content_request.status_code != 200: return None else: return content_request.content def get_ubuntu_stamp(uri): '''Downloads the jenkins build id from stamp file''' try: ubuntu_stamp = requests.get('%s/quantal-ubuntu_stamp' % uri) if ubuntu_stamp.status_code != 200: ubuntu_stamp = requests.get('%s/ubuntu_stamp' % uri) if ubuntu_stamp.status_code != 200: log.error('Latest build detection not supported... bailing') exit(1) # Make list and get rid of empties build_data = filter(lambda x: x.startswith('JENKINS_BUILD='), ubuntu_stamp.content.split('\n')) jenkins_build_id = build_data[0].split('=')[1] except (requests.HTTPError, requests.Timeout, requests.ConnectionError): log.error('Could not download build data from jenkins... bailing') exit(1) except IndexError: raise EnvironmentError('Jenkins data format has changed, incompatible') return jenkins_build_id phablet-tools-1.2+16.04.20160317/phabletutils/arguments.py0000644000015600001650000002774012672627760023605 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import argparse import logging import tempfile import urllib import urlparse from phabletutils import cdimage from phabletutils import environment from phabletutils import resources from phabletutils import settings log = logging.getLogger() class PathAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): log.debug('PathAction: %r %r %r' % (namespace, values, option_string)) uri = urlparse.urlparse(values) if not uri.scheme or uri.scheme == 'file': if '%' in uri.path: zip_file_path = urllib.unquote( urlparse.urlparse(uri.path)) else: zip_file_path = uri.path zip_file_uri = None check = False elif uri.scheme == 'http' or uri.scheme == 'https': zip_file_path = tempfile.mktemp() zip_file_uri = values check = True log.debug('Download from %s, path on disk %s' % (zip_file_uri, zip_file_path)) artifact = resources.File(file_path=zip_file_path, file_uri=zip_file_uri, check=check) setattr(namespace, self.dest, artifact) class RevisionListAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): log.debug('RevisionListAction: %r %r %r' % (namespace, values, option_string)) project = 'ubuntu-touch-preview' uri = '%s/%s' % (settings.cdimage_uri_base, project) setattr(namespace, 'func', environment.list_revisions) setattr(namespace, 'uri', uri) class DeprecatedBackup(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): log.warn('--no-backup is deprecated, use --bootstrap instead') setattr(namespace, 'bootstrap', True) class RevisionAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): log.debug('RevisionAction: %r %r %r' % (namespace, values, option_string)) project = 'ubuntu-touch-preview' base_uri = '%s/%s' % (settings.cdimage_uri_base, project) if values: revision_split = values.split('/') if len(revision_split) != 2: raise EnvironmentError( 'Improper use of revision, needs to be formatted like' '[series]/[revision]. Use --list-revisions to find' 'the available revisions on cdimage') series = revision_split[0] build = revision_split[1] else: series, build = cdimage.get_latest_revision(base_uri) uri = '%s/%s/%s' % (base_uri, series, build) setattr(namespace, self.dest, True) setattr(namespace, 'series', series) setattr(namespace, 'build', build) setattr(namespace, 'uri', uri) def cdimage_touch(parent_parser, parents): parser = parent_parser.add_parser( 'cdimage-touch', parents=parents, help='Provisions the device with a CDimage build of Ubuntu Touch.') parser.set_defaults(func=environment.setup_cdimage_touch, project='ubuntu-touch', series=settings.default_series, build=None, uri=None) parser.add_argument('-b', '--bootstrap', help='''Bootstrap the target device, this only works on Nexus devices or devices that use fastboot and are unlocked. All user data is destroyed''', action='store_true') group = parser.add_mutually_exclusive_group() group.add_argument('--pending', action='store_true', required=False, help='Get pending link from cdimage') group.add_argument('-p', '--base-path', required=False, default=None, help='''Installs from base path, you must have the same directory structure as if you downloaded for real. This option is completely offline.''') return parser def ubuntu_system(parent_parser, parents): parser = parent_parser.add_parser( 'ubuntu-system', parents=parents, help='Provisions the device with an Ubuntu Image Based Upgrade image.') parser.set_defaults(func=environment.setup_ubuntu_system, revision=0, series=settings.default_series, project='imageupdates') parser.add_argument('--channel', default='stable', help='''Use an alternate system-image channel, e.g. devel-proposed; defaults to stable.''') parser.add_argument('--revision', type=int, help='''Download a relative revision from current (-1, -2, ...) or a specific version.''') parser.add_argument('--system-image-ready', action='store_true', help='''Explicitly state that the image already on the device is a system image''') parser.add_argument('--alternate-server', default=settings.system_image_uri, help='''Use an alternate system server, the default server is %(default)s''') group = parser.add_mutually_exclusive_group() group.add_argument('--no-backup', action=DeprecatedBackup, nargs=0, help='''(Deprecated) Disables backup procedure of current the Ubuntu install.''') group.add_argument('-b', '--bootstrap', action='store_true', help='''Bootstraps the system into Ubuntu wiping all data while doing so.''') return parser def legacy(parent_parser, parents): parser = parent_parser.add_parser( 'cdimage-legacy', parents=parents, help='Provisions the device with legacy unflipped images.') parser.set_defaults(func=environment.setup_cdimage_legacy, project='ubuntu-touch-preview', series=settings.cdimage_legacy_series, build=None, uri=None) parser.add_argument('-b', '--bootstrap', help='''Bootstrap the target device, this only works on Nexus devices or devices that use fastboot and are unlocked. All user data is destroyed''', action='store_true') group = parser.add_mutually_exclusive_group() group.add_argument('--list-revisions', action=RevisionListAction, nargs=0, help='List available revisions on cdimage and exits') group.add_argument('-r', '--revision', action=RevisionAction, help='''Choose a specific release to install from cdimage, the format is [series]/[rev].''') group.add_argument('-l', '--latest-revision', action=RevisionAction, nargs=0, help='''Pulls the latest tagged revision.''') group.add_argument('-p', '--base-path', required=False, default=None, help='''Installs from base path, you must have the same directory structure as if you downloaded for real. This option is completely offline.''') return parser def community(parent_parser, parents): parser = parent_parser.add_parser( 'community', parents=parents, help='Provisions the device with a community supported build.') parser.add_argument('-d', '--device', required=True, help='''Specify device to flash. Find out more about flashable devices at https://wiki.ubuntu.com/Touch/Devices''') parser.set_defaults(func=environment.setup_community, series=settings.default_series) return parser def common_non_system(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument('--device-path', action=PathAction, help='''uri to device zip to flash, e.g.; file:///..., http://.''',) parser.add_argument('--ubuntu-path', action=PathAction, help='''uri to ubuntu zip to flash, e.g.; file:///..., http://.''',) parser.add_argument('--wipe', action='store_true', help='''Wipes device data.''') return parser def common_supported(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument('-d', '--device', help='''Target device to deploy.''', required=False, choices=settings.supported_devices) return parser def common(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument('--debug', action='store_true', help='''Enable debug messages.''') parser.add_argument('-s', '--serial', help='''Device serial. Use when more than one device is connected.''') parser.add_argument('-D', '--download-only', action='store_true', help='Download image only, but do not flash device.') return parser def get_parser(): """ Returns a Namespace of the parsed arguments from the command line. """ parser = argparse.ArgumentParser( description='''phablet-flash is used to provision devices. It does a best effort to deploy in different ways.''', epilog='''Use -h or --help after each command to learn about their provisioning options.''') # Parsers common_parser = common() common_supported_parser = common_supported() common_non_system_parser = common_non_system() sub = parser.add_subparsers(title='Commands', metavar='') cdimage_touch(sub, [common_parser, common_supported_parser, common_non_system_parser]) legacy(sub, [common_parser, common_supported_parser, common_non_system_parser]) ubuntu_system(sub, [common_parser, common_supported_parser, ]) community(sub, [common_parser, common_non_system_parser, ]) return parser phablet-tools-1.2+16.04.20160317/phabletutils/community.py0000644000015600001650000001171212672627760023614 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from __future__ import print_function import json import hashlib import logging import os import os.path import subprocess from phabletutils import cdimage from phabletutils import downloads from phabletutils import resources from phabletutils import license from phabletutils import settings log = logging.getLogger() branch_template = 'lp:~{0}-image-dev/phablet-image-info/{0}' base_dir = os.path.join(settings.download_dir, 'community') license_template = '''This community project has the following license: {0} ''' def branch_project(device): branch = branch_template.format(device.replace('_', '-')) log.info('Obtaining project branch from %s' % branch) download_dir = downloads.get_full_path(os.path.join(base_dir, device)) target = os.path.join(download_dir, 'config') if os.path.exists(target): subprocess.check_call(['bzr', 'update'], cwd=target) else: subprocess.check_call( ['bzr', 'checkout', '--lightweight', branch, target]) log.info('Target config retrieved to %s' % target) # Best time to do this is right after retrieving the config ensure_license_accept(download_dir, os.path.join(target, 'license')) return target def ensure_license_accept(download_dir, license_file): if not os.path.exists(license_file): raise EnvironmentError('Project does not offer a license file') accept_path = os.path.join(download_dir, '.license_accept') with open(license_file, 'r') as f: device_license = f.read() device_license = 'LICENSE TEXT NOT PROVIDED BY PORT MAINTAINER' \ if not device_license else device_license message = license_template.format(device_license) if not license.has_accepted(accept_path) and \ not license.query(message, accept_path): raise RuntimeError('License not accepted.') def load_manifest(directory): manifest_file = os.path.join(directory, 'manifest.json') if not os.path.exists(manifest_file): raise RuntimeError('Cannot locate %s' % manifest_file) with open(manifest_file) as f: manifest_dict = json.load(f) if 'device' not in manifest_dict: raise EnvironmentError('device entry required in manifest') if 'revision' not in manifest_dict: manifest_dict['revision'] = None if 'storage' not in manifest_dict: manifest_dict['storage'] = '/sdcard/' if 'ubuntu' not in manifest_dict: manifest_dict['ubuntu'] = None log.debug(json.dumps(manifest_dict)) return manifest_dict def get_download_dir(device, revision=None): download_dir = os.path.join(settings.download_dir, 'community', device) if revision: download_dir = os.path.join(download_dir, revision) return downloads.get_full_path(download_dir) def get_files(manifest_dict, download_dir, series): files = {} for key in ('device', 'ubuntu'): if isinstance(manifest_dict[key], dict): item = manifest_dict[key] hash_type = item['hash_func'] if 'hash_func' in item else None log.debug('%s has config uri: %s' % (key, item['uri'])) files[key] = resources.File( file_path=os.path.join(download_dir, '%s.zip' % key), file_uri=item['uri'], file_hash=item['hash'] if 'hash' in item else None, file_hash_func=get_hash_func(hash_type) if hash_type else None) elif isinstance(manifest_dict[key], str) or \ isinstance(manifest_dict[key], unicode): log.debug('%s has config uri: %s' % (key, manifest_dict[key])) files[key] = resources.File( file_path=os.path.join(download_dir, '%s.zip' % key), file_uri=manifest_dict[key], file_hash=None) log.debug('%s is type %s' % (key, type(manifest_dict[key]))) if not manifest_dict['ubuntu']: log.warning('Using Ubuntu Touch current build for ubuntu image') files['ubuntu'] = cdimage.get_file(file_key='ubuntu_zip', series=series, download_dir=download_dir) return files def get_hash_func(hash_type): return { 'md5': hashlib.md5, 'sha256': hashlib.sha256, }.get(hash_type, None) phablet-tools-1.2+16.04.20160317/phabletutils/device.py0000644000015600001650000001524512672627760023034 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import subprocess import logging from time import sleep log = logging.getLogger() def call(args): subprocess.check_call(args, shell=True) def check_output(args): return subprocess.check_output(args, shell=True) class Device(object): '''Android device.''' def __init__(self, cmd, device=None): if device: log.info('Setting device %s' % device) self._cmd = '%s -s %s %%s' % (cmd, device) else: self._cmd = '%s %%s' % cmd self._device = device @property def device(self): '''Returns the device used for the adb interface.''' return self._device class AndroidBridge(Device): '''Interface to adb.''' def __init__(self, device=None): '''Initializes an adb interface attached to a given device.''' super(AndroidBridge, self).__init__(device=device, cmd='adb') def start(self): '''Attempts to start adb if not running.''' log.debug('Starting adb server') cmd = 'start-server' call(self._cmd % cmd) def push(self, src, dst): '''Performs and adb push.''' log.info('Pushing %s to %s' % (src, dst)) cmd = 'push %s %s' % (src, dst) call(self._cmd % cmd) def pull(self, src, dst): '''Performs and adb pull.''' log.info('Pulling %s to %s' % (src, dst)) cmd = 'pull %s %s' % (src, dst) call(self._cmd % cmd) def wait_for_device(self, wait=2): '''Waits for device.''' # Hack wait to avoid LP:1176929 log.debug('Waiting for device...') sleep(wait) call(self._cmd % 'wait-for-device') log.debug('Device is available') def wait_for_network(self): '''Wait for networking to become active on the device.''' cmd = 'phablet-network --skip-setup' if self._device: cmd += ' -s %s' % self._device log.info('Waiting for networking to become active...') call(cmd) log.info('Network is active') def wait_for_recovery(self): '''Waits for recovery.''' # adb wait-for-device when in recovery stalls, this # works around that issue. log.info('Waiting for recovery image to boot') # Initial wait time wait_try = 200 reboot_success = False for wait in range(wait_try): sleep(10) try: output = self.shell('ls /sbin/recovery 2>/dev/null') except: output = None if output: reboot_success = True break wait += 1 if not reboot_success: raise RuntimeError('Wait for recovery expired') log.info('Wait for recovery image to boot complete') def root(self): '''Set device to work as root.''' call(self._cmd % 'root') self.wait_for_device() def chmod(self, filename, mode): '''Performs a chmod on target device.''' cmd = 'shell chmod %s %s' % (mode, filename) call(self._cmd % cmd) def chown(self, user, path): '''Performs a chmod on target device.''' cmd = 'shell chown -R %s:%s %s' % (user, user, path) call(self._cmd % cmd) def getprop(self, android_property): '''Returns an android property.''' cmd = 'shell getprop %s ' % (android_property) return check_output(self._cmd % cmd) def tcp_forward(self, src, dst): '''Creates a tcp forwarding rule.''' cmd = 'forward tcp:%s tcp:%s' % (src, dst) call(self._cmd % cmd) def shell(self, command, ignore_errors=True): '''Runs shell command and returns output''' if not ignore_errors: command = '"%s ; echo ADB_RC=\\$?"' % command cmd = 'shell %s' % command output = check_output(self._cmd % cmd) if not ignore_errors: # get the last line of output rc = output.split('\r\n')[-2] if not rc.startswith('ADB_RC='): raise RuntimeError('unexpected output: %s' % rc) rc = int(rc[7:]) if rc != 0: raise subprocess.CalledProcessError(rc, command, output) return output def chroot(self, command, root='data/ubuntu'): '''Runs command in chroot.''' log.debug('Running in chroot: %s' % command) cmd = 'shell "PATH=/usr/sbin:/usr/bin:/sbin:/bin ' \ 'system/xbin/chroot %s %s"' % (root, command) call(self._cmd % cmd) def reboot(self, recovery=False, bootloader=False): '''Reboots device.''' log.info('Restarting device... wait') if recovery: cmd = 'reboot recovery' elif bootloader: cmd = 'reboot bootloader' else: cmd = 'reboot' call(self._cmd % cmd) if recovery: sleep(20) log.info('Restarting device... wait complete') class Fastboot(Device): '''Interface to fastboot''' def __init__(self, device=None): super(Fastboot, self).__init__(device=device, cmd='fastboot') def flash(self, image_partition, image_file): log.info('Flashing %s to %s' % (image_partition, image_file)) cmd = 'flash %s %s' % (image_partition, image_file) call(self._cmd % cmd) def flash_system(self, image_file): self.flash('system', image_file) def flash_recovery(self, image_file): self.flash('recovery', image_file) def flash_boot(self, image_file): self.flash('boot', image_file) def reboot(self): log.info('Rebooting device') cmd = 'reboot' call(self._cmd % cmd) def boot(self, image_file=None): if image_file: log.info('Booting %s' % image_file) cmd = 'boot %s' % image_file else: log.info('Booting OS') cmd = 'boot' call(self._cmd % cmd) def wipe(self): log.info('Wiping all userdata') cmd = '-w' call(self._cmd % cmd) phablet-tools-1.2+16.04.20160317/phabletutils/ubuntuimage.py0000644000015600001650000000623112672627760024115 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import json import os.path from phabletutils import downloads from phabletutils import fileutils from phabletutils import resources def _get_json(device, channel, uri): json_index_uri = '%s/%s/%s/index.json' % \ (uri, channel, device) json_content = downloads.get_content(json_index_uri) if not json_content: raise RuntimeError('%s cannot be retrieved' % json_index_uri) return json.loads(json_content) def get_json_from_index(device, channel, index, uri): """Returns json index for device""" index -= 1 json_index = _get_json(device, channel, uri) json_dict = sorted([entry for entry in json_index['images'] if entry['type'] == "full"], key=lambda entry: entry['version'])[index] return json_dict def get_json_from_version(device, channel, version, uri): for entry in _get_json(device, channel, uri)['images']: if entry['type'] == 'full' and entry['version'] == version: return entry raise RuntimeError('Version %s cannot be retrieved' % version) def get_files(download_dir, uri, json): files = {} command_part = '' files = [] for entry in sorted(json['files'], key=lambda entry: entry['order']): filename = entry['path'].split("/")[-1] signame = entry['signature'].split("/")[-1] paths = {} for path in ('path', 'signature'): paths[path] = fileutils.create_path( download_dir, os.path.dirname(entry[path].strip(os.path.sep))) f = resources.SignedFile( file_path=os.path.join(paths['path'], filename), sig_path=os.path.join(paths['signature'], signame), file_uri='%s%s' % (uri, entry['path']), sig_uri='%s%s' % (uri, entry['signature']), file_hash=entry['checksum']) files.append(f) command_part += 'update %s %s\n' % (filename, signame) gpg_download_dir = fileutils.create_temp_dir() for keyring in ('image-master', 'image-signing'): filename = '%s.tar.xz' % keyring signame = '%s.asc' % filename f = resources.SignedFile( file_path=os.path.join(gpg_download_dir, filename), sig_path=os.path.join(gpg_download_dir, signame), file_uri='%s/gpg/%s' % (uri, filename), sig_uri='%s/gpg/%s.asc' % (uri, filename), file_hash=None) files.append(f) return files, command_part phablet-tools-1.2+16.04.20160317/phabletutils/backup.py0000644000015600001650000000245012672627760023034 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import logging import tempfile log = logging.getLogger() def backup(adb, backup_file=tempfile.mkstemp()[1]): adb.shell('tar -czpf /tmp/backup.tar.gz ' '/home/phablet ' '/etc/NetworkManager/system-connections') log.info('Saving backup to %s' % backup_file) adb.pull('/tmp/backup.tar.gz', backup_file) return backup_file def restore(adb, backup_file): adb.push(backup_file, '/tmp/backup.tar.gz') log.info('Restoring from %s' % backup_file) adb.shell('tar -xzpf /tmp/backup.tar.gz -C /') adb.reboot() phablet-tools-1.2+16.04.20160317/phabletutils/projects.py0000644000015600001650000002751612672627760023432 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Holds different projects or ways Ubuntu Touch is delivered.""" import os import os.path import tempfile import logging import subprocess import gzip from phabletutils.downloads import checksum_verify from phabletutils.resources import (File, SignedFile) from phabletutils import downloads from phabletutils import fileutils from time import sleep from textwrap import dedent log = logging.getLogger() def gunzip(file_path): if not file_path.endswith('.gz'): return file_path target_path = file_path[:-3] log.info('Decompressing %s' % file_path) with open(target_path, 'wb') as target_file: with gzip.open(file_path, 'r') as gzip_file: for chunk in gzip_file.read(): target_file.write(chunk) return target_path def wipe_device(adb): log.info('Clearing /data and /cache') adb.shell('mount /data') adb.shell('rm -Rf /cache/* /data/* /data/.developer_mode ' '/data/.writable_image') adb.shell('mkdir /cache/recovery') adb.shell('mkdir /data/media') class BaseProject(object): """A provisioning mechanism for all the projects.""" def __init__(self, recovery=None, system=None, boot=None, device=None, ubuntu=None, wipe=False): self._list = [] for item in (recovery, system, boot, device, ubuntu): if item and not isinstance(item, File): raise TypeError('%s is not of type File' % item) elif item: self._list.append(item) if item.check and not item.uri and not item.verified: raise EnvironmentError( '%s is not on disk' % item.path) self._recovery = recovery self._system = system self._boot = boot self._device = device self._ubuntu = ubuntu self._wipe = wipe def download(self): """Downloads and verifies resources.""" download_list = filter((lambda x: x.check), self._list) download_list = filter((lambda x: not x.verified), download_list) log.debug('Download list %s' % download_list) if not download_list: log.info('Download not required') return for entry in download_list: log.debug('Download entry %s %s' % (entry.path, entry.verified)) downloads.download(entry) if entry.hash and \ not checksum_verify(entry.path, entry.hash, entry.hash_type): raise EnvironmentError( 'Checksum does not match after download for %s ' 'and hash %s' % (entry.path, entry.hash)) download_list = filter(lambda x: isinstance(x, SignedFile), self._list) for entry in download_list: downloads.download_sig(entry) def install(self): raise EnvironmentError('Requires implementation') def _loop_until_installed(self, adb): log.info('Waiting for install to finish on device. Please do not ' 'unplug device until phablet-flash finishes.') # Initial wait time sleep(180) wait_try = 100 install_success = False for wait in range(wait_try): sleep(10) try: output = adb.shell('pgrep unity8 2>/dev/null') except: output = None if output: install_success = True break wait += 1 if not install_success: raise RuntimeError('Installation is taking too long or an error ' 'occured along the way.') log.info('Installation complete') class Android(BaseProject): """Standard Android Project.""" def __init__(self, boot, system): super(Android, self).__init__(boot=boot, system=system) def install(self, adb, fastboot): adb.reboot(bootloader=True) log.warning('Device needs to be unlocked for the following to work') fastboot.flash('system', gunzip(self._system.path)) fastboot.flash('boot', self._boot.path) log.info('Installation will complete soon and reboot into Android') fastboot.reboot() class UbuntuTouchBootstrap(BaseProject): def __init__(self, boot, system, recovery, ubuntu): log.debug('UbuntuTouchBootstrap ' 'boot: %s, system: %s, recovery: %s, ubuntu: %s' % (boot.path, system.path, recovery.path, ubuntu.path)) super(UbuntuTouchBootstrap, self).__init__( boot=boot, system=system, recovery=recovery, ubuntu=ubuntu, wipe=True) def install(self, adb, fastboot): adb.reboot(bootloader=True) log.warning('Device needs to be unlocked for the following to work') fastboot.flash('system', self._system.path) fastboot.flash('boot', self._boot.path) fastboot.flash('recovery', self._recovery.path) fastboot.boot(self._recovery.path) adb.wait_for_recovery() wipe_device(adb) adb.push(self._ubuntu.path, '/sdcard/autodeploy.zip') log.info('Deploying Ubuntu') adb.reboot(recovery=True) log.info('Once completed the device should reboot into Ubuntu') class UbuntuTouchRecovery(BaseProject): recovery_script_template = dedent('''\ mount("{0}"); install_zip("{1}"); install_zip("{2}"); ''') def __init__(self, device, ubuntu, storage='/sdcard/', wipe=False): log.debug('UbuntuTouchRecovery device: %s, ubuntu: %s, wipe: %s' % (device.path, ubuntu.path, wipe)) super(UbuntuTouchRecovery, self).__init__( ubuntu=ubuntu, device=device, wipe=wipe) self._storage = storage def install(self, adb, fastboot=None): """ Deploys recovery files, recovery script and then reboots to install. """ log.warning('The device needs to have a clockwork mod recovery image ' '(or one that supports extendedcommands) ' 'in place for the provisioning to work') adb.reboot(recovery=True) adb.wait_for_recovery() if self._wipe: wipe_device(adb) adb.shell('mount %s' % self._storage) adb.push(self._device.path, self._storage) adb.push(self._ubuntu.path, self._storage) recovery_file = self.create_recovery_file() adb.push(recovery_file, '/cache/recovery/extendedcommand') adb.reboot(recovery=True) log.info('Once completed the device should reboot into Ubuntu') log.debug('Removing recovery file %s' % recovery_file) os.unlink(recovery_file) def create_recovery_file(self): template = self.recovery_script_template recovery_file = tempfile.NamedTemporaryFile(delete=False) device = os.path.join(self._storage, os.path.basename(self._device.path)) ubuntu = os.path.join(self._storage, os.path.basename(self._ubuntu.path)) recovery_script = template.format(self._storage, device, ubuntu) with recovery_file as output_file: output_file.write(recovery_script) return recovery_file.name class UbuntuTouchSystem(BaseProject): ubuntu_recovery_script = dedent('''\ format system load_keyring image-master.tar.xz image-master.tar.xz.asc load_keyring image-signing.tar.xz image-signing.tar.xz.asc mount system ''') def __init__(self, file_list, device, command_part, wipe, system_image_ready): log.debug('UbuntuTouchSystem') super(UbuntuTouchSystem, self).__init__(wipe=wipe) for item in file_list: if item and not isinstance(item, File): raise TypeError('%s is not of type File' % item) elif item: self._list.append(item) self._recovery_list = file_list self._command_part = command_part self._device = device self._system_image_ready = system_image_ready def _is_device_file(self, entry): f = os.path.basename(entry.path) return (f.startswith('device') or f.startswith(self._device)) \ and f.endswith('.xz') def _get_recovery_image(self): recovery_path = None for entry in self._recovery_list: if self._is_device_file(entry): recovery_path = fileutils.lzma_extract_file( entry.path, 'partitions/recovery.img') if not recovery_path: raise RuntimeError('Cannot find recovery image to flash ' 'from downloaded files') log.debug('Recovery found in %s' % recovery_path) return recovery_path def _get_current_version(self, adb): try: image_info = adb.shell('system-image-cli -i', ignore_errors=False).split('\r\n') version = [i.split(':')[1].strip() for i in image_info if 'build number: ' in i][0] log.debug('Current version on system is %s' % version) return version except subprocess.CalledProcessError: return '0' def install(self, adb, fastboot=None): """ Deploys recovery files, recovery script and then reboots to install. """ if self._system_image_ready: log.warning('Not doing any verification that the system ' 'has the required dependencies before flashing') elif not self._wipe and self._get_current_version(adb) == '0': raise RuntimeError( 'Backup requested but cannot be completed succesfully, try ' 'with --system-image-ready if the system is already on an ' 'Image Based Ubuntu System to force it or use --bootstrap ' 'if data saving is not important or the system is not already ' 'on an Image Based Ubuntu System.') recovery_path = self._get_recovery_image() adb.reboot(bootloader=True) fastboot.boot(recovery_path) adb.wait_for_recovery() if self._wipe: wipe_device(adb) for entry in self._recovery_list: adb.push(entry.path, '/cache/recovery/') try: adb.push(entry.sig_path, '/cache/recovery/') except AttributeError: pass adb.push(self.create_ubuntu_command_file(), '/cache/recovery/ubuntu_command') adb.reboot(bootloader=True) fastboot.flash('recovery', recovery_path) fastboot.boot(recovery_path) self._loop_until_installed(adb) def create_ubuntu_command_file(self): ubuntu_command_file = tempfile.NamedTemporaryFile(delete=False) with ubuntu_command_file as output_file: if self._wipe: output_file.write('format data\n') output_file.write(self.ubuntu_recovery_script) output_file.write(self._command_part) output_file.write('unmount system\n') return ubuntu_command_file.name phablet-tools-1.2+16.04.20160317/phabletutils/license.py0000644000015600001650000000306012672627760023207 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os import logging log = logging.getLogger() def accepted(pathname): ''' Remember that the user accepted the license. ''' open(pathname, 'w').close() def has_accepted(pathname): ''' Return True if the user accepted the license once. ''' return os.path.exists(pathname) def query(message, accept_path): '''Display end user agreement to continue with deployment.''' try: while True: print message print 'Do you accept? [yes|no]' answer = raw_input().lower() if answer == 'yes': accepted(accept_path) return True elif answer == 'no': return False except KeyboardInterrupt: log.error('Interruption detected, cancelling install') return False phablet-tools-1.2+16.04.20160317/phabletutils/hashes.py0000644000015600001650000000454012672627760023044 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import logging import os.path from phabletutils import downloads log = logging.getLogger() def hash2dict(hash_file_content): '''Returns a dictionary with the sha256 sums for all files.''' if not hash_file_content: log.debug('hash file is empty') return None hash_list = filter((lambda x: len(x) is not 0), hash_file_content.split('\n')) hash_list = [h.split() for h in hash_list] hash_dict = {} for hash_entry in hash_list: if hash_entry[1][0] == '*': hash_entry[1] = hash_entry[1][1:] hash_dict[hash_entry[1]] = hash_entry[0] return hash_dict def load_hash(uri, artifact, download_dir=None): if download_dir: hash_path = os.path.join(download_dir, artifact) else: hash_path = None hashes = {} if hash_path and os.path.exists(hash_path): with open(hash_path, 'r') as f: file_hash_content = f.read() hashes = hash2dict(file_hash_content) if uri: uri = '%s/%s' % (uri, artifact) hash_content = downloads.get_content(uri) if not hash_content: raise RuntimeError('%s cannot be downloaded' % uri) hashes.update(hash2dict(hash_content)) if hash_path: log.debug('Storing hash to %s' % hash_path) with downloads.flocked(hash_path): with open(hash_path, 'w') as f: for key in hashes: f.write('%s %s\n' % (hashes[key], key)) if hashes: return hashes else: raise RuntimeError('%s cannot be obtained for verifiaction' % artifact) phablet-tools-1.2+16.04.20160317/phabletutils/resources.py0000644000015600001650000000453712672627760023611 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Resources for downloading and installing Ubuntu Touch.""" import downloads import hashlib import logging log = logging.getLogger() class File(object): """A file object that can be downloaded and flashed.""" @property def uri(self): return self._uri @property def path(self): return self._path @property def verified(self): return self._verified @property def hash(self): return self._hash @property def hash_type(self): return self._hash_func @property def check(self): return self._check def __init__(self, file_uri, file_path, check=True, file_hash=None, file_hash_func=hashlib.sha256): self._uri = file_uri self._path = file_path self._hash = file_hash self._hash_func = file_hash_func self._check = check if check and file_hash: self._verified = downloads.checksum_verify(file_path, file_hash, file_hash_func) log.debug('%s verified: %s' % (file_path, self._verified)) else: self._verified = False class SignedFile(File): def sig_uri(self): return self._sig_uri @property def sig_path(self): return self._sig_path def __init__(self, file_uri, file_path, file_hash, sig_path, sig_uri, check=True, file_hash_func=hashlib.sha256): super(SignedFile, self).__init__( file_uri, file_path, check, file_hash, file_hash_func) self._sig_path = sig_path self.sig_uri = sig_uri phablet-tools-1.2+16.04.20160317/phabletutils/settings.py0000644000015600001650000000566312672627760023440 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . revision = 2 default_series = 'trusty' cdimage_legacy_series = 'saucy' cdimage_uri_base = 'http://cdimage.ubuntu.com' system_image_uri = 'https://system-image.ubuntu.com' download_dir = 'phablet-flash' files_arch_any = { 'ubuntu-touch': { 'device_zip': '%s-preinstalled-touch-armel+%s.zip', 'system_img': '%s-preinstalled-system-armel+%s.img', 'boot_img': '%s-preinstalled-boot-armhf+%s.img', 'recovery_img': '%s-preinstalled-recovery-armel+%s.img', }, 'ubuntu-touch-preview': { 'device_zip': '%s-preinstalled-armel+%s.zip', 'system_img': '%s-preinstalled-system-armel+%s.img', 'boot_img': '%s-preinstalled-boot-armel+%s.img', 'recovery_img': '%s-preinstalled-recovery-armel+%s.img', }, } files_arch_all = { 'ubuntu-touch': { 'ubuntu_zip': '%s-preinstalled-touch-armhf.zip', }, 'ubuntu-touch-preview': { 'ubuntu_zip': '%s-preinstalled-phablet-armhf.zip', } } recovery_script_template = '''boot-recovery --update_package=/sdcard/{0} --user_data_update_package=/sdcard/{1} reboot ''' supported_devices = ('mako', 'maguro', 'manta', 'flo', 'grouper', 'krillin', ) legal_notice = '''"Touch Developer Preview for Ubuntu" is released for free non-commercial use. It is provided without warranty, even the implied warranty of merchantability, satisfaction or fitness for a particular use. See the licence included with each program for details. Some licences may grant additional rights; this notice shall not limit your rights under each program's licence. Licences for each program are available in the usr/share/doc directory. Source code for Ubuntu can be downloaded from archive.ubuntu.com. Ubuntu, the Ubuntu logo and Canonical are registered trademarks of Canonical Ltd. All other trademarks are the property of their respective owners. "Touch Preview for Ubuntu" is released for limited use due to the inclusion of binary hardware support files. The original components and licenses can be found at: https://developers.google.com/android/nexus/drivers. ''' accept_path = '~/.phablet_accepted' phablet-tools-1.2+16.04.20160317/phabletutils/environment.py0000644000015600001650000001720712672627760024141 0ustar pbuserpbgroup00000000000000# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from __future__ import print_function import hashlib import logging import os.path from phabletutils.device import AndroidBridge from phabletutils import cdimage from phabletutils import community from phabletutils import downloads from phabletutils import hashes from phabletutils import resources from phabletutils import projects from phabletutils import settings from phabletutils import ubuntuimage from subprocess import CalledProcessError log = logging.getLogger() def device_friendly_error_message(f): def wrapper(*args, **kwargs): try: return f(*args, **kwargs) except CalledProcessError: raise EnvironmentError( 'Device either not connected, doesn\'t have adb enabled ' 'or the property system cannot be accessed. Make sure the ' 'device is booted into the operating system and that adb ' 'is working correctly.') return wrapper @device_friendly_error_message def detect_device(serial, device=None): '''If no argument passed determine them from the connected device.''' # Check CyanogenMod property if not device: adb = AndroidBridge(serial) adb.start() device = adb.getprop('ro.cm.device').strip() # Check Android property if not device: device = adb.getprop('ro.product.device').strip() log.info('Device detected as %s' % device) # property may not exist or we may not map it yet if device not in settings.supported_devices: raise EnvironmentError('Unsupported device, autodetect fails device') return device def setup_cdimage_files(project_name, uri, download_dir, series, device, legacy=False): downloads.setup_download_directory(download_dir) templ_arch_any = settings.files_arch_any[project_name] templ_arch_all = settings.files_arch_all[project_name] file_names = {} for key in templ_arch_any: file_names[key] = templ_arch_any[key] % (series, device) for key in templ_arch_all: file_names[key] = templ_arch_all[key] % series if legacy: hash_func = hashlib.md5 hash_dict = {} for key in file_names: file_hash = hashes.load_hash(uri, '%s.md5sum' % file_names[key], download_dir) hash_dict[file_names[key]] = file_hash[file_names[key]] else: hash_func = hashlib.sha256 hash_dict = hashes.load_hash(uri, 'SHA256SUMS', download_dir) files = {} for key in file_names: if uri: file_uri = '%s/%s' % (uri, file_names[key]) else: file_uri = None files[key] = resources.File( file_path=os.path.join(download_dir, file_names[key]), file_uri=file_uri, file_hash=hash_dict[file_names[key]], file_hash_func=hash_func) return files def setup_cdimage_touch(args): device = detect_device(args.serial, args.device) series = args.series base_uri = '%s/%s' % (settings.cdimage_uri_base, args.project) if args.base_path: uri = None download_dir = args.base_path else: daily_uri = '%s/daily-preinstalled' % (base_uri, ) build = cdimage.get_build(daily_uri, args.pending) uri = '%s/%s' % (daily_uri, build) download_dir = downloads.get_full_path( os.path.join(settings.download_dir, args.project, build)) files = setup_cdimage_files( args.project, uri, download_dir, series, device) return cdimage_project(files, args) def setup_cdimage_legacy(args): series = args.series uri = args.uri device = detect_device(args.serial, args.device) if args.base_path: download_dir = args.base_path elif args.revision or args.latest_revision: build = args.build uri = args.uri download_dir = downloads.get_full_path( os.path.join(args.project, series, build)) else: base_uri = '%s/%s' % (settings.cdimage_uri_base, args.project) daily_uri = '%s/daily-preinstalled' % (base_uri, ) build = cdimage.get_build(daily_uri) uri = '%s/%s' % (daily_uri, build) download_dir = downloads.get_full_path( os.path.join(settings.download_dir, args.project, build)) files = setup_cdimage_files( args.project, uri, download_dir, series, device, legacy=True) return cdimage_project(files, args) def cdimage_project(files, args): if args.bootstrap: return projects.UbuntuTouchBootstrap( system=files['system_img'], boot=files['boot_img'], recovery=files['recovery_img'], ubuntu=files['ubuntu_zip']) else: if args.device_path: files['device_zip'] = args.device_path if args.ubuntu_path: files['ubuntu_zip'] = args.ubuntu_path return projects.UbuntuTouchRecovery( device=files['device_zip'], ubuntu=files['ubuntu_zip'], wipe=args.wipe) def setup_ubuntu_system(args): device = detect_device(args.serial, args.device) uri = args.alternate_server if args.revision <= 0: json = ubuntuimage.get_json_from_index(device, args.channel, args.revision, uri) else: json = ubuntuimage.get_json_from_version(device, args.channel, args.revision, uri) download_dir_part = os.path.join(settings.download_dir, args.project) if uri != settings.system_image_uri: base_uri = downloads.get_sha256_hash(uri) download_dir_part = os.path.join(download_dir_part, base_uri) download_dir = downloads.get_full_path(download_dir_part) log.info('Flashing revision %s from channel %s' % (json['version'], args.channel)) files, command_part = ubuntuimage.get_files(download_dir, uri, json) return projects.UbuntuTouchSystem( file_list=files, command_part=command_part, device=device, wipe=args.bootstrap, system_image_ready=args.system_image_ready) def setup_community(args): config_dir = community.branch_project(args.device) json_dict = community.load_manifest(config_dir) download_dir = community.get_download_dir( args.device, json_dict['revision']) files = community.get_files(json_dict, download_dir, args.series) return projects.UbuntuTouchRecovery( device=files['device'], ubuntu=files['ubuntu'], storage=json_dict['storage'], wipe=args.wipe) def list_revisions(args): # Easy hack to get rid of the logger and inhibit requests from logging log.setLevel(logging.FATAL) revisions = cdimage.get_available_revisions(args.uri) cdimage.display_revisions(revisions) phablet-tools-1.2+16.04.20160317/phablet-test-run0000755000015600001650000001541212672627760021643 0ustar pbuserpbgroup00000000000000#!/bin/sh -e # This program is free software: you can redistribute it and/or modify it # under the terms of the the GNU General Public License version 3, as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranties of # MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR # PURPOSE. See the applicable version of the GNU General Public # License for more details. #. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Copyright (C) 2012 Canonical, Ltd. if [ -f "$(dirname $0)/shell-adb-common.sh" ]; then . "$(dirname $0)/shell-adb-common.sh" else . "/usr/share/phabletutils/shell-adb-common.sh" fi TESTSUITE="" TESTPACKAGES="" LOCALPACKAGES="" RESULTDIR="" ARTIFACTS="" APFORMAT="xml" APEXTRA="" EXECUTE_COMMAND=0 USER=phablet NOSHELL=0 RETVAL=0 VERBOSE="" ASKPASS="" SUDO="" print_usage() { cat << EOF usage: $0 [-s SERIAL] [-s] [-n] [-x] [-v] [-p PACKAGENAME] [ -r PASSWORD/PIN ] [-c PACKAGE] [-o DIR] [-a ARTIFACT] [-f xml|subunit|text] [-A args] testsuite Run the specified testsuite on the device -s SERIAL Device serial number -p PACKAGENAME Additional package to be installed, may be used multiple times (requires -r option) -r PASSWORD/PIN Device password or PIN for package installation -c PACKAGE Copy and install local package to device, may be used multiple times -n Stop the shell during the test run -o DIR Test report and artifacts output dir -f format Specifies the output format autopilot will use: xml, subunit, or text. Default=$APFORMAT (requires -o) -A Extra arguments to pass to autopilot. -a ARTIFACT Artifact to fetch after the test, may be used multiple times (requires -o) -x Execute command line, will not use autopilot by default -v Run autopilot with -v option for more verbose output EOF } wait_for_device() { adb wait-for-device } set_up_sudo() { if [ -z "$PW" ]; then echo "Please use the -r option to provide a device password or PIN" echo print_usage exit 0 fi ASKPASS="$(adb shell "mktemp -t sudo_askpass.XXXX|tr -d '\n'")" adb shell "printf '#\x21/bin/sh\necho \"%s\"\n' '${PW}' >$ASKPASS; chmod +x $ASKPASS" SUDO="SUDO_ASKPASS=$ASKPASS sudo -A" } clean_up_sudo() { [ -n "$ASKPASS" ] && adb shell "rm -rf $ASKPASS" } exec_with_adb() { set_up_sudo adb shell "LC_ALL=C $SUDO /usr/bin/env -i PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin $@" clean_up_sudo } exec_with_adb_user() { adb shell "LC_ALL=C $@" } install_packages() { if test -n "$TESTPACKAGES"; then exec_with_adb DEBIAN_FRONTEND=noninteractive apt-get -y -q install $TESTPACKAGES fi if test -n "$LOCALPACKAGES"; then exec_with_adb mkdir -p /tmp/phablet-run-test/ exec_with_adb rm -rf /tmp/phablet-run-test/* PACKAGELIST="" for PACKAGEPATH in $LOCALPACKAGES; do PACKAGE=$(basename $PACKAGEPATH) echo "Pushing $PACKAGE..." adb push $PACKAGEPATH /tmp/phablet-run-test/ PACKAGELIST="$PACKAGELIST /tmp/phablet-run-test/$PACKAGE" done exec_with_adb dpkg -i $PACKAGELIST exec_with_adb DEBIAN_FRONTEND=noninteractive apt-get -fyq install fi } disable_shell() { exec_with_adb_user initctl stop unity8 } restore_shell() { exec_with_adb_user initctl start unity8 } get_returncode() { while read line; do set +e RETVAL=$(echo $line | grep -Po '(?<=ADB_RC=)\d+') if [ $? -eq 0 ] ; then set -e return $RETVAL fi echo $line set -e done } run_autopilot_test() { # This directory doesn't exist in a freshly flashed device, so create it. exec_with_adb_user mkdir -p /home/phablet/autopilot # adb shell always returns 0, so we have to do some hackery to get the # actual RC from the test { apbase="cd /home/phablet/autopilot;SUPPRESS_DEPRECATED_NOTE=yes autopilot3 run $VERBOSE $APEXTRA" if [ "$RESULTDIR" ]; then adb shell "$apbase -o /tmp/test_results.$APFORMAT -f $APFORMAT $TESTSUITE; echo ADB_RC=\$?" if [ $APFORMAT = "xml" ]; then echo "***** Test summary *****" exec_with_adb_user "head -n 1 /tmp/test_results.$APFORMAT" fi else adb shell "$apbase $TESTSUITE; echo ADB_RC=\$?" fi } | get_returncode } run_cli_command() { apbase="cd /home/phablet; $TESTSUITE" # adb shell always returns 0, so we have to do some hackery to get the # actual RC from the test { if [ "$RESULTDIR" ]; then result_output=/tmp/test_results.$APFORMAT adb shell 'rm -rf $result_output' adb shell "$apbase | tee $result_output; echo ADB_RC=\$?" adb pull $result_output $RESULTDIR else adb shell "$apbase; echo ADB_RC=\$?" fi } | get_returncode } fetch_artifacts() { if [ "$RESULTDIR" ]; then mkdir -p $RESULTDIR echo "***** Artifacts ($RESULTDIR) *****" set +e if [ $EXECUTE_COMMAND -eq 0 ]; then adb pull /tmp/test_results.$APFORMAT $RESULTDIR fi for artifact in $ARTIFACTS; do adb pull $artifact $RESULTDIR done set -e fi } while getopts A:a:c:f:hnxo:p:r:s:v opt; do case $opt in A) APEXTRA=$OPTARG ;; a) ARTIFACTS="$ARTIFACTS $OPTARG" ;; c) LOCALPACKAGES="$LOCALPACKAGES $OPTARG" ;; f) APFORMAT=$OPTARG ;; h) print_usage exit 0 ;; n) NOSHELL=1 ;; o) RESULTDIR=$OPTARG ;; p) TESTPACKAGES="$TESTPACKAGES $OPTARG" ;; r) PW=$OPTARG ;; s) SERIAL="$OPTARG" ;; x) EXECUTE_COMMAND=1 ;; v) VERBOSE="-v" ;; esac done shift $((OPTIND - 1)) # exporting ANDROID_SERIAL to support multiple devices connected # seamlessly [ -z "$SERIAL" ] || export ANDROID_SERIAL="$SERIAL" TESTSUITE=$@ if test -z "$TESTSUITE"; then echo To run a test please specify a test suite exit 0 fi check_devices install_packages if [ $NOSHELL -eq 1 ]; then echo "Disabling shell" disable_shell fi if [ $EXECUTE_COMMAND -eq 1 ]; then echo "running $TESTSUITE" run_cli_command || RETVAL=1 else run_autopilot_test || RETVAL=1 fi fetch_artifacts if [ $NOSHELL -eq 1 ]; then echo "Restoring shell" restore_shell fi exit $RETVAL phablet-tools-1.2+16.04.20160317/phablet-demo-setup0000755000015600001650000001117712672627760022150 0ustar pbuserpbgroup00000000000000#! /usr/bin/python # This program is free software: you can redistribute it and/or modify it # under the terms of the the GNU General Public License version 3, as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranties of # MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR # PURPOSE. See the applicable version of the GNU Lesser General Public # License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Copyright (C) 2013 Canonical, Ltd. import argparse import logging import tempfile import StringIO import os from phabletutils.device import AndroidBridge from phabletutils import downloads from phabletutils import fileutils logging.basicConfig(level=logging.INFO, format='%(message)s') log = logging.getLogger() log.name = 'phablet-demo-setup' basic_template = '''#!/bin/sh set -ex ''' SERVER_URL = 'http://people.canonical.com/~cwayne/phablet-tools' TMP_DOWNLOAD_DIR = fileutils.create_temp_dir() def download(artifact): '''Downloads demo content onto the host, to be pushed to device''' remote_file = '%s/%s' % (SERVER_URL, artifact) download_path = os.path.join(TMP_DOWNLOAD_DIR, artifact) if not os.path.isfile(download_path): downloads._download(remote_file, download_path) return download_path def parse_arguments(): '''Parses arguments passed in to script.''' parser = argparse.ArgumentParser( description='''phablet demo setup tool. Requires a prior run of phablet-networking-setup -i. If called with no options all demo content available is setup.''') parser.add_argument('-s', '--serial', help='''Device serial. Use when more than one device is connected.''', ) parser.add_argument('--disable-fake-contacts', action='store_true', required=False, default=False, help='Disables setup of demo contacts.' ) parser.add_argument('--disable-fake-messages', action='store_true', required=False, default=False, help='Disables setup of demo messages.' ) parser.add_argument('--disable-fake-pictures', action='store_true', required=False, default=False, help='Disables setup of demo pictures.' ) return parser.parse_args() def setup_fake_pictures(script): script.write('tar -C /home/phablet/Pictures/ --strip-components=1 -xzf ' '/tmp/pictures.tgz\n') return script def setup_fake_contacts(script): script.write('tar -C /home/phablet -xzf /tmp/contacts.tgz \n') script.write('/home/phablet/.local/bin/manage-address-books create \n') return script def setup_fake_conversations(script): script.write('tar -C /home/phablet -xzf /tmp/conversations.tgz \n') return script def provision_device(adb, serial, script): script_dst = '/tmp/provision' adb.push(script, script_dst) adb.chmod(script_dst, '700') adb.shell('sh ' + script_dst) log.info('Getting ready to restart') adb.shell('sync') def main(args): if args.serial: adb = AndroidBridge(args.serial) else: adb = AndroidBridge() dest = '/tmp' script = StringIO.StringIO() script.write(basic_template) if not args.disable_fake_contacts: log.info('Setting up for demo contacts') contact_tar = download('contacts.tgz') adb.push(contact_tar, dest) script = setup_fake_contacts(script) if not args.disable_fake_messages: log.info('Setting up for demo conversations') convo_tar = download('conversations.tgz') adb.push(convo_tar, dest) script = setup_fake_conversations(script) if not args.disable_fake_pictures: log.info('Setting up for demo pictures') pictures_tar = download('pictures.tgz') adb.push(pictures_tar, dest) script = setup_fake_pictures(script) script_file = tempfile.NamedTemporaryFile(delete=False) with script_file as f: f.write(script.getvalue()) script.close() provision_device(adb, args.serial, script_file.name) if __name__ == "__main__": args = parse_arguments() main(args) phablet-tools-1.2+16.04.20160317/phablet-network0000755000015600001650000001106112672627760021547 0ustar pbuserpbgroup00000000000000#!/bin/sh # This program is free software: you can redistribute it and/or modify it # under the terms of the the GNU General Public License version 3, as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranties of # MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR # PURPOSE. See the applicable version of the GNU General Public # License for more details. #. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Copyright (C) 2012 Canonical, Ltd. if [ -f "$(dirname $0)/shell-adb-common.sh" ]; then . "$(dirname $0)/shell-adb-common.sh" else . "/usr/share/phabletutils/shell-adb-common.sh" fi export LC_ALL=C usage() { cat </dev/null" echo echo Network setup complete } wait_for_network() { timeout $WAIT_TIMEOUT sh <. # # Copyright (C) 2014 Canonical, Ltd. set -e usage () { cat </dev/null" } # check if we even have a local ssh setup and keys before starting # bug 1364913 if [ ! -d ~/.ssh ]; then echo "no local key, please run the ssh-keygen command first," echo "then run phablet-shell again" exit 1 fi # if sshd is already runing, do not attempt to start it SSH_RUNNING="$(adb shell pgrep sshd)" # Start ssh on the device and use port forwarding to connect to it. # This means that we'll connect to the device through the USB cable # and won't depend on if the device has it's wifi configured or not. [ -n "$SSH_RUNNING" ] || toggle_ssh true for PORT in `seq 2222 2299`; do adb forward tcp:$PORT tcp:22 && break done SSH_OPTS="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p $PORT" # Purge the device host key so that SSH doesn't print a scary warning about it # (it changes every time the device is reflashed and this is expected) touch ~/.ssh/known_hosts ssh-keygen -f ~/.ssh/known_hosts -R [localhost]:$PORT # Copy your ssh id down to the device so you never need a password. NEWEST_KEY=$(ls -t ~/.ssh/*.pub | grep -v -- -cert.pub | head -1) KEY_CONTENT="$(cat $NEWEST_KEY)" # make sure we have a ~/.ssh/ dir before trying to write to it adb shell "[ -d ~/.ssh ] || mkdir ~/.ssh" # append the key to authorized_keys if it is not there already adb shell "touch ~/.ssh/authorized_keys" if [ -z "$(adb shell "grep \"$KEY_CONTENT\" ~/.ssh/authorized_keys")" ]; then adb shell "echo $KEY_CONTENT >>~/.ssh/authorized_keys" adb shell "chmod 700 ~/.ssh" adb shell "chmod 600 ~/.ssh/authorized_keys" fi # Copy your bash config down to the device so you get the benefit of your # colourful $PS1 prompt and any bash aliases that you may be used to from your # host device. if [ "$COPY_BASHRC" ]; then rsync -qae "ssh $SSH_OPTS" ~/.bashrc phablet@localhost:/home/phablet fi # Now connect to the device and provide the user with a shell. ssh $SSH_OPTS phablet@localhost # turn off ssh access again [ -n "$SSH_RUNNING" ] || toggle_ssh false phablet-tools-1.2+16.04.20160317/phablet-screenshot0000755000015600001650000001220012672627760022227 0ustar pbuserpbgroup00000000000000#!/bin/sh # # Screen capture of Mir devices # # Copyright (C) 2013 Canonical # # Authors: Jean-Baptiste Lallement # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # # Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin # Street, Fifth Floor, Boston, MA 02110-1301 USA set -eu if [ -f "$(dirname $0)/shell-adb-common.sh" ]; then . "$(dirname $0)/shell-adb-common.sh" else . "/usr/share/phabletutils/shell-adb-common.sh" fi PICDIR=$(mktemp -d /tmp/$(basename $0).XXXXXX) FBDEV=fb0 SERIAL="" CONVERTOPTS="-alpha off" REQUIREDPKGS="android-tools-adb imagemagick" size="" cleanup() { # # Cleanup temporary files # [ -d "$PICDIR" ] && rm -Rf "$PICDIR" } trap cleanup EXIT INT QUIT ABRT PIPE TERM usage() { # # Print usage and exit # cat < Dump /dev/$FBDEV from a touch device and write it to FILENAME Arguments: FILENAME Name of the output image, the output format must be supported by convert from the package imagemagick. Options -d,--debug Enable debug -h,--help This help -s,--serial SERIAL Serial number of the device -z,--resize FACTOR Resize the image EOF exit 1 } check_prerequisites() { # Check list of required packages okay=1 pkgs="$REQUIREDPKGS" for pkg in $pkgs; do if ! dpkg-query -W -f '${Status}\t${Package}\n' $pkg 2>/dev/null| grep "ok installed" >/dev/null 2>&1; then okay=0 echo "E: Package '$pkg' is required and is not installed." fi done if [ $okay -ne 1 ]; then echo "E: pre-requisites are not met. Exiting!" exit 1 fi } sf_is_running() { # Return 0 if surface flinger is running then we'll use screencap # instead sf=$(adb shell pidof surfaceflinger) if [ -z "$sf" ]; then return 1 else echo "I: surfaceflinger detected" return 0 fi } screenshot_mir() { # Dump framebuffer to capture Mir screenshot # # Arguments: # $1: Size # $2: Depth # $3: Device codename size=$1 depth=$2 device=$3 sfx="rgba" CONVERTOPTS="$CONVERTOPTS -depth $depth -size $size" MIRFILENAME="/tmp/mir_screencast_$size.$sfx" # for backwards compatibility we check for socket existence and fall # back to the old location if the new socket does not exist SOCKET=$(adb shell "ls /run/mir_socket 2>/dev/null | tr -d '\n'") [ -z "$SOCKET" ] && SOCKET="/tmp/mir_socket" echo "I: Dumping $FBDEV ..." adb shell mirscreencast -m $SOCKET -n1 -f $MIRFILENAME adb pull $MIRFILENAME ${PICDIR}/fb [ ! -e "${PICDIR}/fb" ] && echo "E: Capture failed!" && return convert $CONVERTOPTS $sfx:${PICDIR}/fb[0] "$DST" } get_device() { # Get device name device=$(adb shell getprop ro.product.device) echo "$device"|tr -d '\r' } screenshot_sf() { # Use screencap if surfaceflinger is running echo "I: Capturing screenshot with screencap ..." capfile=screencap.png adb shell /system/bin/screencap /tmp/$capfile adb pull /tmp/$capfile ${PICDIR}/$capfile [ ! -e "${PICDIR}/${capfile}" ] && echo "E: Capture failed!" && return convert $CONVERTOPTS ${PICDIR}/$capfile "$DST" } SHORTOPTS="hdr:s:z:" LONGOPTS="help,debug,resolution:,serial:,resize:" TEMP=$(getopt -o $SHORTOPTS --long $LONGOPTS -- "$@") eval set -- "$TEMP" while true ; do case "$1" in -h|--help) usage;; -d|--debug) set -x shift;; -r|--resolution) echo "I: The '--resolution' option is deprecated" shift 2;; -s|--serial) SERIAL="$2" shift 2;; -z|--resize) CONVERTOPTS="$CONVERTOPTS -resize $2" shift 2;; --) shift; break;; *) usage;; esac done [ $# -eq 0 ] && usage DST="$1" # exporting ANDROID_SERIAL to support multiple devices connected # seamlessly [ -z "$SERIAL" ] || export ANDROID_SERIAL="$SERIAL" check_prerequisites # We want to make sure the adb server is up and running. This is a noop if # the server is already running. adb start-server check_devices if sf_is_running; then # Use screencap for surfaceflinger screenshot_sf else # Otherwise just dump the framebuffer # Set resolution and depth for device depth=8 size="$(adb shell fbset|sed -n -e's/^mode.*\"\([0-9]\+x[0-9]\+\)[-\"].*$/\1/p')" device="$(get_device)" if [ -z "$size" ]; then echo "E: Resolution not found. Device is not supported." exit 1 fi screenshot_mir "$size" "$depth" "$device" fi echo "I: Done" phablet-tools-1.2+16.04.20160317/phablet-bootchart0000755000015600001650000000756012672627760022054 0ustar pbuserpbgroup00000000000000#! /bin/sh set -eu TMPDIR=$(mktemp -d /tmp/$(basename $0).XXXXX) SUITE="trusty" PREFIX="ubuntu-phablet" CHARTOPTS="${CHARTOPTS---crop-after=unity8 --annotate=unity8}" SKIPINST="" KEEPTAR="" PNOPTS="" BUILDID="" OUTDIR="." SFX="png" ERROR="" ADBOPTS="" YESTOALL="" cleanup(){ [ -n "$ERROR" ] && echo "Error: $ERROR" [ -d "$TMPDIR" ] && rm -rf $TMPDIR >/dev/null 2>&1 } usage(){ cat < point to wlan config -o|--outdir define (and create) output dir -f|--format (png|svg) output format (default: png) -s|--serial operate on certain adb device -y|--yes-to-all do not ask when wiping (for automation) If [build id] is provided this image will be used for installation EOF exit 0 } reboot_and_wait(){ adb $ADBOPTS reboot && adb $ADBOPTS wait-for-device [ -n "$1" ] && sleep $1 } do_install(){ if [ -z "$YESTOALL" ]; then echo -n "This will wipe all data on the device, proceed ? (y/n) " read yesno [ "$yesno" != "y" ] && exit 1 fi echo "Installing Image $1" if [ -z "$(fastboot devices)" ]; then adb $ADBOPTS reboot bootloader || \ ERROR="can not reboot to bootloader" exit 1 fi FLASHOPTS="--developer-mode --password 0000 --channel devel-proposed --bootstrap" [ -n "$1" ] && FLASHOPTS="${FLASHOPTS} --revision $1" ubuntu-device-flash $FLASHOPTS adb $ADBOPTS wait-for-device } trap cleanup EXIT INT QUIT ILL KILL SEGV TERM [ -x /usr/bin/pybootchartgui ] || ERROR="please install pybootchartgui" exit 1 while [ $# -gt 0 ]; do case "$1" in -n|--noinstall) SKIPINST=1 ;; -y|--yes-to-all) YESTOALL=1 ;; -k|--keeptarball) KEEPTAR=1 ;; -w|--wlancfg) [ -n "$2" ] && PNOPTS="-n $2" shift || \ ERROR="-w needs a file path" exit 1 ;; -s|--serial) [ -n "$2" ] && ADBOPTS="$ADBOPTS -s $2" shift || \ ERROR="-s needs serial" exit 1 ;; -f|--format) if [ -n "$2" ]; then SFX="$2" shift || \ ERROR="-f needs png or svg as argument" exit 1 CHARTOPTS="$CHARTOPTS -f $SFX" fi ;; -o|--outdir) [ -n "$2" ] && OUTDIR="$2" shift || \ ERROR="-o needs a path" exit 1 [ -d "$OUTDIR" ] || mkdir -p $OUTDIR ;; -h|--help) usage ;; *[0-9]) BUILDID=$1 ;; *) ERROR="$1 is unknown" exit 1 ;; esac shift done [ -z "$SKIPINST" ] && do_install "$BUILDID" echo "Enabling network" phablet-network $PNOPTS || \ ERROR="need working network on the device" exit 1 echo "Making Image writable" phablet-config writable-image || \ ERROR="could not make image writable" exit 1 reboot_and_wait 30 echo "Installing bootchart" adb $ADBOPTS shell "echo 0000|sudo -p \"\" -S \ FLASH_KERNEL_SKIP=true apt-get install -yq --force-yes bootchart" echo "Disabling Welcome Wizard" phablet-config welcome-wizard --disable || \ ERROR="could not disable welcome wizard" exit 1 echo "Disabling Intro Demo" phablet-config edges-intro --disable || \ ERROR="could not disable intro" exit 1 echo "Rebooting three times to get accurate data" reboot_and_wait 60 reboot_and_wait 60 reboot_and_wait 1 adb $ADBOPTS shell "echo 0000|sudo -p \"\" -S rm -rf /var/log/bootchart/*" sleep 60 echo "Pulling and processing bootchart tarball" while [ -n "$(adb $ADBOPTS shell pgrep collector)" ]; do sleep 30 done sleep 30 adb $ADBOPTS pull /var/log/bootchart $TMPDIR/ VER="$(adb $ADBOPTS shell system-image-cli -i | grep "^.* ver" | tr -d '[:cntrl:]')" VER="${VER##* }" SUITE="$(adb $ADBOPTS shell lsb_release -cs | tr -d '[:cntrl:]')" echo "Creating $SFX for $VER." OUTNAME="$OUTDIR/$PREFIX-$SUITE-$VER" CHARTOPTS="$CHARTOPTS -o $OUTNAME.$SFX" pybootchartgui -q $CHARTOPTS $TMPDIR/*.tgz >/dev/null 2>&1 if [ -n "$KEEPTAR" ]; then cp $TMPDIR/*.tgz $OUTNAME.tgz echo "Keeping tarball at $OUTNAME.tgz" fi echo "Created $OUTNAME.$SFX" phablet-tools-1.2+16.04.20160317/phablet-click-test-setup0000755000015600001650000002305012672627760023257 0ustar pbuserpbgroup00000000000000#! /usr/bin/python2.7 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- # Copyright (C) 2013 Canonical Ltd. # Author: Sergio Schvezov # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from __future__ import print_function from launchpadlib.launchpad import Launchpad from phabletutils.device import AndroidBridge from os import path from subprocess import (check_call, check_output) import argparse import atexit import json import os import shutil import tempfile import urllib2 import sys class LP(object): @property def arch_series(self): return self._arch_series @property def archive(self): return self._archive @property def series(self): return self._series def __init__(self, distribution, release, arch): self.lp = Launchpad.login_anonymously('phablet-click-test-setup', 'production', '~/.launchpadlib/cache', version="devel") distro = self.lp.distributions[distribution] self._series = distro.getSeries(name_or_version=release) self._arch_series = self._series.getDistroArchSeries(archtag=arch) self._archive = self.lp.distributions[distribution].main_archive lp = None basic_packages = ( ) class UbuntuDevice(AndroidBridge): def __init__(self, device=None): super(UbuntuDevice, self).__init__(device=device) def get_package_version(self, package): cmd = 'shell dpkg-query --show --showformat \'\${Version}\' %s ' % \ package return check_output(self._cmd % cmd, shell=True) def get_click_manifest(self, user): cmd = 'shell click list --user=%s --manifest' % user return json.loads(check_output(self._cmd % cmd, shell=True)) def parse_arguments(): parser = argparse.ArgumentParser( description='Sets up a device to be tested.') parser.add_argument('--manifest', help='Manifest with package dependencies') parser.add_argument('-s', '--serial', help='''Device serial. Use when more than one device is connected.''', ) parser.add_argument('--click', default=None, help='Specific click package to setup for.' ) parser.add_argument('--user', default='phablet', help='User on device to use') parser.add_argument('--wipe', action='store_true', help='Clean up previous setup on device') parser.add_argument('--distribution', default='ubuntu', help='Selects distribution to use') parser.add_argument('--series', default=None, help='Selects series to use') parser.add_argument('--depends', dest='depends', default=None, nargs='+', help='Packages to copy to the device. Packages cannot \ contain or depend on architecture specifics.') return parser.parse_args() def cleanup(directory): if os.path.exists(directory) and os.path.isdir(directory): print('Removing directory %s' % directory) shutil.rmtree(directory) def get_python_binary_package(package, target_dir): tmp_dir = tempfile.mkdtemp() atexit.register(cleanup, tmp_dir) print('Fetching %s - into %s' % (package, tmp_dir)) bpph = lp.archive.getPublishedBinaries( binary_name=package, distro_arch_series=lp.arch_series, status="Published", pocket='Release', exact_match=True) version = bpph[0].binary_package_version bin_url = bpph[0].binaryFileUrls()[0] print('Downloading %s version %s' % (package, version)) url = urllib2.urlopen(bin_url) data = url.read() package_name = "%s_%s_%s.deb" % (package, version, 'armhf') target = path.join(tmp_dir, package_name) with open(target, "wb") as package: package.write(data) extract_dir = path.join(tmp_dir, 'deb') check_call(['dpkg-deb', '-x', target, extract_dir]) python3_modules_dir = os.path.join(extract_dir, 'usr/lib/python3/dist-packages') if os.path.exists(python3_modules_dir): for f in os.listdir(python3_modules_dir): source = path.join(python3_modules_dir, f) if path.islink(source): source = path.join(python3_modules_dir, os.readlink(source)) print('Moving %s to %s' % (source, target_dir)) shutil.move(source, target_dir) def get_source_package_tests(package, version, target_dir): tmp_dir = tempfile.mkdtemp() atexit.register(cleanup, tmp_dir) print('Fetching %s - into %s' % (package, tmp_dir)) try: sp = lp.archive.getPublishedSources( source_name=package, version=version, distro_series=lp.series, exact_match=True) # TODO needs filtering source_url = sp[0].sourceFileUrls()[0] print('Downloading %s version %s from %s' % (package, version, source_url)) url = urllib2.urlopen(source_url) data = url.read() target = path.join(tmp_dir, 'source_file') with open(target, "wb") as p: p.write(data) check_call(['tar', '-xf', target], cwd=tmp_dir) print('Keeping tests from obtained package') package_source = filter((lambda x: x.startswith(package)), os.listdir(tmp_dir)) # Just let an exception be thrown if more than one match which means # there's a problem somewhere test_base_dir = path.join(tmp_dir, package_source[0], 'tests', 'autopilot') test_dirs = filter((lambda x: path.isdir(path.join(test_base_dir, x))), os.listdir(test_base_dir)) for test_dir in test_dirs: test_dir = path.join(test_base_dir, test_dir) print('Moving %s to %s' % (test_dir, target_dir)) shutil.move(test_dir, target_dir) except IndexError: print('package %s, version %s not found in %s' % (package, version, lp.series)) print('Use --distribution and --series if needed') raise except: print('Unexpected error: ', sys.exc_info()[0]) raise def get_bzr_tests(branch, revision, autopilot_dir, target_dir): tmp_dir = tempfile.mkdtemp() atexit.register(cleanup, tmp_dir) print('Checking out %s to %s' % (branch, path.join(tmp_dir, 'work'))) check_call(['bzr', 'checkout', '--lightweight', branch, '-r', revision, 'work'], cwd=tmp_dir) test_base_dir = path.join(tmp_dir, 'work', autopilot_dir) test_dirs = filter((lambda x: path.isdir(path.join(test_base_dir, x))), os.listdir(test_base_dir)) for test_dir in test_dirs: test_dir = path.join(test_base_dir, test_dir) print('Moving %s to %s' % (test_dir, target_dir)) shutil.move(test_dir, target_dir) def fetch_test_base(adb, test_dir, arch, python_packages=None): if python_packages: for package in python_packages: get_python_binary_package(package, test_dir) for package in basic_packages: binaries = package['binary'] binary = binaries[arch] if arch in binaries else binaries['all'] version = adb.get_package_version(binary) get_source_package_tests(package['source'], version, test_dir) def fetch_click_tests(adb, test_dir, user, click=None): manifest = adb.get_click_manifest(user) if click: print('Only setting up for %s' % click) manifest = [entry for entry in manifest if click == entry['name']] print('Only keeping entries with x-source') manifest = [entry for entry in manifest if 'x-source' in entry] for entry in manifest: get_bzr_tests(entry['x-source']['vcs-bzr'], entry['x-source']['vcs-bzr-revno'], 'tests/autopilot', test_dir) def main(): global lp args = parse_arguments() adb = UbuntuDevice(args.serial) adb.start() arch = adb.shell('sudo -iu phablet dpkg --print-architecture').strip() if not args.series: args.series = adb.shell('lsb_release -c -s').strip() lp = LP(args.distribution, args.series, arch) test_dir = tempfile.mkdtemp() atexit.register(cleanup, test_dir) fetch_test_base(adb, test_dir, arch, args.depends) fetch_click_tests(adb, test_dir, args.user, args.click) destination = path.join('/home', args.user, 'autopilot') if args.wipe: print('Clearing previous test setup in %s' % destination) adb.shell('rm -Rf %s' % destination) adb.push(test_dir, destination) adb.chown(args.user, destination) print('Files setup in %s on device' % destination) if __name__ == '__main__': main() phablet-tools-1.2+16.04.20160317/phablet-dev-bootstrap0000755000015600001650000001265412672627760022660 0ustar pbuserpbgroup00000000000000#! /usr/bin/env python2.7 # This program is free software: you can redistribute it and/or modify it # under the terms of the the GNU General Public License version 3, as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranties of # MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR # PURPOSE. See the applicable version of the GNU General Public # License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Copyright (C) 2013 Canonical, Ltd. # TODO Install packages # TODO allow new vendor setup from existing repo import argparse import logging import os import subprocess from os import path logging.basicConfig(level=logging.DEBUG) log = logging.getLogger() log.name = 'phablet-dev-bootstrap' repo = { 'aosp': 'https://code-review.phablet.ubuntu.com/p/aosp/platform/manifest.git', } repo_branch = 'phablet-4.4.2_r1' valid_vendors = ('mako', 'flo', 'deb', 'manta', 'hammerhead', 'generic') vendor_blobs = 'lp:~phablet-team/phablet-tools/aosp-vendor-4.4.2' class StringSplitAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): setattr(namespace, self.dest, values.split(',')) def validate_vendors(vendors): for vendor in vendors: if vendor not in valid_vendors: log.error('Vendor device %s not supported' % vendor) exit(1) def setup_sync_dir(target_directory, continue_sync=False): '''Creates and changes to target directory''' if not continue_sync: try: if os.path.isfile(target_directory): raise OSError('%s is not a directory' % target_directory) elif not os.path.isdir(target_directory): log.debug('Creating sync directory %s' % target_directory) os.mkdir(target_directory) elif os.listdir(target_directory): raise OSError('%s is not empty and not using -c' % target_directory) except OSError as e: if not e.message: log.error('Cannot setup environment in %s' % target_directory) else: log.error(e.message) exit(1) log.info('Changing to workdir %s' % target_directory) os.chdir(target_directory) def sync_repository(source, branch, jobs='1', reference=None): '''Syncs android sources with the repo command''' try: log.info('Initializing repository') init_cmd = ['repo', 'init', '-u', repo[source], '-b', branch] if reference: init_cmd += ['--reference', reference] subprocess.check_call(init_cmd) subprocess.check_call(['repo', 'sync', '-j%s' % jobs] ) except subprocess.CalledProcessError: log.error('Error while trying to sync repository') exit(1) def sync_vendors(vendors): cmd = '''bzr branch %s vendor''' % vendor_blobs log.debug('Executing %s' % cmd) subprocess.check_call(cmd, shell=True, executable='/bin/bash') def parse_arguments(): parser = argparse.ArgumentParser( description='Phablet Development Environment Setup Tool') parser.add_argument('-v', '--vendors', dest='vendors', help='''Comma separated list of devices to Setup such as mako, flo, deb, manta, hammerhead, generic''', action=StringSplitAction, ) parser.add_argument('-j', '--jobs', dest='jobs', help='''Ammount of sync jobs''', default='1', ) parser.add_argument('-c', '--continue', dest='continue_sync', action='store_true', help='''Continue a previously started sync''', default=False, ) parser.add_argument('-r', '--reference', help='Use another dev environment as reference for ' 'git', default='', ) parser.add_argument('--repo-branch', help='Choose branch to init from', default=repo_branch, ) parser.add_argument('--sources', default='aosp', choices=['aosp'], help='Use to select a different source target.', ) parser.add_argument('target_directory', help='Target directory for sources', ) return parser.parse_args() def main(args): if args.vendors: validate_vendors(args.vendors) setup_sync_dir(path.abspath(path.expanduser(args.target_directory)), args.continue_sync) sync_repository(args.sources, args.repo_branch, args.jobs, args.reference) if args.vendors: sync_vendors(args.vendors) if __name__ == "__main__": args = parse_arguments() main(args)