fb2docker: New directory
This commit is contained in:
parent
3bb2e8f8ac
commit
3d6c5d840f
41
fb2docker/products.json
Normal file
41
fb2docker/products.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"comment": "B2Docker Fedora Remix",
|
||||
|
||||
"osname": "fb2docker",
|
||||
"repo": "http://rpm-ostree.cloud.fedoraproject.org/repo",
|
||||
|
||||
"gpg_key": "843833DF",
|
||||
|
||||
"architectures": ["x86_64"],
|
||||
|
||||
"releases": ["20", "rawhide"],
|
||||
|
||||
"add-repos": ["walters-rpm-ostree"],
|
||||
|
||||
"selinux": false,
|
||||
|
||||
"bootstrap_base": ["filesystem", "glibc", "nss-altfiles", "shadow-utils"],
|
||||
|
||||
"base_required_packages": ["kernel", "ostree", "fedora-release", "lvm2",
|
||||
"btrfs-progs", "e2fsprogs", "xfsprogs",
|
||||
"rpm-ostree-public-gpg-key", "gnupg2"],
|
||||
|
||||
"postprocess": ["remove-root-password"],
|
||||
|
||||
"products":
|
||||
{
|
||||
"core":
|
||||
{
|
||||
"docker": { "packages": ["docker-io", "NetworkManager", "vim-minimal", "nano"],
|
||||
"units": ["docker.service"],
|
||||
"postprocess": ["remove-locales",
|
||||
"remove-gpu-drivers",
|
||||
"remove-docs"],
|
||||
"disk": { "sizeMb": 1024,
|
||||
"bootsizeMb": 0,
|
||||
"swapsizeMb": 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
911
fb2docker/web/angular-route.js
vendored
Normal file
911
fb2docker/web/angular-route.js
vendored
Normal file
@ -0,0 +1,911 @@
|
||||
/**
|
||||
* @license AngularJS v1.2.8
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name ngRoute
|
||||
* @description
|
||||
*
|
||||
* # ngRoute
|
||||
*
|
||||
* The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
|
||||
*
|
||||
* ## Example
|
||||
* See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
|
||||
*
|
||||
* {@installModule route}
|
||||
*
|
||||
* <div doc-module-components="ngRoute"></div>
|
||||
*/
|
||||
/* global -ngRouteModule */
|
||||
var ngRouteModule = angular.module('ngRoute', ['ng']).
|
||||
provider('$route', $RouteProvider);
|
||||
|
||||
/**
|
||||
* @ngdoc object
|
||||
* @name ngRoute.$routeProvider
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* Used for configuring routes.
|
||||
*
|
||||
* ## Example
|
||||
* See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
|
||||
*
|
||||
* ## Dependencies
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*/
|
||||
function $RouteProvider(){
|
||||
function inherit(parent, extra) {
|
||||
return angular.extend(new (angular.extend(function() {}, {prototype:parent}))(), extra);
|
||||
}
|
||||
|
||||
var routes = {};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name ngRoute.$routeProvider#when
|
||||
* @methodOf ngRoute.$routeProvider
|
||||
*
|
||||
* @param {string} path Route path (matched against `$location.path`). If `$location.path`
|
||||
* contains redundant trailing slash or is missing one, the route will still match and the
|
||||
* `$location.path` will be updated to add or drop the trailing slash to exactly match the
|
||||
* route definition.
|
||||
*
|
||||
* * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up
|
||||
* to the next slash are matched and stored in `$routeParams` under the given `name`
|
||||
* when the route matches.
|
||||
* * `path` can contain named groups starting with a colon and ending with a star:
|
||||
* e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name`
|
||||
* when the route matches.
|
||||
* * `path` can contain optional named groups with a question mark: e.g.`:name?`.
|
||||
*
|
||||
* For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
|
||||
* `/color/brown/largecode/code/with/slashs/edit` and extract:
|
||||
*
|
||||
* * `color: brown`
|
||||
* * `largecode: code/with/slashs`.
|
||||
*
|
||||
*
|
||||
* @param {Object} route Mapping information to be assigned to `$route.current` on route
|
||||
* match.
|
||||
*
|
||||
* Object properties:
|
||||
*
|
||||
* - `controller` – `{(string|function()=}` – Controller fn that should be associated with
|
||||
* newly created scope or the name of a {@link angular.Module#controller registered
|
||||
* controller} if passed as a string.
|
||||
* - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
|
||||
* published to scope under the `controllerAs` name.
|
||||
* - `template` – `{string=|function()=}` – html template as a string or a function that
|
||||
* returns an html template as a string which should be used by {@link
|
||||
* ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
|
||||
* This property takes precedence over `templateUrl`.
|
||||
*
|
||||
* If `template` is a function, it will be called with the following parameters:
|
||||
*
|
||||
* - `{Array.<Object>}` - route parameters extracted from the current
|
||||
* `$location.path()` by applying the current route
|
||||
*
|
||||
* - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
|
||||
* template that should be used by {@link ngRoute.directive:ngView ngView}.
|
||||
*
|
||||
* If `templateUrl` is a function, it will be called with the following parameters:
|
||||
*
|
||||
* - `{Array.<Object>}` - route parameters extracted from the current
|
||||
* `$location.path()` by applying the current route
|
||||
*
|
||||
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
|
||||
* be injected into the controller. If any of these dependencies are promises, the router
|
||||
* will wait for them all to be resolved or one to be rejected before the controller is
|
||||
* instantiated.
|
||||
* If all the promises are resolved successfully, the values of the resolved promises are
|
||||
* injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is
|
||||
* fired. If any of the promises are rejected the
|
||||
* {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. The map object
|
||||
* is:
|
||||
*
|
||||
* - `key` – `{string}`: a name of a dependency to be injected into the controller.
|
||||
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
|
||||
* Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected}
|
||||
* and the return value is treated as the dependency. If the result is a promise, it is
|
||||
* resolved before its value is injected into the controller. Be aware that
|
||||
* `ngRoute.$routeParams` will still refer to the previous route within these resolve
|
||||
* functions. Use `$route.current.params` to access the new route parameters, instead.
|
||||
*
|
||||
* - `redirectTo` – {(string|function())=} – value to update
|
||||
* {@link ng.$location $location} path with and trigger route redirection.
|
||||
*
|
||||
* If `redirectTo` is a function, it will be called with the following parameters:
|
||||
*
|
||||
* - `{Object.<string>}` - route parameters extracted from the current
|
||||
* `$location.path()` by applying the current route templateUrl.
|
||||
* - `{string}` - current `$location.path()`
|
||||
* - `{Object}` - current `$location.search()`
|
||||
*
|
||||
* The custom `redirectTo` function is expected to return a string which will be used
|
||||
* to update `$location.path()` and `$location.search()`.
|
||||
*
|
||||
* - `[reloadOnSearch=true]` - {boolean=} - reload route when only `$location.search()`
|
||||
* or `$location.hash()` changes.
|
||||
*
|
||||
* If the option is set to `false` and url in the browser changes, then
|
||||
* `$routeUpdate` event is broadcasted on the root scope.
|
||||
*
|
||||
* - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
|
||||
*
|
||||
* If the option is set to `true`, then the particular route can be matched without being
|
||||
* case sensitive
|
||||
*
|
||||
* @returns {Object} self
|
||||
*
|
||||
* @description
|
||||
* Adds a new route definition to the `$route` service.
|
||||
*/
|
||||
this.when = function(path, route) {
|
||||
routes[path] = angular.extend(
|
||||
{reloadOnSearch: true},
|
||||
route,
|
||||
path && pathRegExp(path, route)
|
||||
);
|
||||
|
||||
// create redirection for trailing slashes
|
||||
if (path) {
|
||||
var redirectPath = (path[path.length-1] == '/')
|
||||
? path.substr(0, path.length-1)
|
||||
: path +'/';
|
||||
|
||||
routes[redirectPath] = angular.extend(
|
||||
{redirectTo: path},
|
||||
pathRegExp(redirectPath, route)
|
||||
);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param path {string} path
|
||||
* @param opts {Object} options
|
||||
* @return {?Object}
|
||||
*
|
||||
* @description
|
||||
* Normalizes the given path, returning a regular expression
|
||||
* and the original path.
|
||||
*
|
||||
* Inspired by pathRexp in visionmedia/express/lib/utils.js.
|
||||
*/
|
||||
function pathRegExp(path, opts) {
|
||||
var insensitive = opts.caseInsensitiveMatch,
|
||||
ret = {
|
||||
originalPath: path,
|
||||
regexp: path
|
||||
},
|
||||
keys = ret.keys = [];
|
||||
|
||||
path = path
|
||||
.replace(/([().])/g, '\\$1')
|
||||
.replace(/(\/)?:(\w+)([\?|\*])?/g, function(_, slash, key, option){
|
||||
var optional = option === '?' ? option : null;
|
||||
var star = option === '*' ? option : null;
|
||||
keys.push({ name: key, optional: !!optional });
|
||||
slash = slash || '';
|
||||
return ''
|
||||
+ (optional ? '' : slash)
|
||||
+ '(?:'
|
||||
+ (optional ? slash : '')
|
||||
+ (star && '(.+?)' || '([^/]+)')
|
||||
+ (optional || '')
|
||||
+ ')'
|
||||
+ (optional || '');
|
||||
})
|
||||
.replace(/([\/$\*])/g, '\\$1');
|
||||
|
||||
ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name ngRoute.$routeProvider#otherwise
|
||||
* @methodOf ngRoute.$routeProvider
|
||||
*
|
||||
* @description
|
||||
* Sets route definition that will be used on route change when no other route definition
|
||||
* is matched.
|
||||
*
|
||||
* @param {Object} params Mapping information to be assigned to `$route.current`.
|
||||
* @returns {Object} self
|
||||
*/
|
||||
this.otherwise = function(params) {
|
||||
this.when(null, params);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
this.$get = ['$rootScope',
|
||||
'$location',
|
||||
'$routeParams',
|
||||
'$q',
|
||||
'$injector',
|
||||
'$http',
|
||||
'$templateCache',
|
||||
'$sce',
|
||||
function($rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) {
|
||||
|
||||
/**
|
||||
* @ngdoc object
|
||||
* @name ngRoute.$route
|
||||
* @requires $location
|
||||
* @requires $routeParams
|
||||
*
|
||||
* @property {Object} current Reference to the current route definition.
|
||||
* The route definition contains:
|
||||
*
|
||||
* - `controller`: The controller constructor as define in route definition.
|
||||
* - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
|
||||
* controller instantiation. The `locals` contain
|
||||
* the resolved values of the `resolve` map. Additionally the `locals` also contain:
|
||||
*
|
||||
* - `$scope` - The current route scope.
|
||||
* - `$template` - The current route template HTML.
|
||||
*
|
||||
* @property {Array.<Object>} routes Array of all configured routes.
|
||||
*
|
||||
* @description
|
||||
* `$route` is used for deep-linking URLs to controllers and views (HTML partials).
|
||||
* It watches `$location.url()` and tries to map the path to an existing route definition.
|
||||
*
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*
|
||||
* You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API.
|
||||
*
|
||||
* The `$route` service is typically used in conjunction with the
|
||||
* {@link ngRoute.directive:ngView `ngView`} directive and the
|
||||
* {@link ngRoute.$routeParams `$routeParams`} service.
|
||||
*
|
||||
* @example
|
||||
This example shows how changing the URL hash causes the `$route` to match a route against the
|
||||
URL, and the `ngView` pulls in the partial.
|
||||
|
||||
Note that this example is using {@link ng.directive:script inlined templates}
|
||||
to get it working on jsfiddle as well.
|
||||
|
||||
<example module="ngViewExample" deps="angular-route.js">
|
||||
<file name="index.html">
|
||||
<div ng-controller="MainCntl">
|
||||
Choose:
|
||||
<a href="Book/Moby">Moby</a> |
|
||||
<a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
||||
<a href="Book/Gatsby">Gatsby</a> |
|
||||
<a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
||||
<a href="Book/Scarlet">Scarlet Letter</a><br/>
|
||||
|
||||
<div ng-view></div>
|
||||
<hr />
|
||||
|
||||
<pre>$location.path() = {{$location.path()}}</pre>
|
||||
<pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
|
||||
<pre>$route.current.params = {{$route.current.params}}</pre>
|
||||
<pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
|
||||
<pre>$routeParams = {{$routeParams}}</pre>
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="book.html">
|
||||
controller: {{name}}<br />
|
||||
Book Id: {{params.bookId}}<br />
|
||||
</file>
|
||||
|
||||
<file name="chapter.html">
|
||||
controller: {{name}}<br />
|
||||
Book Id: {{params.bookId}}<br />
|
||||
Chapter Id: {{params.chapterId}}
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
angular.module('ngViewExample', ['ngRoute'])
|
||||
|
||||
.config(function($routeProvider, $locationProvider) {
|
||||
$routeProvider.when('/Book/:bookId', {
|
||||
templateUrl: 'book.html',
|
||||
controller: BookCntl,
|
||||
resolve: {
|
||||
// I will cause a 1 second delay
|
||||
delay: function($q, $timeout) {
|
||||
var delay = $q.defer();
|
||||
$timeout(delay.resolve, 1000);
|
||||
return delay.promise;
|
||||
}
|
||||
}
|
||||
});
|
||||
$routeProvider.when('/Book/:bookId/ch/:chapterId', {
|
||||
templateUrl: 'chapter.html',
|
||||
controller: ChapterCntl
|
||||
});
|
||||
|
||||
// configure html5 to get links working on jsfiddle
|
||||
$locationProvider.html5Mode(true);
|
||||
});
|
||||
|
||||
function MainCntl($scope, $route, $routeParams, $location) {
|
||||
$scope.$route = $route;
|
||||
$scope.$location = $location;
|
||||
$scope.$routeParams = $routeParams;
|
||||
}
|
||||
|
||||
function BookCntl($scope, $routeParams) {
|
||||
$scope.name = "BookCntl";
|
||||
$scope.params = $routeParams;
|
||||
}
|
||||
|
||||
function ChapterCntl($scope, $routeParams) {
|
||||
$scope.name = "ChapterCntl";
|
||||
$scope.params = $routeParams;
|
||||
}
|
||||
</file>
|
||||
|
||||
<file name="scenario.js">
|
||||
it('should load and compile correct template', function() {
|
||||
element('a:contains("Moby: Ch1")').click();
|
||||
var content = element('.doc-example-live [ng-view]').text();
|
||||
expect(content).toMatch(/controller\: ChapterCntl/);
|
||||
expect(content).toMatch(/Book Id\: Moby/);
|
||||
expect(content).toMatch(/Chapter Id\: 1/);
|
||||
|
||||
element('a:contains("Scarlet")').click();
|
||||
sleep(2); // promises are not part of scenario waiting
|
||||
content = element('.doc-example-live [ng-view]').text();
|
||||
expect(content).toMatch(/controller\: BookCntl/);
|
||||
expect(content).toMatch(/Book Id\: Scarlet/);
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngRoute.$route#$routeChangeStart
|
||||
* @eventOf ngRoute.$route
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
* Broadcasted before a route change. At this point the route services starts
|
||||
* resolving all of the dependencies needed for the route change to occurs.
|
||||
* Typically this involves fetching the view template as well as any dependencies
|
||||
* defined in `resolve` route property. Once all of the dependencies are resolved
|
||||
* `$routeChangeSuccess` is fired.
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object.
|
||||
* @param {Route} next Future route information.
|
||||
* @param {Route} current Current route information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngRoute.$route#$routeChangeSuccess
|
||||
* @eventOf ngRoute.$route
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
* Broadcasted after a route dependencies are resolved.
|
||||
* {@link ngRoute.directive:ngView ngView} listens for the directive
|
||||
* to instantiate the controller and render the view.
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object.
|
||||
* @param {Route} current Current route information.
|
||||
* @param {Route|Undefined} previous Previous route information, or undefined if current is
|
||||
* first route entered.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngRoute.$route#$routeChangeError
|
||||
* @eventOf ngRoute.$route
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
* Broadcasted if any of the resolve promises are rejected.
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object
|
||||
* @param {Route} current Current route information.
|
||||
* @param {Route} previous Previous route information.
|
||||
* @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngRoute.$route#$routeUpdate
|
||||
* @eventOf ngRoute.$route
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
*
|
||||
* The `reloadOnSearch` property has been set to false, and we are reusing the same
|
||||
* instance of the Controller.
|
||||
*/
|
||||
|
||||
var forceReload = false,
|
||||
$route = {
|
||||
routes: routes,
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name ngRoute.$route#reload
|
||||
* @methodOf ngRoute.$route
|
||||
*
|
||||
* @description
|
||||
* Causes `$route` service to reload the current route even if
|
||||
* {@link ng.$location $location} hasn't changed.
|
||||
*
|
||||
* As a result of that, {@link ngRoute.directive:ngView ngView}
|
||||
* creates new scope, reinstantiates the controller.
|
||||
*/
|
||||
reload: function() {
|
||||
forceReload = true;
|
||||
$rootScope.$evalAsync(updateRoute);
|
||||
}
|
||||
};
|
||||
|
||||
$rootScope.$on('$locationChangeSuccess', updateRoute);
|
||||
|
||||
return $route;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @param on {string} current url
|
||||
* @param route {Object} route regexp to match the url against
|
||||
* @return {?Object}
|
||||
*
|
||||
* @description
|
||||
* Check if the route matches the current url.
|
||||
*
|
||||
* Inspired by match in
|
||||
* visionmedia/express/lib/router/router.js.
|
||||
*/
|
||||
function switchRouteMatcher(on, route) {
|
||||
var keys = route.keys,
|
||||
params = {};
|
||||
|
||||
if (!route.regexp) return null;
|
||||
|
||||
var m = route.regexp.exec(on);
|
||||
if (!m) return null;
|
||||
|
||||
for (var i = 1, len = m.length; i < len; ++i) {
|
||||
var key = keys[i - 1];
|
||||
|
||||
var val = 'string' == typeof m[i]
|
||||
? decodeURIComponent(m[i])
|
||||
: m[i];
|
||||
|
||||
if (key && val) {
|
||||
params[key.name] = val;
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
function updateRoute() {
|
||||
var next = parseRoute(),
|
||||
last = $route.current;
|
||||
|
||||
if (next && last && next.$$route === last.$$route
|
||||
&& angular.equals(next.pathParams, last.pathParams)
|
||||
&& !next.reloadOnSearch && !forceReload) {
|
||||
last.params = next.params;
|
||||
angular.copy(last.params, $routeParams);
|
||||
$rootScope.$broadcast('$routeUpdate', last);
|
||||
} else if (next || last) {
|
||||
forceReload = false;
|
||||
$rootScope.$broadcast('$routeChangeStart', next, last);
|
||||
$route.current = next;
|
||||
if (next) {
|
||||
if (next.redirectTo) {
|
||||
if (angular.isString(next.redirectTo)) {
|
||||
$location.path(interpolate(next.redirectTo, next.params)).search(next.params)
|
||||
.replace();
|
||||
} else {
|
||||
$location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
|
||||
.replace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$q.when(next).
|
||||
then(function() {
|
||||
if (next) {
|
||||
var locals = angular.extend({}, next.resolve),
|
||||
template, templateUrl;
|
||||
|
||||
angular.forEach(locals, function(value, key) {
|
||||
locals[key] = angular.isString(value) ?
|
||||
$injector.get(value) : $injector.invoke(value);
|
||||
});
|
||||
|
||||
if (angular.isDefined(template = next.template)) {
|
||||
if (angular.isFunction(template)) {
|
||||
template = template(next.params);
|
||||
}
|
||||
} else if (angular.isDefined(templateUrl = next.templateUrl)) {
|
||||
if (angular.isFunction(templateUrl)) {
|
||||
templateUrl = templateUrl(next.params);
|
||||
}
|
||||
templateUrl = $sce.getTrustedResourceUrl(templateUrl);
|
||||
if (angular.isDefined(templateUrl)) {
|
||||
next.loadedTemplateUrl = templateUrl;
|
||||
template = $http.get(templateUrl, {cache: $templateCache}).
|
||||
then(function(response) { return response.data; });
|
||||
}
|
||||
}
|
||||
if (angular.isDefined(template)) {
|
||||
locals['$template'] = template;
|
||||
}
|
||||
return $q.all(locals);
|
||||
}
|
||||
}).
|
||||
// after route change
|
||||
then(function(locals) {
|
||||
if (next == $route.current) {
|
||||
if (next) {
|
||||
next.locals = locals;
|
||||
angular.copy(next.params, $routeParams);
|
||||
}
|
||||
$rootScope.$broadcast('$routeChangeSuccess', next, last);
|
||||
}
|
||||
}, function(error) {
|
||||
if (next == $route.current) {
|
||||
$rootScope.$broadcast('$routeChangeError', next, last, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @returns the current active route, by matching it against the URL
|
||||
*/
|
||||
function parseRoute() {
|
||||
// Match a route
|
||||
var params, match;
|
||||
angular.forEach(routes, function(route, path) {
|
||||
if (!match && (params = switchRouteMatcher($location.path(), route))) {
|
||||
match = inherit(route, {
|
||||
params: angular.extend({}, $location.search(), params),
|
||||
pathParams: params});
|
||||
match.$$route = route;
|
||||
}
|
||||
});
|
||||
// No route matched; fallback to "otherwise" route
|
||||
return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns interpolation of the redirect path with the parameters
|
||||
*/
|
||||
function interpolate(string, params) {
|
||||
var result = [];
|
||||
angular.forEach((string||'').split(':'), function(segment, i) {
|
||||
if (i === 0) {
|
||||
result.push(segment);
|
||||
} else {
|
||||
var segmentMatch = segment.match(/(\w+)(.*)/);
|
||||
var key = segmentMatch[1];
|
||||
result.push(params[key]);
|
||||
result.push(segmentMatch[2] || '');
|
||||
delete params[key];
|
||||
}
|
||||
});
|
||||
return result.join('');
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
ngRouteModule.provider('$routeParams', $RouteParamsProvider);
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc object
|
||||
* @name ngRoute.$routeParams
|
||||
* @requires $route
|
||||
*
|
||||
* @description
|
||||
* The `$routeParams` service allows you to retrieve the current set of route parameters.
|
||||
*
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*
|
||||
* The route parameters are a combination of {@link ng.$location `$location`}'s
|
||||
* {@link ng.$location#methods_search `search()`} and {@link ng.$location#methods_path `path()`}.
|
||||
* The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched.
|
||||
*
|
||||
* In case of parameter name collision, `path` params take precedence over `search` params.
|
||||
*
|
||||
* The service guarantees that the identity of the `$routeParams` object will remain unchanged
|
||||
* (but its properties will likely change) even when a route change occurs.
|
||||
*
|
||||
* Note that the `$routeParams` are only updated *after* a route change completes successfully.
|
||||
* This means that you cannot rely on `$routeParams` being correct in route resolve functions.
|
||||
* Instead you can use `$route.current.params` to access the new route's parameters.
|
||||
*
|
||||
* @example
|
||||
* <pre>
|
||||
* // Given:
|
||||
* // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
|
||||
* // Route: /Chapter/:chapterId/Section/:sectionId
|
||||
* //
|
||||
* // Then
|
||||
* $routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
|
||||
* </pre>
|
||||
*/
|
||||
function $RouteParamsProvider() {
|
||||
this.$get = function() { return {}; };
|
||||
}
|
||||
|
||||
ngRouteModule.directive('ngView', ngViewFactory);
|
||||
ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngRoute.directive:ngView
|
||||
* @restrict ECA
|
||||
*
|
||||
* @description
|
||||
* # Overview
|
||||
* `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
|
||||
* including the rendered template of the current route into the main layout (`index.html`) file.
|
||||
* Every time the current route changes, the included view changes with it according to the
|
||||
* configuration of the `$route` service.
|
||||
*
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*
|
||||
* @animations
|
||||
* enter - animation is used to bring new content into the browser.
|
||||
* leave - animation is used to animate existing content away.
|
||||
*
|
||||
* The enter and leave animation occur concurrently.
|
||||
*
|
||||
* @scope
|
||||
* @priority 400
|
||||
* @example
|
||||
<example module="ngViewExample" deps="angular-route.js" animations="true">
|
||||
<file name="index.html">
|
||||
<div ng-controller="MainCntl as main">
|
||||
Choose:
|
||||
<a href="Book/Moby">Moby</a> |
|
||||
<a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
||||
<a href="Book/Gatsby">Gatsby</a> |
|
||||
<a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
||||
<a href="Book/Scarlet">Scarlet Letter</a><br/>
|
||||
|
||||
<div class="view-animate-container">
|
||||
<div ng-view class="view-animate"></div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<pre>$location.path() = {{main.$location.path()}}</pre>
|
||||
<pre>$route.current.templateUrl = {{main.$route.current.templateUrl}}</pre>
|
||||
<pre>$route.current.params = {{main.$route.current.params}}</pre>
|
||||
<pre>$route.current.scope.name = {{main.$route.current.scope.name}}</pre>
|
||||
<pre>$routeParams = {{main.$routeParams}}</pre>
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="book.html">
|
||||
<div>
|
||||
controller: {{book.name}}<br />
|
||||
Book Id: {{book.params.bookId}}<br />
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="chapter.html">
|
||||
<div>
|
||||
controller: {{chapter.name}}<br />
|
||||
Book Id: {{chapter.params.bookId}}<br />
|
||||
Chapter Id: {{chapter.params.chapterId}}
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="animations.css">
|
||||
.view-animate-container {
|
||||
position:relative;
|
||||
height:100px!important;
|
||||
position:relative;
|
||||
background:white;
|
||||
border:1px solid black;
|
||||
height:40px;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.view-animate {
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
.view-animate.ng-enter, .view-animate.ng-leave {
|
||||
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
||||
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
||||
|
||||
display:block;
|
||||
width:100%;
|
||||
border-left:1px solid black;
|
||||
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
right:0;
|
||||
bottom:0;
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
.view-animate.ng-enter {
|
||||
left:100%;
|
||||
}
|
||||
.view-animate.ng-enter.ng-enter-active {
|
||||
left:0;
|
||||
}
|
||||
.view-animate.ng-leave.ng-leave-active {
|
||||
left:-100%;
|
||||
}
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
angular.module('ngViewExample', ['ngRoute', 'ngAnimate'],
|
||||
function($routeProvider, $locationProvider) {
|
||||
$routeProvider.when('/Book/:bookId', {
|
||||
templateUrl: 'book.html',
|
||||
controller: BookCntl,
|
||||
controllerAs: 'book'
|
||||
});
|
||||
$routeProvider.when('/Book/:bookId/ch/:chapterId', {
|
||||
templateUrl: 'chapter.html',
|
||||
controller: ChapterCntl,
|
||||
controllerAs: 'chapter'
|
||||
});
|
||||
|
||||
// configure html5 to get links working on jsfiddle
|
||||
$locationProvider.html5Mode(true);
|
||||
});
|
||||
|
||||
function MainCntl($route, $routeParams, $location) {
|
||||
this.$route = $route;
|
||||
this.$location = $location;
|
||||
this.$routeParams = $routeParams;
|
||||
}
|
||||
|
||||
function BookCntl($routeParams) {
|
||||
this.name = "BookCntl";
|
||||
this.params = $routeParams;
|
||||
}
|
||||
|
||||
function ChapterCntl($routeParams) {
|
||||
this.name = "ChapterCntl";
|
||||
this.params = $routeParams;
|
||||
}
|
||||
</file>
|
||||
|
||||
<file name="scenario.js">
|
||||
it('should load and compile correct template', function() {
|
||||
element('a:contains("Moby: Ch1")').click();
|
||||
var content = element('.doc-example-live [ng-view]').text();
|
||||
expect(content).toMatch(/controller\: ChapterCntl/);
|
||||
expect(content).toMatch(/Book Id\: Moby/);
|
||||
expect(content).toMatch(/Chapter Id\: 1/);
|
||||
|
||||
element('a:contains("Scarlet")').click();
|
||||
content = element('.doc-example-live [ng-view]').text();
|
||||
expect(content).toMatch(/controller\: BookCntl/);
|
||||
expect(content).toMatch(/Book Id\: Scarlet/);
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngRoute.directive:ngView#$viewContentLoaded
|
||||
* @eventOf ngRoute.directive:ngView
|
||||
* @eventType emit on the current ngView scope
|
||||
* @description
|
||||
* Emitted every time the ngView content is reloaded.
|
||||
*/
|
||||
ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate'];
|
||||
function ngViewFactory( $route, $anchorScroll, $animate) {
|
||||
return {
|
||||
restrict: 'ECA',
|
||||
terminal: true,
|
||||
priority: 400,
|
||||
transclude: 'element',
|
||||
link: function(scope, $element, attr, ctrl, $transclude) {
|
||||
var currentScope,
|
||||
currentElement,
|
||||
autoScrollExp = attr.autoscroll,
|
||||
onloadExp = attr.onload || '';
|
||||
|
||||
scope.$on('$routeChangeSuccess', update);
|
||||
update();
|
||||
|
||||
function cleanupLastView() {
|
||||
if (currentScope) {
|
||||
currentScope.$destroy();
|
||||
currentScope = null;
|
||||
}
|
||||
if(currentElement) {
|
||||
$animate.leave(currentElement);
|
||||
currentElement = null;
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
var locals = $route.current && $route.current.locals,
|
||||
template = locals && locals.$template;
|
||||
|
||||
if (angular.isDefined(template)) {
|
||||
var newScope = scope.$new();
|
||||
var current = $route.current;
|
||||
|
||||
// Note: This will also link all children of ng-view that were contained in the original
|
||||
// html. If that content contains controllers, ... they could pollute/change the scope.
|
||||
// However, using ng-view on an element with additional content does not make sense...
|
||||
// Note: We can't remove them in the cloneAttchFn of $transclude as that
|
||||
// function is called before linking the content, which would apply child
|
||||
// directives to non existing elements.
|
||||
var clone = $transclude(newScope, function(clone) {
|
||||
$animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
|
||||
if (angular.isDefined(autoScrollExp)
|
||||
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
||||
$anchorScroll();
|
||||
}
|
||||
});
|
||||
cleanupLastView();
|
||||
});
|
||||
|
||||
currentElement = clone;
|
||||
currentScope = current.scope = newScope;
|
||||
currentScope.$emit('$viewContentLoaded');
|
||||
currentScope.$eval(onloadExp);
|
||||
} else {
|
||||
cleanupLastView();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// This directive is called during the $transclude call of the first `ngView` directive.
|
||||
// It will replace and compile the content of the element with the loaded template.
|
||||
// We need this directive so that the element content is already filled when
|
||||
// the link function of another directive on the same element as ngView
|
||||
// is called.
|
||||
ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route'];
|
||||
function ngViewFillContentFactory($compile, $controller, $route) {
|
||||
return {
|
||||
restrict: 'ECA',
|
||||
priority: -400,
|
||||
link: function(scope, $element) {
|
||||
var current = $route.current,
|
||||
locals = current.locals;
|
||||
|
||||
$element.html(locals.$template);
|
||||
|
||||
var link = $compile($element.contents());
|
||||
|
||||
if (current.controller) {
|
||||
locals.$scope = scope;
|
||||
var controller = $controller(current.controller, locals);
|
||||
if (current.controllerAs) {
|
||||
scope[current.controllerAs] = controller;
|
||||
}
|
||||
$element.data('$ngControllerController', controller);
|
||||
$element.children().data('$ngControllerController', controller);
|
||||
}
|
||||
|
||||
link(scope);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
})(window, window.angular);
|
20554
fb2docker/web/angular.js
vendored
Normal file
20554
fb2docker/web/angular.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
117
fb2docker/web/app.css
Normal file
117
fb2docker/web/app.css
Normal file
@ -0,0 +1,117 @@
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
|
||||
margin: 0;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
-moz-box-flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
article {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
footer {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
|
||||
text-align: center;
|
||||
background-color: lightgray;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.machine {
|
||||
display: -moz-box;
|
||||
display: flex;
|
||||
|
||||
border-radius: 6px;
|
||||
padding: 1em;
|
||||
margin: 1em 0;
|
||||
|
||||
background-color: beige;
|
||||
color: #333366;
|
||||
|
||||
position: relative;
|
||||
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.machine .status {
|
||||
font-size: larger;
|
||||
font-weight: bold;
|
||||
|
||||
align-self: center;
|
||||
height: 64px;
|
||||
line-height: 64px;
|
||||
|
||||
margin-right: 16px;
|
||||
padding-right: 72px;
|
||||
background-size: 64px 64px;
|
||||
background-position: center right;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.task-failed {
|
||||
color: red
|
||||
}
|
||||
|
||||
.machine.good {
|
||||
background-color: lightgreen;
|
||||
}
|
||||
|
||||
.machine.bad {
|
||||
background-color: salmon;
|
||||
}
|
||||
|
||||
.machine.good .status {
|
||||
background-image: url(images/build-good.svg);
|
||||
}
|
||||
|
||||
.machine.bad .status {
|
||||
background-image: url(images/build-bad.svg);
|
||||
}
|
||||
|
||||
.app {
|
||||
padding: 1em;
|
||||
float: left;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.app .icon, .app .icon img {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.app .emblem {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
.app.good .emblem {
|
||||
background-image: url(images/app-good.png);
|
||||
}
|
22
fb2docker/web/app.js
Normal file
22
fb2docker/web/app.js
Normal file
@ -0,0 +1,22 @@
|
||||
(function(exports) {
|
||||
'use strict';
|
||||
|
||||
var fb2docker = angular.module('fb2docker', [
|
||||
'ngRoute',
|
||||
'fb2dockerControllers',
|
||||
]);
|
||||
|
||||
fb2docker.config(['$routeProvider', function($routeProvider) {
|
||||
$routeProvider.
|
||||
when('/', {
|
||||
templateUrl: 'partials/home.html'
|
||||
}).
|
||||
when('/installation', {
|
||||
templateUrl: 'partials/installation.html'
|
||||
}).
|
||||
otherwise({
|
||||
redirectTo: 'partials/unknown.html',
|
||||
});
|
||||
}]);
|
||||
|
||||
})(window);
|
6
fb2docker/web/controllers.js
Normal file
6
fb2docker/web/controllers.js
Normal file
@ -0,0 +1,6 @@
|
||||
(function(exports) {
|
||||
'use strict';
|
||||
|
||||
var fb2dockerControllers = angular.module('fb2dockerControllers', []);
|
||||
|
||||
})(window);
|
BIN
fb2docker/web/fedora-remix.png
Normal file
BIN
fb2docker/web/fedora-remix.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
19
fb2docker/web/index.html
Normal file
19
fb2docker/web/index.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!doctype html>
|
||||
<html ng-app="fb2docker">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link href="app.css" rel="stylesheet">
|
||||
<script src="angular.js"></script>
|
||||
<script src="angular-route.js"></script>
|
||||
<script src="app.js"></script>
|
||||
<script src="controllers.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div ng-view class="content"></div>
|
||||
|
||||
<footer>
|
||||
This site is maintained in the <a href="https://github.com/cgwalters/rpm-ostree">rpm-ostree</a> git module.
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
35
fb2docker/web/partials/home.html
Normal file
35
fb2docker/web/partials/home.html
Normal file
@ -0,0 +1,35 @@
|
||||
<article>
|
||||
<h1>B2Docker Fedora Remix</h1>
|
||||
<blockquote>A fast moving, minimized operating system acting as a
|
||||
<a href="http://www.docker.io/">Docker</a> host.</blockquote>
|
||||
<img src="fedora-remix.png">
|
||||
<h3>Features</h3>
|
||||
<ul>
|
||||
<li>Tracking latest Docker builds and testing</li>
|
||||
<li>Built using Fedora RPM technology on the server side for a
|
||||
known base, but
|
||||
with <a href="http://live.gnome.org/Projects/OSTree">OSTree</a>
|
||||
on the client side for <i>fully atomic</i> upgrades.
|
||||
</li>
|
||||
<li>A familiar Unix environment, with a writable <tt>etc</tt></li>
|
||||
<li>The ability to choose between multiple variant trees, with
|
||||
additional RPM content.</li>
|
||||
</ul>
|
||||
<h3>Installation</h3>
|
||||
<p>The latest release is 20140131.0.</p>
|
||||
<p>QEMU (qcow2):</p>
|
||||
<p>VirtualBox: </p>
|
||||
<p>Vagrant: </p>
|
||||
<p>Inside the system, use <tt>ostree admin upgrade</tt> to download
|
||||
the latest code, and then <tt>reboot</tt>. Upgrades are GPG
|
||||
signed for security.
|
||||
</p>
|
||||
<h3>News</h3>
|
||||
<p>Fri Jan 31 21:44:57 UTC 2014: Project is created.</p>
|
||||
<h3>Source code</h3>
|
||||
<p>All source code used for this project
|
||||
is <a href="https://www.gnu.org/philosophy/free-sw.html">Free
|
||||
Software</a>. You can find
|
||||
the <a href="https://github.com/cgwalters/rpm-ostree">build server
|
||||
source</a> here.</p>
|
||||
</article>
|
132
fb2docker/web/partials/installation.html
Normal file
132
fb2docker/web/partials/installation.html
Normal file
@ -0,0 +1,132 @@
|
||||
<article>
|
||||
<h1>Installation</h1>
|
||||
<p>It is recommended currently to only use fedostree inside a
|
||||
non-essential, disposable virtual machine (or a similar physical
|
||||
machine). While OSTree is carefully engineered to be safe, there
|
||||
is the fact that at the moment the binaries are not GPG signed
|
||||
nor is TLS not provided on the current server.
|
||||
</p>
|
||||
<h3>Installation instructions (install preconfigured VM)</h3>
|
||||
<p>If you just want to experiment with complete safety, a prebuilt
|
||||
VM image is provided <a href="http://rpm-ostree.cloud.fedoraproject.org/images/">here</a>.
|
||||
It's called <tt>fedostree-f20-demo.img.xz</tt>. To install, you must
|
||||
first uncompress it with <tt>xz -d fedostree-f20-demo.img.xz</tt>. Then
|
||||
using e.g. <tt>virt-manager</tt>, choose "Import existing disk image".
|
||||
</p>
|
||||
<p>IMPORTANT: This system contains <b>both</b> a traditional Fedora
|
||||
install and an OSTree root. To try out fedostree, you must (at
|
||||
present) run through the <tt>bls_import</tt> step at the GRUB
|
||||
commandline <emphasis>every</emphasis> time you boot to reveal the
|
||||
additional OSTree-generated boot entries. Otherwise, you will be
|
||||
booting the (quite ordinary) Fedora install.
|
||||
</p>
|
||||
<p>Log in to the VM as root - there is no password.</p>
|
||||
<p>Skip to <b>Booting the system</b> below.</p>
|
||||
<h3>Installation instructions (inside an existing OS)</h3>
|
||||
<p>First, you should understand what you'll be doing here. OSTree
|
||||
allows dynamically parallel installing operating systems;
|
||||
(almost) all of its data goes in the new toplevel
|
||||
directory <tt>/ostree</tt>. At the end you will have a dual
|
||||
boot.
|
||||
</p>
|
||||
<p>Install the ostree package, and make sure you have ostree 2013.7
|
||||
or newer.</p>
|
||||
<pre>
|
||||
yum install ostree
|
||||
</pre>
|
||||
<p>
|
||||
This bit of one time initialization will both
|
||||
create <tt>/ostree</tt> for you, as well
|
||||
as <tt>/ostree/deploy/fedostree</tt>. Only a few directories are
|
||||
created, we haven't really affected the system much yet.
|
||||
</p>
|
||||
<pre>
|
||||
ostree admin os-init fedostree
|
||||
</pre>
|
||||
<p>This step tells OSTree how to find the repository you built on
|
||||
the server. You only need to do this once.</p>
|
||||
<pre>
|
||||
ostree remote add --set=gpg-verify=false fedostree http://rpm-ostree.cloud.fedoraproject.org/repo
|
||||
</pre>
|
||||
<p>We still have only initialized configuration. This next step
|
||||
will just download (but not install) a "minimal" system (just
|
||||
@core):</p>
|
||||
<pre>
|
||||
ostree pull fedostree fedostree/20/x86_64/base/minimal
|
||||
</pre>
|
||||
<p>This step extracts the root filesystem, and updates the bootloader
|
||||
configuration:</p>
|
||||
<pre>
|
||||
ostree admin deploy --os=fedostree fedostree:fedostree/20/x86_64/base/minimal
|
||||
</pre>
|
||||
<p>We need to do some initial setup before we actually boot the system.
|
||||
Copy in the storage configuration:</p>
|
||||
<pre>
|
||||
cp /etc/fstab /ostree/deploy/fedostree/current/etc
|
||||
</pre>
|
||||
<p>And set a root password:</p>
|
||||
<pre>
|
||||
chroot /ostree/deploy/fedostree/current passwd
|
||||
</pre>
|
||||
<p>And there is one final (manual) step: You must copy your system's
|
||||
kernel arguments from <tt>/boot/grub2/grub.cfg</tt> and add them to
|
||||
<tt>/boot/loader/entries/ostree-fedora-0.conf</tt>, on the <tt>options</tt>
|
||||
line. This step may be automated further in the future.
|
||||
</p>
|
||||
<p>
|
||||
IMPORTANT NOTE: You must use <tt>selinux=0</tt> for now.
|
||||
</p>
|
||||
<h3 id="booting">Booting the system</h3>
|
||||
<p>Your system now contains <b>both</b> a traditional Fedora install
|
||||
and an OSTree root. There is no impact on your installed system
|
||||
except for additional disk space in the <tt>/boot/loader</tt> and <tt>/ostree</tt>
|
||||
directories.
|
||||
</p>
|
||||
<p>At the GRUB prompt, instead of choosing one of the two listed
|
||||
entries, press <tt>c</tt> to get a command line. Now, enter:</p>
|
||||
<pre>
|
||||
bls_import
|
||||
</pre>
|
||||
<p>Then press <tt>Esc</tt>. You should have an additional boot menu entry,
|
||||
named <tt>ostree:fedora:0</tt>. Nagivate to it and press <tt>Enter</tt>.</p>
|
||||
|
||||
<h3>Inside the system</h3>
|
||||
<p>To upgrade, run as root</p>
|
||||
<pre>
|
||||
ostree admin upgrade
|
||||
</pre>
|
||||
<p>Although <tt>yum</tt> is installed, it will operate in read-only
|
||||
mode. Do not attempt to use it at the moment. See the section
|
||||
on the homepage "Development area: Local package assembly".</p>
|
||||
|
||||
<p>But with OSTree, it's possible to atomically transition between
|
||||
different complete bootable filesystem trees. Let's now try the
|
||||
<tt>standard-docker-io</tt> tree:</p>
|
||||
<pre>
|
||||
ostree pull fedostree fedostree/20/x86_64/server/docker-io
|
||||
</pre>
|
||||
<p>If you look at the <a href="https://github.com/cgwalters/rpm-ostree/blob/master/fedostree/products.json">products.json</a> script
|
||||
you can see this tree contains <tt>@core</tt>, <tt>@standard</tt>, and finally
|
||||
<tt>docker-io</tt>.
|
||||
</p>
|
||||
<p>Like above, let's now deploy it:</p>
|
||||
<pre>
|
||||
ostree admin deploy --os=fedostree fedostree:fedostree/20/x86_64/server/docker-io
|
||||
systemctl reboot
|
||||
</pre>
|
||||
<p>After you reboot, note two things. First, you'll have <i>two</i>
|
||||
OSTree boot entries. That's because our previous <tt>minimal</tt>
|
||||
tree is still there. Choose the first OSTree boot entry. When you
|
||||
boot into this tree, note that you'll have
|
||||
a <tt>/usr/bin/docker</tt> binary. We have successfully atomically
|
||||
transitioned to a new filesystem tree.
|
||||
</p>
|
||||
<p>Why the triple specification of "fedostree"? First, OSTree
|
||||
allows arbitrarily named "OS"es which have independent /var. You
|
||||
could have two deployments of the same tree, say
|
||||
"feostree-testing" and "fedostree". Second, "fedostree" is the
|
||||
name of the remote. Third, a naming convention for refs includes
|
||||
an OS name prefix at the front, here "fedostree". Some or all of
|
||||
these may be different.
|
||||
</p>
|
||||
</article>
|
Loading…
Reference in New Issue
Block a user